Skip to content

Commit 8b5cbd7

Browse files
committed
Complete deletion of CnsFileAccessConfig instance if associated nodeVM instance is not found
1 parent 21521e2 commit 8b5cbd7

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

pkg/internalapis/cnsoperator/cnsfilevolumeclient/cnsfilevolumeclient.go

+57
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ type FileVolumeClient interface {
4949
// clientVMIP for a given file volume. fileVolumeName is used
5050
// to uniquely identify CnsFileVolumeClient instances.
5151
RemoveClientVMFromIPList(ctx context.Context, fileVolumeName, clientVMName, clientVMIP string) error
52+
// GetVMIPFromVMName returns the VMIP associated with a
53+
// given client VM name.
54+
GetVMIPFromVMName(ctx context.Context, fileVolumeName string, clientVMName string) (string, int, error)
5255
}
5356

5457
// fileVolumeClient maintains a client to the API
@@ -302,3 +305,57 @@ func (f *fileVolumeClient) RemoveClientVMFromIPList(ctx context.Context,
302305
log.Debugf("Could not find VM %s in list. Returning.", clientVMName)
303306
return nil
304307
}
308+
309+
// GetVMIPFromVMName returns the VM IP associated with a
310+
// given client VM name.
311+
// Callers need to specify fileVolumeName as a combination of
312+
// "<SV-namespace>/<SV-PVC-name>". This combination is used to uniquely
313+
// identify CnsFileVolumeClient instances.
314+
// Returns an empty string if the instance doesn't exist OR if the
315+
// input VM name is not present in this instance.
316+
// Returns an error if any operations fails.
317+
func (f *fileVolumeClient) GetVMIPFromVMName(ctx context.Context,
318+
fileVolumeName string, clientVMName string) (string, int, error) {
319+
log := logger.GetLogger(ctx)
320+
321+
log.Infof("Fetching client VM IP from cnsfilevolumeclient %s for VM name %s", fileVolumeName, clientVMName)
322+
actual, _ := f.volumeLock.LoadOrStore(fileVolumeName, &sync.Mutex{})
323+
instanceLock, ok := actual.(*sync.Mutex)
324+
if !ok {
325+
return "", 0, fmt.Errorf("failed to cast lock for cnsfilevolumeclient instance: %s", fileVolumeName)
326+
}
327+
instanceLock.Lock()
328+
defer instanceLock.Unlock()
329+
330+
instance := &v1alpha1.CnsFileVolumeClient{}
331+
instanceNamespace, instanceName, err := cache.SplitMetaNamespaceKey(fileVolumeName)
332+
if err != nil {
333+
log.Errorf("failed to split key %s with error: %+v", fileVolumeName, err)
334+
return "", 0, err
335+
}
336+
instanceKey := types.NamespacedName{
337+
Namespace: instanceNamespace,
338+
Name: instanceName,
339+
}
340+
err = f.client.Get(ctx, instanceKey, instance)
341+
if err != nil {
342+
if errors.IsNotFound(err) {
343+
// If the get() on the instance fails, then we return empty string.
344+
log.Infof("Cnsfilevolumeclient instance %s not found. Returning empty string", fileVolumeName)
345+
return "", 0, nil
346+
}
347+
log.Errorf("failed to get cnsfilevolumeclient instance %s with error: %+v", fileVolumeName, err)
348+
return "", 0, err
349+
}
350+
351+
// Verify if input VM IP exists in Spec.ExternalIPtoClientVms
352+
log.Debugf("Verifying if ExternalIPtoClientVms list has VM name: %s", clientVMName)
353+
for vmIP, vmNames := range instance.Spec.ExternalIPtoClientVms {
354+
for _, vmName := range vmNames {
355+
if vmName == clientVMName {
356+
return vmIP, len(vmNames), nil
357+
}
358+
}
359+
}
360+
return "", 0, nil
361+
}

pkg/syncer/cnsoperator/controller/cnsfileaccessconfig/cnsfileaccessconfig_controller.go

+86
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,52 @@ func (r *ReconcileCnsFileAccessConfig) Reconcile(ctx context.Context,
246246
msg := fmt.Sprintf("Failed to get virtualmachine instance for the VM with name: %q. Error: %+v",
247247
instance.Spec.VMName, err)
248248
log.Error(msg)
249+
// If virtualmachine instance is NotFound and if deletion timestamp is set on CnsFileAccessConfig instance,
250+
// then proceed with the deletion of CnsFileAccessConfig instance.
251+
if apierrors.IsNotFound(err) && instance.DeletionTimestamp != nil {
252+
log.Infof("CnsFileAccessConfig instance %q has deletion timestamp set, but VM instance with "+
253+
"name %q is not found. Processing the deletion of CnsFileAccessConfig instance.",
254+
instance.Name, instance.Spec.VMName)
255+
// Fetch the PVC and PV instance and get volume ID
256+
skipConfigureVolumeACL := false
257+
volumeID, err := cnsoperatorutil.GetVolumeID(ctx, r.client, instance.Spec.PvcName, instance.Namespace)
258+
if err != nil {
259+
if apierrors.IsNotFound(err) {
260+
// If PVC instance is NotFound (deleted), then there is no need to configure ACL on file volume
261+
skipConfigureVolumeACL = true
262+
} else {
263+
msg := fmt.Sprintf("Failed to get volumeID from pvcName: %q. Error: %+v", instance.Spec.PvcName, err)
264+
log.Error(msg)
265+
setInstanceError(ctx, r, instance, msg)
266+
return reconcile.Result{RequeueAfter: timeout}, nil
267+
}
268+
}
269+
if !skipConfigureVolumeACL {
270+
err = r.removePermissionsForFileVolume(ctx, volumeID, instance)
271+
if err != nil {
272+
msg := fmt.Sprintf("Failed to remove file volume permissions with error: %+v", err)
273+
log.Error(msg)
274+
setInstanceError(ctx, r, instance, msg)
275+
return reconcile.Result{RequeueAfter: timeout}, nil
276+
}
277+
}
278+
279+
// Remove finalizer from CnsFileAccessConfig CRD
280+
removeFinalizerFromCRDInstance(ctx, instance)
281+
err = updateCnsFileAccessConfig(ctx, r.client, instance)
282+
if err != nil {
283+
msg := fmt.Sprintf("failed to update CnsFileAccessConfig instance: %q on namespace: %q. Error: %+v",
284+
instance.Name, instance.Namespace, err)
285+
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
286+
return reconcile.Result{RequeueAfter: timeout}, nil
287+
}
288+
// Cleanup instance entry from backOffDuration map.
289+
backOffDurationMapMutex.Lock()
290+
delete(backOffDuration, instance.Name)
291+
backOffDurationMapMutex.Unlock()
292+
return reconcile.Result{}, nil
293+
}
294+
249295
setInstanceError(ctx, r, instance, msg)
250296
return reconcile.Result{RequeueAfter: timeout}, nil
251297
}
@@ -412,6 +458,46 @@ func (r *ReconcileCnsFileAccessConfig) Reconcile(ctx context.Context,
412458
return reconcile.Result{}, nil
413459
}
414460

461+
// removePermissionsForFileVolume helps to remove net permissions for a given file volume.
462+
// This method is used when we don't have VM instance. It fetches the VM IP from CNSFileVolumeClient
463+
// instance for the VM name assocaited with CnsFileAccessConfig.
464+
func (r *ReconcileCnsFileAccessConfig) removePermissionsForFileVolume(ctx context.Context,
465+
volumeID string, instance *cnsfileaccessconfigv1alpha1.CnsFileAccessConfig) error {
466+
log := logger.GetLogger(ctx)
467+
cnsFileVolumeClientInstance, err := cnsfilevolumeclient.GetFileVolumeClientInstance(ctx)
468+
if err != nil {
469+
return logger.LogNewErrorf(log, "Failed to get CNSFileVolumeClient instance. Error: %+v", err)
470+
}
471+
472+
vmIP, vmsAssociatedWithIP, err := cnsFileVolumeClientInstance.GetVMIPFromVMName(ctx,
473+
instance.Namespace+"/"+instance.Spec.PvcName, instance.Spec.VMName)
474+
if err != nil {
475+
return logger.LogNewErrorf(log, "Failed to get VM IP from VM name in CNSFileVolumeClient instance. "+
476+
"Error: %+v", err)
477+
}
478+
if vmIP == "" {
479+
// vmIP is "" if we can't find given vmName in ExternalIPtoClientVms map of CNSFileVolumeClient instance.
480+
// Assuming that this vmName is already removed, return success.
481+
return nil
482+
}
483+
if vmsAssociatedWithIP == 1 {
484+
err = r.configureVolumeACLs(ctx, volumeID, vmIP, true)
485+
if err != nil {
486+
return logger.LogNewErrorf(log, "Failed to remove net permissions for file volume %q. Error: %+v",
487+
volumeID, err)
488+
}
489+
}
490+
err = cnsFileVolumeClientInstance.RemoveClientVMFromIPList(ctx,
491+
instance.Namespace+"/"+instance.Spec.PvcName, instance.Spec.VMName, vmIP)
492+
if err != nil {
493+
return logger.LogNewErrorf(log, "Failed to remove VM %q with IP %q from IPList. Error: %+v",
494+
instance.Spec.VMName, vmIP, err)
495+
}
496+
log.Infof("Successfully removed VM IP %q from IPList for CnsFileAccessConfig request with name: %q on "+
497+
"namespace: %q", vmIP, instance.Name, instance.Namespace)
498+
return nil
499+
}
500+
415501
// configureNetPermissionsForFileVolume helps to add or remove net permissions
416502
// for a given file volume. The callers of this method can remove or add net
417503
// permissions by setting the parameter removePermission to true or false

0 commit comments

Comments
 (0)