Skip to content

Commit 42650bc

Browse files
authored
Merge pull request #360 from xing-yang/remove_finalizer
Fix the race between PVC finalizer and snapshot finalizer removal
2 parents 34af0c5 + 1ba5602 commit 42650bc

File tree

2 files changed

+34
-35
lines changed

2 files changed

+34
-35
lines changed

pkg/common-controller/framework_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ func testAddPVCFinalizer(ctrl *csiSnapshotCommonController, reactor *snapshotRea
11471147
}
11481148

11491149
func testRemovePVCFinalizer(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {
1150-
return ctrl.checkandRemovePVCFinalizer(test.initialSnapshots[0])
1150+
return ctrl.checkandRemovePVCFinalizer(test.initialSnapshots[0], false)
11511151
}
11521152

11531153
func testAddSnapshotFinalizer(ctrl *csiSnapshotCommonController, reactor *snapshotReactor, test controllerTest) error {

pkg/common-controller/snapshot_controller.go

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnap
182182
klog.V(5).Infof("syncSnapshot [%s]: check if we should remove finalizer on snapshot PVC source and remove it if we can", utils.SnapshotKey(snapshot))
183183

184184
// Check if we should remove finalizer on PVC and remove it if we can.
185-
if err := ctrl.checkandRemovePVCFinalizer(snapshot); err != nil {
185+
if err := ctrl.checkandRemovePVCFinalizer(snapshot, false); err != nil {
186186
klog.Errorf("error check and remove PVC finalizer for snapshot [%s]: %v", snapshot.Name, err)
187187
// Log an event and keep the original error from checkandRemovePVCFinalizer
188188
ctrl.eventRecorder.Event(snapshot, v1.EventTypeWarning, "ErrorPVCFinalizer", "Error check and remove PVC Finalizer for VolumeSnapshot")
@@ -198,11 +198,8 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnap
198198
return err
199199
}
200200

201-
// Proceed with snapshot deletion only if snapshot is not in the middled of being
202-
// created from a PVC with a finalizer. This is to ensure that the PVC finalizer
203-
// can be removed even if a delete snapshot request is received before create
204-
// snapshot has completed.
205-
if snapshot.ObjectMeta.DeletionTimestamp != nil && !ctrl.isPVCwithFinalizerInUseByCurrentSnapshot(snapshot) {
201+
// Proceed with snapshot deletion and remove finalizers when needed
202+
if snapshot.ObjectMeta.DeletionTimestamp != nil {
206203
return ctrl.processSnapshotWithDeletionTimestamp(snapshot)
207204
}
208205

@@ -234,27 +231,6 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnap
234231
return ctrl.syncReadySnapshot(snapshot)
235232
}
236233

237-
// Check if PVC has a finalizer and if it is being used by the current snapshot as source.
238-
func (ctrl *csiSnapshotCommonController) isPVCwithFinalizerInUseByCurrentSnapshot(snapshot *crdv1.VolumeSnapshot) bool {
239-
// Get snapshot source which is a PVC
240-
pvc, err := ctrl.getClaimFromVolumeSnapshot(snapshot)
241-
if err != nil {
242-
klog.Infof("cannot get claim from snapshot [%s]: [%v] Claim may be deleted already.", snapshot.Name, err)
243-
return false
244-
}
245-
246-
// Check if there is a Finalizer on PVC. If not, return false
247-
if !utils.ContainsString(pvc.ObjectMeta.Finalizers, utils.PVCFinalizer) {
248-
return false
249-
}
250-
251-
if !utils.IsSnapshotReady(snapshot) {
252-
klog.V(2).Infof("PVC %s/%s is being used by snapshot %s/%s as source", pvc.Namespace, pvc.Name, snapshot.Namespace, snapshot.Name)
253-
return true
254-
}
255-
return false
256-
}
257-
258234
// processSnapshotWithDeletionTimestamp processes finalizers and deletes the content when appropriate. It has the following steps:
259235
// 1. Get the content which the to-be-deleted VolumeSnapshot points to and verifies bi-directional binding.
260236
// 2. Call checkandRemoveSnapshotFinalizersAndCheckandDeleteContent() with information obtained from step 1. This function name is very long but the name suggests what it does. It determines whether to remove finalizers on snapshot and whether to delete content.
@@ -858,7 +834,7 @@ func (ctrl *csiSnapshotCommonController) ensurePVCFinalizer(snapshot *crdv1.Volu
858834
}
859835

860836
// removePVCFinalizer removes a Finalizer for VolumeSnapshot Source PVC.
861-
func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVolumeClaim, snapshot *crdv1.VolumeSnapshot) error {
837+
func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVolumeClaim) error {
862838
// Get snapshot source which is a PVC
863839
// TODO(xyang): We get PVC from informer but it may be outdated
864840
// Should get it from API server directly before removing finalizer
@@ -874,8 +850,9 @@ func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVo
874850
return nil
875851
}
876852

877-
// isPVCBeingUsed checks if a PVC is being used as a source to create a snapshot
878-
func (ctrl *csiSnapshotCommonController) isPVCBeingUsed(pvc *v1.PersistentVolumeClaim, snapshot *crdv1.VolumeSnapshot) bool {
853+
// isPVCBeingUsed checks if a PVC is being used as a source to create a snapshot.
854+
// If skipCurrentSnapshot is true, skip checking if the current snapshot is using the PVC as source.
855+
func (ctrl *csiSnapshotCommonController) isPVCBeingUsed(pvc *v1.PersistentVolumeClaim, snapshot *crdv1.VolumeSnapshot, skipCurrentSnapshot bool) bool {
879856
klog.V(5).Infof("Checking isPVCBeingUsed for snapshot [%s]", utils.SnapshotKey(snapshot))
880857

881858
// Going through snapshots in the cache (snapshotLister). If a snapshot's PVC source
@@ -886,6 +863,10 @@ func (ctrl *csiSnapshotCommonController) isPVCBeingUsed(pvc *v1.PersistentVolume
886863
return false
887864
}
888865
for _, snap := range snapshots {
866+
// Skip the current snapshot
867+
if skipCurrentSnapshot && snap.Name == snapshot.Name {
868+
continue
869+
}
889870
// Skip pre-provisioned snapshot without a PVC source
890871
if snap.Spec.Source.PersistentVolumeClaimName == nil && snap.Spec.Source.VolumeSnapshotContentName != nil {
891872
klog.V(4).Infof("Skipping static bound snapshot %s when checking PVC %s/%s", snap.Name, pvc.Namespace, pvc.Name)
@@ -902,8 +883,9 @@ func (ctrl *csiSnapshotCommonController) isPVCBeingUsed(pvc *v1.PersistentVolume
902883
}
903884

904885
// checkandRemovePVCFinalizer checks if the snapshot source finalizer should be removed
905-
// and removed it if needed.
906-
func (ctrl *csiSnapshotCommonController) checkandRemovePVCFinalizer(snapshot *crdv1.VolumeSnapshot) error {
886+
// and removed it if needed. If skipCurrentSnapshot is true, skip checking if the current
887+
// snapshot is using the PVC as source.
888+
func (ctrl *csiSnapshotCommonController) checkandRemovePVCFinalizer(snapshot *crdv1.VolumeSnapshot, skipCurrentSnapshot bool) error {
907889
if snapshot.Spec.Source.PersistentVolumeClaimName == nil {
908890
// PVC finalizer is only needed for dynamic provisioning
909891
return nil
@@ -922,10 +904,10 @@ func (ctrl *csiSnapshotCommonController) checkandRemovePVCFinalizer(snapshot *cr
922904
if utils.ContainsString(pvc.ObjectMeta.Finalizers, utils.PVCFinalizer) {
923905
// There is a Finalizer on PVC. Check if PVC is used
924906
// and remove finalizer if it's not used.
925-
inUse := ctrl.isPVCBeingUsed(pvc, snapshot)
907+
inUse := ctrl.isPVCBeingUsed(pvc, snapshot, skipCurrentSnapshot)
926908
if !inUse {
927909
klog.Infof("checkandRemovePVCFinalizer[%s]: Remove Finalizer for PVC %s as it is not used by snapshots in creation", snapshot.Name, pvc.Name)
928-
err = ctrl.removePVCFinalizer(pvc, snapshot)
910+
err = ctrl.removePVCFinalizer(pvc)
929911
if err != nil {
930912
klog.Errorf("checkandRemovePVCFinalizer [%s]: removePVCFinalizer failed to remove finalizer %v", snapshot.Name, err)
931913
return err
@@ -1325,6 +1307,23 @@ func (ctrl *csiSnapshotCommonController) removeSnapshotFinalizer(snapshot *crdv1
13251307
return nil
13261308
}
13271309

1310+
// NOTE(xyang): We have to make sure PVC finalizer is deleted before
1311+
// the VolumeSnapshot API object is deleted. Once the VolumeSnapshot
1312+
// API object is deleted, there won't be any VolumeSnapshot update
1313+
// event that can trigger the PVC finalizer removal any more.
1314+
// We also can't remove PVC finalizer too early. PVC finalizer should
1315+
// not be removed if a VolumeSnapshot API object is still using it.
1316+
// If we are here, it means we are going to remove finalizers from the
1317+
// VolumeSnapshot API object so that the VolumeSnapshot API object can
1318+
// be deleted. This means we no longer need to keep the PVC finalizer
1319+
// for this particular snapshot.
1320+
if err := ctrl.checkandRemovePVCFinalizer(snapshot, true); err != nil {
1321+
klog.Errorf("removeSnapshotFinalizer: error check and remove PVC finalizer for snapshot [%s]: %v", snapshot.Name, err)
1322+
// Log an event and keep the original error from checkandRemovePVCFinalizer
1323+
ctrl.eventRecorder.Event(snapshot, v1.EventTypeWarning, "ErrorPVCFinalizer", "Error check and remove PVC Finalizer for VolumeSnapshot")
1324+
return newControllerUpdateError(snapshot.Name, err.Error())
1325+
}
1326+
13281327
snapshotClone := snapshot.DeepCopy()
13291328
if removeSourceFinalizer {
13301329
snapshotClone.ObjectMeta.Finalizers = utils.RemoveString(snapshotClone.ObjectMeta.Finalizers, utils.VolumeSnapshotAsSourceFinalizer)

0 commit comments

Comments
 (0)