From c29722ce7a4cde3dc0d271ef7b3d5b50034df2ba Mon Sep 17 00:00:00 2001 From: f10atin9 Date: Mon, 27 Dec 2021 13:59:37 +0800 Subject: [PATCH] add snapshotclass Signed-off-by: f10atin9 --- .../resources/v1alpha3/resource/resource.go | 3 + .../volumesnapshotclass.go | 88 ++++++++++ .../volumesnapshotclass_test.go | 150 ++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass.go create mode 100644 pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass_test.go diff --git a/pkg/models/resources/v1alpha3/resource/resource.go b/pkg/models/resources/v1alpha3/resource/resource.go index 24fc7f7ca..7e0a04a65 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/volumesnapshotclass" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/persistentvolume" snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1" @@ -115,6 +117,7 @@ func NewResourceGetter(factory informers.InformerFactory, cache cache.Cache) *Re clusterResourceGetters[schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumes"}] = persistentvolume.New(factory.KubernetesSharedInformerFactory()) 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()) 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/volumesnapshotclass/volumesnapshotclass.go b/pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass.go new file mode 100644 index 000000000..7e480aac6 --- /dev/null +++ b/pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass.go @@ -0,0 +1,88 @@ +/* +Copyright 2021 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volumesnapshotclass + +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 ( + deletionPolicy = "deletionPolicy" + driver = "driver" +) + +type volumeSnapshotClassGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informer externalversions.SharedInformerFactory) v1alpha3.Interface { + return &volumeSnapshotClassGetter{informers: informer} +} + +func (v *volumeSnapshotClassGetter) Get(namespace, name string) (runtime.Object, error) { + return v.informers.Snapshot().V1().VolumeSnapshotClasses().Lister().Get(name) +} + +func (v *volumeSnapshotClassGetter) List(namespace string, query *query.Query) (*api.ListResult, error) { + all, err := v.informers.Snapshot().V1().VolumeSnapshotClasses().Lister().List(query.Selector()) + if err != nil { + return nil, err + } + + var result []runtime.Object + for _, snapshotClass := range all { + result = append(result, snapshotClass) + } + + return v1alpha3.DefaultList(result, query, v.compare, v.filter), nil +} + +func (v *volumeSnapshotClassGetter) compare(left, right runtime.Object, field query.Field) bool { + leftSnapshotClass, ok := left.(*v1.VolumeSnapshotClass) + if !ok { + return false + } + rightSnapshotClass, ok := right.(*v1.VolumeSnapshotClass) + if !ok { + return false + } + return v1alpha3.DefaultObjectMetaCompare(leftSnapshotClass.ObjectMeta, rightSnapshotClass.ObjectMeta, field) +} + +func (v *volumeSnapshotClassGetter) filter(object runtime.Object, filter query.Filter) bool { + snapshotClass, ok := object.(*v1.VolumeSnapshotClass) + if !ok { + return false + } + + switch filter.Field { + case deletionPolicy: + return strings.EqualFold(string(snapshotClass.DeletionPolicy), string(filter.Value)) + case driver: + return strings.EqualFold(snapshotClass.Driver, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(snapshotClass.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass_test.go b/pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass_test.go new file mode 100644 index 000000000..26383a113 --- /dev/null +++ b/pkg/models/resources/v1alpha3/volumesnapshotclass/volumesnapshotclass_test.go @@ -0,0 +1,150 @@ +/* +Copyright 2021 The KubeSphere Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package volumesnapshotclass + +import ( + "encoding/json" + "fmt" + "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" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "kubesphere.io/kubesphere/pkg/apiserver/query" +) + +const ( + baseVolumeSnapshotClass = `{ + "apiVersion": "snapshot.storage.k8s.io/v1", + "deletionPolicy": "Delete", + "driver": "disk.csi.qingcloud.com", + "kind": "VolumeSnapshotClass", + "metadata": { + "creationTimestamp": "2021-12-23T09:53:19Z" + } +}` +) + +func newVolumeSnapshotClass(name string) *snapshotv1.VolumeSnapshotClass { + volumeSnapshotclass := &snapshotv1.VolumeSnapshotClass{} + err := json.Unmarshal([]byte(baseVolumeSnapshotClass), volumeSnapshotclass) + if err != nil { + return nil + } + volumeSnapshotclass.Name = name + return volumeSnapshotclass +} + +func TestListVolumeSnapshotClass(t *testing.T) { + RegisterFailHandler(Fail) + + client := fake.NewSimpleClientset() + informer := externalversions.NewSharedInformerFactory(client, 0) + + snapshotClass1 := newVolumeSnapshotClass("snapshotClass1") + fmt.Println(snapshotClass1.CreationTimestamp) + snapshotClass1.CreationTimestamp = v1.NewTime(snapshotClass1.CreationTimestamp.Add(time.Hour * 1)) + + snapshotClass2 := newVolumeSnapshotClass("snapshotClass2") + snapshotClass2.CreationTimestamp = v1.NewTime(snapshotClass1.CreationTimestamp.Add(time.Hour * 2)) + snapshotClass2.Driver = "target.csi.qingcloud.com" + + snapshotClass3 := newVolumeSnapshotClass("snapshotClass3") + snapshotClass3.CreationTimestamp = v1.NewTime(snapshotClass1.CreationTimestamp.Add(time.Hour * 3)) + snapshotClass3.DeletionPolicy = snapshotv1.VolumeSnapshotContentRetain + + volumeSnapshotClasses := []interface{}{snapshotClass1, snapshotClass2, snapshotClass3} + + for _, s := range volumeSnapshotClasses { + _ = informer.Snapshot().V1().VolumeSnapshotClasses().Informer().GetIndexer().Add(s) + } + getter := New(informer) + + Describe("condition", func() { + It("match name", func() { + query1 := query.New() + query1.Filters[query.FieldName] = query.Value(snapshotClass1.Name) + snapshotClassList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotClassList.TotalItems).To(Equal(1)) + Expect(snapshotClassList.Items[0]).To(Equal(snapshotClass1)) + }) + + It("match driver", func() { + query1 := query.New() + query1.Filters[driver] = query.Value(snapshotClass2.Driver) + snapshotClassList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotClassList.TotalItems).To(Equal(1)) + Expect(snapshotClassList.Items[0]).To(Equal(snapshotClass2)) + }) + + It("match deletionPolicy", func() { + query1 := query.New() + query1.Filters[deletionPolicy] = query.Value("Retain") + snapshotClassList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotClassList.TotalItems).To(Equal(1)) + Expect(snapshotClassList.Items[0]).To(Equal(snapshotClass3)) + }) + + }) + + Describe("order", func() { + It("by createTime ", func() { + query1 := query.New() + query1.SortBy = query.FieldCreateTime + query1.Ascending = true + snapshotClassList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotClassList.TotalItems).To(Equal(3)) + Expect(snapshotClassList.Items[0].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass1.Name)) + Expect(snapshotClassList.Items[1].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass2.Name)) + Expect(snapshotClassList.Items[2].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass3.Name)) + }) + + It("by name", func() { + query1 := query.New() + query1.SortBy = query.FieldName + query1.Ascending = true + snapshotClassList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotClassList.TotalItems).To(Equal(3)) + Expect(snapshotClassList.Items[0].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass1.Name)) + Expect(snapshotClassList.Items[1].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass2.Name)) + Expect(snapshotClassList.Items[2].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass3.Name)) + }) + It("by name and reverse", func() { + query1 := query.New() + query1.SortBy = query.FieldName + query1.Ascending = false + snapshotList, err := getter.List("", query1) + Expect(err).To(BeNil()) + Expect(snapshotList.TotalItems).To(Equal(3)) + Expect(snapshotList.Items[0].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass3.Name)) + Expect(snapshotList.Items[1].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass2.Name)) + Expect(snapshotList.Items[2].(*snapshotv1.VolumeSnapshotClass).Name).To(Equal(snapshotClass1.Name)) + }) + }) + + RunSpecs(t, "volume snapshotclass getter list") +}