Skip to content

Commit 8c40671

Browse files
Merge pull request kubernetes-csi#15 from jsafrane/fix-retain-delete
Bug 1802467: Fix deletion of snapshots with Retain policy
2 parents 3da7dad + 1373e47 commit 8c40671

7 files changed

+213
-120
lines changed

pkg/common-controller/framework_test.go

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,17 @@ type reactorError struct {
164164
error error
165165
}
166166

167-
func withSnapshotFinalizer(snapshot *crdv1.VolumeSnapshot) *crdv1.VolumeSnapshot {
168-
snapshot.ObjectMeta.Finalizers = append(snapshot.ObjectMeta.Finalizers, utils.VolumeSnapshotContentFinalizer)
169-
snapshot.ObjectMeta.Finalizers = append(snapshot.ObjectMeta.Finalizers, utils.VolumeSnapshotAsSourceFinalizer)
170-
snapshot.ObjectMeta.Finalizers = append(snapshot.ObjectMeta.Finalizers, utils.VolumeSnapshotBoundFinalizer)
171-
return snapshot
167+
func withSnapshotFinalizers(snapshots []*crdv1.VolumeSnapshot, finalizers ...string) []*crdv1.VolumeSnapshot {
168+
for i := range snapshots {
169+
for _, f := range finalizers {
170+
snapshots[i].ObjectMeta.Finalizers = append(snapshots[i].ObjectMeta.Finalizers, f)
171+
}
172+
}
173+
return snapshots
172174
}
173175

174176
func withContentFinalizer(content *crdv1.VolumeSnapshotContent) *crdv1.VolumeSnapshotContent {
175177
content.ObjectMeta.Finalizers = append(content.ObjectMeta.Finalizers, utils.VolumeSnapshotContentFinalizer)
176-
metav1.SetMetaDataAnnotation(&content.ObjectMeta, utils.AnnVolumeSnapshotBeingDeleted, "yes")
177178
return content
178179
}
179180

@@ -824,6 +825,18 @@ func newContent(contentName, boundToSnapshotUID, boundToSnapshotName, snapshotHa
824825
return &content
825826
}
826827

828+
func withContentAnnotations(contents []*crdv1.VolumeSnapshotContent, annotations map[string]string) []*crdv1.VolumeSnapshotContent {
829+
for i := range contents {
830+
if contents[i].ObjectMeta.Annotations == nil {
831+
contents[i].ObjectMeta.Annotations = make(map[string]string)
832+
}
833+
for k, v := range annotations {
834+
contents[i].ObjectMeta.Annotations[k] = v
835+
}
836+
}
837+
return contents
838+
}
839+
827840
func newContentArray(contentName, boundToSnapshotUID, boundToSnapshotName, snapshotHandle, snapshotClassName, desiredSnapshotHandle, volumeHandle string,
828841
deletionPolicy crdv1.DeletionPolicy, size, creationTime *int64,
829842
withFinalizer bool) []*crdv1.VolumeSnapshotContent {
@@ -863,14 +876,15 @@ func newContentWithUnmatchDriverArray(contentName, boundToSnapshotUID, boundToSn
863876
func newSnapshot(
864877
snapshotName, snapshotUID, pvcName, targetContentName, snapshotClassName, boundContentName string,
865878
readyToUse *bool, creationTime *metav1.Time, restoreSize *resource.Quantity,
866-
err *crdv1.VolumeSnapshotError, nilStatus bool, withFinalizer bool) *crdv1.VolumeSnapshot {
879+
err *crdv1.VolumeSnapshotError, nilStatus bool, withAllFinalizers bool, deletionTimestamp *metav1.Time) *crdv1.VolumeSnapshot {
867880
snapshot := crdv1.VolumeSnapshot{
868881
ObjectMeta: metav1.ObjectMeta{
869-
Name: snapshotName,
870-
Namespace: testNamespace,
871-
UID: types.UID(snapshotUID),
872-
ResourceVersion: "1",
873-
SelfLink: "/apis/snapshot.storage.k8s.io/v1beta1/namespaces/" + testNamespace + "/volumesnapshots/" + snapshotName,
882+
Name: snapshotName,
883+
Namespace: testNamespace,
884+
UID: types.UID(snapshotUID),
885+
ResourceVersion: "1",
886+
SelfLink: "/apis/snapshot.storage.k8s.io/v1beta1/namespaces/" + testNamespace + "/volumesnapshots/" + snapshotName,
887+
DeletionTimestamp: deletionTimestamp,
874888
},
875889
Spec: crdv1.VolumeSnapshotSpec{
876890
VolumeSnapshotClassName: nil,
@@ -903,18 +917,18 @@ func newSnapshot(
903917
VolumeSnapshotContentName: &targetContentName,
904918
}
905919
}
906-
if withFinalizer {
907-
return withSnapshotFinalizer(&snapshot)
920+
if withAllFinalizers {
921+
return withSnapshotFinalizers([]*crdv1.VolumeSnapshot{&snapshot}, utils.VolumeSnapshotAsSourceFinalizer, utils.VolumeSnapshotBoundFinalizer)[0]
908922
}
909923
return &snapshot
910924
}
911925

912926
func newSnapshotArray(
913927
snapshotName, snapshotUID, pvcName, targetContentName, snapshotClassName, boundContentName string,
914928
readyToUse *bool, creationTime *metav1.Time, restoreSize *resource.Quantity,
915-
err *crdv1.VolumeSnapshotError, nilStatus bool, withFinalizer bool) []*crdv1.VolumeSnapshot {
929+
err *crdv1.VolumeSnapshotError, nilStatus bool, withAllFinalizers bool, deletionTimestamp *metav1.Time) []*crdv1.VolumeSnapshot {
916930
return []*crdv1.VolumeSnapshot{
917-
newSnapshot(snapshotName, snapshotUID, pvcName, targetContentName, snapshotClassName, boundContentName, readyToUse, creationTime, restoreSize, err, nilStatus, withFinalizer),
931+
newSnapshot(snapshotName, snapshotUID, pvcName, targetContentName, snapshotClassName, boundContentName, readyToUse, creationTime, restoreSize, err, nilStatus, withAllFinalizers, deletionTimestamp),
918932
}
919933
}
920934

@@ -1070,6 +1084,14 @@ func testSyncContent(ctrl *csiSnapshotCommonController, reactor *snapshotReactor
10701084
return ctrl.syncContent(test.initialContents[0])
10711085
}
10721086

1087+
func testSyncContentError(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
1088+
err := ctrl.syncContent(test.initialContents[0])
1089+
if err != nil {
1090+
return nil
1091+
}
1092+
return fmt.Errorf("syncContent succeeded when failure was expected")
1093+
}
1094+
10731095
func testAddPVCFinalizer(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
10741096
return ctrl.ensurePVCFinalizer(test.initialSnapshots[0])
10751097
}

pkg/common-controller/snapshot_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
249249
}
250250

251251
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent[%s]: set DeletionTimeStamp on content.", utils.SnapshotKey(snapshot))
252+
252253
// If content exists, set DeletionTimeStamp on the content;
253254
// content won't be deleted immediately due to the finalizer
254255
if content != nil && deleteContent && !inUse {
@@ -261,6 +262,9 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
261262
}
262263

263264
if !inUse {
265+
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent: Set VolumeSnapshotBeingDeleted annotation on the content [%s]", content.Name)
266+
ctrl.setAnnVolumeSnapshotBeingDeleted(content)
267+
264268
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent: Remove Finalizer for VolumeSnapshot[%s]", utils.SnapshotKey(snapshot))
265269
doesContentExist := false
266270
if content != nil {

pkg/common-controller/snapshot_create_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ func TestCreateSnapshotSync(t *testing.T) {
7171
name: "6-1 - successful create snapshot with snapshot class gold",
7272
initialContents: nocontents,
7373
expectedContents: newContentArrayNoStatus("snapcontent-snapuid6-1", "snapuid6-1", "snap6-1", "sid6-1", classGold, "", "pv-handle6-1", deletionPolicy, nil, nil, false, false),
74-
initialSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "", &False, nil, nil, nil, false, true),
75-
expectedSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "snapcontent-snapuid6-1", &False, nil, nil, nil, false, true),
74+
initialSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "", &False, nil, nil, nil, false, true, nil),
75+
expectedSnapshots: newSnapshotArray("snap6-1", "snapuid6-1", "claim6-1", "", classGold, "snapcontent-snapuid6-1", &False, nil, nil, nil, false, true, nil),
7676
initialClaims: newClaimArray("claim6-1", "pvc-uid6-1", "1Gi", "volume6-1", v1.ClaimBound, &classEmpty),
7777
initialVolumes: newVolumeArray("volume6-1", "pv-uid6-1", "pv-handle6-1", "1Gi", "pvc-uid6-1", "claim6-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
7878
errors: noerrors,
@@ -82,8 +82,8 @@ func TestCreateSnapshotSync(t *testing.T) {
8282
name: "6-2 - successful create snapshot with snapshot class silver",
8383
initialContents: nocontents,
8484
expectedContents: newContentArrayNoStatus("snapcontent-snapuid6-2", "snapuid6-2", "snap6-2", "sid6-2", classSilver, "", "pv-handle6-2", deletionPolicy, nil, nil, false, false),
85-
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false, true),
86-
expectedSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "snapcontent-snapuid6-2", &False, nil, nil, nil, false, true),
85+
initialSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "", &False, nil, nil, nil, false, true, nil),
86+
expectedSnapshots: newSnapshotArray("snap6-2", "snapuid6-2", "claim6-2", "", classSilver, "snapcontent-snapuid6-2", &False, nil, nil, nil, false, true, nil),
8787
initialClaims: newClaimArray("claim6-2", "pvc-uid6-2", "1Gi", "volume6-2", v1.ClaimBound, &classEmpty),
8888
initialVolumes: newVolumeArray("volume6-2", "pv-uid6-2", "pv-handle6-2", "1Gi", "pvc-uid6-2", "claim6-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
8989
errors: noerrors,
@@ -93,8 +93,8 @@ func TestCreateSnapshotSync(t *testing.T) {
9393
name: "7-1 - fail to create snapshot with non-existing snapshot class",
9494
initialContents: nocontents,
9595
expectedContents: nocontents,
96-
initialSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, nil, false, true),
97-
expectedSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-1: \"failed to retrieve snapshot class non-existing from the informer: \\\"volumesnapshotclass.snapshot.storage.k8s.io \\\\\\\"non-existing\\\\\\\" not found\\\"\""), false, true),
96+
initialSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, nil, false, true, nil),
97+
expectedSnapshots: newSnapshotArray("snap7-1", "snapuid7-1", "claim7-1", "", classNonExisting, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-1: \"failed to retrieve snapshot class non-existing from the informer: \\\"volumesnapshotclass.snapshot.storage.k8s.io \\\\\\\"non-existing\\\\\\\" not found\\\"\""), false, true, nil),
9898
initialClaims: newClaimArray("claim7-1", "pvc-uid7-1", "1Gi", "volume7-1", v1.ClaimBound, &classEmpty),
9999
initialVolumes: newVolumeArray("volume7-1", "pv-uid7-1", "pv-handle7-1", "1Gi", "pvc-uid7-1", "claim7-1", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
100100
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
@@ -107,8 +107,8 @@ func TestCreateSnapshotSync(t *testing.T) {
107107
name: "7-2 - fail to update snapshot reports warning event",
108108
initialContents: newContentArrayWithReadyToUse("snapcontent-snapuid7-2", "snapuid7-2", "snap7-2", "sid7-2", classGold, "sid7-2", "pv-handle7-2", deletionPolicy, nil, nil, &True, false),
109109
expectedContents: newContentArrayWithReadyToUse("snapcontent-snapuid7-2", "snapuid7-2", "snap7-2", "sid7-2", classGold, "sid7-2", "pv-handle7-2", deletionPolicy, nil, nil, &True, false),
110-
initialSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", classGold, "snapcontent-snapuid7-2", &False, nil, nil, nil, false, true),
111-
expectedSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", classGold, "snapcontent-snapuid7-2", &False, nil, nil, newVolumeError("Snapshot status update failed, snapshot controller failed to update default/snap7-2 on API server: mock update error"), false, true),
110+
initialSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", classGold, "snapcontent-snapuid7-2", &False, nil, nil, nil, false, true, nil),
111+
expectedSnapshots: newSnapshotArray("snap7-2", "snapuid7-2", "claim7-2", "", classGold, "snapcontent-snapuid7-2", &False, nil, nil, newVolumeError("Snapshot status update failed, snapshot controller failed to update default/snap7-2 on API server: mock update error"), false, true, nil),
112112
initialClaims: newClaimArray("claim7-2", "pvc-uid7-2", "1Gi", "volume7-2", v1.ClaimBound, &classGold),
113113
initialVolumes: newVolumeArray("volume7-2", "pv-uid7-2", "pv-handle7-2", "1Gi", "pvc-uid7-2", "claim7-2", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classGold),
114114
expectedEvents: []string{"Warning SnapshotStatusUpdateFailed"},
@@ -138,8 +138,8 @@ func TestCreateSnapshotSync(t *testing.T) {
138138
name: "7-4 - fail create snapshot with no-existing claim",
139139
initialContents: nocontents,
140140
expectedContents: nocontents,
141-
initialSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, nil, false, true),
142-
expectedSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error snapshot controller failed to update snap7-4 on API server: cannot get claim from snapshot"), false, true),
141+
initialSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, nil, false, true, nil),
142+
expectedSnapshots: newSnapshotArray("snap7-4", "snapuid7-4", "claim7-4", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error snapshot controller failed to update snap7-4 on API server: cannot get claim from snapshot"), false, true, nil),
143143
initialVolumes: newVolumeArray("volume7-4", "pv-uid7-4", "pv-handle7-4", "1Gi", "pvc-uid7-4", "claim7-4", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classEmpty),
144144
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
145145
errors: noerrors,
@@ -150,8 +150,8 @@ func TestCreateSnapshotSync(t *testing.T) {
150150
name: "7-5 - fail create snapshot with no-existing volume",
151151
initialContents: nocontents,
152152
expectedContents: nocontents,
153-
initialSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, nil, false, true),
154-
expectedSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-5: \"failed to retrieve PV volume7-5 from the API server: \\\"cannot find volume volume7-5\\\"\""), false, true),
153+
initialSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, nil, false, true, nil),
154+
expectedSnapshots: newSnapshotArray("snap7-5", "snapuid7-5", "claim7-5", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-5: \"failed to retrieve PV volume7-5 from the API server: \\\"cannot find volume volume7-5\\\"\""), false, true, nil),
155155
initialClaims: newClaimArray("claim7-5", "pvc-uid7-5", "1Gi", "volume7-5", v1.ClaimBound, &classEmpty),
156156
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
157157
errors: noerrors,
@@ -163,8 +163,8 @@ func TestCreateSnapshotSync(t *testing.T) {
163163
name: "7-6 - fail create snapshot with claim that is not yet bound",
164164
initialContents: nocontents,
165165
expectedContents: nocontents,
166-
initialSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, nil, false, true),
167-
expectedSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-6: \"the PVC claim7-6 is not yet bound to a PV, will not attempt to take a snapshot\""), false, true),
166+
initialSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, nil, false, true, nil),
167+
expectedSnapshots: newSnapshotArray("snap7-6", "snapuid7-6", "claim7-6", "", classGold, "", &False, nil, nil, newVolumeError("Failed to create snapshot content with error failed to get input parameters to create snapshot snap7-6: \"the PVC claim7-6 is not yet bound to a PV, will not attempt to take a snapshot\""), false, true, nil),
168168
initialClaims: newClaimArray("claim7-6", "pvc-uid7-6", "1Gi", "", v1.ClaimPending, &classEmpty),
169169
expectedEvents: []string{"Warning SnapshotContentCreationFailed"},
170170
errors: noerrors,

0 commit comments

Comments
 (0)