From ea170394541a27997fa00118f5a09da1eb4e0d48 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Fri, 5 Oct 2018 17:04:53 -0700 Subject: [PATCH] Add Finalizer for VolumeSnapshot/VolumeSnapshotContent This PR adds a Finalizer for VolumeSnapshotContent. If the VolumeSnapshotContent is bound to a VolumeSnapshot, the VolumeSnapshotContent is being used and cannot be deleted. This PR also adds a Finalizer for VolumeSnapshot. If a volume is being created from the snapshot, the VolumeSnapshot is being used and cannot be deleted. --- pkg/controller/framework_test.go | 23 ++- pkg/controller/snapshot_controller.go | 155 +++++++++++++++++++++ pkg/controller/snapshot_controller_test.go | 4 +- pkg/controller/snapshot_create_test.go | 12 +- pkg/controller/snapshot_delete_test.go | 56 ++++---- pkg/controller/snapshot_ready_test.go | 44 +++--- pkg/controller/util.go | 25 ++++ 7 files changed, 256 insertions(+), 63 deletions(-) diff --git a/pkg/controller/framework_test.go b/pkg/controller/framework_test.go index 9208f5750..9a57ca4be 100644 --- a/pkg/controller/framework_test.go +++ b/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, deletionPolicy *crdv1.DeletionPolicy, 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, @@ -779,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, deletionPolicy *crdv1.DeletionPolicy, 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, deletionPolicy, size, creationTime), + newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, withFinalizer), } } 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) + content := newContent(name, className, snapshotHandle, volumeUID, volumeName, boundToSnapshotUID, boundToSnapshotName, deletionPolicy, size, creationTime, false) content.Spec.VolumeSnapshotSource.CSI.Driver = "fake" return []*crdv1.VolumeSnapshotContent{ content, @@ -821,7 +834,7 @@ func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, }, } - 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/pkg/controller/snapshot_controller.go b/pkg/controller/snapshot_controller.go index 1910f707c..3418b28c8 100644 --- a/pkg/controller/snapshot_controller.go +++ b/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 @@ -154,6 +175,23 @@ 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 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 { @@ -410,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 { @@ -899,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/pkg/controller/snapshot_controller_test.go b/pkg/controller/snapshot_controller_test.go index ab45abe87..625f9d700 100644 --- a/pkg/controller/snapshot_controller_test.go +++ b/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, 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, 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/pkg/controller/snapshot_create_test.go b/pkg/controller/snapshot_create_test.go index 08d392058..a8861f15b 100644 --- a/pkg/controller/snapshot_create_test.go +++ b/pkg/controller/snapshot_create_test.go @@ -68,7 +68,7 @@ func TestCreateSnapshotSync(t *testing.T) { { 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", &deletePolicy, &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), @@ -92,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", &deletePolicy, &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), @@ -116,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", &deletePolicy, &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), @@ -142,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", &deletePolicy, &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), @@ -168,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", &deletePolicy, &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), @@ -192,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", &deletePolicy, &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/pkg/controller/snapshot_delete_test.go b/pkg/controller/snapshot_delete_test.go index e9610c403..6be2be119 100644 --- a/pkg/controller/snapshot_delete_test.go +++ b/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", &deletePolicy, 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-1", classEmpty, "sid2-1", "vuid2-1", "volume2-1", "", "snap2-1", &deletePolicy, 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", &deletePolicy, 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", &deletePolicy, 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content1-4", invalidSecretClass, "sid1-4", "vuid1-4", "volume1-4", "snapuid1-4", "snap1-4", &deletePolicy, 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content1-5", validSecretClass, "sid1-5", "vuid1-5", "volume1-5", "snapuid1-5", "snap1-5", &deletePolicy, 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content1-6", validSecretClass, "sid1-6", "vuid1-6", "volume1-6", "snapuid1-6", "snap1-6", &deletePolicy, 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", &deletePolicy, 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", &deletePolicy, 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content1-9", validSecretClass, "sid1-9", "vuid1-9", "volume1-9", "snapuid1-9", "snap1-9", &deletePolicy, 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", &deletePolicy, 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), @@ -258,8 +258,8 @@ func TestDeleteSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content1-10", validSecretClass, "sid1-10", "vuid1-10", "volume1-10", "snapuid1-10-x", "snap1-10", &retainPolicy, nil, nil), + 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, @@ -269,8 +269,8 @@ func TestDeleteSync(t *testing.T) { }, { 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content1-11", validSecretClass, "sid1-11", "vuid1-11", "volume1-11", "", "snap1-11", &deletePolicy, 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, @@ -280,8 +280,8 @@ func TestDeleteSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content1-12", classEmpty, "sid1-12", "vuid1-12", "volume1-12", "snapuid1-12", "snap1-12", &retainPolicy, nil, nil), + 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, @@ -290,8 +290,8 @@ func TestDeleteSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content1-1", classEmpty, "sid1-1", "vuid1-1", "volume1-1", "snapuid1-1", "snap1-1", nil, nil, nil), + 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, @@ -300,8 +300,8 @@ func TestDeleteSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content1-14", validSecretClass, "sid1-14", "vuid1-14", "volume1-14", "snapuid1-14", "snap1-14", &retainPolicy, nil, nil), + 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, @@ -311,8 +311,8 @@ func TestDeleteSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content1-10", validSecretClass, "sid1-15", "vuid1-15", "volume1-15", "snapuid1-15-x", "snap1-15", nil, nil, nil), + 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, diff --git a/pkg/controller/snapshot_ready_test.go b/pkg/controller/snapshot_ready_test.go index 62cc751ce..51e8194ec 100644 --- a/pkg/controller/snapshot_ready_test.go +++ b/pkg/controller/snapshot_ready_test.go @@ -55,8 +55,8 @@ 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-2", validSecretClass, "sid2-2", "vuid2-2", "volume2-2", "snapuid2-2-x", "snap2-2", &deletePolicy, 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"}, @@ -65,8 +65,8 @@ func TestSync(t *testing.T) { }, { 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), - expectedContents: newContentArray("content2-3", validSecretClass, "sid2-3", "vuid2-3", "volume2-3", "snapuid2-3", "snap2-3", &deletePolicy, nil, nil), + 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), initialClaims: newClaimArray("claim2-3", "pvc-uid2-3", "1Gi", "volume2-3", v1.ClaimBound, &classEmpty), @@ -91,8 +91,8 @@ 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-4", validSecretClass, "sid2-4", "vuid2-4", "volume2-4", "snapuid2-4", "snap2-4", &deletePolicy, nil, nil), + 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, @@ -100,8 +100,8 @@ func TestSync(t *testing.T) { }, { 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-5", validSecretClass, "sid2-5", "vuid2-5", "volume2-5", "snapuid2-5", "snap2-5", &deletePolicy, 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), initialClaims: newClaimArray("claim2-5", "pvc-uid2-5", "1Gi", "volume2-5", v1.ClaimBound, &classEmpty), @@ -125,8 +125,8 @@ func TestSync(t *testing.T) { }, { 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-7", validSecretClass, "sid2-7", "vuid2-7", "volume2-7", "snapuid2-7", "snap2-7", &deletePolicy, 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: mock create snapshot error"), metaTimeNow, nil), expectedEvents: []string{"Warning SnapshotCheckandUpdateFailed"}, @@ -148,8 +148,8 @@ func TestSync(t *testing.T) { }, { 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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-8", validSecretClass, "sid2-8", "vuid2-8", "volume2-8", "snapuid2-8", "snap2-8", &deletePolicy, 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 SnapshotCheckandUpdateFailed"}, @@ -179,8 +179,8 @@ func TestSync(t *testing.T) { }, { name: "2-9 - bind when snapshot and content matches", - initialContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-9", validSecretClass, "sid2-9", "vuid2-9", "volume2-9", "snapuid2-9", "snap2-9", &deletePolicy, 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, @@ -188,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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content2-10", validSecretClass, "sid2-10", "vuid2-10", "volume2-10", "snapuid2-10-x", "snap2-10", &deletePolicy, 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, @@ -217,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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content3-3", validSecretClass, "sid3-3", "vuid3-3", "volume3-3", "snapuid3-3", "snap3-3", &deletePolicy, 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, @@ -226,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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-4", &deletePolicy, 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, @@ -245,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", &deletePolicy, nil, nil), - expectedContents: newContentArray("content3-4", validSecretClass, "sid3-4", "vuid3-4", "volume3-4", "snapuid3-4-x", "snap3-6", &deletePolicy, 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"}, diff --git a/pkg/controller/util.go b/pkg/controller/util.go index 8c64de836..498d0dba0 100644 --- a/pkg/controller/util.go +++ b/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) +}