@@ -25,6 +25,7 @@ import (
25
25
"github.com/onsi/gomega"
26
26
v1 "k8s.io/api/core/v1"
27
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ "k8s.io/client-go/util/retry"
28
29
storagehelpers "k8s.io/component-helpers/storage/volume"
29
30
"k8s.io/kubernetes/pkg/features"
30
31
"k8s.io/kubernetes/test/e2e/feature"
@@ -189,4 +190,120 @@ var _ = utils.SIGDescribe("CSI Mock honor pv reclaim policy", feature.HonorPVRec
189
190
gomega .Expect (m .driver .GetCalls (ctx )).NotTo (gomega .ContainElement (gomega .HaveField ("Method" , gomega .Equal ("DeleteVolume" ))))
190
191
})
191
192
})
193
+
194
+ ginkgo .Context ("CSI honor pv reclaim policy changes using mock driver" , func () {
195
+ ginkgo .It ("should honor pv reclaim policy after it is changed from retain to deleted" , func (ctx context.Context ) {
196
+ m .init (ctx , testParameters {
197
+ registerDriver : true ,
198
+ enableHonorPVReclaimPolicy : true ,
199
+ reclaimPolicy : ptr .To (v1 .PersistentVolumeReclaimRetain ),
200
+ })
201
+ ginkgo .DeferCleanup (m .cleanup )
202
+
203
+ _ , pvc := m .createPVC (ctx )
204
+
205
+ ginkgo .By (fmt .Sprintf ("Waiting for PVC %s to be bound" , pvc .Name ))
206
+ pvs , err := e2epv .WaitForPVClaimBoundPhase (ctx , f .ClientSet , []* v1.PersistentVolumeClaim {pvc }, framework .ClaimProvisionTimeout )
207
+ framework .ExpectNoError (err , "failed to wait for PVC to be bound" )
208
+ gomega .Expect (pvs ).To (gomega .HaveLen (1 ), "expected 1 PV to be bound to PVC, got %d" , len (pvs ))
209
+
210
+ pv := pvs [0 ]
211
+ ginkgo .By (fmt .Sprintf ("PVC %s is bound to PV %s" , pvc .Name , pv .Name ))
212
+ gomega .Expect (pv .Spec .PersistentVolumeReclaimPolicy ).To (gomega .Equal (v1 .PersistentVolumeReclaimRetain ),
213
+ "expected PV %s to have reclaim policy %s, got %s" , pv .Name , v1 .PersistentVolumeReclaimRetain , pv .Spec .PersistentVolumeReclaimPolicy )
214
+
215
+ ginkgo .By (fmt .Sprintf ("Verifying that the PV %s does not have finalizer %s after creation" , pv .Name , storagehelpers .PVDeletionProtectionFinalizer ))
216
+ gomega .Consistently (ctx , framework .GetObject (f .ClientSet .CoreV1 ().PersistentVolumes ().Get , pv .Name , metav1.GetOptions {})).
217
+ WithPolling (framework .Poll ).WithTimeout (framework .ClaimProvisionTimeout ).ShouldNot (gomega .HaveField ("Finalizers" ,
218
+ gomega .ContainElement (storagehelpers .PVDeletionProtectionFinalizer )), "pv unexpectedly has the finalizer %s" , storagehelpers .PVDeletionProtectionFinalizer )
219
+
220
+ ginkgo .By (fmt .Sprintf ("Changing the reclaim policy of PV %s to %s" , pv .Name , v1 .PersistentVolumeReclaimDelete ))
221
+ err = retry .RetryOnConflict (retry .DefaultRetry , func () error {
222
+ pv , err := f .ClientSet .CoreV1 ().PersistentVolumes ().Get (ctx , pv .Name , metav1.GetOptions {})
223
+ if err != nil {
224
+ return err
225
+ }
226
+ pv .Spec .PersistentVolumeReclaimPolicy = v1 .PersistentVolumeReclaimDelete
227
+ _ , err = f .ClientSet .CoreV1 ().PersistentVolumes ().Update (ctx , pv , metav1.UpdateOptions {})
228
+ return err
229
+ })
230
+ framework .ExpectNoError (err , "failed to update PV %s" , pv .Name )
231
+
232
+ ginkgo .By (fmt .Sprintf ("Verifying that the PV %s has finalizer %s after reclaim policy is changed" , pv .Name , storagehelpers .PVDeletionProtectionFinalizer ))
233
+ gomega .Eventually (ctx , framework .GetObject (f .ClientSet .CoreV1 ().PersistentVolumes ().Get , pv .Name , metav1.GetOptions {})).
234
+ WithPolling (framework .Poll ).WithTimeout (framework .ClaimProvisionTimeout ).Should (gomega .HaveField ("Finalizers" ,
235
+ gomega .ContainElement (storagehelpers .PVDeletionProtectionFinalizer )), "failed to wait for PV to have finalizer %s" , storagehelpers .PVDeletionProtectionFinalizer )
236
+
237
+ ginkgo .By (fmt .Sprintf ("Deleting PV %s" , pv .Name ))
238
+ err = f .ClientSet .CoreV1 ().PersistentVolumes ().Delete (ctx , pv .Name , metav1.DeleteOptions {})
239
+ framework .ExpectNoError (err , "failed to delete PV %s" , pv .Name )
240
+
241
+ ginkgo .By (fmt .Sprintf ("Deleting PVC %s" , pvc .Name ))
242
+ err = f .ClientSet .CoreV1 ().PersistentVolumeClaims (pvc .Namespace ).Delete (ctx , pvc .Name , metav1.DeleteOptions {})
243
+ framework .ExpectNoError (err , "failed to delete PVC %s" , pvc .Name )
244
+
245
+ ginkgo .By (fmt .Sprintf ("Waiting for PV %s to be deleted" , pv .Name ))
246
+ err = e2epv .WaitForPersistentVolumeDeleted (ctx , f .ClientSet , pv .Name , framework .Poll , 2 * time .Minute )
247
+ framework .ExpectNoError (err , "failed to wait for PV to be deleted" )
248
+
249
+ ginkgo .By (fmt .Sprintf ("Verifying that the driver received DeleteVolume call for PV %s" , pv .Name ))
250
+ gomega .Expect (m .driver .GetCalls (ctx )).To (gomega .ContainElement (gomega .HaveField ("Method" , gomega .Equal ("DeleteVolume" ))))
251
+ })
252
+
253
+ ginkgo .It ("should honor pv reclaim policy after it is changed from deleted to retain" , func (ctx context.Context ) {
254
+ m .init (ctx , testParameters {
255
+ registerDriver : true ,
256
+ enableHonorPVReclaimPolicy : true ,
257
+ reclaimPolicy : ptr .To (v1 .PersistentVolumeReclaimDelete ),
258
+ })
259
+ ginkgo .DeferCleanup (m .cleanup )
260
+
261
+ _ , pvc := m .createPVC (ctx )
262
+
263
+ ginkgo .By (fmt .Sprintf ("Waiting for PVC %s to be bound" , pvc .Name ))
264
+ pvs , err := e2epv .WaitForPVClaimBoundPhase (ctx , f .ClientSet , []* v1.PersistentVolumeClaim {pvc }, framework .ClaimProvisionTimeout )
265
+ framework .ExpectNoError (err , "failed to wait for PVC to be bound" )
266
+ gomega .Expect (pvs ).To (gomega .HaveLen (1 ), "expected 1 PV to be bound to PVC, got %d" , len (pvs ))
267
+
268
+ pv := pvs [0 ]
269
+ ginkgo .By (fmt .Sprintf ("PVC %s is bound to PV %s" , pvc .Name , pv .Name ))
270
+ gomega .Expect (pv .Spec .PersistentVolumeReclaimPolicy ).To (gomega .Equal (v1 .PersistentVolumeReclaimDelete ),
271
+ "expected PV %s to have reclaim policy %s, got %s" , pv .Name , v1 .PersistentVolumeReclaimDelete , pv .Spec .PersistentVolumeReclaimPolicy )
272
+ // For dynamic provisioning, the PV should be created with the deletion protection finalizer.
273
+ gomega .Expect (pv .Finalizers ).To (gomega .ContainElement (storagehelpers .PVDeletionProtectionFinalizer ),
274
+ "expected PV %s to have finalizer %s" , pv .Name , storagehelpers .PVDeletionProtectionFinalizer )
275
+
276
+ ginkgo .By (fmt .Sprintf ("Changing the reclaim policy of PV %s to %s" , pv .Name , v1 .PersistentVolumeReclaimRetain ))
277
+ err = retry .RetryOnConflict (retry .DefaultRetry , func () error {
278
+ pv , err := f .ClientSet .CoreV1 ().PersistentVolumes ().Get (ctx , pv .Name , metav1.GetOptions {})
279
+ if err != nil {
280
+ return err
281
+ }
282
+ pv .Spec .PersistentVolumeReclaimPolicy = v1 .PersistentVolumeReclaimRetain
283
+ _ , err = f .ClientSet .CoreV1 ().PersistentVolumes ().Update (ctx , pv , metav1.UpdateOptions {})
284
+ return err
285
+ })
286
+ framework .ExpectNoError (err , "failed to update PV %s" , pv .Name )
287
+
288
+ ginkgo .By (fmt .Sprintf ("Verifying that the PV %s drops finalizer %s after reclaim policy is changed" , pv .Name , storagehelpers .PVDeletionProtectionFinalizer ))
289
+ gomega .Eventually (ctx , framework .GetObject (f .ClientSet .CoreV1 ().PersistentVolumes ().Get , pv .Name , metav1.GetOptions {})).
290
+ WithPolling (framework .Poll ).WithTimeout (framework .ClaimProvisionTimeout ).ShouldNot (gomega .HaveField ("Finalizers" ,
291
+ gomega .ContainElement (storagehelpers .PVDeletionProtectionFinalizer )), "pv unexpectedly has the finalizer %s" , storagehelpers .PVDeletionProtectionFinalizer )
292
+
293
+ ginkgo .By (fmt .Sprintf ("Deleting PV %s" , pv .Name ))
294
+ err = f .ClientSet .CoreV1 ().PersistentVolumes ().Delete (ctx , pv .Name , metav1.DeleteOptions {})
295
+ framework .ExpectNoError (err , "failed to delete PV %s" , pv .Name )
296
+
297
+ ginkgo .By (fmt .Sprintf ("Deleting PVC %s" , pvc .Name ))
298
+ err = f .ClientSet .CoreV1 ().PersistentVolumeClaims (pvc .Namespace ).Delete (ctx , pvc .Name , metav1.DeleteOptions {})
299
+ framework .ExpectNoError (err , "failed to delete PVC %s" , pvc .Name )
300
+
301
+ ginkgo .By (fmt .Sprintf ("Waiting for PV %s to be deleted" , pv .Name ))
302
+ err = e2epv .WaitForPersistentVolumeDeleted (ctx , f .ClientSet , pv .Name , framework .Poll , 2 * time .Minute )
303
+ framework .ExpectNoError (err , "failed to wait for PV to be deleted" )
304
+
305
+ ginkgo .By (fmt .Sprintf ("Verifying that the driver did not receive DeleteVolume call for PV %s" , pv .Name ))
306
+ gomega .Expect (m .driver .GetCalls (ctx )).NotTo (gomega .ContainElement (gomega .HaveField ("Method" , gomega .Equal ("DeleteVolume" ))))
307
+ })
308
+ })
192
309
})
0 commit comments