Skip to content

Commit 903fd7f

Browse files
committed
Initial impl of delete workflow
1 parent 71e23e9 commit 903fd7f

File tree

3 files changed

+129
-42
lines changed

3 files changed

+129
-42
lines changed

pkg/syncer/cnsoperator/controller/cnsunregistervolume/controller.go

Lines changed: 120 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,15 @@ func (r *Reconciler) Reconcile(ctx context.Context,
195195
}()
196196

197197
if instance.DeletionTimestamp != nil {
198-
// TODO: Need to handle deletion if the instance is not fully processed.
199-
log.Info("instance is being deleted")
200-
err = removeFinalizer(ctx, r.client, instance)
198+
log.Info("instance is marked for deletion")
199+
err = r.reconcileDelete(ctx, *instance, request)
200+
if err != nil {
201+
log.Error("failed to reconcile with error ", err)
202+
return reconcile.Result{}, err
203+
}
204+
205+
log.Info("removing finalizer and allowing deletion of the instance")
206+
err := removeFinalizer(ctx, r.client, instance)
201207
if err != nil {
202208
log.Error("failed to remove finalizer from the instance with error ", err)
203209
return reconcile.Result{}, err
@@ -220,81 +226,150 @@ func (r *Reconciler) Reconcile(ctx context.Context,
220226
return reconcile.Result{}, err
221227
}
222228

223-
// Initialize backOffDuration for the instance, if required.
224-
duration := getBackoffDuration(ctx, request.NamespacedName)
225-
params, err := getValidatedParams(ctx, *instance)
229+
err = r.reconcile(ctx, instance, request)
226230
if err != nil {
227-
log.Error("failed to get input parameters with error ", err)
231+
log.Error("failed to reconcile with error ", err)
228232
setInstanceError(ctx, r, instance, err.Error())
229-
return reconcile.Result{RequeueAfter: duration}, nil
233+
return reconcile.Result{RequeueAfter: getBackoffDuration(ctx, request.NamespacedName)}, nil
230234
}
231235

232-
k8sClient, err := newK8sClient(ctx)
236+
msg := "successfully unregistered the volume"
237+
err = setInstanceSuccess(ctx, r, instance, msg)
233238
if err != nil {
234-
log.Error("failed to init K8s client for volume unregistration with error ", err)
235-
setInstanceError(ctx, r, instance, "failed to init K8s client for volume unregistration")
236-
return reconcile.Result{RequeueAfter: duration}, nil
239+
log.Warn("failed to set instance to success with error ", err)
240+
setInstanceError(ctx, r, instance, "failed to set instance to success")
241+
return reconcile.Result{RequeueAfter: getBackoffDuration(ctx, request.NamespacedName)}, nil
242+
}
243+
244+
deleteBackoffEntry(ctx, request.NamespacedName)
245+
log.Info(msg)
246+
return reconcile.Result{}, nil
247+
}
248+
249+
func (r *Reconciler) reconcile(ctx context.Context,
250+
instance *v1a1.CnsUnregisterVolume, request reconcile.Request) error {
251+
log := logger.GetLogger(ctx).With("name", request.NamespacedName)
252+
253+
params, err := getValidatedParams(ctx, *instance)
254+
if err != nil {
255+
log.Error("invalid input parameters", err)
256+
return err
237257
}
238258

239-
usageInfo, err := getVolumeUsageInfo(ctx, k8sClient, params.pvcName, params.namespace,
259+
usageInfo, err := getVolumeUsageInfo(ctx, params.pvcName, params.namespace,
240260
instance.Spec.ForceUnregister)
241261
if err != nil {
242-
setInstanceError(ctx, r, instance, err.Error())
243-
return reconcile.Result{RequeueAfter: duration}, nil
262+
log.Error("failed to get volume usage info with error ", err)
263+
return err
244264
}
245265

246266
if usageInfo.isInUse {
247267
msg := fmt.Sprintf("volume %s cannot be unregistered because %s", params.volumeID, usageInfo)
248268
log.Error(msg)
249-
setInstanceError(ctx, r, instance, msg)
250-
return reconcile.Result{RequeueAfter: duration}, nil
269+
return errors.New(msg)
270+
}
271+
272+
err = unregisterVolume(ctx, *r, request, *params)
273+
if err != nil {
274+
log.Error("failed to unregister volume with error ", err)
275+
return err
276+
}
277+
278+
log.Info("successfully unregistered volume")
279+
return nil
280+
}
281+
282+
// reconcileDelete handles deletion of a CnsUnregisterVolume instance.
283+
// The reconciler tries to keep the system consistent by carefully deciding
284+
// when to continue with volume unregistration.
285+
// The finalizer on the instance will only be removed if the result will keep the system in a consistent state.
286+
func (r *Reconciler) reconcileDelete(ctx context.Context,
287+
instance v1a1.CnsUnregisterVolume, request reconcile.Request) error {
288+
log := logger.GetLogger(ctx).With("name", request.NamespacedName)
289+
290+
if instance.Status.Unregistered {
291+
// If the volume is already unregistered, the instance can be deleted.
292+
log.Info("volume is already unregistered")
293+
return nil
294+
}
295+
296+
params, err := getValidatedParams(ctx, instance)
297+
if err != nil {
298+
// If input parameters are invalid, the instance can be deleted
299+
// since the volume cannot be unregistered.
300+
log.Info("invalid input parameters")
301+
return nil
302+
}
303+
304+
usageInfo, err := getVolumeUsageInfo(ctx, params.pvcName, params.namespace,
305+
instance.Spec.ForceUnregister)
306+
if err != nil {
307+
log.Error("failed to get volume usage info with error ", err)
308+
return err
309+
}
310+
311+
if usageInfo.isInUse {
312+
// If the volume is in use, the instance can be deleted
313+
// since the volume cannot be unregistered.
314+
log.Info(usageInfo)
315+
return nil
316+
}
317+
318+
err = unregisterVolume(ctx, *r, request, *params)
319+
if err != nil {
320+
log.Error("failed to unregister volume with error ", err)
321+
return err
322+
}
323+
324+
log.Info("successfully unregistered volume")
325+
return nil
326+
}
327+
328+
func unregisterVolume(ctx context.Context, r Reconciler,
329+
request reconcile.Request, params params) error {
330+
log := logger.GetLogger(ctx).With("name", request.NamespacedName)
331+
332+
k8sClient, err := newK8sClient(ctx)
333+
if err != nil {
334+
log.Error("failed to init K8s client for volume unregistration with error ", err)
335+
return err
251336
}
252337

253338
err = protectPVC(ctx, k8sClient, params.pvcName, params.namespace,
254339
cnsoptypes.CNSUnregisterProtectionFinalizer)
255340
if err != nil {
256-
setInstanceError(ctx, r, instance, "failed to add finalizer on PVC")
257-
return reconcile.Result{RequeueAfter: duration}, nil
341+
log.Error("failed to add finalizer on PVC with error ", err)
342+
return errors.New("failed to protect PVC")
258343
}
259344

260345
err = deletePVC(ctx, k8sClient, params.pvcName, params.namespace)
261346
if err != nil {
262-
setInstanceError(ctx, r, instance, "failed to delete PVC")
263-
return reconcile.Result{RequeueAfter: duration}, nil
347+
log.Error("failed to delete PVC with error ", err)
348+
return errors.New("failed to delete PVC")
264349
}
265350

266351
err = deletePV(ctx, k8sClient, params.pvName)
267352
if err != nil {
268-
setInstanceError(ctx, r, instance, "failed to delete PV")
269-
return reconcile.Result{RequeueAfter: duration}, nil
353+
log.Error("failed to delete PV with error ", err)
354+
return errors.New("failed to delete PV")
270355
}
271356

272-
unregDisk := !instance.Spec.RetainFCD
357+
unregDisk := !params.retainFCD // If retainFCD is false, unregister the FCD too.
273358
err = r.volumeManager.UnregisterVolume(ctx, params.volumeID, unregDisk)
274359
if err != nil {
275-
setInstanceError(ctx, r, instance, "failed to unregister volume")
276-
return reconcile.Result{RequeueAfter: duration}, nil
360+
log.Error("failed to unregister volume with error ", err)
361+
return errors.New("failed to unregister volume")
277362
}
278363

279364
err = removeFinalizerFromPVC(ctx, k8sClient, params.pvcName, params.namespace,
280365
cnsoptypes.CNSUnregisterProtectionFinalizer)
281366
if err != nil {
282-
setInstanceError(ctx, r, instance, "failed to remove finalizer from PVC")
283-
return reconcile.Result{RequeueAfter: duration}, nil
367+
log.Error("failed to remove finalizer from PVC with error ", err)
368+
return errors.New("failed to remove finalizer from PVC")
284369
}
285370

286371
log.Infof("successfully unregistered CNS volume %s", params.volumeID)
287-
msg := "successfully unregistered the volume"
288-
err = setInstanceSuccess(ctx, r, instance, msg)
289-
if err != nil {
290-
log.Warn("failed to set instance to success with error ", err)
291-
setInstanceError(ctx, r, instance, "failed to set instance to success")
292-
return reconcile.Result{RequeueAfter: duration}, nil
293-
}
294-
295-
deleteBackoffEntry(ctx, request.NamespacedName)
296-
log.Info(msg)
297-
return reconcile.Result{}, nil
372+
return nil
298373
}
299374

300375
// setInstanceError sets error and records an event on the CnsUnregisterVolume
@@ -359,6 +434,11 @@ type params struct {
359434
pvName string
360435
}
361436

437+
func (p *params) String() string {
438+
return fmt.Sprintf("retainFCD: %t, force: %t, namespace: %s, volumeID: %s, pvcName: %s, pvName: %s",
439+
p.retainFCD, p.force, p.namespace, p.volumeID, p.pvcName, p.pvName)
440+
}
441+
362442
var getValidatedParams = _getValidatedParams
363443

364444
func _getValidatedParams(ctx context.Context, instance v1a1.CnsUnregisterVolume) (*params, error) {
@@ -398,6 +478,7 @@ func _getValidatedParams(ctx context.Context, instance v1a1.CnsUnregisterVolume)
398478
log.Info("no PV found for the Volume ID ", p.volumeID)
399479
}
400480

481+
log.Debug("validated input parameters: ", p)
401482
return &p, nil
402483
}
403484

pkg/syncer/cnsoperator/controller/cnsunregistervolume/util.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,23 @@ var getVolumeUsageInfo = _getVolumeUsageInfo
7070
// getVolumeUsageInfo checks if the PVC is in use by any resources in the specified namespace.
7171
// For the sake of efficiency, the function returns as soon as it finds that the volume is in use by any resource.
7272
// If ignoreVMUsage is set to true, the function skips checking if the volume is in use by any virtual machines.
73-
func _getVolumeUsageInfo(ctx context.Context, k8sClient clientset.Interface, pvcName string, pvcNamespace string,
73+
func _getVolumeUsageInfo(ctx context.Context, pvcName string, pvcNamespace string,
7474
ignoreVMUsage bool) (*volumeUsageInfo, error) {
7575
log := logger.GetLogger(ctx)
7676

7777
var volumeUsageInfo volumeUsageInfo
7878
if pvcName == "" {
79-
log.Debugf("PVC name is empty. Nothing to do.")
79+
log.Debug("PVC name is empty. Nothing to do.")
8080
return &volumeUsageInfo, nil
8181
}
8282

8383
var err error
84+
k8sClient, err := k8s.NewClient(ctx)
85+
if err != nil {
86+
log.Errorf("failed to create k8s client. Error: %v", err)
87+
return nil, err
88+
}
89+
8490
volumeUsageInfo.pods, volumeUsageInfo.isInUse, err = getPodsForPVC(ctx, pvcName, pvcNamespace, k8sClient)
8591
if err != nil {
8692
return nil, err

pkg/syncer/cnsoperator/types/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const (
4141
CNSUnregisterVolumeFinalizer = "cns.vmware.com/unregister-volume"
4242

4343
// CNSUnregisterProtectionFinalizer is the finalizer on Supervisor PVC
44-
// to avoid deletion of PVCs which are in the process of UnregisterVolume operation.
44+
// to avoid deletion of PVCs which are in the process of being unregistered.
4545
CNSUnregisterProtectionFinalizer = "cns.vmware.com/unregister-protection"
4646

4747
// VSphereCSIDriverName is the vsphere CSI driver name

0 commit comments

Comments
 (0)