@@ -85,43 +85,38 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
85
85
86
86
snapshotName := utils .SnapshotRefKey (& content .Spec .VolumeSnapshotRef )
87
87
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
-
94
88
klog .V (4 ).Infof ("synchronizing VolumeSnapshotContent[%s]: content is bound to snapshot %s" , content .Name , snapshotName )
95
89
// The VolumeSnapshotContent is reserved for a VolumeSnapshot;
96
90
// that VolumeSnapshot has not yet been bound to this VolumeSnapshotContent; the VolumeSnapshot sync will handle it.
97
91
if content .Spec .VolumeSnapshotRef .UID == "" {
98
92
klog .V (4 ).Infof ("synchronizing VolumeSnapshotContent[%s]: VolumeSnapshotContent is pre-bound to VolumeSnapshot %s" , content .Name , snapshotName )
99
93
return nil
100
94
}
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
102
106
var snapshot * crdv1.VolumeSnapshot
103
- obj , found , err := ctrl .snapshotStore . GetByKey (snapshotName )
107
+ snapshot , err := ctrl .snapshotExists (snapshotName )
104
108
if err != nil {
105
109
return err
106
110
}
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
+
118
112
if snapshot != nil && snapshot .UID != content .Spec .VolumeSnapshotRef .UID {
119
113
// The snapshot that the content was pointing to was deleted, and another
120
114
// with the same name created.
121
115
klog .V (4 ).Infof ("synchronizing VolumeSnapshotContent[%s]: content %s has different UID, the old one must have been deleted" , content .Name , snapshotName )
122
116
// Treat the content as bound to a missing snapshot.
123
117
snapshot = nil
124
118
} 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
125
120
// Check if content status is set to true and update snapshot status if so
126
121
if snapshot != nil && content .Status != nil && content .Status .ReadyToUse != nil && * content .Status .ReadyToUse == true {
127
122
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
131
126
}
132
127
}
133
128
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.
134
132
// Trigger content deletion if snapshot has deletion
135
- // timestamp or snapshot does not exist any more
133
+ // timestamp.
136
134
// If snapshot has deletion timestamp and finalizers, set
137
135
// AnnVolumeSnapshotBeingDeleted annotation on the content.
138
136
// This may trigger the deletion of the content in the
139
137
// sidecar controller depending on the deletion policy
140
138
// on the content.
141
139
// Snapshot won't be deleted until content is deleted
142
140
// 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
160
146
}
161
147
}
162
148
@@ -171,28 +157,31 @@ func (ctrl *csiSnapshotCommonController) syncContent(content *crdv1.VolumeSnapsh
171
157
func (ctrl * csiSnapshotCommonController ) syncSnapshot (snapshot * crdv1.VolumeSnapshot ) error {
172
158
klog .V (5 ).Infof ("synchronizing VolumeSnapshot[%s]: %s" , utils .SnapshotKey (snapshot ), utils .GetSnapshotStatusForLogging (snapshot ))
173
159
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 )
181
176
}
182
- return ctrl . syncReadySnapshot ( snapshot )
177
+ return nil
183
178
}
184
179
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 ) {
192
181
// If content is deleted already, remove SnapshotBound finalizer
193
182
content , err := ctrl .contentExists (snapshot )
194
183
if err != nil {
195
- return err
184
+ return nil , false , false , err
196
185
}
197
186
deleteContent := false
198
187
// It is possible for contentExists to return nil, nil
@@ -206,18 +195,29 @@ func (ctrl *csiSnapshotCommonController) processFinalizersAndCheckandDeleteConte
206
195
if content != nil && utils .IsSnapshotBound (snapshot , content ) {
207
196
klog .Infof ("syncSnapshot: VolumeSnapshot %s is bound to volumeSnapshotContent [%s]" , snapshot .Name , content .Name )
208
197
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
209
212
}
210
213
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 ))
212
215
err = ctrl .checkandRemoveSnapshotFinalizersAndCheckandDeleteContent (snapshot , content , deleteContent )
213
216
if err != nil {
214
217
return err
215
218
}
216
219
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 ))
221
221
222
222
// Check if we should remove finalizer on PVC and remove it if we can.
223
223
errFinalizer := ctrl .checkandRemovePVCFinalizer (snapshot )
@@ -231,7 +231,7 @@ func (ctrl *csiSnapshotCommonController) processFinalizersAndCheckandDeleteConte
231
231
232
232
// checkandRemoveSnapshotFinalizersAndCheckandDeleteContent deletes the content and removes snapshot finalizers if needed
233
233
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 ))
235
235
236
236
var err error
237
237
// Check is snapshot deletionTimestamp is set and any finalizer is on
@@ -241,7 +241,7 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
241
241
// Check if a volume is being created from snapshot.
242
242
inUse := ctrl .isVolumeBeingCreatedFromSnapshot (snapshot )
243
243
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 ))
245
245
// If content exists, set DeletionTimeStamp on the content;
246
246
// content won't be deleted immediately due to the finalizer
247
247
if content != nil && deleteContent && ! inUse {
@@ -254,7 +254,7 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
254
254
}
255
255
256
256
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 ))
258
258
doesContentExist := false
259
259
if content != nil {
260
260
doesContentExist = true
@@ -266,7 +266,12 @@ func (ctrl *csiSnapshotCommonController) checkandRemoveSnapshotFinalizersAndChec
266
266
}
267
267
268
268
// 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
+
270
275
addSourceFinalizer := false
271
276
addBoundFinalizer := false
272
277
if utils .NeedToAddSnapshotAsSourceFinalizer (snapshot ) {
@@ -281,10 +286,11 @@ func (ctrl *csiSnapshotCommonController) checkandAddSnapshotFinalizers(snapshot
281
286
klog .V (5 ).Infof ("checkandAddSnapshotFinalizers: Add Finalizer for VolumeSnapshot[%s]" , utils .SnapshotKey (snapshot ))
282
287
ctrl .addSnapshotFinalizer (snapshot , addSourceFinalizer , addBoundFinalizer )
283
288
}
289
+ return nil
284
290
}
285
291
286
292
// 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.
288
294
func (ctrl * csiSnapshotCommonController ) syncReadySnapshot (snapshot * crdv1.VolumeSnapshot ) error {
289
295
if ! utils .IsBoundVolumeSnapshotContentNameSet (snapshot ) {
290
296
return nil
@@ -984,11 +990,34 @@ func (ctrl *csiSnapshotCommonController) getVolumeFromVolumeSnapshot(snapshot *c
984
990
return nil , fmt .Errorf ("failed to retrieve PV %s from the API server: %q" , pvName , err )
985
991
}
986
992
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
+
987
1000
klog .V (5 ).Infof ("getVolumeFromVolumeSnapshot: snapshot [%s] PV name [%s]" , snapshot .Name , pvName )
988
1001
989
1002
return pv , nil
990
1003
}
991
1004
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
+
992
1021
func (ctrl * csiSnapshotCommonController ) getStorageClassFromVolumeSnapshot (snapshot * crdv1.VolumeSnapshot ) (* storagev1.StorageClass , error ) {
993
1022
// Get storage class from PVC or PV
994
1023
pvc , err := ctrl .getClaimFromVolumeSnapshot (snapshot )
@@ -1193,3 +1222,48 @@ func (ctrl *csiSnapshotCommonController) contentExists(snapshot *crdv1.VolumeSna
1193
1222
// Found in content cache store and convert object is successful
1194
1223
return content , nil
1195
1224
}
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
+ }
0 commit comments