diff --git a/pkg/models/resources/v1alpha3/resource/resource.go b/pkg/models/resources/v1alpha3/resource/resource.go index 7e0a04a65..f6da869c0 100644 --- a/pkg/models/resources/v1alpha3/resource/resource.go +++ b/pkg/models/resources/v1alpha3/resource/resource.go @@ -19,6 +19,8 @@ package resource import ( "errors" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/volumesnapshotcontent" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/volumesnapshotclass" "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/persistentvolume" @@ -118,6 +120,7 @@ func NewResourceGetter(factory informers.InformerFactory, cache cache.Cache) *Re namespacedResourceGetters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaims"}] = persistentvolumeclaim.New(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory()) namespacedResourceGetters[snapshotv1.SchemeGroupVersion.WithResource("volumesnapshots")] = volumesnapshot.New(factory.SnapshotSharedInformerFactory()) clusterResourceGetters[snapshotv1.SchemeGroupVersion.WithResource("volumesnapshotclasses")] = volumesnapshotclass.New(factory.SnapshotSharedInformerFactory()) + clusterResourceGetters[snapshotv1.SchemeGroupVersion.WithResource("volumesnapshotcontents")] = volumesnapshotcontent.New(factory.SnapshotSharedInformerFactory()) namespacedResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralRoleBinding)] = rolebinding.New(factory.KubernetesSharedInformerFactory()) namespacedResourceGetters[rbacv1.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralRole)] = role.New(factory.KubernetesSharedInformerFactory()) clusterResourceGetters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "nodes"}] = node.New(factory.KubernetesSharedInformerFactory()) diff --git a/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent.go b/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent.go new file mode 100644 index 000000000..9da9b0e4d --- /dev/null +++ b/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent.go @@ -0,0 +1,76 @@ +package volumesnapshotcontent + +import ( + "strings" + + v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1" + "github.com/kubernetes-csi/external-snapshotter/client/v4/informers/externalversions" + + "k8s.io/apimachinery/pkg/runtime" + + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" +) + +const ( + volumeSnapshotClassName = "volumeSnapshotClassName" + volumeSnapshotName = "volumeSnapshotName" + volumeSnapshotNameSpace = "volumeSnapshotNamespace" +) + +type volumesnapshotcontentGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informer externalversions.SharedInformerFactory) v1alpha3.Interface { + return &volumesnapshotcontentGetter{informers: informer} +} + +func (v *volumesnapshotcontentGetter) Get(namespace, name string) (runtime.Object, error) { + return v.informers.Snapshot().V1().VolumeSnapshotContents().Lister().Get(name) +} + +func (v *volumesnapshotcontentGetter) List(namespace string, query *query.Query) (*api.ListResult, error) { + all, err := v.informers.Snapshot().V1().VolumeSnapshotContents().Lister().List(query.Selector()) + if err != nil { + return nil, err + } + + var result []runtime.Object + for _, snapshotContent := range all { + result = append(result, snapshotContent) + } + + return v1alpha3.DefaultList(result, query, v.compare, v.filter), nil +} + +func (v *volumesnapshotcontentGetter) compare(left, right runtime.Object, field query.Field) bool { + leftSnapshotContent, ok := left.(*v1.VolumeSnapshotContent) + if !ok { + return false + } + rightSnapshotContent, ok := right.(*v1.VolumeSnapshotContent) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaCompare(leftSnapshotContent.ObjectMeta, rightSnapshotContent.ObjectMeta, field) +} + +func (v *volumesnapshotcontentGetter) filter(object runtime.Object, filter query.Filter) bool { + snapshotcontent, ok := object.(*v1.VolumeSnapshotContent) + if !ok { + return false + } + + switch filter.Field { + case volumeSnapshotClassName: + return strings.EqualFold(*snapshotcontent.Spec.VolumeSnapshotClassName, string(filter.Value)) + case volumeSnapshotName: + return strings.EqualFold(snapshotcontent.Spec.VolumeSnapshotRef.Name, string(filter.Value)) + case volumeSnapshotNameSpace: + return strings.EqualFold(snapshotcontent.Spec.VolumeSnapshotRef.Namespace, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(snapshotcontent.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent_test.go b/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent_test.go new file mode 100644 index 000000000..bdd88c870 --- /dev/null +++ b/pkg/models/resources/v1alpha3/volumesnapshotcontent/volumesnapshotcontent_test.go @@ -0,0 +1,159 @@ +package volumesnapshotcontent + +import ( + "encoding/json" + "testing" + "time" + + snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1" + "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned/fake" + "github.com/kubernetes-csi/external-snapshotter/client/v4/informers/externalversions" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "kubesphere.io/kubesphere/pkg/apiserver/query" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + baseVolumeSnapshotContent = `{ + "apiVersion": "snapshot.storage.k8s.io/v1", + "kind": "VolumeSnapshotContent", + "metadata": { + "creationTimestamp": "2020-04-29T06:52:06Z", + "finalizers": [ + "snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection" + ], + "generation": 1, + "name": "snapcontent-1", + "resourceVersion": "827984", + "uid": "80dce0bc-67dd-4d87-b91c-e1d4ad7350f3" + }, + "spec": { + "deletionPolicy": "Delete", + "driver": "disk.csi.qingcloud.com", + "source": { + "volumeHandle": "vol-hrguk3bo" + }, + "volumeSnapshotClassName": "csi-qingcloud", + "volumeSnapshotRef": { + "apiVersion": "snapshot.storage.k8s.io/v1", + "kind": "VolumeSnapshot", + "name": "tt", + "namespace": "kubesphere-monitoring-system", + "resourceVersion": "827830", + "uid": "45534028-c659-4dfe-9498-ccc25e03afc2" + } + }, + "status": { + "creationTime": 1638866716000000000, + "readyToUse": true, + "restoreSize": 21474836480, + "snapshotHandle": "ss-83jv1p2a" + } +}` +) + +func newVolumeSnapshotContent(name string) *snapshotv1.VolumeSnapshotContent { + volumeSnapshotContent := &snapshotv1.VolumeSnapshotContent{} + err := json.Unmarshal([]byte(baseVolumeSnapshotContent), volumeSnapshotContent) + if err != nil { + return nil + } + volumeSnapshotContent.Name = name + return volumeSnapshotContent +} + +func TestListVolumeSnapshot(t *testing.T) { + RegisterFailHandler(Fail) + + client := fake.NewSimpleClientset() + informer := externalversions.NewSharedInformerFactory(client, 0) + + snapshotContent1 := newVolumeSnapshotContent("snapshotContent-1") + snapshotContent1.CreationTimestamp = v1.NewTime(snapshotContent1.CreationTimestamp.Add(time.Hour * 3)) + + snapshotContent2 := newVolumeSnapshotContent("snapshotContent-2") + snapshotContent2.CreationTimestamp = v1.NewTime(snapshotContent2.CreationTimestamp.Add(time.Hour * 2)) + targetName := "targetVolumeSnapshotClassName" + snapshotContent2.Spec.VolumeSnapshotClassName = &targetName + + snapshotContent3 := newVolumeSnapshotContent("snapshotContent-3") + snapshotContent3.CreationTimestamp = v1.NewTime(snapshotContent3.CreationTimestamp.Add(time.Hour * 1)) + snapshotContent3.Spec.VolumeSnapshotRef.Name = "target-snapshot" + + snapshotContents := []interface{}{snapshotContent1, snapshotContent2, snapshotContent3} + + for _, s := range snapshotContents { + _ = informer.Snapshot().V1().VolumeSnapshotContents().Informer().GetIndexer().Add(s) + } + getter := New(informer) + + Describe("condition", func() { + It("match name", func() { + query1 := query.New() + query1.Filters[query.FieldName] = query.Value(snapshotContent1.Name) + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.TotalItems).To(Equal(1)) + Expect(snapshotContentList.Items[0]).To(Equal(snapshotContent1)) + }) + + It("match volumeSnapshotClassName", func() { + query1 := query.New() + query1.Filters[volumeSnapshotClassName] = query.Value(*snapshotContent2.Spec.VolumeSnapshotClassName) + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.TotalItems).To(Equal(1)) + Expect(snapshotContentList.Items[0]).To(Equal(snapshotContent2)) + }) + + It("match volumeSnapshotName", func() { + query1 := query.New() + query1.Filters[volumeSnapshotName] = query.Value(snapshotContent3.Spec.VolumeSnapshotRef.Name) + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.TotalItems).To(Equal(1)) + Expect(snapshotContentList.Items[0]).To(Equal(snapshotContent3)) + }) + }) + + Describe("list", func() { + It("by createTime", func() { + query1 := query.New() + query1.SortBy = query.FieldCreateTime + query1.Ascending = true + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.Items[0].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent3.Name)) + Expect(snapshotContentList.Items[1].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent2.Name)) + Expect(snapshotContentList.Items[2].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent1.Name)) + }) + + It("by name", func() { + query1 := query.New() + query1.SortBy = query.FieldName + query1.Ascending = true + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.Items[0].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent1.Name)) + Expect(snapshotContentList.Items[1].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent2.Name)) + Expect(snapshotContentList.Items[2].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent3.Name)) + + }) + + It("by name and reverse", func() { + query1 := query.New() + query1.SortBy = query.FieldName + query1.Ascending = false + snapshotContentList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotContentList.Items[0].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent3.Name)) + Expect(snapshotContentList.Items[1].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent2.Name)) + Expect(snapshotContentList.Items[2].(*snapshotv1.VolumeSnapshotContent).Name).To(Equal(snapshotContent1.Name)) + + }) + }) + RunSpecs(t, "volume snapshot content list") +}