Skip to content

Commit e090c56

Browse files
committed
Only attach the volumes which need to be attached
1 parent 3a9e5c3 commit e090c56

File tree

3 files changed

+391
-90
lines changed

3 files changed

+391
-90
lines changed

pkg/syncer/cnsoperator/controller/cnsnodevmbatchattachment/cnsnodevmbatchattachment_controller.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ func (r *Reconciler) Reconcile(ctx context.Context,
264264
}
265265

266266
volumesToDetach := make(map[string]string)
267+
volumesToAttach := make(map[string]string)
267268
if vm == nil {
268269
// If VM is nil, it means it is deleted from the vCenter.
269270
if instance.DeletionTimestamp == nil {
@@ -278,7 +279,7 @@ func (r *Reconciler) Reconcile(ctx context.Context,
278279
request.NamespacedName)
279280
} else {
280281
// If VM was found on vCenter, find the volumes to be detached from it.
281-
volumesToDetach, err = getVolumesToDetach(batchAttachCtx, instance, vm, r.client, k8sClient)
282+
volumesToAttach, volumesToDetach, err = getVolumesToAttachAndDetach(batchAttachCtx, instance, vm, r.client, k8sClient)
282283
if err != nil {
283284
log.Errorf("failed to find volumes to detach for instance %s. Err: %s",
284285
request.NamespacedName.String(), err)
@@ -335,7 +336,8 @@ func (r *Reconciler) Reconcile(ctx context.Context,
335336
}
336337

337338
// Call reconcile when deletion timestamp is not set on the instance.
338-
err := r.reconcileInstanceWithoutDeletionTimestamp(batchAttachCtx, k8sClient, instance, volumesToDetach, vm)
339+
err := r.reconcileInstanceWithoutDeletionTimestamp(batchAttachCtx, k8sClient, instance, volumesToDetach,
340+
volumesToAttach, vm)
339341
if err != nil {
340342
log.Errorf("failed to reconile instance %s. Err: %s", request.NamespacedName.String(), err)
341343
return r.completeReconciliationWithError(batchAttachCtx, instance, request.NamespacedName, timeout, err)
@@ -385,6 +387,7 @@ func (r *Reconciler) reconcileInstanceWithoutDeletionTimestamp(ctx context.Conte
385387
k8sClient kubernetes.Interface,
386388
instance *v1alpha1.CnsNodeVMBatchAttachment,
387389
volumesToDetach map[string]string,
390+
volumesToAttach map[string]string,
388391
vm *cnsvsphere.VirtualMachine) error {
389392
log := logger.GetLogger(ctx)
390393

@@ -400,7 +403,7 @@ func (r *Reconciler) reconcileInstanceWithoutDeletionTimestamp(ctx context.Conte
400403
}
401404

402405
// Call batch attach for volumes.
403-
attachErr := r.processBatchAttach(ctx, k8sClient, vm, instance)
406+
attachErr := r.processBatchAttach(ctx, k8sClient, vm, instance, volumesToAttach)
404407
if attachErr != nil {
405408
log.Errorf("failed to attach all volumes. Err: %+v", attachErr)
406409
}
@@ -497,16 +500,18 @@ func removeFinalizerAndStatusEntry(ctx context.Context, client client.Client, k8
497500
// and then calls CNS batch attach for them.
498501
func (r *Reconciler) processBatchAttach(ctx context.Context, k8sClient kubernetes.Interface,
499502
vm *cnsvsphere.VirtualMachine,
500-
instance *v1alpha1.CnsNodeVMBatchAttachment) error {
503+
instance *v1alpha1.CnsNodeVMBatchAttachment,
504+
volumesToAttach map[string]string) error {
501505
log := logger.GetLogger(ctx)
502506

503-
if len(instance.Spec.Volumes) == 0 {
507+
if len(instance.Spec.Volumes) == 0 || len(volumesToAttach) == 0 {
504508
log.Infof("No volumes to attach to VM %q", instance.Spec.InstanceUUID)
505509
return nil
506510
}
507511

508512
// Construct batch attach request
509-
pvcsInSpec, volumeIdsInSpec, batchAttachRequest, err := constructBatchAttachRequest(ctx, instance)
513+
pvcsInAttachList, volumeIdsInAttachList, batchAttachRequest, err := constructBatchAttachRequest(ctx,
514+
volumesToAttach, instance)
510515
if err != nil {
511516
log.Errorf("failed to construct batch attach request. Err: %s", err)
512517
return err
@@ -522,12 +527,12 @@ func (r *Reconciler) processBatchAttach(ctx context.Context, k8sClient kubernete
522527

523528
// Update instance based on the result of BatchAttach
524529
for _, result := range batchAttachResult {
525-
pvcName, ok := volumeIdsInSpec[result.VolumeID]
530+
pvcName, ok := volumeIdsInAttachList[result.VolumeID]
526531
if !ok {
527532
log.Errorf("failed to get pvcName for volumeID %s", result.VolumeID)
528533
return fmt.Errorf("failed to get pvcName for volumeID %s", result.VolumeID)
529534
}
530-
volumeName, ok := pvcsInSpec[pvcName]
535+
volumeName, ok := pvcsInAttachList[pvcName]
531536
if !ok {
532537
log.Errorf("failed to get volumeName for pvc %s", pvcName)
533538
return fmt.Errorf("failed to get volumeName for pvc %s", pvcName)

pkg/syncer/cnsoperator/controller/cnsnodevmbatchattachment/cnsnodevmbatchattachment_helper.go

Lines changed: 147 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,67 @@ func getVolumesToDetachFromInstance(ctx context.Context,
138138
return pvcsToDetach, nil
139139
}
140140

141+
// getVolumesToAttach adds those PVCs to attach list which satisfy either of the following:
142+
// 1. The volumes which are present in instance spec but not in attachedFCDs list.
143+
// 2. The volumes which are present in instance spec and in attachedFCDs list but have different backing details.
144+
func getVolumesToAttach(ctx context.Context,
145+
instance *v1alpha1.CnsNodeVMBatchAttachment,
146+
attachedFCDs map[string]FCDBackingDetails,
147+
volumeIdsInSpec map[string]FCDBackingDetails,
148+
pvcNameToVolumeIDInSpec map[string]string) (pvcsToAttach map[string]string, err error) {
149+
log := logger.GetLogger(ctx)
150+
151+
// Map contains volumes which need to be attached.
152+
pvcsToAttach = make(map[string]string)
153+
154+
pvcsInStatus := make(map[string]bool)
155+
for _, volumeStatus := range instance.Status.VolumeStatus {
156+
pvcsInStatus[volumeStatus.PersistentVolumeClaim.ClaimName] = false
157+
if volumeStatus.PersistentVolumeClaim.Error != "" {
158+
pvcsInStatus[volumeStatus.PersistentVolumeClaim.ClaimName] = true
159+
}
160+
}
161+
162+
/// Add those volumes to to pvcsToAttach
163+
// which are present in attachedFCDs list but not in
164+
// instance spec.
165+
for _, pvc := range instance.Spec.Volumes {
166+
volumeIDForPVC, ok := pvcNameToVolumeIDInSpec[pvc.PersistentVolumeClaim.ClaimName]
167+
if !ok {
168+
msg := fmt.Sprintf("failed to find volumeID for PVC %s", pvc.PersistentVolumeClaim.ClaimName)
169+
log.Errorf(msg)
170+
err = errors.New(msg)
171+
return
172+
}
173+
174+
attachedFcdIDBacking, found := attachedFCDs[volumeIDForPVC]
175+
if !found {
176+
log.Infof("PVC %s not attached to VM. Adding it to volumesToAttach list",
177+
pvc.PersistentVolumeClaim.ClaimName)
178+
// If PVC is present in instance spec but is not attached to the VM, then add it to PVCs to attach list.
179+
pvcsToAttach[pvc.PersistentVolumeClaim.ClaimName] = volumeIDForPVC
180+
} else if *pvc.PersistentVolumeClaim.ControllerKey != attachedFcdIDBacking.ControllerKey ||
181+
*pvc.PersistentVolumeClaim.UnitNumber != attachedFcdIDBacking.UnitNumber ||
182+
string(pvc.PersistentVolumeClaim.SharingMode) != attachedFcdIDBacking.SharingMode ||
183+
string(pvc.PersistentVolumeClaim.DiskMode) != attachedFcdIDBacking.DiskMode {
184+
log.Infof("PVC %s is attached to VM but its backing has changed. Adding it to volumesToAttach list",
185+
pvc.PersistentVolumeClaim.ClaimName)
186+
// If PVC is already attached to VM, but its device backing has changed, then add it to PVCs to attach list,
187+
// as it needs to be re-attached with new details.
188+
pvcsToAttach[pvc.PersistentVolumeClaim.ClaimName] = volumeIDForPVC
189+
} else if hasError,
190+
pvcExistsInStatus := pvcsInStatus[pvc.PersistentVolumeClaim.ClaimName]; !pvcExistsInStatus || hasError {
191+
log.Infof("PVC %s is missing or is not successful in Status. Adding it to attach list.",
192+
pvc.PersistentVolumeClaim.ClaimName)
193+
pvcsToAttach[pvc.PersistentVolumeClaim.ClaimName] = volumeIDForPVC
194+
}
195+
196+
}
197+
198+
log.Infof("Obtained volumes to attach %+v for instance %s", pvcsToAttach, instance.Name)
199+
return pvcsToAttach, nil
200+
}
201+
141202
// isSharedPvc returns true for PVCs which allow multi attach.
142203
func isSharedPvc(pvcObj v1.PersistentVolumeClaim) bool {
143204
for _, accessMode := range pvcObj.Spec.AccessModes {
@@ -227,20 +288,16 @@ func getVolumesToDetachForVmFromVC(ctx context.Context,
227288
instance *v1alpha1.CnsNodeVMBatchAttachment,
228289
client client.Client,
229290
k8sClient kubernetes.Interface,
230-
attachedFCDs map[string]FCDBackingDetails) (map[string]string, error) {
291+
attachedFCDs map[string]FCDBackingDetails,
292+
volumeIdsInSpec map[string]FCDBackingDetails,
293+
volumeNamesInSpec map[string]string) (map[string]string, error) {
231294
log := logger.GetLogger(ctx)
232295

233296
pvcsToDetach := make(map[string]string)
234-
// Get all PVCs and their corresponding volumeID mapping from instance spec.
235-
volumeIdsInSpec, volumeNamesInSpec, err := getVolumeNameVolumeIdMapsInSpec(ctx, instance)
236-
if err != nil {
237-
log.Errorf("failed to get PVCs in spec. Err: %s", err)
238-
return pvcsToDetach, err
239-
}
240297

241298
// Find out the volumes to detach by taking a diff between
242299
// the instance spec and the FCDs currently attached to the VM on vCenter.
243-
pvcsToDetach, err = getVolumesToDetachFromInstance(ctx, instance, attachedFCDs, volumeIdsInSpec)
300+
pvcsToDetach, err := getVolumesToDetachFromInstance(ctx, instance, attachedFCDs, volumeIdsInSpec)
244301
if err != nil {
245302
log.Errorf("failed to find volumes to attach and volumes to detach from instance spec. Err: %s", err)
246303
return pvcsToDetach, err
@@ -358,17 +415,21 @@ func deleteVolumeFromStatus(pvc string, instance *v1alpha1.CnsNodeVMBatchAttachm
358415
})
359416
}
360417

361-
// getVolumeNameVolumeIdMapsInSpec returns the volumes in instance spec.
362-
// It return two maps:
418+
// getVolumeMetadataMaps returns the volumes in instance spec.
419+
// It returns three maps:
363420
// 1. volumeID to PVC name
364421
// 2. VolumeName to PVC name
365-
func getVolumeNameVolumeIdMapsInSpec(ctx context.Context,
422+
// 3. PVC name to volumeID
423+
func getVolumeMetadataMaps(ctx context.Context,
366424
instance *v1alpha1.CnsNodeVMBatchAttachment) (volumeIdsInSpec map[string]FCDBackingDetails,
367-
volumeNamesInSpec map[string]string, err error) {
425+
volumeNamesInSpec map[string]string,
426+
pvcNameToVolumeIDInSpec map[string]string,
427+
err error) {
368428
log := logger.GetLogger(ctx)
369429

370430
volumeIdsInSpec = make(map[string]FCDBackingDetails)
371431
volumeNamesInSpec = make(map[string]string)
432+
pvcNameToVolumeIDInSpec = make(map[string]string)
372433
for _, volume := range instance.Spec.Volumes {
373434
volumeId, ok := commonco.ContainerOrchestratorUtility.GetVolumeIDFromPVCName(
374435
instance.Namespace, volume.PersistentVolumeClaim.ClaimName)
@@ -378,9 +439,13 @@ func getVolumeNameVolumeIdMapsInSpec(ctx context.Context,
378439
err = errors.New(msg)
379440
return
380441
}
381-
volumeIdsInSpec[volumeId] = FCDBackingDetails{*volume.PersistentVolumeClaim.ControllerKey,
382-
*volume.PersistentVolumeClaim.UnitNumber,
383-
string(volume.PersistentVolumeClaim.SharingMode), string(volume.PersistentVolumeClaim.DiskMode)}
442+
volumeNamesInSpec[volume.Name] = volume.PersistentVolumeClaim.ClaimName
443+
volumeIdsInSpec[volumeId] = FCDBackingDetails{
444+
ControllerKey: *volume.PersistentVolumeClaim.ControllerKey,
445+
UnitNumber: *volume.PersistentVolumeClaim.UnitNumber,
446+
SharingMode: string(volume.PersistentVolumeClaim.SharingMode),
447+
DiskMode: string(volume.PersistentVolumeClaim.DiskMode)}
448+
pvcNameToVolumeIDInSpec[volume.PersistentVolumeClaim.ClaimName] = volumeId
384449
}
385450
return
386451
}
@@ -466,7 +531,11 @@ func listAttachedFcdsForVM(ctx context.Context,
466531
}
467532

468533
log.Infof("Adding volume with ID %s to attachedFCDs list", virtualDisk.VDiskId.Id)
469-
attachedFCDs[virtualDisk.VDiskId.Id] = FCDBackingDetails{controllerKey, unitNumber, sharingMode, diskMode}
534+
attachedFCDs[virtualDisk.VDiskId.Id] = FCDBackingDetails{
535+
ControllerKey: controllerKey,
536+
UnitNumber: unitNumber,
537+
SharingMode: sharingMode,
538+
DiskMode: diskMode}
470539
}
471540

472541
}
@@ -477,6 +546,7 @@ func listAttachedFcdsForVM(ctx context.Context,
477546
// constructs the batchAttach request for each of them.
478547
// It also validates each of the requests to make sure user input is correct.
479548
func constructBatchAttachRequest(ctx context.Context,
549+
volumesToAttach map[string]string,
480550
instance *v1alpha1.CnsNodeVMBatchAttachment) (pvcsInSpec map[string]string,
481551
volumeIdsInSpec map[string]string,
482552
batchAttachRequest []volumes.BatchAttachRequest, err error) {
@@ -491,31 +561,27 @@ func constructBatchAttachRequest(ctx context.Context,
491561
// This map has mapping of volumeID to PVC.
492562
volumeIdsInSpec = make(map[string]string)
493563

494-
for _, volume := range instance.Spec.Volumes {
495-
pvcName := volume.PersistentVolumeClaim.ClaimName
496-
volumeName := volume.Name
497-
498-
// Find volumeID for PVC.
499-
attachVolumeId, ok := commonco.ContainerOrchestratorUtility.GetVolumeIDFromPVCName(instance.Namespace, pvcName)
500-
if !ok {
501-
err := fmt.Errorf("failed to find volumeID for PVC %s", pvcName)
502-
log.Error(err)
503-
return pvcsInSpec, volumeIdsInSpec, batchAttachRequest, err
504-
}
564+
for pvcName, volumeID := range volumesToAttach {
565+
for _, volume := range instance.Spec.Volumes {
566+
if volume.PersistentVolumeClaim.ClaimName != pvcName {
567+
continue
568+
}
505569

506-
// Populate these 2 maps as these values are required later during batch attach.
507-
pvcsInSpec[volume.PersistentVolumeClaim.ClaimName] = volumeName
508-
volumeIdsInSpec[attachVolumeId] = volume.PersistentVolumeClaim.ClaimName
570+
// Populate these 2 maps as these values are required later during batch attach.
571+
pvcsInSpec[volume.PersistentVolumeClaim.ClaimName] = volume.Name
572+
volumeIdsInSpec[volumeID] = volume.PersistentVolumeClaim.ClaimName
573+
574+
// Populate values for attach request.
575+
currentBatchAttachRequest := volumes.BatchAttachRequest{
576+
VolumeID: volumeID,
577+
SharingMode: string(volume.PersistentVolumeClaim.SharingMode),
578+
DiskMode: string(volume.PersistentVolumeClaim.DiskMode),
579+
ControllerKey: volume.PersistentVolumeClaim.ControllerKey,
580+
UnitNumber: volume.PersistentVolumeClaim.UnitNumber,
581+
}
582+
batchAttachRequest = append(batchAttachRequest, currentBatchAttachRequest)
509583

510-
// Populate values for attach request.
511-
currentBatchAttachRequest := volumes.BatchAttachRequest{
512-
VolumeID: attachVolumeId,
513-
SharingMode: string(volume.PersistentVolumeClaim.SharingMode),
514-
DiskMode: string(volume.PersistentVolumeClaim.DiskMode),
515-
ControllerKey: volume.PersistentVolumeClaim.ControllerKey,
516-
UnitNumber: volume.PersistentVolumeClaim.UnitNumber,
517584
}
518-
batchAttachRequest = append(batchAttachRequest, currentBatchAttachRequest)
519585
}
520586
return pvcsInSpec, volumeIdsInSpec, batchAttachRequest, nil
521587
}
@@ -541,52 +607,71 @@ func getVmObject(ctx context.Context, client client.Client, configInfo config.Co
541607
return vm, nil
542608
}
543609

544-
// getVolumesToDetach checks if:
545-
// Instance is being deleted, then it adds all the volumes in the spec for detach.
546-
// If instance is not being deleted then finds the volumes to be detached by querying vCenter.
547-
func getVolumesToDetach(ctx context.Context, instance *v1alpha1.CnsNodeVMBatchAttachment,
548-
vm *cnsvsphere.VirtualMachine, client client.Client, k8sClient kubernetes.Interface) (map[string]string, error) {
610+
func getVolumesToAttachAndDetach(ctx context.Context, instance *v1alpha1.CnsNodeVMBatchAttachment,
611+
vm *cnsvsphere.VirtualMachine, client client.Client, k8sClient kubernetes.Interface) (map[string]string,
612+
map[string]string, error) {
549613
log := logger.GetLogger(ctx)
550614

615+
pvcsToAttach := make(map[string]string, 0)
616+
pvcsToDetach := make(map[string]string, 0)
617+
551618
if instance.DeletionTimestamp != nil {
552619
log.Debugf("Instance %s is being deleted, adding all volumes in spec to volumesToDetach list.", instance.Name)
553620
volumesToDetach, err := getPvcsInSpec(ctx, instance, k8sClient)
554621
if err != nil {
555622
log.Errorf("failed to get volumes to detach from instance spec. Err: %s", err)
556-
return volumesToDetach, err
623+
return pvcsToAttach, volumesToDetach, err
557624
}
558625
log.Debugf("Volumes to detach list %+v for instance %s", volumesToDetach, instance.Name)
559-
return volumesToDetach, nil
626+
return pvcsToAttach, volumesToDetach, nil
627+
}
628+
629+
// Query vCenter to find the list of FCDs which are attached to the VM.
630+
attachedFcdList, err := listAttachedFcdsForVM(ctx, vm)
631+
if err != nil {
632+
log.Errorf("failed to find the FCDs attached to VM %s. Err: %s", vm, err)
633+
return map[string]string{}, map[string]string{}, err
634+
}
635+
log.Infof("List of attached FCDs %+v to VM %s", attachedFcdList, instance.Spec.InstanceUUID)
636+
637+
// Get all PVCs and their corresponding volumeID mapping from instance spec.
638+
volumeIdsInSpec, volumeNamesInSpec, pvcNameToVolumeIDInSpec, err := getVolumeMetadataMaps(ctx, instance)
639+
if err != nil {
640+
log.Errorf("failed to get PVCs in spec. Err: %s", err)
641+
return pvcsToAttach, pvcsToDetach, err
560642
}
561643

562644
// Find the volumes to detach from the vCenter.
563-
volumesToDetach, err := getVolumesToDetachFromVM(ctx, client, k8sClient, instance, vm)
645+
pvcsToDetach, err = getVolumesToDetach(ctx, client, k8sClient, instance, vm,
646+
attachedFcdList, volumeIdsInSpec, volumeNamesInSpec)
564647
if err != nil {
565648
log.Errorf("failed to find volumes to detach from the vCenter for instance %s", instance.Name)
566-
return volumesToDetach, err
649+
return pvcsToAttach, pvcsToDetach, err
567650
}
568-
log.Debugf("Volumes to detach list %+v for instance %s", volumesToDetach, instance.Name)
569-
return volumesToDetach, nil
651+
652+
// Find the volumes to attach from the vCenter.
653+
pvcsToAttach, err = getVolumesToAttach(ctx, instance,
654+
attachedFcdList, volumeIdsInSpec, pvcNameToVolumeIDInSpec)
655+
if err != nil {
656+
log.Errorf("failed to find volumes to attach from the vCenter for instance %s", instance.Name)
657+
return pvcsToAttach, pvcsToDetach, err
658+
}
659+
log.Debugf("Volumes to attach list %+v for instance %s", pvcsToAttach, instance.Name)
660+
return pvcsToAttach, pvcsToDetach, nil
570661
}
571662

572-
// getVolumesToDetachFromVM queries vCenter to find the list of FCDs
663+
// getVolumesToDetach queries vCenter to find the list of FCDs
573664
// which have to be detached from the VM.
574-
func getVolumesToDetachFromVM(ctx context.Context, client client.Client,
665+
func getVolumesToDetach(ctx context.Context, client client.Client,
575666
k8sClient kubernetes.Interface,
576667
instance *v1alpha1.CnsNodeVMBatchAttachment,
577-
vm *cnsvsphere.VirtualMachine) (map[string]string, error) {
668+
vm *cnsvsphere.VirtualMachine, attachedFcdList map[string]FCDBackingDetails,
669+
volumeIdsInSpec map[string]FCDBackingDetails, volumeNamesInSpec map[string]string) (map[string]string, error) {
578670
log := logger.GetLogger(ctx)
579671

580-
// Query vCenter to find the list of FCDs which are attached to the VM.
581-
attachedFcdList, err := listAttachedFcdsForVM(ctx, vm)
582-
if err != nil {
583-
log.Errorf("failed to find the FCDs attached to VM %s. Err: %s", vm, err)
584-
return map[string]string{}, err
585-
}
586-
log.Infof("List of attached FCDs %+v to VM %s", attachedFcdList, instance.Spec.InstanceUUID)
587-
588672
// Find volumes to be detached from the VM by takinga diff with FCDs attached to VM on vCenter.
589-
volumesToDetach, err := getVolumesToDetachForVmFromVC(ctx, instance, client, k8sClient, attachedFcdList)
673+
volumesToDetach, err := getVolumesToDetachForVmFromVC(ctx, instance, client, k8sClient,
674+
attachedFcdList, volumeIdsInSpec, volumeNamesInSpec)
590675
if err != nil {
591676
log.Errorf("failed to find volumes to attach and detach. Err: %s", err)
592677
return map[string]string{}, err
@@ -595,7 +680,6 @@ func getVolumesToDetachFromVM(ctx context.Context, client client.Client,
595680
log.Infof("Volumes to be detached %+v for instance %s", volumesToDetach, instance.Name)
596681

597682
return volumesToDetach, nil
598-
599683
}
600684

601685
// addPvcAnnotation adds the vmInstanceUUID as an annotation to the given PVC.
@@ -632,7 +716,7 @@ func patchPVCAnnotations(ctx context.Context, k8sClient kubernetes.Interface,
632716
log.Infof("Removing annotation %s from PVC %s", key, pvc.Name)
633717
patchAnnotations[key] = nil
634718
} else {
635-
log.Infof("Adding annotation %s on PVC", key, pvc.Name)
719+
log.Infof("Adding annotation %s on PVC %s", key, pvc.Name)
636720
patchAnnotations[key] = ""
637721
}
638722

0 commit comments

Comments
 (0)