volume snapshot
This commit is contained in:
@@ -387,6 +387,25 @@ func (s *APIServer) waitForResourceSync(stopCh <-chan struct{}) error {
|
||||
appInformerFactory.Start(stopCh)
|
||||
appInformerFactory.WaitForCacheSync(stopCh)
|
||||
|
||||
snapshotInformerFactory := s.InformerFactory.SnapshotSharedInformerFactory()
|
||||
snapshotGVRs := []schema.GroupVersionResource{
|
||||
{Group: "snapshot.storage.k8s.io", Version: "v1beta1", Resource: "volumesnapshotclasses"},
|
||||
{Group: "snapshot.storage.k8s.io", Version: "v1beta1", Resource: "volumesnapshots"},
|
||||
{Group: "snapshot.storage.k8s.io", Version: "v1beta1", Resource: "volumesnapshotcontents"},
|
||||
}
|
||||
for _, gvr := range snapshotGVRs {
|
||||
if !isResourceExists(gvr) {
|
||||
klog.Warningf("resource %s not exists in the cluster", gvr)
|
||||
} else {
|
||||
_, err = snapshotInformerFactory.ForResource(gvr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
snapshotInformerFactory.Start(stopCh)
|
||||
snapshotInformerFactory.WaitForCacheSync(stopCh)
|
||||
|
||||
klog.V(0).Info("Finished caching objects")
|
||||
|
||||
return nil
|
||||
|
||||
@@ -231,7 +231,7 @@ resources_in_cluster1 {
|
||||
|
||||
ksClient := fake.NewSimpleClientset()
|
||||
k8sClient := fakek8s.NewSimpleClientset()
|
||||
factory := factory.NewInformerFactories(k8sClient, ksClient, nil, nil)
|
||||
factory := factory.NewInformerFactories(k8sClient, ksClient, nil, nil, nil)
|
||||
for _, role := range globalRoles {
|
||||
err := factory.KubeSphereSharedInformerFactory().Iam().V1alpha2().GlobalRoles().Informer().GetIndexer().Add(role)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ package authorizerfactory
|
||||
import (
|
||||
"errors"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fakesnapshot "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned/fake"
|
||||
fakeapp "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
@@ -240,7 +241,9 @@ func newMockRBACAuthorizer(staticRoles *StaticRoles) (*RBACAuthorizer, error) {
|
||||
k8sClient := fakek8s.NewSimpleClientset()
|
||||
istioClient := fakeistio.NewSimpleClientset()
|
||||
appClient := fakeapp.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
|
||||
snapshotClient := fakesnapshot.NewSimpleClientset()
|
||||
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient, snapshotClient)
|
||||
|
||||
k8sInformerFactory := fakeInformerFactory.KubernetesSharedInformerFactory()
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package informers
|
||||
|
||||
import (
|
||||
snapshotclient "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
|
||||
snapshotinformer "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
applicationclient "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
|
||||
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
|
||||
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
||||
@@ -39,19 +41,22 @@ type InformerFactory interface {
|
||||
KubeSphereSharedInformerFactory() ksinformers.SharedInformerFactory
|
||||
IstioSharedInformerFactory() istioinformers.SharedInformerFactory
|
||||
ApplicationSharedInformerFactory() applicationinformers.SharedInformerFactory
|
||||
SnapshotSharedInformerFactory() snapshotinformer.SharedInformerFactory
|
||||
|
||||
// Start shared informer factory one by one if they are not nil
|
||||
Start(stopCh <-chan struct{})
|
||||
}
|
||||
|
||||
type informerFactories struct {
|
||||
informerFactory k8sinformers.SharedInformerFactory
|
||||
ksInformerFactory ksinformers.SharedInformerFactory
|
||||
istioInformerFactory istioinformers.SharedInformerFactory
|
||||
appInformerFactory applicationinformers.SharedInformerFactory
|
||||
informerFactory k8sinformers.SharedInformerFactory
|
||||
ksInformerFactory ksinformers.SharedInformerFactory
|
||||
istioInformerFactory istioinformers.SharedInformerFactory
|
||||
appInformerFactory applicationinformers.SharedInformerFactory
|
||||
snapshotInformerFactory snapshotinformer.SharedInformerFactory
|
||||
}
|
||||
|
||||
func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interface, istioClient istioclient.Interface, appClient applicationclient.Interface) InformerFactory {
|
||||
func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interface, istioClient istioclient.Interface,
|
||||
appClient applicationclient.Interface, snapshotClient snapshotclient.Interface) InformerFactory {
|
||||
factory := &informerFactories{}
|
||||
|
||||
if client != nil {
|
||||
@@ -70,6 +75,10 @@ func NewInformerFactories(client kubernetes.Interface, ksClient versioned.Interf
|
||||
factory.istioInformerFactory = istioinformers.NewSharedInformerFactory(istioClient, defaultResync)
|
||||
}
|
||||
|
||||
if snapshotClient != nil {
|
||||
factory.snapshotInformerFactory = snapshotinformer.NewSharedInformerFactory(snapshotClient, defaultResync)
|
||||
}
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
@@ -89,6 +98,10 @@ func (f *informerFactories) IstioSharedInformerFactory() istioinformers.SharedIn
|
||||
return f.istioInformerFactory
|
||||
}
|
||||
|
||||
func (f *informerFactories) SnapshotSharedInformerFactory() snapshotinformer.SharedInformerFactory {
|
||||
return f.snapshotInformerFactory
|
||||
}
|
||||
|
||||
func (f *informerFactories) Start(stopCh <-chan struct{}) {
|
||||
if f.informerFactory != nil {
|
||||
f.informerFactory.Start(stopCh)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package informers
|
||||
|
||||
import (
|
||||
snapshotinformer "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
appinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions"
|
||||
istioinformers "istio.io/client-go/pkg/informers/externalversions"
|
||||
"k8s.io/client-go/informers"
|
||||
@@ -30,5 +31,9 @@ func (n nullInformerFactory) ApplicationSharedInformerFactory() appinformers.Sha
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n nullInformerFactory) SnapshotSharedInformerFactory() snapshotinformer.SharedInformerFactory {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n nullInformerFactory) Start(stopCh <-chan struct{}) {
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestGeranteAgentDeployment(t *testing.T) {
|
||||
k8sclient := fake2.NewSimpleClientset(service)
|
||||
ksclient := fake.NewSimpleClientset(cluster)
|
||||
|
||||
informersFactory := informers.NewInformerFactories(k8sclient, ksclient, nil, nil)
|
||||
informersFactory := informers.NewInformerFactories(k8sclient, ksclient, nil, nil, nil)
|
||||
|
||||
informersFactory.KubernetesSharedInformerFactory().Core().V1().Services().Informer().GetIndexer().Add(service)
|
||||
informersFactory.KubeSphereSharedInformerFactory().Cluster().V1alpha1().Clusters().Informer().GetIndexer().Add(cluster)
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1alpha3
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fakesnapshot "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned/fake"
|
||||
fakeapp "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
|
||||
fakeistio "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -164,7 +165,9 @@ func prepare() (informers.InformerFactory, error) {
|
||||
k8sClient := fakek8s.NewSimpleClientset()
|
||||
istioClient := fakeistio.NewSimpleClientset()
|
||||
appClient := fakeapp.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
|
||||
snapshotClient := fakesnapshot.NewSimpleClientset()
|
||||
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient, snapshotClient)
|
||||
|
||||
k8sInformerFactory := fakeInformerFactory.KubernetesSharedInformerFactory()
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package persistentvolumeclaim
|
||||
|
||||
import (
|
||||
snapshotinformer "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
"k8s.io/client-go/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"strconv"
|
||||
@@ -36,11 +37,15 @@ const (
|
||||
)
|
||||
|
||||
type persistentVolumeClaimSearcher struct {
|
||||
informers informers.SharedInformerFactory
|
||||
informers informers.SharedInformerFactory
|
||||
snapshotInformers snapshotinformer.SharedInformerFactory
|
||||
}
|
||||
|
||||
func NewPersistentVolumeClaimSearcher(informers informers.SharedInformerFactory) v1alpha2.Interface {
|
||||
return &persistentVolumeClaimSearcher{informers: informers}
|
||||
func NewPersistentVolumeClaimSearcher(informers informers.SharedInformerFactory, snapshotInformer snapshotinformer.SharedInformerFactory) v1alpha2.Interface {
|
||||
return &persistentVolumeClaimSearcher{
|
||||
informers: informers,
|
||||
snapshotInformers: snapshotInformer,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *persistentVolumeClaimSearcher) Get(namespace, name string) (interface{}, error) {
|
||||
@@ -117,11 +122,12 @@ func (s *persistentVolumeClaimSearcher) Search(namespace string, conditions *par
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
inUse := s.countPods(i.Name, i.Namespace)
|
||||
isSnapshotAllow := s.isSnapshotAllowed(i.GetAnnotations()["volume.beta.kubernetes.io/storage-provisioner"])
|
||||
if i.Annotations == nil {
|
||||
i.Annotations = make(map[string]string)
|
||||
}
|
||||
i.Annotations["kubesphere.io/in-use"] = strconv.FormatBool(inUse)
|
||||
|
||||
i.Annotations["kubesphere.io/allow-snapshot"] = strconv.FormatBool(isSnapshotAllow)
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
@@ -142,3 +148,19 @@ func (s *persistentVolumeClaimSearcher) countPods(name, namespace string) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *persistentVolumeClaimSearcher) isSnapshotAllowed(provisioner string) bool {
|
||||
if len(provisioner) == 0 {
|
||||
return false
|
||||
}
|
||||
volumeSnapshotClasses, err := s.snapshotInformers.Snapshot().V1beta1().VolumeSnapshotClasses().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, volumeSnapshotClass := range volumeSnapshotClasses {
|
||||
if volumeSnapshotClass.Driver == provisioner {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package resource
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fakesnapshot "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned/fake"
|
||||
fakeapp "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
|
||||
fakeistio "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -215,7 +216,8 @@ func prepare() (informers.InformerFactory, error) {
|
||||
k8sClient := fakek8s.NewSimpleClientset()
|
||||
istioClient := fakeistio.NewSimpleClientset()
|
||||
appClient := fakeapp.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
|
||||
snapshotClient := fakesnapshot.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient, snapshotClient)
|
||||
|
||||
k8sInformerFactory := fakeInformerFactory.KubernetesSharedInformerFactory()
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
|
||||
resourceGetters[v1alpha2.Deployments] = deployment.NewDeploymentSetSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.Ingresses] = ingress.NewIngressSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.Jobs] = job.NewJobSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.PersistentVolumeClaims] = persistentvolumeclaim.NewPersistentVolumeClaimSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.PersistentVolumeClaims] = persistentvolumeclaim.NewPersistentVolumeClaimSearcher(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.Secrets] = secret.NewSecretSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.Services] = service.NewServiceSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.StatefulSets] = statefulset.NewStatefulSetSearcher(factory.KubernetesSharedInformerFactory())
|
||||
@@ -79,7 +79,7 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
|
||||
resourceGetters[v1alpha2.Nodes] = node.NewNodeSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.Namespaces] = namespace.NewNamespaceSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.ClusterRoles] = clusterrole.NewClusterRoleSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.StorageClasses] = storageclass.NewStorageClassesSearcher(factory.KubernetesSharedInformerFactory(), factory.SnapshotSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.HorizontalPodAutoscalers] = hpa.NewHpaSearcher(factory.KubernetesSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.S2iBuilders] = s2ibuilder.NewS2iBuilderSearcher(factory.KubeSphereSharedInformerFactory())
|
||||
resourceGetters[v1alpha2.S2iRuns] = s2irun.NewS2iRunSearcher(factory.KubeSphereSharedInformerFactory())
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package storageclass
|
||||
|
||||
import (
|
||||
snapshotinformer "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -25,14 +26,19 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type storageClassesSearcher struct {
|
||||
informers informers.SharedInformerFactory
|
||||
informers informers.SharedInformerFactory
|
||||
snapshotInformers snapshotinformer.SharedInformerFactory
|
||||
}
|
||||
|
||||
func NewStorageClassesSearcher(informers informers.SharedInformerFactory) v1alpha2.Interface {
|
||||
return &storageClassesSearcher{informers: informers}
|
||||
func NewStorageClassesSearcher(informers informers.SharedInformerFactory, snapshotInformer snapshotinformer.SharedInformerFactory) v1alpha2.Interface {
|
||||
return &storageClassesSearcher{
|
||||
informers: informers,
|
||||
snapshotInformers: snapshotInformer,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *storageClassesSearcher) Get(namespace, name string) (interface{}, error) {
|
||||
@@ -85,9 +91,11 @@ func (s *storageClassesSearcher) Search(namespace string, conditions *params.Con
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
count := s.countPersistentVolumeClaims(i.Name)
|
||||
isSnapshotAllow := s.isSnapshotAllowed(i.Provisioner)
|
||||
if i.Annotations == nil {
|
||||
i.Annotations = make(map[string]string)
|
||||
i.Annotations["kubesphere.io/pvc-count"] = string(count)
|
||||
i.Annotations["kubesphere.io/allow-snapshot"] = strconv.FormatBool(isSnapshotAllow)
|
||||
}
|
||||
|
||||
r = append(r, i)
|
||||
@@ -110,3 +118,20 @@ func (s *storageClassesSearcher) countPersistentVolumeClaims(name string) int {
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (s *storageClassesSearcher) isSnapshotAllowed(provisioner string) bool {
|
||||
if len(provisioner) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
volumeSnapshotClasses, err := s.snapshotInformers.Snapshot().V1beta1().VolumeSnapshotClasses().Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, volumeSnapshotClass := range volumeSnapshotClasses {
|
||||
if volumeSnapshotClass.Driver == provisioner {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package resource
|
||||
|
||||
import (
|
||||
"errors"
|
||||
snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/pod"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/role"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/user"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/volumesnapshot"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspace"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/workspacerole"
|
||||
)
|
||||
@@ -64,7 +66,7 @@ func NewResourceGetter(factory informers.InformerFactory) *ResourceGetter {
|
||||
getters[iamv1alpha2.SchemeGroupVersion.WithResource(iamv1alpha2.ResourcesPluralUser)] = user.New(factory.KubeSphereSharedInformerFactory())
|
||||
getters[rbacv1.SchemeGroupVersion.WithResource("roles")] = role.New(factory.KubernetesSharedInformerFactory())
|
||||
getters[rbacv1.SchemeGroupVersion.WithResource("clusterroles")] = clusterrole.New(factory.KubernetesSharedInformerFactory())
|
||||
|
||||
getters[snapshotv1beta1.SchemeGroupVersion.WithResource("volumesnapshots")] = volumesnapshot.New(factory.SnapshotSharedInformerFactory())
|
||||
return &ResourceGetter{
|
||||
getters: getters,
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package resource
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
fakesnapshot "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned/fake"
|
||||
fakeapp "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned/fake"
|
||||
fakeistio "istio.io/client-go/pkg/clientset/versioned/fake"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -108,7 +109,8 @@ func prepare() *ResourceGetter {
|
||||
k8sClient := fakek8s.NewSimpleClientset()
|
||||
istioClient := fakeistio.NewSimpleClientset()
|
||||
appClient := fakeapp.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient)
|
||||
snapshotClient := fakesnapshot.NewSimpleClientset()
|
||||
fakeInformerFactory := informers.NewInformerFactories(k8sClient, ksClient, istioClient, appClient, snapshotClient)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
fakeInformerFactory.KubernetesSharedInformerFactory().Core().V1().
|
||||
|
||||
106
pkg/models/resources/v1alpha3/volumesnapshot/volumesnapshot.go
Normal file
106
pkg/models/resources/v1alpha3/volumesnapshot/volumesnapshot.go
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 volumesnapshot
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
|
||||
)
|
||||
|
||||
const (
|
||||
statusCreating = "creating"
|
||||
statusReady = "ready"
|
||||
|
||||
volumeSnapshotClassName = "volumeSnapshotClassName"
|
||||
persistentVolumeClaimName = "persistentVolumeClaimName"
|
||||
)
|
||||
|
||||
type volumeSnapshotGetter struct {
|
||||
informer externalversions.SharedInformerFactory
|
||||
}
|
||||
|
||||
func New(informer externalversions.SharedInformerFactory) v1alpha3.Interface {
|
||||
return &volumeSnapshotGetter{informer: informer}
|
||||
}
|
||||
|
||||
func (v *volumeSnapshotGetter) Get(namespace, name string) (runtime.Object, error) {
|
||||
return v.informer.Snapshot().V1beta1().VolumeSnapshots().Lister().VolumeSnapshots(namespace).Get(name)
|
||||
}
|
||||
|
||||
func (v *volumeSnapshotGetter) List(namespace string, query *query.Query) (*api.ListResult, error) {
|
||||
all, err := v.listVolumeSnapshots(namespace, query.Selector())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []runtime.Object
|
||||
for _, app := range all {
|
||||
result = append(result, app)
|
||||
}
|
||||
|
||||
return v1alpha3.DefaultList(result, query, v.compare, v.filter), nil
|
||||
}
|
||||
|
||||
func (v *volumeSnapshotGetter) compare(left, right runtime.Object, field query.Field) bool {
|
||||
leftSnapshot, ok := left.(*v1beta1.VolumeSnapshot)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
rightSnapshot, ok := right.(*v1beta1.VolumeSnapshot)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return v1alpha3.DefaultObjectMetaCompare(leftSnapshot.ObjectMeta, rightSnapshot.ObjectMeta, field)
|
||||
}
|
||||
|
||||
func (v *volumeSnapshotGetter) filter(object runtime.Object, filter query.Filter) bool {
|
||||
snapshot, ok := object.(*v1beta1.VolumeSnapshot)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch filter.Field {
|
||||
case query.FieldStatus:
|
||||
return snapshotStatus(snapshot) == string(filter.Value)
|
||||
case volumeSnapshotClassName:
|
||||
name := snapshot.Spec.VolumeSnapshotClassName
|
||||
return name != nil && *name == string(filter.Value)
|
||||
case persistentVolumeClaimName:
|
||||
name := snapshot.Spec.Source.PersistentVolumeClaimName
|
||||
return name != nil && *name == string(filter.Value)
|
||||
default:
|
||||
return v1alpha3.DefaultObjectMetaFilter(snapshot.ObjectMeta, filter)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *volumeSnapshotGetter) listVolumeSnapshots(namespace string, selector labels.Selector) (ret []*v1beta1.VolumeSnapshot, err error) {
|
||||
return v.informer.Snapshot().V1beta1().VolumeSnapshots().Lister().VolumeSnapshots(namespace).List(selector)
|
||||
}
|
||||
|
||||
func snapshotStatus(item *v1beta1.VolumeSnapshot) string {
|
||||
status := statusCreating
|
||||
if *item.Status.ReadyToUse {
|
||||
status = statusReady
|
||||
}
|
||||
return status
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 volumesnapshot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
||||
"github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned/fake"
|
||||
"github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/informers/externalversions"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
baseVolumeSnapshot = `{
|
||||
"apiVersion": "snapshot.storage.k8s.io/v1beta1",
|
||||
"kind": "VolumeSnapshot",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2020-04-29T06:52:06Z",
|
||||
"finalizers": [
|
||||
"snapshot.storage.kubernetes.io/volumesnapshot-as-source-protection",
|
||||
"snapshot.storage.kubernetes.io/volumesnapshot-bound-protection"
|
||||
],
|
||||
"generation": 1,
|
||||
"name": "snap-1",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "5027277",
|
||||
"selfLink": "/apis/snapshot.storage.k8s.io/v1beta1/namespaces/default/volumesnapshots/snap-1",
|
||||
"uid": "dc66842d-17bf-4087-a8e8-7592d129a956"
|
||||
},
|
||||
"spec": {
|
||||
"source": {
|
||||
"persistentVolumeClaimName": "pvc-source"
|
||||
},
|
||||
"volumeSnapshotClassName": "csi-neonsan"
|
||||
},
|
||||
"status": {
|
||||
"boundVolumeSnapshotContentName": "snapcontent-dc66842d-17bf-4087-a8e8-7592d129a956",
|
||||
"creationTime": "2020-04-29T06:52:06Z",
|
||||
"readyToUse": true,
|
||||
"restoreSize": "20Gi"
|
||||
}
|
||||
}`
|
||||
defaultNamespace = "default"
|
||||
)
|
||||
|
||||
func newVolumeSnapshot(name string) *v1beta1.VolumeSnapshot {
|
||||
volumeSnapshot := &v1beta1.VolumeSnapshot{}
|
||||
err := json.Unmarshal([]byte(baseVolumeSnapshot), volumeSnapshot)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
volumeSnapshot.Name = name
|
||||
return volumeSnapshot
|
||||
}
|
||||
|
||||
func TestListVolumeSnapshot(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
client := fake.NewSimpleClientset()
|
||||
informer := externalversions.NewSharedInformerFactory(client, 0)
|
||||
|
||||
pvcName1, pvcName2, pvcName3 := "pvc-1", "pvc-2", "pvc-3"
|
||||
snapshot1 := newVolumeSnapshot("snap-1")
|
||||
snapshot1.CreationTimestamp = v1.NewTime(snapshot1.CreationTimestamp.Add(time.Hour * 3))
|
||||
snapshot1.Spec.Source.PersistentVolumeClaimName = &pvcName1
|
||||
|
||||
snapshot2 := newVolumeSnapshot("snap-2")
|
||||
snapshot2.CreationTimestamp = v1.NewTime(snapshot2.CreationTimestamp.Add(time.Hour * 2))
|
||||
snapshot2.Spec.Source.PersistentVolumeClaimName = &pvcName2
|
||||
|
||||
snapshot3 := newVolumeSnapshot("snap-3")
|
||||
snapshot3.CreationTimestamp = v1.NewTime(snapshot3.CreationTimestamp.Add(time.Hour))
|
||||
snapshot3.Spec.Source.PersistentVolumeClaimName = &pvcName3
|
||||
readyToUse := false
|
||||
snapshot3.Status.ReadyToUse = &readyToUse
|
||||
volumeSnapshotClassNameTest := "csi.aws.com"
|
||||
snapshot3.Spec.VolumeSnapshotClassName = &volumeSnapshotClassNameTest
|
||||
|
||||
volumeSnapshots := []interface{}{snapshot1, snapshot2, snapshot3}
|
||||
|
||||
for _, s := range volumeSnapshots {
|
||||
_ = informer.Snapshot().V1beta1().VolumeSnapshots().Informer().GetIndexer().Add(s)
|
||||
}
|
||||
getter := New(informer)
|
||||
|
||||
Describe("condition", func() {
|
||||
It("match name", func() {
|
||||
query1 := query.New()
|
||||
query1.Filters[query.FieldName] = query.Value(snapshot1.Name)
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(1))
|
||||
Expect(snapshotList.Items[0]).To(Equal(snapshot1))
|
||||
})
|
||||
|
||||
It("match persistentVolumeClaimName", func() {
|
||||
query1 := query.New()
|
||||
query1.Filters[persistentVolumeClaimName] = query.Value(*snapshot2.Spec.Source.PersistentVolumeClaimName)
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(1))
|
||||
Expect(snapshotList.Items[0]).To(Equal(snapshot2))
|
||||
})
|
||||
|
||||
It("match status", func() {
|
||||
query1 := query.New()
|
||||
query1.Filters[query.FieldStatus] = query.Value(statusCreating)
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(1))
|
||||
Expect(snapshotList.Items[0]).To(Equal(snapshot3))
|
||||
})
|
||||
|
||||
It("match volumeSnapshotClassName", func() {
|
||||
query1 := query.New()
|
||||
query1.Filters[volumeSnapshotClassName] = query.Value(*snapshot3.Spec.VolumeSnapshotClassName)
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(1))
|
||||
Expect(snapshotList.Items[0]).To(Equal(snapshot3))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Describe("order", func() {
|
||||
It("by createTime ", func() {
|
||||
query1 := query.New()
|
||||
query1.SortBy = query.FieldCreateTime
|
||||
query1.Ascending = true
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(3))
|
||||
Expect(snapshotList.Items[0].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot3.Name))
|
||||
Expect(snapshotList.Items[1].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot2.Name))
|
||||
Expect(snapshotList.Items[2].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot1.Name))
|
||||
})
|
||||
|
||||
It("by name", func() {
|
||||
query1 := query.New()
|
||||
query1.SortBy = query.FieldName
|
||||
query1.Ascending = true
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(3))
|
||||
Expect(snapshotList.Items[0].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot1.Name))
|
||||
Expect(snapshotList.Items[1].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot2.Name))
|
||||
Expect(snapshotList.Items[2].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot3.Name))
|
||||
})
|
||||
It("by name and reverse", func() {
|
||||
query1 := query.New()
|
||||
query1.SortBy = query.FieldName
|
||||
query1.Ascending = false
|
||||
snapshotList, err := getter.List(defaultNamespace, query1)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(snapshotList.TotalItems).To(Equal(3))
|
||||
Expect(snapshotList.Items[0].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot3.Name))
|
||||
Expect(snapshotList.Items[1].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot2.Name))
|
||||
Expect(snapshotList.Items[2].(*v1beta1.VolumeSnapshot).Name).To(Equal(snapshot1.Name))
|
||||
})
|
||||
})
|
||||
|
||||
RunSpecs(t, "volume snapshot getter list")
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
snapshotclient "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
|
||||
applicationclientset "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
|
||||
istioclient "istio.io/client-go/pkg/clientset/versioned"
|
||||
"k8s.io/client-go/discovery"
|
||||
@@ -16,6 +17,7 @@ type Client interface {
|
||||
KubeSphere() kubesphere.Interface
|
||||
Istio() istioclient.Interface
|
||||
Application() applicationclientset.Interface
|
||||
Snapshot() snapshotclient.Interface
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
Master() string
|
||||
Config() *rest.Config
|
||||
@@ -35,6 +37,8 @@ type kubernetesClient struct {
|
||||
|
||||
istio istioclient.Interface
|
||||
|
||||
snapshot snapshotclient.Interface
|
||||
|
||||
master string
|
||||
|
||||
config *rest.Config
|
||||
@@ -56,6 +60,7 @@ func NewKubernetesClientOrDie(options *KubernetesOptions) Client {
|
||||
ks: kubesphere.NewForConfigOrDie(config),
|
||||
istio: istioclient.NewForConfigOrDie(config),
|
||||
application: applicationclientset.NewForConfigOrDie(config),
|
||||
snapshot: snapshotclient.NewForConfigOrDie(config),
|
||||
master: config.Host,
|
||||
config: config,
|
||||
}
|
||||
@@ -104,6 +109,11 @@ func NewKubernetesClient(options *KubernetesOptions) (Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k.snapshot, err = snapshotclient.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k.master = options.Master
|
||||
k.config = config
|
||||
|
||||
@@ -130,6 +140,10 @@ func (k *kubernetesClient) Istio() istioclient.Interface {
|
||||
return k.istio
|
||||
}
|
||||
|
||||
func (k *kubernetesClient) Snapshot() snapshotclient.Interface {
|
||||
return k.snapshot
|
||||
}
|
||||
|
||||
// master address used to generate kubeconfig for downloading
|
||||
func (k *kubernetesClient) Master() string {
|
||||
return k.master
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
snapshotclient "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
|
||||
application "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
|
||||
istio "istio.io/client-go/pkg/clientset/versioned"
|
||||
"k8s.io/client-go/discovery"
|
||||
@@ -32,6 +33,10 @@ func (n nullClient) Application() application.Interface {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n nullClient) Snapshot() snapshotclient.Interface {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n nullClient) Discovery() discovery.DiscoveryInterface {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user