diff --git a/Gopkg.lock b/Gopkg.lock index 1b484224b6..a6cea57a7d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -208,7 +208,7 @@ version = "v1.0.0-rc2" [[projects]] - digest = "1:b2a0c30d7f061553bda00f5f2a60507faeee00055ad93a96c83b75557113445a" + digest = "1:459b9594f891e8b707192976d0cb38d723a0ad71ccd81e58cd842807e5919298" name = "github.com/kubernetes-csi/external-snapshotter" packages = [ "pkg/apis/volumesnapshot/v1alpha1", @@ -219,8 +219,8 @@ "pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/fake", ] pruneopts = "" - revision = "bdd3a9bbc88b0c38bbe25e265149532b2219a74a" - version = "v1.0.0-rc3" + revision = "7f0070ed917ebab6e931cfa403e7e3e0e4490138" + version = "v1.0.0-rc4" [[projects]] digest = "1:5cfa5be1a5843dd9fb09cc36a57087748c6aaff22b2e64e1b2fdf8120f7b9332" @@ -856,6 +856,7 @@ "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned", "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/fake", "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/controller", + "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/util", "github.com/spf13/pflag", "google.golang.org/grpc", "google.golang.org/grpc/codes", diff --git a/Gopkg.toml b/Gopkg.toml index 00bfffef08..2e4a873f81 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -38,7 +38,7 @@ [[constraint]] name = "github.com/kubernetes-csi/external-snapshotter" - version = "1.0.0-rc3" + version = "1.0.0-rc4" [[constraint]] name = "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner" diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 0358161d1c..d17036f36d 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -595,7 +595,7 @@ func (p *csiProvisioner) getVolumeContentSource(options controller.VolumeOptions if err != nil { return nil, fmt.Errorf("error getting snapshot %s from api server: %v", options.PVC.Spec.DataSource.Name, err) } - if snapshotObj.Status.Ready == false { + if snapshotObj.Status.ReadyToUse == false { return nil, fmt.Errorf("snapshot %s is not Ready", options.PVC.Spec.DataSource.Name) } diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index b51dd48ba9..3bf7e386a2 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -1290,7 +1290,7 @@ func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, }, Status: crdv1.VolumeSnapshotStatus{ CreationTime: creationTime, - Ready: ready, + ReadyToUse: ready, Error: err, RestoreSize: size, }, diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/Makefile b/vendor/github.com/kubernetes-csi/external-snapshotter/Makefile index fcb0d78b17..4a12664215 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/Makefile +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/Makefile @@ -16,7 +16,7 @@ REGISTRY_NAME=quay.io/k8scsi IMAGE_NAME=csi-snapshotter -IMAGE_VERSION=v1.0.0 +IMAGE_VERSION=v1.0.0-canary IMAGE_TAG=$(REGISTRY_NAME)/$(IMAGE_NAME):$(IMAGE_VERSION) REV=$(shell git describe --long --tags --match='v*' --dirty) diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/setup-csi-snapshotter.yaml b/vendor/github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/setup-csi-snapshotter.yaml index 65484d635f..5381fff814 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/setup-csi-snapshotter.yaml +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/setup-csi-snapshotter.yaml @@ -72,7 +72,7 @@ spec: serviceAccount: csi-snapshotter containers: - name: csi-provisioner - image: quay.io/k8scsi/csi-provisioner:v0.4.0 + image: quay.io/k8scsi/csi-provisioner:v1.0.0 args: - "--provisioner=csi-hostpath" - "--csi-address=$(ADDRESS)" @@ -85,7 +85,7 @@ spec: - name: socket-dir mountPath: /csi - name: csi-snapshotter - image: quay.io/k8scsi/csi-snapshotter:v0.4.0 + image: quay.io/k8scsi/csi-snapshotter:v1.0.0 args: - "--csi-address=$(ADDRESS)" - "--connection-timeout=15s" @@ -97,7 +97,7 @@ spec: - name: socket-dir mountPath: /csi - name: hostpath - image: quay.io/k8scsi/hostpathplugin:v0.4.0 + image: quay.io/k8scsi/hostpathplugin:v1.0.0 args: - "--v=5" - "--endpoint=$(CSI_ENDPOINT)" diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/types.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/types.go index a542090e99..c0740683b5 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/types.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/types.go @@ -96,12 +96,12 @@ type VolumeSnapshotStatus struct { // +optional RestoreSize *resource.Quantity `json:"restoreSize" protobuf:"bytes,2,opt,name=restoreSize"` - // Ready is set to true only if the snapshot is ready to use (e.g., finish uploading if + // ReadyToUse is set to true only if the snapshot is ready to use (e.g., finish uploading if // there is an uploading phase) and also VolumeSnapshot and its VolumeSnapshotContent - // bind correctly with each other. If any of the above condition is not true, Ready is + // bind correctly with each other. If any of the above condition is not true, ReadyToUse is // set to false // +optional - Ready bool `json:"ready" protobuf:"varint,3,opt,name=ready"` + ReadyToUse bool `json:"readyToUse" protobuf:"varint,3,opt,name=readyToUse"` // The last error encountered during create snapshot operation, if any. // This field must only be set by the entity completing the create snapshot @@ -132,6 +132,11 @@ type VolumeSnapshotClass struct { // to the snapshotter. // +optional Parameters map[string]string `json:"parameters,omitempty" protobuf:"bytes,3,rep,name=parameters"` + + // Optional: what happens to a snapshot content when released from its snapshot. + // The default policy is Delete if not specified. + // +optional + DeletionPolicy *DeletionPolicy `json:"deletionPolicy,omitempty" protobuf:"bytes,4,opt,name=deletionPolicy"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -195,6 +200,11 @@ type VolumeSnapshotContentSpec struct { // be used if it is available. // +optional VolumeSnapshotClassName *string `json:"snapshotClassName" protobuf:"bytes,4,opt,name=snapshotClassName"` + + // Optional: what happens to a snapshot content when released from its snapshot. It will be set to Delete by default + // if not specified + // +optional + DeletionPolicy *DeletionPolicy `json:"deletionPolicy" protobuf:"bytes,5,opt,name=deletionPolicy"` } // VolumeSnapshotSource represents the actual location and type of the snapshot. Only one of its members may be specified. @@ -232,3 +242,15 @@ type CSIVolumeSnapshotSource struct { // +optional RestoreSize *int64 `json:"restoreSize,omitempty" protobuf:"bytes,4,opt,name=restoreSize"` } + +// DeletionPolicy describes a policy for end-of-life maintenance of volume snapshot contents +type DeletionPolicy string + +const ( + // VolumeSnapshotContentDelete means the snapshot content will be deleted from Kubernetes on release from its volume snapshot. + VolumeSnapshotContentDelete DeletionPolicy = "Delete" + + // VolumeSnapshotContentRetain means the snapshot will be left in its current state on release from its volume snapshot. + // The default policy is Retain if not specified. + VolumeSnapshotContentRetain DeletionPolicy = "Retain" +) diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/zz_generated.deepcopy.go index 138970018a..baed77c6f1 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1/zz_generated.deepcopy.go @@ -92,6 +92,11 @@ func (in *VolumeSnapshotClass) DeepCopyInto(out *VolumeSnapshotClass) { (*out)[key] = val } } + if in.DeletionPolicy != nil { + in, out := &in.DeletionPolicy, &out.DeletionPolicy + *out = new(DeletionPolicy) + **out = **in + } return } @@ -225,6 +230,11 @@ func (in *VolumeSnapshotContentSpec) DeepCopyInto(out *VolumeSnapshotContentSpec *out = new(string) **out = **in } + if in.DeletionPolicy != nil { + in, out := &in.DeletionPolicy, &out.DeletionPolicy + *out = new(DeletionPolicy) + **out = **in + } return } diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshot.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshot.go index 849ce84088..f383e8073a 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshot.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshot.go @@ -19,6 +19,8 @@ limitations under the License. package v1alpha1 import ( + "time" + v1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1" scheme "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -76,11 +78,16 @@ func (c *volumeSnapshots) Get(name string, options v1.GetOptions) (result *v1alp // List takes label and field selectors, and returns the list of VolumeSnapshots that match those selectors. func (c *volumeSnapshots) List(opts v1.ListOptions) (result *v1alpha1.VolumeSnapshotList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } result = &v1alpha1.VolumeSnapshotList{} err = c.client.Get(). Namespace(c.ns). Resource("volumesnapshots"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Do(). Into(result) return @@ -88,11 +95,16 @@ func (c *volumeSnapshots) List(opts v1.ListOptions) (result *v1alpha1.VolumeSnap // Watch returns a watch.Interface that watches the requested volumeSnapshots. func (c *volumeSnapshots) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } opts.Watch = true return c.client.Get(). Namespace(c.ns). Resource("volumesnapshots"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Watch() } @@ -150,10 +162,15 @@ func (c *volumeSnapshots) Delete(name string, options *v1.DeleteOptions) error { // DeleteCollection deletes a collection of objects. func (c *volumeSnapshots) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } return c.client.Delete(). Namespace(c.ns). Resource("volumesnapshots"). VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). Body(options). Do(). Error() diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotclass.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotclass.go index a38603165c..9e48bd9459 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotclass.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotclass.go @@ -19,6 +19,8 @@ limitations under the License. package v1alpha1 import ( + "time" + v1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1" scheme "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -72,10 +74,15 @@ func (c *volumeSnapshotClasses) Get(name string, options v1.GetOptions) (result // List takes label and field selectors, and returns the list of VolumeSnapshotClasses that match those selectors. func (c *volumeSnapshotClasses) List(opts v1.ListOptions) (result *v1alpha1.VolumeSnapshotClassList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } result = &v1alpha1.VolumeSnapshotClassList{} err = c.client.Get(). Resource("volumesnapshotclasses"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Do(). Into(result) return @@ -83,10 +90,15 @@ func (c *volumeSnapshotClasses) List(opts v1.ListOptions) (result *v1alpha1.Volu // Watch returns a watch.Interface that watches the requested volumeSnapshotClasses. func (c *volumeSnapshotClasses) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } opts.Watch = true return c.client.Get(). Resource("volumesnapshotclasses"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Watch() } @@ -125,9 +137,14 @@ func (c *volumeSnapshotClasses) Delete(name string, options *v1.DeleteOptions) e // DeleteCollection deletes a collection of objects. func (c *volumeSnapshotClasses) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } return c.client.Delete(). Resource("volumesnapshotclasses"). VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). Body(options). Do(). Error() diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotcontent.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotcontent.go index 9855153b9d..11aac51596 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotcontent.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/typed/volumesnapshot/v1alpha1/volumesnapshotcontent.go @@ -19,6 +19,8 @@ limitations under the License. package v1alpha1 import ( + "time" + v1alpha1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1" scheme "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -72,10 +74,15 @@ func (c *volumeSnapshotContents) Get(name string, options v1.GetOptions) (result // List takes label and field selectors, and returns the list of VolumeSnapshotContents that match those selectors. func (c *volumeSnapshotContents) List(opts v1.ListOptions) (result *v1alpha1.VolumeSnapshotContentList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } result = &v1alpha1.VolumeSnapshotContentList{} err = c.client.Get(). Resource("volumesnapshotcontents"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Do(). Into(result) return @@ -83,10 +90,15 @@ func (c *volumeSnapshotContents) List(opts v1.ListOptions) (result *v1alpha1.Vol // Watch returns a watch.Interface that watches the requested volumeSnapshotContents. func (c *volumeSnapshotContents) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } opts.Watch = true return c.client.Get(). Resource("volumesnapshotcontents"). VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). Watch() } @@ -125,9 +137,14 @@ func (c *volumeSnapshotContents) Delete(name string, options *v1.DeleteOptions) // DeleteCollection deletes a collection of objects. func (c *volumeSnapshotContents) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } return c.client.Delete(). Resource("volumesnapshotcontents"). VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). Body(options). Do(). Error() diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/csi_handler.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/csi_handler.go index d703c8e204..9cb065d479 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/csi_handler.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/csi_handler.go @@ -77,7 +77,7 @@ func (handler *csiHandler) DeleteSnapshot(content *crdv1.VolumeSnapshotContent, err := handler.csiConnection.DeleteSnapshot(ctx, content.Spec.CSI.SnapshotHandle, snapshotterCredentials) if err != nil { - return fmt.Errorf("failed to delete snapshot data %s: %q", content.Name, err) + return fmt.Errorf("failed to delete snapshot content %s: %q", content.Name, err) } return nil @@ -92,7 +92,7 @@ func (handler *csiHandler) GetSnapshotStatus(content *crdv1.VolumeSnapshotConten csiSnapshotStatus, timestamp, size, err := handler.csiConnection.GetSnapshotStatus(ctx, content.Spec.CSI.SnapshotHandle) if err != nil { - return false, 0, 0, fmt.Errorf("failed to list snapshot data %s: %q", content.Name, err) + return false, 0, 0, fmt.Errorf("failed to list snapshot content %s: %q", content.Name, err) } return csiSnapshotStatus, timestamp, size, nil diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/framework_test.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/framework_test.go index 7bd2016f93..9a57ca4be7 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/framework_test.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/framework_test.go @@ -166,6 +166,16 @@ type reactorError struct { error error } +func withSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) *crdv1.VolumeSnapshot { + snapshot.ObjectMeta.Finalizers = append(snapshot.ObjectMeta.Finalizers, VolumeSnapshotFinalizer) + return snapshot +} + +func withContentFinalizer(content *crdv1.VolumeSnapshotContent) *crdv1.VolumeSnapshotContent { + content.ObjectMeta.Finalizers = append(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer) + return content +} + // React is a callback called by fake kubeClient from the controller. // In other words, every snapshot/content change performed by the controller ends // here. @@ -744,7 +754,7 @@ func newTestController(kubeClient kubernetes.Interface, clientset clientset.Inte } // newContent returns a new content with given attributes -func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) *crdv1.VolumeSnapshotContent { +func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64, withFinalizer bool) *crdv1.VolumeSnapshotContent { content := crdv1.VolumeSnapshotContent{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -766,6 +776,7 @@ func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToS UID: types.UID(volumeUID), Name: volumeName, }, + DeletionPolicy: deletionPolicy, }, } if boundToSnapshotName != "" { @@ -778,17 +789,20 @@ func newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToS } } + if withFinalizer { + return withContentFinalizer(&content) + } return &content } -func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent { +func newContentArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64, withFinalizer bool) []*crdv1.VolumeSnapshotContent { return []*crdv1.VolumeSnapshotContent{ - newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, size, creationTime), + newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, withFinalizer), } } -func newContentWithUnmatchDriverArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent { - content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, size, creationTime) +func newContentWithUnmatchDriverArray(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName string, deletionPolicy *crdv1.DeletionPolicy, size *int64, creationTime *int64) []*crdv1.VolumeSnapshotContent { + content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, false) content.Spec.VolumeSnapshotSource.CSI.Driver = "fake" return []*crdv1.VolumeSnapshotContent{ content, @@ -814,13 +828,13 @@ func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, }, Status: crdv1.VolumeSnapshotStatus{ CreationTime: creationTime, - Ready: ready, + ReadyToUse: ready, Error: err, RestoreSize: size, }, } - return &snapshot + return withSnapshotFinalizer(&snapshot) } func newSnapshotArray(name, className, boundToContent, snapshotUID, claimName string, ready bool, err *storagev1beta1.VolumeError, creationTime *metav1.Time, size *resource.Quantity) []*crdv1.VolumeSnapshot { diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller.go index f41b8c3d2d..3418b28c8b 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller.go @@ -34,6 +34,7 @@ import ( ref "k8s.io/client-go/tools/reference" "k8s.io/kubernetes/pkg/util/goroutinemap" "k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff" + "k8s.io/kubernetes/pkg/util/slice" ) // ================================================================== @@ -77,6 +78,9 @@ import ( const pvcKind = "PersistentVolumeClaim" const apiGroup = "" +const snapshotKind = "VolumeSnapshot" +const snapshotAPIGroup = crdv1.GroupName + const controllerUpdateFailMsg = "snapshot controller failed to update" const IsDefaultSnapshotClassAnnotation = "snapshot.storage.kubernetes.io/is-default-class" @@ -85,6 +89,23 @@ const IsDefaultSnapshotClassAnnotation = "snapshot.storage.kubernetes.io/is-defa func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotContent) error { glog.V(5).Infof("synchronizing VolumeSnapshotContent[%s]", content.Name) + if isContentDeletionCandidate(content) { + // Volume snapshot content should be deleted. Check if it's used + // and remove finalizer if it's not. + // Check if snapshot content is still bound to a snapshot. + isUsed := ctrl.isSnapshotContentBeingUsed(content) + if !isUsed { + glog.V(5).Infof("syncContent: Remove Finalizer for VolumeSnapshotContent[%s]", content.Name) + return ctrl.removeContentFinalizer(content) + } + } + + if needToAddContentFinalizer(content) { + // Content is not being deleted -> it should have the finalizer. + glog.V(5).Infof("syncContent: Add Finalizer for VolumeSnapshotContent[%s]", content.Name) + return ctrl.addContentFinalizer(content) + } + // VolumeSnapshotContent is not bound to any VolumeSnapshot, in this case we just return err if content.Spec.VolumeSnapshotRef == nil { // content is not bound @@ -125,9 +146,24 @@ func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotCont snapshot = nil } if snapshot == nil { - ctrl.deleteSnapshotContent(content) - } + if content.Spec.DeletionPolicy != nil { + switch *content.Spec.DeletionPolicy { + case crdv1.VolumeSnapshotContentRetain: + glog.V(4).Infof("VolumeSnapshotContent[%s]: policy is Retain, nothing to do", content.Name) + + case crdv1.VolumeSnapshotContentDelete: + glog.V(4).Infof("VolumeSnapshotContent[%s]: policy is Delete", content.Name) + ctrl.deleteSnapshotContent(content) + default: + // Unknown VolumeSnapshotDeletionolicy + ctrl.eventRecorder.Event(content, v1.EventTypeWarning, "SnapshotUnknownDeletionPolicy", "Volume Snapshot Content has unrecognized deletion policy") + } + return nil + } + // By default, we use Retain policy if it is not set by users + glog.V(4).Infof("VolumeSnapshotContent[%s]: by default the policy is Retain", content.Name) + } return nil } @@ -139,7 +175,24 @@ func (ctrl *csiSnapshotController) syncContent(content *crdv1.VolumeSnapshotCont func (ctrl *csiSnapshotController) syncSnapshot(snapshot *crdv1.VolumeSnapshot) error { glog.V(5).Infof("synchonizing VolumeSnapshot[%s]: %s", snapshotKey(snapshot), getSnapshotStatusForLogging(snapshot)) - if !snapshot.Status.Ready { + if isSnapshotDeletionCandidate(snapshot) { + // Volume snapshot should be deleted. Check if it's used + // and remove finalizer if it's not. + // Check if a volume is being created from snapshot. + isUsed := ctrl.isVolumeBeingCreatedFromSnapshot(snapshot) + if !isUsed { + glog.V(5).Infof("syncSnapshot: Remove Finalizer for VolumeSnapshot[%s]", snapshotKey(snapshot)) + return ctrl.removeSnapshotFinalizer(snapshot) + } + } + + if needToAddSnapshotFinalizer(snapshot) { + // Snapshot is not being deleted -> it should have the finalizer. + glog.V(5).Infof("syncSnapshot: Add Finalizer for VolumeSnapshot[%s]", snapshotKey(snapshot)) + return ctrl.addSnapshotFinalizer(snapshot) + } + + if !snapshot.Status.ReadyToUse { return ctrl.syncUnreadySnapshot(snapshot) } else { return ctrl.syncReadySnapshot(snapshot) @@ -364,7 +417,7 @@ func (ctrl *csiSnapshotController) updateSnapshotErrorStatusWithEvent(snapshot * } snapshotClone.Status.Error = statusError - snapshotClone.Status.Ready = false + snapshotClone.Status.ReadyToUse = false newSnapshot, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone) if err != nil { glog.V(4).Infof("updating VolumeSnapshot[%s] error status failed %v", snapshotKey(snapshot), err) @@ -384,7 +437,7 @@ func (ctrl *csiSnapshotController) updateSnapshotErrorStatusWithEvent(snapshot * // Stateless functions func getSnapshotStatusForLogging(snapshot *crdv1.VolumeSnapshot) string { - return fmt.Sprintf("bound to: %q, Completed: %v", snapshot.Spec.SnapshotContentName, snapshot.Status.Ready) + return fmt.Sprintf("bound to: %q, Completed: %v", snapshot.Spec.SnapshotContentName, snapshot.Status.ReadyToUse) } func IsSnapshotBound(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) bool { @@ -395,6 +448,48 @@ func IsSnapshotBound(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapsh return false } +// isSnapshotConentBeingUsed checks if snapshot content is bound to snapshot. +func (ctrl *csiSnapshotController) isSnapshotContentBeingUsed(content *crdv1.VolumeSnapshotContent) bool { + if content.Spec.VolumeSnapshotRef != nil { + snapshotObj, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(content.Spec.VolumeSnapshotRef.Namespace).Get(content.Spec.VolumeSnapshotRef.Name, metav1.GetOptions{}) + if err != nil { + glog.Infof("isSnapshotContentBeingUsed: Cannot get snapshot %s from api server: [%v]. VolumeSnapshot object may be deleted already.", content.Spec.VolumeSnapshotRef.Name, err) + return false + } + + // Check if the snapshot content is bound to the snapshot + if IsSnapshotBound(snapshotObj, content) && snapshotObj.Spec.SnapshotContentName == content.Name { + glog.Infof("isSnapshotContentBeingUsed: VolumeSnapshot %s is bound to volumeSnapshotContent [%s]", snapshotObj.Name, content.Name) + return true + } + } + + glog.V(5).Infof("isSnapshotContentBeingUsed: Snapshot content %s is not being used", content.Name) + return false +} + +// isVolumeBeingCreatedFromSnapshot checks if an volume is being created from the snapshot. +func (ctrl *csiSnapshotController) isVolumeBeingCreatedFromSnapshot(snapshot *crdv1.VolumeSnapshot) bool { + pvcList, err := ctrl.client.CoreV1().PersistentVolumeClaims(snapshot.Namespace).List(metav1.ListOptions{}) + if err != nil { + glog.Errorf("Failed to retrieve PVCs from the API server to check if volume snapshot %s is being used by a volume: %q", snapshotKey(snapshot), err) + return false + } + for _, pvc := range pvcList.Items { + if pvc.Spec.DataSource != nil && len(pvc.Spec.DataSource.Name) > 0 && pvc.Spec.DataSource.Name == snapshot.Name { + if pvc.Spec.DataSource.Kind == snapshotKind && *(pvc.Spec.DataSource.APIGroup) == snapshotAPIGroup { + if pvc.Status.Phase == v1.ClaimPending { + // A volume is being created from the snapshot + glog.Infof("isVolumeBeingCreatedFromSnapshot: volume %s is being created from snapshot %s", pvc.Name, pvc.Spec.DataSource.Name) + return true + } + } + } + } + glog.V(5).Infof("isVolumeBeingCreatedFromSnapshot: no volume is being created from snapshot %s", snapshotKey(snapshot)) + return false +} + // The function checks whether the volumeSnapshotRef in snapshot content matches the given snapshot. If match, it binds the content with the snapshot func (ctrl *csiSnapshotController) checkandBindSnapshotContent(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent) error { if content.Spec.VolumeSnapshotRef == nil || content.Spec.VolumeSnapshotRef.Name != snapshot.Name { @@ -538,6 +633,10 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum return nil, err } + if class.DeletionPolicy == nil { + class.DeletionPolicy = new(crdv1.DeletionPolicy) + *class.DeletionPolicy = crdv1.VolumeSnapshotContentDelete + } snapshotContent := &crdv1.VolumeSnapshotContent{ ObjectMeta: metav1.ObjectMeta{ Name: contentName, @@ -554,8 +653,10 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum }, }, VolumeSnapshotClassName: &(class.Name), + DeletionPolicy: class.DeletionPolicy, }, } + glog.V(3).Infof("volume snapshot content %v", snapshotContent) // Try to create the VolumeSnapshotContent object several times for i := 0; i < ctrl.createSnapshotContentRetryCount; i++ { glog.V(5).Infof("createSnapshot [%s]: trying to save volume snapshot content %s", snapshotKey(snapshot), snapshotContent.Name) @@ -565,7 +666,7 @@ func (ctrl *csiSnapshotController) createSnapshotOperation(snapshot *crdv1.Volum glog.V(3).Infof("volume snapshot content %q for snapshot %q already exists, reusing", snapshotContent.Name, snapshotKey(snapshot)) err = nil } else { - glog.V(3).Infof("volume snapshot content %q for snapshot %q saved", snapshotContent.Name, snapshotKey(snapshot)) + glog.V(3).Infof("volume snapshot content %q for snapshot %q saved, %v", snapshotContent.Name, snapshotKey(snapshot), snapshotContent) } break } @@ -700,7 +801,7 @@ func (ctrl *csiSnapshotController) updateSnapshotStatus(snapshot *crdv1.VolumeSn snapshotClone := snapshot.DeepCopy() if readyToUse { if bound { - status.Ready = true + status.ReadyToUse = true // Remove the error if checking snapshot is already bound and ready status.Error = nil change = true @@ -878,3 +979,78 @@ func isControllerUpdateFailError(err *storage.VolumeError) bool { } return false } + +// addContentFinalizer adds a Finalizer for VolumeSnapshotContent. +func (ctrl *csiSnapshotController) addContentFinalizer(content *crdv1.VolumeSnapshotContent) error { + contentClone := content.DeepCopy() + contentClone.ObjectMeta.Finalizers = append(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer) + + _, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone) + if err != nil { + return newControllerUpdateError(content.Name, err.Error()) + } + + _, err = ctrl.storeContentUpdate(contentClone) + if err != nil { + glog.Errorf("failed to update content store %v", err) + } + + glog.V(5).Infof("Added protection finalizer to volume snapshot content %s", content.Name) + return nil +} + +// removeContentFinalizer removes a Finalizer for VolumeSnapshotContent. +func (ctrl *csiSnapshotController) removeContentFinalizer(content *crdv1.VolumeSnapshotContent) error { + contentClone := content.DeepCopy() + contentClone.ObjectMeta.Finalizers = slice.RemoveString(contentClone.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil) + + _, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshotContents().Update(contentClone) + if err != nil { + return newControllerUpdateError(content.Name, err.Error()) + } + + _, err = ctrl.storeContentUpdate(contentClone) + if err != nil { + glog.Errorf("failed to update content store %v", err) + } + + glog.V(5).Infof("Removed protection finalizer from volume snapshot content %s", content.Name) + return nil +} + +// addSnapshotFinalizer adds a Finalizer for VolumeSnapshot. +func (ctrl *csiSnapshotController) addSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) error { + snapshotClone := snapshot.DeepCopy() + snapshotClone.ObjectMeta.Finalizers = append(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer) + _, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone) + if err != nil { + return newControllerUpdateError(snapshot.Name, err.Error()) + } + + _, err = ctrl.storeSnapshotUpdate(snapshotClone) + if err != nil { + glog.Errorf("failed to update snapshot store %v", err) + } + + glog.V(5).Infof("Added protection finalizer to volume snapshot %s", snapshotKey(snapshot)) + return nil +} + +// removeContentFinalizer removes a Finalizer for VolumeSnapshot. +func (ctrl *csiSnapshotController) removeSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) error { + snapshotClone := snapshot.DeepCopy() + snapshotClone.ObjectMeta.Finalizers = slice.RemoveString(snapshotClone.ObjectMeta.Finalizers, VolumeSnapshotFinalizer, nil) + + _, err := ctrl.clientset.VolumesnapshotV1alpha1().VolumeSnapshots(snapshotClone.Namespace).Update(snapshotClone) + if err != nil { + return newControllerUpdateError(snapshot.Name, err.Error()) + } + + _, err = ctrl.storeSnapshotUpdate(snapshotClone) + if err != nil { + glog.Errorf("failed to update snapshot store %v", err) + } + + glog.V(5).Infof("Removed protection finalizer from volume snapshot %s", snapshotKey(snapshot)) + return nil +} diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_base.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_base.go index 348e034d50..ab171b2b51 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_base.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_base.go @@ -139,7 +139,7 @@ func (ctrl *csiSnapshotController) Run(workers int, stopCh <-chan struct{}) { glog.Infof("Starting CSI snapshotter") defer glog.Infof("Shutting CSI snapshotter") - if !cache.WaitForCacheSync(stopCh, ctrl.snapshotListerSynced, ctrl.contentListerSynced) { + if !cache.WaitForCacheSync(stopCh, ctrl.snapshotListerSynced, ctrl.contentListerSynced, ctrl.classListerSynced) { glog.Errorf("Cannot sync caches") return } @@ -475,8 +475,8 @@ func (ctrl *csiSnapshotController) initializeCaches(snapshotLister storagelister } for _, content := range contentList { contentClone := content.DeepCopy() - if _, err = ctrl.storeSnapshotUpdate(contentClone); err != nil { - glog.Errorf("error updating volume snapshot cache: %v", err) + if _, err = ctrl.storeContentUpdate(contentClone); err != nil { + glog.Errorf("error updating volume snapshot content cache: %v", err) } } diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_test.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_test.go index 1b8b170828..625f9d7008 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_test.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_controller_test.go @@ -23,7 +23,7 @@ import ( ) func storeVersion(t *testing.T, prefix string, c cache.Store, version string, expectedReturn bool) { - content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil) + content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, false) content.ResourceVersion = version ret, err := storeObjectUpdate(c, content, "content") if err != nil { @@ -82,7 +82,7 @@ func TestControllerCacheParsingError(t *testing.T) { // There must be something in the cache to compare with storeVersion(t, "Step1", c, "1", true) - content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil) + content := newContent("contentName", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, false) content.ResourceVersion = "xxx" _, err := storeObjectUpdate(c, content, "content") if err == nil { diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_create_test.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_create_test.go index fa8b0ca81f..a8861f15b7 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_create_test.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_create_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1" "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -33,7 +34,8 @@ var metaTimeNowUnix = &metav1.Time{ } var defaultSize int64 = 1000 - +var deletePolicy = crdv1.VolumeSnapshotContentDelete +var retainPolicy = crdv1.VolumeSnapshotContentRetain var sameDriverStorageClass = &storage.StorageClass{ TypeMeta: metav1.TypeMeta{ Kind: "StorageClass", @@ -61,11 +63,12 @@ var diffDriverStorageClass = &storage.StorageClass{ // 2. Call the SyncSnapshot *once*. // 3. Compare resulting contents with expected contents. func TestCreateSnapshotSync(t *testing.T) { + tests := []controllerTest{ { name: "6-1 - successful create snapshot with snapshot class gold", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-1", classGold, "sid6-1", "pv-uid6-1", "volume6-1", "snapuid6-1", "snap6-1", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-1", classGold, "", "snapuid6-1", "claim6-1", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-1", classGold, "snapcontent-snapuid6-1", "snapuid6-1", "claim6-1", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty), @@ -89,7 +92,7 @@ func TestCreateSnapshotSync(t *testing.T) { { name: "6-2 - successful create snapshot with snapshot class silver", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-2", classSilver, "sid6-2", "pv-uid6-2", "volume6-2", "snapuid6-2", "snap6-2", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-2", classSilver, "", "snapuid6-2", "claim6-2", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-2", classSilver, "snapcontent-snapuid6-2", "snapuid6-2", "claim6-2", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty), @@ -113,7 +116,7 @@ func TestCreateSnapshotSync(t *testing.T) { { name: "6-3 - successful create snapshot with snapshot class valid-secret-class", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-3", validSecretClass, "sid6-3", "pv-uid6-3", "volume6-3", "snapuid6-3", "snap6-3", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-3", validSecretClass, "", "snapuid6-3", "claim6-3", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-3", validSecretClass, "snapcontent-snapuid6-3", "snapuid6-3", "claim6-3", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-3", "pvc-uid6-3", "1Gi", "volume6-3", v1.ClaimBound, &classEmpty), @@ -139,7 +142,7 @@ func TestCreateSnapshotSync(t *testing.T) { { name: "6-4 - successful create snapshot with snapshot class empty-secret-class", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-4", emptySecretClass, "sid6-4", "pv-uid6-4", "volume6-4", "snapuid6-4", "snap6-4", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "", "snapuid6-4", "claim6-4", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-4", emptySecretClass, "snapcontent-snapuid6-4", "snapuid6-4", "claim6-4", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-4", "pvc-uid6-4", "1Gi", "volume6-4", v1.ClaimBound, &classEmpty), @@ -165,7 +168,7 @@ func TestCreateSnapshotSync(t *testing.T) { { name: "6-5 - successful create snapshot with status uploading", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-5", classGold, "sid6-5", "pv-uid6-5", "volume6-5", "snapuid6-5", "snap6-5", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-5", classGold, "", "snapuid6-5", "claim6-5", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-5", classGold, "snapcontent-snapuid6-5", "snapuid6-5", "claim6-5", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-5", "pvc-uid6-5", "1Gi", "volume6-5", v1.ClaimBound, &classEmpty), @@ -189,7 +192,7 @@ func TestCreateSnapshotSync(t *testing.T) { { name: "6-6 - successful create snapshot with status error uploading", initialContents: nocontents, - expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &defaultSize, &timeNow), + expectedContents: newContentArray("snapcontent-snapuid6-6", classGold, "sid6-6", "pv-uid6-6", "volume6-6", "snapuid6-6", "snap6-6", &deletePolicy, &defaultSize, &timeNow, false), initialSnapshots: newSnapshotArray("snap6-6", classGold, "", "snapuid6-6", "claim6-6", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap6-6", classGold, "snapcontent-snapuid6-6", "snapuid6-6", "claim6-6", false, nil, metaTimeNowUnix, getSize(defaultSize)), initialClaims: newClaimArray("claim6-6", "pvc-uid6-6", "1Gi", "volume6-6", v1.ClaimBound, &classEmpty), diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_delete_test.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_delete_test.go index 33e60ab19a..6be2be119c 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_delete_test.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_delete_test.go @@ -119,7 +119,7 @@ func TestDeleteSync(t *testing.T) { tests := []controllerTest{ { name: "1-1 - content with empty snapshot class is deleted if it is bound to a non-exist snapshot and also has a snapshot uid specified", - initialContents: newContentArray("content1-1", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil), + initialContents: newContentArray("content1-1", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, @@ -130,8 +130,8 @@ func TestDeleteSync(t *testing.T) { }, { name: "2-1 - content with empty snapshot class will not be deleted if it is bound to a non-exist snapshot but it does not have a snapshot uid specified", - initialContents: newContentArray("content2-1", classEmpty, "sid2-1", "vuid2-1", "volume2-1", "", "snap2-1", nil, nil), - expectedContents: newContentArray("content2-1", classEmpty, "sid2-1", "vuid2-1", "volume2-1", "", "snap2-1", nil, nil), + initialContents: newContentArray("content2-1", classEmpty, "sid2-1", "vuid2-1", "volume2-1", "", "snap2-1", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content2-1", classEmpty, "sid2-1", "vuid2-1", "volume2-1", "", "snap2-1", &deletePolicy, nil, nil, true), initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, expectedEvents: noevents, @@ -141,7 +141,7 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-2 - successful delete with snapshot class that has empty secret parameter", - initialContents: newContentArray("content1-2", emptySecretClass, "sid1-2", "vuid1-2", "volume1-2", "snapuid1-2", "snap1-2", nil, nil), + initialContents: newContentArray("content1-2", emptySecretClass, "sid1-2", "vuid1-2", "volume1-2", "snapuid1-2", "snap1-2", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, @@ -153,7 +153,7 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-3 - successful delete with snapshot class that has valid secret parameter", - initialContents: newContentArray("content1-3", validSecretClass, "sid1-3", "vuid1-3", "volume1-3", "snapuid1-3", "snap1-3", nil, nil), + initialContents: newContentArray("content1-3", validSecretClass, "sid1-3", "vuid1-3", "volume1-3", "snapuid1-3", "snap1-3", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, @@ -165,8 +165,8 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-4 - fail delete with snapshot class that has invalid secret parameter", - initialContents: newContentArray("content1-4", invalidSecretClass, "sid1-4", "vuid1-4", "volume1-4", "snapuid1-4", "snap1-4", nil, nil), - expectedContents: newContentArray("content1-4", invalidSecretClass, "sid1-4", "vuid1-4", "volume1-4", "snapuid1-4", "snap1-4", nil, nil), + initialContents: newContentArray("content1-4", invalidSecretClass, "sid1-4", "vuid1-4", "volume1-4", "snapuid1-4", "snap1-4", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content1-4", invalidSecretClass, "sid1-4", "vuid1-4", "volume1-4", "snapuid1-4", "snap1-4", &deletePolicy, nil, nil, true), initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, expectedEvents: noevents, @@ -175,8 +175,8 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-5 - csi driver delete snapshot returns error", - initialContents: newContentArray("content1-5", validSecretClass, "sid1-5", "vuid1-5", "volume1-5", "snapuid1-5", "snap1-5", nil, nil), - expectedContents: newContentArray("content1-5", validSecretClass, "sid1-5", "vuid1-5", "volume1-5", "snapuid1-5", "snap1-5", nil, nil), + initialContents: newContentArray("content1-5", validSecretClass, "sid1-5", "vuid1-5", "volume1-5", "snapuid1-5", "snap1-5", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content1-5", validSecretClass, "sid1-5", "vuid1-5", "volume1-5", "snapuid1-5", "snap1-5", &deletePolicy, nil, nil, true), initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, initialSecrets: []*v1.Secret{secret()}, @@ -187,8 +187,8 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-6 - api server delete content returns error", - initialContents: newContentArray("content1-6", validSecretClass, "sid1-6", "vuid1-6", "volume1-6", "snapuid1-6", "snap1-6", nil, nil), - expectedContents: newContentArray("content1-6", validSecretClass, "sid1-6", "vuid1-6", "volume1-6", "snapuid1-6", "snap1-6", nil, nil), + initialContents: newContentArray("content1-6", validSecretClass, "sid1-6", "vuid1-6", "volume1-6", "snapuid1-6", "snap1-6", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content1-6", validSecretClass, "sid1-6", "vuid1-6", "volume1-6", "snapuid1-6", "snap1-6", &deletePolicy, nil, nil, true), initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, initialSecrets: []*v1.Secret{secret()}, @@ -205,7 +205,7 @@ func TestDeleteSync(t *testing.T) { // delete success - snapshot that the content was pointing to was deleted, and another // with the same name created. name: "1-7 - prebound content is deleted while the snapshot exists", - initialContents: newContentArray("content1-7", validSecretClass, "sid1-7", "vuid1-7", "volume1-7", "snapuid1-7", "snap1-7", nil, nil), + initialContents: newContentArray("content1-7", validSecretClass, "sid1-7", "vuid1-7", "volume1-7", "snapuid1-7", "snap1-7", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: newSnapshotArray("snap1-7", validSecretClass, "content1-7", "snapuid1-7-x", "claim1-7", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap1-7", validSecretClass, "content1-7", "snapuid1-7-x", "claim1-7", false, nil, nil, nil), @@ -218,7 +218,7 @@ func TestDeleteSync(t *testing.T) { { // delete success(?) - content is deleted before doDelete() starts name: "1-8 - content is deleted before deleting", - initialContents: newContentArray("content1-8", validSecretClass, "sid1-8", "vuid1-8", "volume1-8", "snapuid1-8", "snap1-8", nil, nil), + initialContents: newContentArray("content1-8", validSecretClass, "sid1-8", "vuid1-8", "volume1-8", "snapuid1-8", "snap1-8", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: nosnapshots, expectedSnapshots: nosnapshots, @@ -235,8 +235,8 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-9 - content will not be deleted if it is bound to a snapshot correctly, snapshot uid is specified", - initialContents: newContentArray("content1-9", validSecretClass, "sid1-9", "vuid1-9", "volume1-9", "snapuid1-9", "snap1-9", nil, nil), - expectedContents: newContentArray("content1-9", validSecretClass, "sid1-9", "vuid1-9", "volume1-9", "snapuid1-9", "snap1-9", nil, nil), + initialContents: newContentArray("content1-9", validSecretClass, "sid1-9", "vuid1-9", "volume1-9", "snapuid1-9", "snap1-9", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content1-9", validSecretClass, "sid1-9", "vuid1-9", "volume1-9", "snapuid1-9", "snap1-9", &deletePolicy, nil, nil, true), initialSnapshots: newSnapshotArray("snap1-9", validSecretClass, "content1-9", "snapuid1-9", "claim1-9", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap1-9", validSecretClass, "content1-9", "snapuid1-9", "claim1-9", false, nil, nil, nil), expectedEvents: noevents, @@ -246,7 +246,7 @@ func TestDeleteSync(t *testing.T) { }, { name: "1-10 - should delete content which is bound to a snapshot incorrectly", - initialContents: newContentArray("content1-10", validSecretClass, "sid1-10", "vuid1-10", "volume1-10", "snapuid1-10-x", "snap1-10", nil, nil), + initialContents: newContentArray("content1-10", validSecretClass, "sid1-10", "vuid1-10", "volume1-10", "snapuid1-10-x", "snap1-10", &deletePolicy, nil, nil, true), expectedContents: nocontents, initialSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-10", "snapuid1-10", "claim1-10", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-10", "snapuid1-10", "claim1-10", false, nil, nil, nil), @@ -256,10 +256,21 @@ func TestDeleteSync(t *testing.T) { expectedDeleteCalls: []deleteCall{{"sid1-10", map[string]string{"foo": "bar"}, nil}}, test: testSyncContent, }, + { + name: "1-10 - will not delete content with retain policy set which is bound to a snapshot incorrectly", + initialContents: newContentArray("content1-10", validSecretClass, "sid1-10", "vuid1-10", "volume1-10", "snapuid1-10-x", "snap1-10", &retainPolicy, nil, nil, true), + expectedContents: newContentArray("content1-10", validSecretClass, "sid1-10", "vuid1-10", "volume1-10", "snapuid1-10-x", "snap1-10", &retainPolicy, nil, nil, true), + initialSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-10", "snapuid1-10", "claim1-10", false, nil, nil, nil), + expectedSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-10", "snapuid1-10", "claim1-10", false, nil, nil, nil), + expectedEvents: noevents, + initialSecrets: []*v1.Secret{secret()}, + errors: noerrors, + test: testSyncContent, + }, { name: "1-11 - content will not be deleted if it is bound to a snapshot correctly, snapsht uid is not specified", - initialContents: newContentArray("content1-11", validSecretClass, "sid1-11", "vuid1-11", "volume1-11", "", "snap1-11", nil, nil), - expectedContents: newContentArray("content1-11", validSecretClass, "sid1-11", "vuid1-11", "volume1-11", "", "snap1-11", nil, nil), + initialContents: newContentArray("content1-11", validSecretClass, "sid1-11", "vuid1-11", "volume1-11", "", "snap1-11", &deletePolicy, nil, nil, true), + expectedContents: newContentArray("content1-11", validSecretClass, "sid1-11", "vuid1-11", "volume1-11", "", "snap1-11", &deletePolicy, nil, nil, true), initialSnapshots: newSnapshotArray("snap1-11", validSecretClass, "content1-11", "snapuid1-11", "claim1-11", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap1-11", validSecretClass, "content1-11", "snapuid1-11", "claim1-11", false, nil, nil, nil), expectedEvents: noevents, @@ -267,6 +278,48 @@ func TestDeleteSync(t *testing.T) { errors: noerrors, test: testSyncContent, }, + { + name: "1-12 - content with retain policy will not be deleted if it is bound to a non-exist snapshot and also has a snapshot uid specified", + initialContents: newContentArray("content1-12", classEmpty, "sid1-12", "vuid1-12", "volume1-12", "snapuid1-12", "snap1-12", &retainPolicy, nil, nil, true), + expectedContents: newContentArray("content1-12", classEmpty, "sid1-12", "vuid1-12", "volume1-12", "snapuid1-12", "snap1-12", &retainPolicy, nil, nil, true), + initialSnapshots: nosnapshots, + expectedSnapshots: nosnapshots, + expectedEvents: noevents, + errors: noerrors, + test: testSyncContent, + }, + { + name: "1-13 - content with empty snapshot class is not deleted when Deletion policy is not set even if it is bound to a non-exist snapshot and also has a snapshot uid specified", + initialContents: newContentArray("content1-1", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, true), + expectedContents: newContentArray("content1-1", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil, true), + initialSnapshots: nosnapshots, + expectedSnapshots: nosnapshots, + expectedEvents: noevents, + errors: noerrors, + test: testSyncContent, + }, + { + name: "1-14 - content will not be deleted if it is bound to a snapshot correctly, snapshot uid is specified", + initialContents: newContentArray("content1-14", validSecretClass, "sid1-14", "vuid1-14", "volume1-14", "snapuid1-14", "snap1-14", &retainPolicy, nil, nil, true), + expectedContents: newContentArray("content1-14", validSecretClass, "sid1-14", "vuid1-14", "volume1-14", "snapuid1-14", "snap1-14", &retainPolicy, nil, nil, true), + initialSnapshots: newSnapshotArray("snap1-14", validSecretClass, "content1-14", "snapuid1-14", "claim1-14", false, nil, nil, nil), + expectedSnapshots: newSnapshotArray("snap1-14", validSecretClass, "content1-14", "snapuid1-14", "claim1-14", false, nil, nil, nil), + expectedEvents: noevents, + initialSecrets: []*v1.Secret{secret()}, + errors: noerrors, + test: testSyncContent, + }, + { + name: "1-15 - content will not be deleted which is bound to a snapshot incorrectly if Deletion policy is not set", + initialContents: newContentArray("content1-10", validSecretClass, "sid1-15", "vuid1-15", "volume1-15", "snapuid1-15-x", "snap1-15", nil, nil, nil, true), + expectedContents: newContentArray("content1-10", validSecretClass, "sid1-15", "vuid1-15", "volume1-15", "snapuid1-15-x", "snap1-15", nil, nil, nil, true), + initialSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-15", "snapuid1-15", "claim1-15", false, nil, nil, nil), + expectedSnapshots: newSnapshotArray("snap1-10", validSecretClass, "content1-15", "snapuid1-15", "claim1-15", false, nil, nil, nil), + expectedEvents: noevents, + initialSecrets: []*v1.Secret{secret()}, + errors: noerrors, + test: testSyncContent, + }, } runSyncTests(t, tests, snapshotClasses) } diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_ready_test.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_ready_test.go index f783517b6d..51e8194ec8 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_ready_test.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/snapshot_ready_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "k8s.io/api/core/v1" storagev1beta1 "k8s.io/api/storage/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -40,8 +41,7 @@ var volumeErr = &storagev1beta1.VolumeError{ // controllerTest.testCall *once*. // 3. Compare resulting contents and snapshots with expected contents and snapshots. func TestSync(t *testing.T) { - // TODO FIXME - _ = []controllerTest{ + tests := []controllerTest{ { // snapshot is bound to a non-existing content name: "2-1 - snapshot is bound to a non-existing content", @@ -55,28 +55,34 @@ func TestSync(t *testing.T) { }, { name: "2-2 - could not bind snapshot and content, the VolumeSnapshotRef does not match", - initialContents: newContentArray("content2-2", validSecretClass, "sid2-2", "vuid2-2", "volume2-2", "snapuid2-2-x", "snap2-2", nil, nil), - expectedContents: newContentArray("content2-2", validSecretClass, "sid2-2", "vuid2-2", "volume2-2", "snapuid2-2-x", "snap2-2", nil, nil), + initialContents: newContentArray("content2-2", validSecretClass, "sid2-2", "vuid2-2", "volume2-2", "snapuid2-2-x", "snap2-2", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-2", validSecretClass, "sid2-2", "vuid2-2", "volume2-2", "snapuid2-2-x", "snap2-2", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-2", validSecretClass, "content2-2", "snapuid2-2", "claim2-2", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap2-2", validSecretClass, "content2-2", "snapuid2-2", "claim2-2", false, newVolumeError("Snapshot failed to bind VolumeSnapshotContent, Could not bind snapshot snap2-2 and content content2-2, the VolumeSnapshotRef does not match"), nil, nil), expectedEvents: []string{"Warning SnapshotBindFailed"}, errors: noerrors, test: testSyncSnapshotError, }, - /* TODO FIXME { - name: "2-3 - success bind snapshot and content, no status changed", - initialContents: newContentArray("content2-3", validSecretClass, "sid2-3", "vuid2-3", "volume2-3", "", "snap2-3", nil, nil), - expectedContents: newContentArray("content2-3", validSecretClass, "sid2-3", "vuid2-3", "volume2-3", "snapuid2-3", "snap2-3", nil, nil), + name: "2-3 - success bind snapshot and content but not ready, no status changed", + initialContents: newContentArray("content2-3", validSecretClass, "sid2-3", "vuid2-3", "volume2-3", "", "snap2-3", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-3", validSecretClass, "sid2-3", "vuid2-3", "volume2-3", "snapuid2-3", "snap2-3", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-3", validSecretClass, "content2-3", "snapuid2-3", "claim2-3", false, nil, metaTimeNow, nil), expectedSnapshots: newSnapshotArray("snap2-3", validSecretClass, "content2-3", "snapuid2-3", "claim2-3", false, nil, metaTimeNow, nil), - expectedListCalls: []listCall{ + initialClaims: newClaimArray("claim2-3", "pvc-uid2-3", "1Gi", "volume2-3", v1.ClaimBound, &classEmpty), + initialVolumes: newVolumeArray("volume2-3", "pv-uid2-3", "pv-handle2-3", "1Gi", "pvc-uid2-3", "claim2-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + initialSecrets: []*v1.Secret{secret()}, + expectedCreateCalls: []createCall{ { - snapshotID: "sid2-3", - status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_UPLOADING, - Details: "uploading", - }, + snapshotName: "snapshot-snapuid2-3", + volume: newVolume("volume2-3", "pv-uid2-3", "pv-handle2-3", "1Gi", "pvc-uid2-3", "claim2-3", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + parameters: class5Parameters, + secrets: map[string]string{"foo": "bar"}, + // information to return + driverName: mockDriverName, + snapshotId: "sid2-3", + timestamp: timeNow, + readyToUse: false, }, }, errors: noerrors, @@ -85,91 +91,83 @@ func TestSync(t *testing.T) { { // nothing changed name: "2-4 - noop", - initialContents: newContentArray("content2-4", validSecretClass, "sid2-4", "vuid2-4", "volume2-4", "snapuid2-4", "snap2-4", nil, nil), - expectedContents: newContentArray("content2-4", validSecretClass, "sid2-4", "vuid2-4", "volume2-4", "snapuid2-4", "snap2-4", nil, nil), - initialSnapshots: newSnapshotArray("snap2-4", validSecretClass, "content2-4", "snapuid2-4", "claim2-4", false, nil, metaTimeNow, nil), - expectedSnapshots: newSnapshotArray("snap2-4", validSecretClass, "content2-4", "snapuid2-4", "claim2-4", false, nil, metaTimeNow, nil), - expectedListCalls: []listCall{ - { - snapshotID: "sid2-4", - status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_UPLOADING, - Details: "uploading", - }, - }, - }, - errors: noerrors, - test: testSyncSnapshot, + initialContents: newContentArray("content2-4", validSecretClass, "sid2-4", "vuid2-4", "volume2-4", "snapuid2-4", "snap2-4", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-4", validSecretClass, "sid2-4", "vuid2-4", "volume2-4", "snapuid2-4", "snap2-4", &deletePolicy, nil, nil, false), + initialSnapshots: newSnapshotArray("snap2-4", validSecretClass, "content2-4", "snapuid2-4", "claim2-4", true, nil, metaTimeNow, nil), + expectedSnapshots: newSnapshotArray("snap2-4", validSecretClass, "content2-4", "snapuid2-4", "claim2-4", true, nil, metaTimeNow, nil), + errors: noerrors, + test: testSyncSnapshot, }, { name: "2-5 - snapshot and content bound, status ready false -> true", - initialContents: newContentArray("content2-5", validSecretClass, "sid2-5", "vuid2-5", "volume2-5", "snapuid2-5", "snap2-5", nil, nil), - expectedContents: newContentArray("content2-5", validSecretClass, "sid2-5", "vuid2-5", "volume2-5", "snapuid2-5", "snap2-5", nil, nil), + initialContents: newContentArray("content2-5", validSecretClass, "sid2-5", "vuid2-5", "volume2-5", "snapuid2-5", "snap2-5", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-5", validSecretClass, "sid2-5", "vuid2-5", "volume2-5", "snapuid2-5", "snap2-5", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-5", validSecretClass, "content2-5", "snapuid2-5", "claim2-5", false, nil, metaTimeNow, nil), expectedSnapshots: newSnapshotArray("snap2-5", validSecretClass, "content2-5", "snapuid2-5", "claim2-5", true, nil, metaTimeNow, nil), - expectedListCalls: []listCall{ + initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty), + initialVolumes: newVolumeArray("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + initialSecrets: []*v1.Secret{secret()}, + expectedCreateCalls: []createCall{ { - snapshotID: "sid2-5", - status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_READY, - Details: "success", - }, + snapshotName: "snapshot-snapuid2-5", + volume: newVolume("volume2-5", "pv-uid2-5", "pv-handle2-5", "1Gi", "pvc-uid2-5", "claim2-5", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + parameters: class5Parameters, + secrets: map[string]string{"foo": "bar"}, + // information to return + driverName: mockDriverName, + snapshotId: "sid2-5", + timestamp: timeNow, + readyToUse: true, }, }, errors: noerrors, test: testSyncSnapshot, }, - { - name: "2-6 - snapshot and content bound, status -> error uploading", - initialContents: newContentArray("content2-6", validSecretClass, "sid2-6", "vuid2-6", "volume2-6", "snapuid2-6", "snap2-6", nil, nil), - expectedContents: newContentArray("content2-6", validSecretClass, "sid2-6", "vuid2-6", "volume2-6", "snapuid2-6", "snap2-6", nil, nil), - initialSnapshots: newSnapshotArray("snap2-6", validSecretClass, "content2-6", "snapuid2-6", "claim2-6", false, nil, metaTimeNow, nil), - expectedSnapshots: newSnapshotArray("snap2-6", validSecretClass, "content2-6", "snapuid2-6", "claim2-6", false, volumeErr, metaTimeNow, nil), - expectedEvents: []string{"Warning SnapshotUploadError"}, - expectedListCalls: []listCall{ - { - snapshotID: "sid2-6", - status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_ERROR_UPLOADING, - Details: "error upload", - }, - }, - }, - errors: noerrors, - test: testSyncSnapshot, - }, - */ { name: "2-7 - snapshot and content bound, csi driver get status error", - initialContents: newContentArray("content2-7", validSecretClass, "sid2-7", "vuid2-7", "volume2-7", "snapuid2-7", "snap2-7", nil, nil), - expectedContents: newContentArray("content2-7", validSecretClass, "sid2-7", "vuid2-7", "volume2-7", "snapuid2-7", "snap2-7", nil, nil), + initialContents: newContentArray("content2-7", validSecretClass, "sid2-7", "vuid2-7", "volume2-7", "snapuid2-7", "snap2-7", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-7", validSecretClass, "sid2-7", "vuid2-7", "volume2-7", "snapuid2-7", "snap2-7", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-7", validSecretClass, "content2-7", "snapuid2-7", "claim2-7", false, nil, metaTimeNow, nil), - expectedSnapshots: newSnapshotArray("snap2-7", validSecretClass, "content2-7", "snapuid2-7", "claim2-7", false, newVolumeError("Failed to check and update snapshot: failed to check snapshot status snap2-7 with error failed to list snapshot data content2-7: \"mock driver get status error\""), metaTimeNow, nil), + expectedSnapshots: newSnapshotArray("snap2-7", validSecretClass, "content2-7", "snapuid2-7", "claim2-7", false, newVolumeError("Failed to check and update snapshot: mock create snapshot error"), metaTimeNow, nil), expectedEvents: []string{"Warning SnapshotCheckandUpdateFailed"}, - expectedListCalls: []listCall{ + initialClaims: newClaimArray("claim2-7", "pvc-uid2-7", "1Gi", "volume2-7", v1.ClaimBound, &classEmpty), + initialVolumes: newVolumeArray("volume2-7", "pv-uid2-7", "pv-handle2-7", "1Gi", "pvc-uid2-7", "claim2-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + initialSecrets: []*v1.Secret{secret()}, + expectedCreateCalls: []createCall{ { - snapshotID: "sid2-7", - err: errors.New("mock driver get status error"), + snapshotName: "snapshot-snapuid2-7", + volume: newVolume("volume2-7", "pv-uid2-7", "pv-handle2-7", "1Gi", "pvc-uid2-7", "claim2-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + parameters: class5Parameters, + secrets: map[string]string{"foo": "bar"}, + // information to return + err: errors.New("mock create snapshot error"), }, }, errors: noerrors, test: testSyncSnapshot, }, - /* TODO FIXME { name: "2-8 - snapshot and content bound, apiserver update status error", - initialContents: newContentArray("content2-8", validSecretClass, "sid2-8", "vuid2-8", "volume2-8", "snapuid2-8", "snap2-8", nil, nil), - expectedContents: newContentArray("content2-8", validSecretClass, "sid2-8", "vuid2-8", "volume2-8", "snapuid2-8", "snap2-8", nil, nil), + initialContents: newContentArray("content2-8", validSecretClass, "sid2-8", "vuid2-8", "volume2-8", "snapuid2-8", "snap2-8", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-8", validSecretClass, "sid2-8", "vuid2-8", "volume2-8", "snapuid2-8", "snap2-8", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-8", validSecretClass, "content2-8", "snapuid2-8", "claim2-8", false, nil, metaTimeNow, nil), expectedSnapshots: newSnapshotArray("snap2-8", validSecretClass, "content2-8", "snapuid2-8", "claim2-8", false, newVolumeError("Failed to check and update snapshot: snapshot controller failed to update default/snap2-8 on API server: mock update error"), metaTimeNow, nil), - expectedEvents: []string{"Warning SnapshotUploadError"}, - expectedListCalls: []listCall{ + expectedEvents: []string{"Warning SnapshotCheckandUpdateFailed"}, + initialClaims: newClaimArray("claim2-8", "pvc-uid2-8", "1Gi", "volume2-8", v1.ClaimBound, &classEmpty), + initialVolumes: newVolumeArray("volume2-8", "pv-uid2-8", "pv-handle2-8", "1Gi", "pvc-uid2-8", "claim2-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + initialSecrets: []*v1.Secret{secret()}, + expectedCreateCalls: []createCall{ { - snapshotID: "sid2-8", - status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_ERROR_UPLOADING, - Details: "error upload", - }, + snapshotName: "snapshot-snapuid2-8", + volume: newVolume("volume2-8", "pv-uid2-8", "pv-handle2-8", "1Gi", "pvc-uid2-8", "claim2-8", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty), + parameters: class5Parameters, + secrets: map[string]string{"foo": "bar"}, + // information to return + driverName: mockDriverName, + size: defaultSize, + snapshotId: "sid2-8", + timestamp: timeNow, + readyToUse: true, }, }, errors: []reactorError{ @@ -179,11 +177,10 @@ func TestSync(t *testing.T) { }, test: testSyncSnapshot, }, - */ { name: "2-9 - bind when snapshot and content matches", - initialContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", nil, nil), - expectedContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", nil, nil), + initialContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-9", validSecretClass, "", "snapuid2-9", "claim2-9", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap2-9", validSecretClass, "content2-9", "snapuid2-9", "claim2-9", false, nil, nil, nil), errors: noerrors, @@ -191,8 +188,8 @@ func TestSync(t *testing.T) { }, { name: "2-10 - do not bind when snapshot and content not match", - initialContents: newContentArray("content2-10", validSecretClass, "sid2-10", "vuid2-10", "volume2-10", "snapuid2-10-x", "snap2-10", nil, nil), - expectedContents: newContentArray("content2-10", validSecretClass, "sid2-10", "vuid2-10", "volume2-10", "snapuid2-10-x", "snap2-10", nil, nil), + initialContents: newContentArray("content2-10", validSecretClass, "sid2-10", "vuid2-10", "volume2-10", "snapuid2-10-x", "snap2-10", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content2-10", validSecretClass, "sid2-10", "vuid2-10", "volume2-10", "snapuid2-10-x", "snap2-10", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap2-10", validSecretClass, "", "snapuid2-10", "claim2-10", false, newVolumeError("mock driver error"), nil, nil), expectedSnapshots: newSnapshotArray("snap2-10", validSecretClass, "", "snapuid2-10", "claim2-10", false, newVolumeError("mock driver error"), nil, nil), errors: noerrors, @@ -220,8 +217,8 @@ func TestSync(t *testing.T) { }, { name: "3-3 - ready snapshot(everything is well, do nothing)", - initialContents: newContentArray("content3-3", validSecretClass, "sid3-3", "vuid3-3", "volume3-3", "snapuid3-3", "snap3-3", nil, nil), - expectedContents: newContentArray("content3-3", validSecretClass, "sid3-3", "vuid3-3", "volume3-3", "snapuid3-3", "snap3-3", nil, nil), + initialContents: newContentArray("content3-3", validSecretClass, "sid3-3", "vuid3-3", "volume3-3", "snapuid3-3", "snap3-3", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content3-3", validSecretClass, "sid3-3", "vuid3-3", "volume3-3", "snapuid3-3", "snap3-3", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap3-3", validSecretClass, "content3-3", "snapuid3-3", "claim3-3", true, nil, metaTimeNow, nil), expectedSnapshots: newSnapshotArray("snap3-3", validSecretClass, "content3-3", "snapuid3-3", "claim3-3", true, nil, metaTimeNow, nil), errors: noerrors, @@ -229,8 +226,8 @@ func TestSync(t *testing.T) { }, { name: "3-4 - ready snapshot misbound to VolumeSnapshotContent", - initialContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-4", nil, nil), - expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-4", nil, nil), + initialContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-4", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-4", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap3-4", validSecretClass, "content3-4", "snapuid3-4", "claim3-4", true, nil, metaTimeNow, nil), expectedSnapshots: newSnapshotArray("snap3-4", validSecretClass, "content3-4", "snapuid3-4", "claim3-4", false, newVolumeError("VolumeSnapshotContent is not bound to the VolumeSnapshot correctly"), metaTimeNow, nil), errors: noerrors, @@ -238,7 +235,7 @@ func TestSync(t *testing.T) { }, { name: "3-5 - snapshot bound to content in which the driver does not match", - initialContents: newContentWithUnmatchDriverArray("content3-5", validSecretClass, "sid3-5", "vuid3-5", "volume3-5", "", "snap3-5", nil, nil), + initialContents: newContentWithUnmatchDriverArray("content3-5", validSecretClass, "sid3-5", "vuid3-5", "volume3-5", "", "snap3-5", &deletePolicy, nil, nil), expectedContents: nocontents, initialSnapshots: newSnapshotArray("snap3-5", validSecretClass, "content3-5", "snapuid3-5", "claim3-5", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap3-5", validSecretClass, "content3-5", "snapuid3-5", "claim3-5", false, newVolumeError("VolumeSnapshotContent is missing"), nil, nil), @@ -248,8 +245,8 @@ func TestSync(t *testing.T) { }, { name: "3-6 - snapshot bound to content in which the snapshot uid does not match", - initialContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-6", nil, nil), - expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-6", nil, nil), + initialContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-6", &deletePolicy, nil, nil, false), + expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-6", &deletePolicy, nil, nil, false), initialSnapshots: newSnapshotArray("snap3-5", validSecretClass, "content3-5", "snapuid3-5", "claim3-5", false, nil, nil, nil), expectedSnapshots: newSnapshotArray("snap3-5", validSecretClass, "content3-5", "snapuid3-5", "claim3-5", false, newVolumeError("VolumeSnapshotContent is missing"), nil, nil), expectedEvents: []string{"Warning SnapshotContentMissing"}, @@ -258,6 +255,5 @@ func TestSync(t *testing.T) { }, } - // TODO FIXME - // runSyncTests(t, tests, snapshotClasses) + runSyncTests(t, tests, snapshotClasses) } diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/util.go b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/util.go index 8c64de8361..498d0dba08 100644 --- a/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/util.go +++ b/vendor/github.com/kubernetes-csi/external-snapshotter/pkg/controller/util.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" + "k8s.io/kubernetes/pkg/util/slice" "os" "strconv" "time" @@ -39,6 +40,10 @@ var ( const snapshotterSecretNameKey = "csiSnapshotterSecretName" const snapshotterSecretNamespaceKey = "csiSnapshotterSecretNamespace" +// Name of finalizer on VolumeSnapshotContents that are bound by VolumeSnapshots +const VolumeSnapshotContentFinalizer = "snapshot.storage.kubernetes.io/volumesnapshotcontent-protection" +const VolumeSnapshotFinalizer = "snapshot.storage.kubernetes.io/volumesnapshot-protection" + func snapshotKey(vs *crdv1.VolumeSnapshot) string { return fmt.Sprintf("%s/%s", vs.Namespace, vs.Name) } @@ -246,3 +251,23 @@ func GetCredentials(k8s kubernetes.Interface, ref *v1.SecretReference) (map[stri func NoResyncPeriodFunc() time.Duration { return 0 } + +// isContentDeletionCandidate checks if a volume snapshot content is a deletion candidate. +func isContentDeletionCandidate(content *crdv1.VolumeSnapshotContent) bool { + return content.ObjectMeta.DeletionTimestamp != nil && slice.ContainsString(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil) +} + +// needToAddContentFinalizer checks if a Finalizer needs to be added for the volume snapshot content. +func needToAddContentFinalizer(content *crdv1.VolumeSnapshotContent) bool { + return content.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil) +} + +// isSnapshotDeletionCandidate checks if a volume snapshot is a deletion candidate. +func isSnapshotDeletionCandidate(snapshot *crdv1.VolumeSnapshot) bool { + return snapshot.ObjectMeta.DeletionTimestamp != nil && slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotFinalizer, nil) +} + +// needToAddSnapshotFinalizer checks if a Finalizer needs to be added for the volume snapshot. +func needToAddSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) bool { + return snapshot.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotFinalizer, nil) +}