Skip to content

Commit f7815c5

Browse files
committed
Update snapshot controller
1 parent 53469c2 commit f7815c5

File tree

2 files changed

+142
-68
lines changed

2 files changed

+142
-68
lines changed

pkg/common-controller/snapshot_controller.go

+137-63
Original file line numberDiff line numberDiff line change
@@ -85,43 +85,38 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
8585

8686
snapshotName := utils.SnapshotRefKey(&content.Spec.VolumeSnapshotRef)
8787

88-
if utils.NeedToAddContentFinalizer(content) {
89-
// Content is not being deleted -> it should have the finalizer.
90-
klog.V(5).Infof("syncContent: Add Finalizer for VolumeSnapshotContent[%s]", content.Name)
91-
return ctrl.addContentFinalizer(content)
92-
}
93-
9488
klog.V(4).Infof("synchronizing VolumeSnapshotContent[%s]: content is bound to snapshot %s", content.Name, snapshotName)
9589
// The VolumeSnapshotContent is reserved for a VolumeSnapshot;
9690
// that VolumeSnapshot has not yet been bound to this VolumeSnapshotContent; the VolumeSnapshot sync will handle it.
9791
if content.Spec.VolumeSnapshotRef.UID == "" {
9892
klog.V(4).Infof("synchronizing VolumeSnapshotContent[%s]: VolumeSnapshotContent is pre-bound to VolumeSnapshot %s", content.Name, snapshotName)
9993
return nil
10094
}
101-
// Get the VolumeSnapshot by _name_
95+
96+
if utils.NeedToAddContentFinalizer(content) {
97+
// Content is not being deleted -> it should have the finalizer.
98+
klog.V(5).Infof("syncContent: Add Finalizer for VolumeSnapshotContent[%s]", content.Name)
99+
return ctrl.addContentFinalizer(content)
100+
}
101+
102+
// Check if snapshot exists in cache store
103+
// If snapshotExists returns (nil, nil), it means snapshot not found
104+
// and it may have already been deleted, and it will fall into the
105+
// snapshot == nil case below
102106
var snapshot *crdv1.VolumeSnapshot
103-
obj, found, err := ctrl.snapshotStore.GetByKey(snapshotName)
107+
snapshot, err := ctrl.snapshotExists(snapshotName)
104108
if err != nil {
105109
return err
106110
}
107-
if !found {
108-
klog.V(4).Infof("synchronizing VolumeSnapshotContent[%s]: snapshot %s not found", content.Name, snapshotName)
109-
// Fall through with snapshot = nil
110-
} else {
111-
var ok bool
112-
snapshot, ok = obj.(*crdv1.VolumeSnapshot)
113-
if !ok {
114-
return fmt.Errorf("cannot convert object from snapshot cache to snapshot %q!?: %#v", content.Name, obj)
115-
}
116-
klog.V(4).Infof("synchronizing VolumeSnapshotContent[%s]: snapshot %s found", content.Name, snapshotName)
117-
}
111+
118112
if snapshot != nil && snapshot.UID != content.Spec.VolumeSnapshotRef.UID {
119113
// The snapshot that the content was pointing to was deleted, and another
120114
// with the same name created.
121115
klog.V(4).Infof("synchronizing VolumeSnapshotContent[%s]: content %s has different UID, the old one must have been deleted", content.Name, snapshotName)
122116
// Treat the content as bound to a missing snapshot.
123117
snapshot = nil
124118
} else {
119+
// TODO(xyang): Write a function to check if snapshot.Status is different from content.Status and add snapshot to queue if there is a difference and it is worth triggering an snapshot status update
125120
// Check if content status is set to true and update snapshot status if so
126121
if snapshot != nil && content.Status != nil && content.Status.ReadyToUse != nil && *content.Status.ReadyToUse == true {
127122
klog.V(4).Infof("synchronizing VolumeSnapshotContent for snapshot [%s]: update snapshot status to true if needed.", snapshotName)
@@ -131,32 +126,23 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
131126
}
132127
}
133128

129+
// If snapshot == nil but snapshot does not have
130+
// deletion timestamp, do not trigger deletion
131+
// of content because it may cause data loss.
134132
// Trigger content deletion if snapshot has deletion
135-
// timestamp or snapshot does not exist any more
133+
// timestamp.
136134
// If snapshot has deletion timestamp and finalizers, set
137135
// AnnVolumeSnapshotBeingDeleted annotation on the content.
138136
// This may trigger the deletion of the content in the
139137
// sidecar controller depending on the deletion policy
140138
// on the content.
141139
// Snapshot won't be deleted until content is deleted
142140
// due to the finalizer
143-
if snapshot == nil || utils.IsSnapshotDeletionCandidate(snapshot) {
144-
// Set AnnVolumeSnapshotBeingDeleted if it is not set yet
145-
if !metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingDeleted) {
146-
klog.V(5).Infof("syncContent: set annotation [%s] on content [%s].", utils.AnnVolumeSnapshotBeingDeleted, content.Name)
147-
metav1.SetMetaDataAnnotation(&content.ObjectMeta, utils.AnnVolumeSnapshotBeingDeleted, "yes")
148-
149-
updateContent, err := ctrl.clientset.SnapshotV1beta1().VolumeSnapshotContents().Update(content)
150-
if err != nil {
151-
return newControllerUpdateError(content.Name, err.Error())
152-
}
153-
154-
_, err = ctrl.storeContentUpdate(updateContent)
155-
if err != nil {
156-
klog.V(4).Infof("updating VolumeSnapshotContent[%s] error status: cannot update internal cache %v", content.Name, err)
157-
return err
158-
}
159-
klog.V(5).Infof("syncContent: volume snapshot content %+v", content)
141+
//if snapshot == nil || utils.IsSnapshotDeletionCandidate(snapshot) {
142+
if utils.IsSnapshotDeletionCandidate(snapshot) {
143+
_, err = ctrl.setAnnVolumeSnapshotBeingDeleted(content)
144+
if err != nil {
145+
return err
160146
}
161147
}
162148

@@ -171,28 +157,31 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
171157
func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnapshot) error {
172158
klog.V(5).Infof("synchronizing VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
173159

174-
err := ctrl.processFinalizersAndCheckandDeleteContent(snapshot)
175-
if err != nil {
176-
return err
177-
}
178-
179-
if !utils.IsSnapshotReady(snapshot) {
180-
return ctrl.syncUnreadySnapshot(snapshot)
160+
if snapshot.ObjectMeta.DeletionTimestamp != nil {
161+
err := ctrl.processIfDeletionTimestampSet(snapshot)
162+
if err != nil {
163+
return err
164+
}
165+
} else {
166+
klog.V(5).Infof("syncSnapshot[%s]: check if we should add finalizers on snapshot", utils.SnapshotKey(snapshot))
167+
ctrl.checkandAddSnapshotFinalizers(snapshot)
168+
// Need to build or update snapshot.Status in following cases:
169+
// 1) snapshot.Status is nil
170+
// 2) snapshot.Status.ReadyToUse is false
171+
// 3) snapshot.Status.BoundVolumeSnapshotContentName is not set
172+
if !utils.IsSnapshotReady(snapshot) || !utils.IsBoundVolumeSnapshotContentNameSet(snapshot) {
173+
return ctrl.syncUnreadySnapshot(snapshot)
174+
}
175+
return ctrl.syncReadySnapshot(snapshot)
181176
}
182-
return ctrl.syncReadySnapshot(snapshot)
177+
return nil
183178
}
184179

185-
// processFinalizersAndCheckandDeleteContent processes finalizers and deletes the content when appropriate
186-
// It checks if contents exists, it checks if snapshot has bi-directional binding, it checks if
187-
// finalizers should be added or removed, and it checks if content should be deleted and deletes it
188-
// if needed.
189-
func (ctrl *csiSnapshotCommonController) processFinalizersAndCheckandDeleteContent(snapshot *crdv1.VolumeSnapshot) error {
190-
klog.V(5).Infof("processFinalizersAndCheckandDeleteContent VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
191-
180+
func (ctrl *csiSnapshotCommonController) checkContentAndBoundStatus(snapshot *crdv1.VolumeSnapshot) (*crdv1.VolumeSnapshotContent, bool, bool, error) {
192181
// If content is deleted already, remove SnapshotBound finalizer
193182
content, err := ctrl.contentExists(snapshot)
194183
if err != nil {
195-
return err
184+
return nil, false, false, err
196185
}
197186
deleteContent := false
198187
// It is possible for contentExists to return nil, nil
@@ -206,18 +195,29 @@ func (ctrl *csiSnapshotCommonController) processFinalizersAndCheckandDeleteConte
206195
if content != nil && utils.IsSnapshotBound(snapshot, content) {
207196
klog.Infof("syncSnapshot: VolumeSnapshot %s is bound to volumeSnapshotContent [%s]", snapshot.Name, content.Name)
208197
snapshotBound = true
198+
199+
}
200+
return content, deleteContent, snapshotBound, nil
201+
}
202+
203+
// processIfDeletionTimestampSet processes finalizers and deletes the content when appropriate
204+
// It checks if contents exists, it checks if snapshot has bi-directional binding, it checks if
205+
// finalizers should be removed, and it checks if content should be deleted and deletes it if needed.
206+
func (ctrl *csiSnapshotCommonController) processIfDeletionTimestampSet(snapshot *crdv1.VolumeSnapshot) error {
207+
klog.V(5).Infof("processIfDeletionTimestampSet VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
208+
209+
content, deleteContent, _, err := ctrl.checkContentAndBoundStatus(snapshot)
210+
if err != nil {
211+
return err
209212
}
210213

211-
klog.V(5).Infof("processFinalizersAndCheckandDeleteContent[%s]: delete snapshot content and remove finalizer from snapshot if needed", utils.SnapshotKey(snapshot))
214+
klog.V(5).Infof("processIfDeletionTimestampSet[%s]: delete snapshot content and remove finalizer from snapshot if needed", utils.SnapshotKey(snapshot))
212215
err = ctrl.checkandRemoveSnapshotFinalizersAndCheckandDeleteContent(snapshot, content, deleteContent)
213216
if err != nil {
214217
return err
215218
}
216219

217-
klog.V(5).Infof("processFinalizersAndCheckandDeleteContent[%s]: check if we should add finalizers on snapshot", utils.SnapshotKey(snapshot))
218-
ctrl.checkandAddSnapshotFinalizers(snapshot, snapshotBound, deleteContent)
219-
220-
klog.V(5).Infof("processFinalizersAndCheckandDeleteContent[%s]: check if we should remove finalizer on snapshot source and remove it if we can", utils.SnapshotKey(snapshot))
220+
klog.V(5).Infof("processIfDeletionTimestampSet[%s]: check if we should remove finalizer on snapshot source and remove it if we can", utils.SnapshotKey(snapshot))
221221

222222
// Check if we should remove finalizer on PVC and remove it if we can.
223223
errFinalizer := ctrl.checkandRemovePVCFinalizer(snapshot)
@@ -231,7 +231,7 @@ func (ctrl *csiSnapshotCommonController) processFinalizersAndCheckandDeleteConte
231231

232232
// checkandRemoveSnapshotFinalizersAndCheckandDeleteContent deletes the content and removes snapshot finalizers if needed
233233
func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndCheckandDeleteContent(snapshot *crdv1.VolumeSnapshot, content *crdv1.VolumeSnapshotContent, deleteContent bool) error {
234-
klog.V(5).Infof("deleteContentAndSnapshotFinalizers VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
234+
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent VolumeSnapshot[%s]: %s", utils.SnapshotKey(snapshot), utils.GetSnapshotStatusForLogging(snapshot))
235235

236236
var err error
237237
// Check is snapshot deletionTimestamp is set and any finalizer is on
@@ -241,7 +241,7 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
241241
// Check if a volume is being created from snapshot.
242242
inUse := ctrl.isVolumeBeingCreatedFromSnapshot(snapshot)
243243

244-
klog.V(5).Infof("syncSnapshot[%s]: set DeletionTimeStamp on content.", utils.SnapshotKey(snapshot))
244+
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent[%s]: set DeletionTimeStamp on content.", utils.SnapshotKey(snapshot))
245245
// If content exists, set DeletionTimeStamp on the content;
246246
// content won't be deleted immediately due to the finalizer
247247
if content != nil && deleteContent && !inUse {
@@ -254,7 +254,7 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
254254
}
255255

256256
if !inUse || (content == nil && err == nil) {
257-
klog.V(5).Infof("syncSnapshot: Remove Finalizer for VolumeSnapshot[%s]", utils.SnapshotKey(snapshot))
257+
klog.V(5).Infof("checkandRemoveSnapshotFinalizersAndCheckandDeleteContent: Remove Finalizer for VolumeSnapshot[%s]", utils.SnapshotKey(snapshot))
258258
doesContentExist := false
259259
if content != nil {
260260
doesContentExist = true
@@ -266,7 +266,12 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
266266
}
267267

268268
// checkandAddSnapshotFinalizers checks and adds snapshot finailzers when needed
269-
func (ctrl *csiSnapshotCommonController) checkandAddSnapshotFinalizers(snapshot *crdv1.VolumeSnapshot, snapshotBound bool, deleteContent bool) {
269+
func (ctrl *csiSnapshotCommonController) checkandAddSnapshotFinalizers(snapshot *crdv1.VolumeSnapshot) error {
270+
_, deleteContent, snapshotBound, err := ctrl.checkContentAndBoundStatus(snapshot)
271+
if err != nil {
272+
return err
273+
}
274+
270275
addSourceFinalizer := false
271276
addBoundFinalizer := false
272277
if utils.NeedToAddSnapshotAsSourceFinalizer(snapshot) {
@@ -281,10 +286,11 @@ func (ctrl *csiSnapshotCommonController) checkandAddSnapshotFinalizers(snapshot
281286
klog.V(5).Infof("checkandAddSnapshotFinalizers: Add Finalizer for VolumeSnapshot[%s]", utils.SnapshotKey(snapshot))
282287
ctrl.addSnapshotFinalizer(snapshot, addSourceFinalizer, addBoundFinalizer)
283288
}
289+
return nil
284290
}
285291

286292
// syncReadySnapshot checks the snapshot which has been bound to snapshot content successfully before.
287-
// If there is any problem with the binding (e.g., snapshot points to a non-exist snapshot content), update the snapshot status and emit event.
293+
// If there is any problem with the binding (e.g., snapshot points to a non-existent snapshot content), update the snapshot status and emit event.
288294
func (ctrl *csiSnapshotCommonController) syncReadySnapshot(snapshot *crdv1.VolumeSnapshot) error {
289295
if !utils.IsBoundVolumeSnapshotContentNameSet(snapshot) {
290296
return nil
@@ -984,11 +990,34 @@ func (ctrl *csiSnapshotCommonController) getVolumeFromVolumeSnapshot(snapshot *c
984990
return nil, fmt.Errorf("failed to retrieve PV %s from the API server: %q", pvName, err)
985991
}
986992

993+
// Verify binding between PV/PVC is still valid
994+
bound := ctrl.isVolumeBoundToClaim(pv, pvc)
995+
if bound == false {
996+
klog.Warningf("binding between PV %s and PVC %s is broken", pvName, pvc.Name)
997+
return nil, fmt.Errorf("claim in dataSource not bound or invalid")
998+
}
999+
9871000
klog.V(5).Infof("getVolumeFromVolumeSnapshot: snapshot [%s] PV name [%s]", snapshot.Name, pvName)
9881001

9891002
return pv, nil
9901003
}
9911004

1005+
// isVolumeBoundToClaim returns true, if given volume is pre-bound or bound
1006+
// to specific claim. Both claim.Name and claim.Namespace must be equal.
1007+
// If claim.UID is present in volume.Spec.ClaimRef, it must be equal too.
1008+
func (ctrl *csiSnapshotCommonController) isVolumeBoundToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) bool {
1009+
if volume.Spec.ClaimRef == nil {
1010+
return false
1011+
}
1012+
if claim.Name != volume.Spec.ClaimRef.Name || claim.Namespace != volume.Spec.ClaimRef.Namespace {
1013+
return false
1014+
}
1015+
if volume.Spec.ClaimRef.UID != "" && claim.UID != volume.Spec.ClaimRef.UID {
1016+
return false
1017+
}
1018+
return true
1019+
}
1020+
9921021
func (ctrl *csiSnapshotCommonController) getStorageClassFromVolumeSnapshot(snapshot *crdv1.VolumeSnapshot) (*storagev1.StorageClass, error) {
9931022
// Get storage class from PVC or PV
9941023
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
@@ -1193,3 +1222,48 @@ func (ctrl *csiSnapshotCommonController) contentExists(snapshot *crdv1.VolumeSna
11931222
// Found in content cache store and convert object is successful
11941223
return content, nil
11951224
}
1225+
1226+
func (ctrl *csiSnapshotCommonController) snapshotExists(snapshotName string) (*crdv1.VolumeSnapshot, error) {
1227+
// Get the VolumeSnapshot by _name_
1228+
var snapshot *crdv1.VolumeSnapshot
1229+
obj, found, err := ctrl.snapshotStore.GetByKey(snapshotName)
1230+
if err != nil {
1231+
return nil, err
1232+
}
1233+
if !found {
1234+
klog.V(4).Infof("snapshotExists: snapshot %s not found", snapshotName)
1235+
// Fall through with snapshot = nil
1236+
return nil, nil
1237+
} else {
1238+
var ok bool
1239+
snapshot, ok = obj.(*crdv1.VolumeSnapshot)
1240+
if !ok {
1241+
return nil, fmt.Errorf("cannot convert object from snapshot cache to snapshot %q!?: %#v", snapshotName, obj)
1242+
}
1243+
klog.V(4).Infof("snapshotExists: snapshot %s found", snapshotName)
1244+
}
1245+
return snapshot, nil
1246+
}
1247+
1248+
func (ctrl *csiSnapshotCommonController) setAnnVolumeSnapshotBeingDeleted(content *crdv1.VolumeSnapshotContent) (*crdv1.VolumeSnapshotContent, error) {
1249+
// Set AnnVolumeSnapshotBeingDeleted if it is not set yet
1250+
if !metav1.HasAnnotation(content.ObjectMeta, utils.AnnVolumeSnapshotBeingDeleted) {
1251+
klog.V(5).Infof("setAnnVolumeSnapshotBeingDeleted: set annotation [%s] on content [%s].", utils.AnnVolumeSnapshotBeingDeleted, content.Name)
1252+
metav1.SetMetaDataAnnotation(&content.ObjectMeta, utils.AnnVolumeSnapshotBeingDeleted, "yes")
1253+
1254+
updateContent, err := ctrl.clientset.SnapshotV1beta1().VolumeSnapshotContents().Update(content)
1255+
if err != nil {
1256+
return content, newControllerUpdateError(content.Name, err.Error())
1257+
}
1258+
// update content if update is successful
1259+
content = updateContent
1260+
1261+
_, err = ctrl.storeContentUpdate(content)
1262+
if err != nil {
1263+
klog.V(4).Infof("setAnnVolumeSnapshotBeingDeleted for content [%s]: cannot update internal cache %v", content.Name, err)
1264+
return content, err
1265+
}
1266+
klog.V(5).Infof("setAnnVolumeSnapshotBeingDeleted: volume snapshot content %+v", content)
1267+
}
1268+
return content, nil
1269+
}

pkg/utils/util.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -318,30 +318,30 @@ func NoResyncPeriodFunc() time.Duration {
318318
return 0
319319
}
320320

321-
// isContentDeletionCandidate checks if a volume snapshot content is a deletion candidate.
321+
// IsContentDeletionCandidate checks if a volume snapshot content is a deletion candidate.
322322
// It is a deletion candidate if DeletionTimestamp is not nil and
323323
// VolumeSnapshotContentFinalizer is set.
324324
func IsContentDeletionCandidate(content *crdv1.VolumeSnapshotContent) bool {
325325
return content.ObjectMeta.DeletionTimestamp != nil && slice.ContainsString(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil)
326326
}
327327

328-
// needToAddContentFinalizer checks if a Finalizer needs to be added for the volume snapshot content.
328+
// NeedToAddContentFinalizer checks if a Finalizer needs to be added for the volume snapshot content.
329329
func NeedToAddContentFinalizer(content *crdv1.VolumeSnapshotContent) bool {
330330
return content.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(content.ObjectMeta.Finalizers, VolumeSnapshotContentFinalizer, nil)
331331
}
332332

333-
// isSnapshotDeletionCandidate checks if a volume snapshot deletionTimestamp
333+
// IsSnapshotDeletionCandidate checks if a volume snapshot deletionTimestamp
334334
// is set and any finalizer is on the snapshot.
335335
func IsSnapshotDeletionCandidate(snapshot *crdv1.VolumeSnapshot) bool {
336336
return snapshot.ObjectMeta.DeletionTimestamp != nil && (slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotAsSourceFinalizer, nil) || slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotBoundFinalizer, nil))
337337
}
338338

339-
// needToAddSnapshotAsSourceFinalizer checks if a Finalizer needs to be added for the volume snapshot as a source for PVC.
339+
// NeedToAddSnapshotAsSourceFinalizer checks if a Finalizer needs to be added for the volume snapshot as a source for PVC.
340340
func NeedToAddSnapshotAsSourceFinalizer(snapshot *crdv1.VolumeSnapshot) bool {
341341
return snapshot.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotAsSourceFinalizer, nil)
342342
}
343343

344-
// needToAddSnapshotBoundFinalizer checks if a Finalizer needs to be added for the bound volume snapshot.
344+
// NeedToAddSnapshotBoundFinalizer checks if a Finalizer needs to be added for the bound volume snapshot.
345345
func NeedToAddSnapshotBoundFinalizer(snapshot *crdv1.VolumeSnapshot) bool {
346346
return snapshot.ObjectMeta.DeletionTimestamp == nil && !slice.ContainsString(snapshot.ObjectMeta.Finalizers, VolumeSnapshotBoundFinalizer, nil) && snapshot.Status != nil && snapshot.Status.BoundVolumeSnapshotContentName != nil
347347
}

0 commit comments

Comments
 (0)