@@ -43,8 +43,9 @@ const (
4343 fullCloneDiskMoveType = types .VirtualMachineRelocateDiskMoveOptionsMoveAllDiskBackingsAndConsolidate
4444 linkCloneDiskMoveType = types .VirtualMachineRelocateDiskMoveOptionsCreateNewChildDiskBacking
4545
46- // maxUnitNumber constant used to define they most devices that can be assigned to a controller. Not all controllers support up to 30, but max is 30.
47- // Documentation on limits / behavior: https://docs.vmware.com/en/VMware-vSphere/8.0/vsphere-vm-administration/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#:~:text=If%20you%20add%20a%20hard,values%20from%200%20to%2014.
46+ // maxUnitNumber constant is used to define the maximum number of devices that can be assigned to a virtual machine's controller.
47+ // Not all controllers support up to 30, but the maximum is 30.
48+ // xref: https://docs.vmware.com/en/VMware-vSphere/8.0/vsphere-vm-administration/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#:~:text=If%20you%20add%20a%20hard,values%20from%200%20to%2014.
4849 maxUnitNumber = 30
4950)
5051
@@ -146,7 +147,6 @@ func Clone(ctx context.Context, vmCtx *capvcontext.VMContext, bootstrapData []by
146147 if err != nil {
147148 return errors .Wrapf (err , "error getting disk spec for %q" , ctx )
148149 }
149- log .V (4 ).Info ("Got the following disks" , "disks" , diskSpecs )
150150 deviceSpecs = append (deviceSpecs , diskSpecs ... )
151151 }
152152
@@ -156,6 +156,7 @@ func Clone(ctx context.Context, vmCtx *capvcontext.VMContext, bootstrapData []by
156156 if err != nil {
157157 return errors .Wrapf (err , "error getting data disks" )
158158 }
159+ log .V (4 ).Info ("Adding the following data disks" , "disks" , dataDisks )
159160 deviceSpecs = append (deviceSpecs , dataDisks ... )
160161 }
161162
@@ -409,7 +410,6 @@ func getDiskConfigSpec(disk *types.VirtualDisk, diskCloneCapacityKB int64) (type
409410func createDataDisks (ctx context.Context , dataDiskDefs []infrav1.VSphereDisk , devices object.VirtualDeviceList ) ([]types.BaseVirtualDeviceConfigSpec , error ) {
410411 log := ctrl .LoggerFrom (ctx )
411412 additionalDisks := []types.BaseVirtualDeviceConfigSpec {}
412- unitOffset := int32 (1 )
413413
414414 disks := devices .SelectByType ((* types .VirtualDisk )(nil ))
415415 if len (disks ) == 0 {
@@ -419,15 +419,21 @@ func createDataDisks(ctx context.Context, dataDiskDefs []infrav1.VSphereDisk, de
419419 // There is at least one disk
420420 primaryDisk := disks [0 ].(* types.VirtualDisk )
421421
422+ // Get the controller of the primary disk.
423+ controller , ok := devices .FindByKey (primaryDisk .ControllerKey ).(types.BaseVirtualController )
424+ if ! ok {
425+ return nil , errors .Errorf ("unable to find controller with key=%v" , primaryDisk .ControllerKey )
426+ }
427+
428+ controllerKey := controller .GetVirtualController ().Key
429+ unitNumberAssigner , err := newUnitNumberAssigner (controller , devices , additionalDisks )
430+ if err != nil {
431+ return nil , err
432+ }
433+
422434 for i , dataDisk := range dataDiskDefs {
423435 log .V (2 ).Info ("Adding disk" , "name" , dataDisk .Name , "spec" , dataDisk )
424436
425- // Get the controller of the primary disk.
426- controller , ok := devices .FindByKey (primaryDisk .ControllerKey ).(types.BaseVirtualController )
427- if ! ok {
428- return nil , errors .Errorf ("unable to find controller with key=%v" , primaryDisk .ControllerKey )
429- }
430-
431437 dev := & types.VirtualDisk {
432438 VirtualDevice : types.VirtualDevice {
433439 Key : devices .NewKey () - int32 (i ),
@@ -443,30 +449,30 @@ func createDataDisks(ctx context.Context, dataDiskDefs []infrav1.VSphereDisk, de
443449 CapacityInKB : int64 (dataDisk .SizeGiB ) * 1024 * 1024 ,
444450 }
445451
446- // Assign unit number to the next slot on the controller.
447- if err := assignUnitNumber (ctx , dev , devices , additionalDisks , controller , unitOffset ); err != nil {
448- return nil , errors .Wrap (err , "failed to assign device unit number to disk" )
452+ vd := dev .GetVirtualDevice ()
453+ vd .ControllerKey = controllerKey
454+
455+ // Assign unit number to the new disk. Should be next available slot on the controller.
456+ unitNumber , err := unitNumberAssigner .assign ()
457+ if err != nil {
458+ return nil , err
449459 }
460+ vd .UnitNumber = & unitNumber
450461
451- // Update unitOffset to current device unitNumber as starting point for next disk to be assigned.
452- unitOffset = * dev .UnitNumber
462+ log .V (4 ).Info ("Created device for data disk device" , "name" , dataDisk .Name , "spec" , dataDisk , "device" , dev )
453463
454- diskConfigSpec := types.VirtualDeviceConfigSpec {
464+ additionalDisks = append ( additionalDisks , & types.VirtualDeviceConfigSpec {
455465 Device : dev ,
456466 Operation : types .VirtualDeviceConfigSpecOperationAdd ,
457467 FileOperation : types .VirtualDeviceConfigSpecFileOperationCreate ,
458- }
459-
460- log .V (4 ).Info ("Generated device" , "dev" , dev )
461-
462- additionalDisks = append (additionalDisks , & diskConfigSpec )
468+ })
463469 }
464470
465471 return additionalDisks , nil
466472}
467473
468474// assignUnitNumber assigns a controller unit number to a device.
469- func assignUnitNumber (ctx context.Context , device types.BaseVirtualDevice , existingDevices object.VirtualDeviceList , newDevices []types.BaseVirtualDeviceConfigSpec , controller types.BaseVirtualController , offset int32 ) error {
475+ /* func assignUnitNumber(ctx context.Context, device types.BaseVirtualDevice, existingDevices object.VirtualDeviceList, newDevices []types.BaseVirtualDeviceConfigSpec, controller types.BaseVirtualController, offset int32) error {
470476 if offset > maxUnitNumber {
471477 return errors.Errorf("%d exceeds maximum number of units %d", offset, maxUnitNumber)
472478 }
@@ -523,6 +529,54 @@ func assignUnitNumber(ctx context.Context, device types.BaseVirtualDevice, exist
523529
524530 // If we are here, we did not find a unit number. Return error.
525531 return errors.Errorf("all unit numbers are already in-use")
532+ }*/
533+
534+ type unitNumberAssigner struct {
535+ used []bool
536+ offset int32
537+ }
538+
539+ func newUnitNumberAssigner (controller types.BaseVirtualController , existingDevices object.VirtualDeviceList , newDevices []types.BaseVirtualDeviceConfigSpec ) (* unitNumberAssigner , error ) {
540+ if controller == nil {
541+ return nil , errors .New ("controller parameter cannot be nil" )
542+ }
543+ used := make ([]bool , maxUnitNumber )
544+ // SCSIControllers also use a unit.
545+ if scsiController , ok := controller .(types.BaseVirtualSCSIController ); ok {
546+ used [scsiController .GetVirtualSCSIController ().ScsiCtlrUnitNumber ] = true
547+ }
548+ controllerKey := controller .GetVirtualController ().Key
549+ // Mark all unit numbers of existing devices as used
550+ for _ , device := range existingDevices {
551+ d := device .GetVirtualDevice ()
552+ if d .ControllerKey == controllerKey && d .UnitNumber != nil {
553+ used [* d .UnitNumber ] = true
554+ }
555+ }
556+ // Mark all unit numbers of new devices as used
557+ /*for _, device := range newDevices {
558+ d := device.GetVirtualDeviceConfigSpec().Device.GetVirtualDevice()
559+ if d.ControllerKey == controllerKey && d.UnitNumber != nil {
560+ used[*d.UnitNumber] = true
561+ }
562+ }*/
563+ // Set offset to 0, it will auto-increment on the first assignment.
564+ return & unitNumberAssigner {used : used , offset : 0 }, nil
565+ }
566+
567+ func (a * unitNumberAssigner ) assign () (int32 , error ) {
568+ if int (a .offset ) > len (a .used ) {
569+ return - 1 , fmt .Errorf ("all unit numbers are already in-use" )
570+ }
571+ for i , isInUse := range a .used [a .offset :] {
572+ unit := int32 (i ) + a .offset
573+ if ! isInUse {
574+ a .used [unit ] = true
575+ a .offset ++
576+ return unit , nil
577+ }
578+ }
579+ return - 1 , fmt .Errorf ("all unit numbers are already in-use" )
526580}
527581
528582const ethCardType = "vmxnet3"
0 commit comments