Skip to content

Commit 25ba78f

Browse files
Add a provision for handling image based bootstrap (#406)
* Add a provision for handling image based bootstrap AHV has a limit of 32KB for cloud-init userdata. In Openshift, the ignition can be rather large (a magnitude over the limit). In order to support larger userdata files, we allow mounting the customization as an image. * Only set guestcustomization explicitly when bootstrap ref is secret * Use lowercase for data_source_reference kind. --------- Co-authored-by: Sid Shukla <[email protected]>
1 parent 92800d9 commit 25ba78f

File tree

2 files changed

+122
-47
lines changed

2 files changed

+122
-47
lines changed

api/v1beta1/nutanixmachine_types.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ const (
3535
// resources associated with NutanixMachine before removing it from the
3636
// API Server.
3737
NutanixMachineFinalizer = "nutanixmachine.infrastructure.cluster.x-k8s.io"
38+
39+
// NutanixMachineBootstrapRefKindSecret represents the Kind of Secret
40+
// referenced by NutanixMachine's BootstrapRef.
41+
NutanixMachineBootstrapRefKindSecret = "Secret"
42+
43+
// NutanixMachineBootstrapRefKindImage represents the Kind of Image
44+
// referenced by NutanixMachine's BootstrapRef. If the BootstrapRef.Kind is set
45+
// to Image, the NutanixMachine will be created with the image mounted
46+
// as a CD-ROM.
47+
NutanixMachineBootstrapRefKindImage = "Image"
3848
)
3949

4050
// NutanixMachineSpec defines the desired state of NutanixMachine

controllers/nutanixmachine_controller.go

Lines changed: 112 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
apitypes "k8s.io/apimachinery/pkg/types"
3535
kerrors "k8s.io/apimachinery/pkg/util/errors"
3636
coreinformers "k8s.io/client-go/informers/core/v1"
37+
"k8s.io/utils/ptr"
3738
capiv1 "sigs.k8s.io/cluster-api/api/v1beta1"
3839
capierrors "sigs.k8s.io/cluster-api/errors"
3940
capiutil "sigs.k8s.io/cluster-api/util"
@@ -55,6 +56,9 @@ import (
5556

5657
const (
5758
projectKind = "project"
59+
60+
deviceTypeCDROM = "CDROM"
61+
adapterTypeIDE = "IDE"
5862
)
5963

6064
var (
@@ -517,31 +521,6 @@ func (r *NutanixMachineReconciler) getOrCreateVM(rctx *nctx.MachineContext) (*nu
517521
return nil, err
518522
}
519523

520-
// Get Image UUID
521-
imageUUID, err := GetImageUUID(ctx, nc, rctx.NutanixMachine.Spec.Image.Name, rctx.NutanixMachine.Spec.Image.UUID)
522-
if err != nil {
523-
errorMsg := fmt.Errorf("failed to get the image UUID to create the VM %s. %v", vmName, err)
524-
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
525-
return nil, err
526-
}
527-
528-
// Get the bootstrapData from the referenced secret
529-
bootstrapData, err := r.getBootstrapData(rctx)
530-
if err != nil {
531-
log.Error(err, fmt.Sprintf("failed to get the bootstrap data to create the VM %s", vmName))
532-
return nil, err
533-
}
534-
// Encode the bootstrapData by base64
535-
bsdataEncoded := base64.StdEncoding.EncodeToString(bootstrapData)
536-
log.V(1).Info(fmt.Sprintf("Retrieved the bootstrap data from secret %s (before encoding size: %d, encoded string size:%d)",
537-
rctx.NutanixMachine.Spec.BootstrapRef.Name, len(bootstrapData), len(bsdataEncoded)))
538-
539-
// Generate metadata for the VM
540-
vmUUID := uuid.New()
541-
metadata := fmt.Sprintf("{\"hostname\": \"%s\", \"uuid\": \"%s\"}", rctx.Machine.Name, vmUUID)
542-
// Encode the metadata by base64
543-
metadataEncoded := base64.StdEncoding.EncodeToString([]byte(metadata))
544-
545524
vmInput := &nutanixClientV3.VMIntentInput{}
546525
vmSpec := &nutanixClientV3.VM{Name: utils.StringPtr(vmName)}
547526

@@ -555,19 +534,6 @@ func (r *NutanixMachineReconciler) getOrCreateVM(rctx *nctx.MachineContext) (*nu
555534
}
556535
}
557536

558-
// Create Disk Spec for systemdisk to be set later in VM Spec
559-
diskSize := rctx.NutanixMachine.Spec.SystemDiskSize
560-
diskSizeMib := GetMibValueOfQuantity(diskSize)
561-
systemDisk, err := CreateSystemDiskSpec(imageUUID, diskSizeMib)
562-
if err != nil {
563-
errorMsg := fmt.Errorf("error occurred while creating system disk spec: %v", err)
564-
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
565-
return nil, errorMsg
566-
}
567-
diskList := []*nutanixClientV3.VMDisk{
568-
systemDisk,
569-
}
570-
571537
// Set Categories to VM Sepc before creating VM
572538
categories, err := GetCategoryVMSpec(ctx, nc, r.getMachineCategoryIdentifiers(rctx))
573539
if err != nil {
@@ -597,8 +563,14 @@ func (r *NutanixMachineReconciler) getOrCreateVM(rctx *nctx.MachineContext) (*nu
597563
return nil, err
598564
}
599565

600-
memorySize := rctx.NutanixMachine.Spec.MemorySize
601-
memorySizeMib := GetMibValueOfQuantity(memorySize)
566+
diskList, err := getDiskList(rctx)
567+
if err != nil {
568+
errorMsg := fmt.Errorf("failed to get the disk list to create the VM %s. %v", vmName, err)
569+
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
570+
return nil, err
571+
}
572+
573+
memorySizeMib := GetMibValueOfQuantity(rctx.NutanixMachine.Spec.MemorySize)
602574
vmSpec.Resources = &nutanixClientV3.VMResources{
603575
PowerState: utils.StringPtr("ON"),
604576
HardwareClockTimezone: utils.StringPtr("UTC"),
@@ -608,19 +580,18 @@ func (r *NutanixMachineReconciler) getOrCreateVM(rctx *nctx.MachineContext) (*nu
608580
NicList: nicList,
609581
DiskList: diskList,
610582
GpuList: gpuList,
611-
GuestCustomization: &nutanixClientV3.GuestCustomization{
612-
IsOverridable: utils.BoolPtr(true),
613-
CloudInit: &nutanixClientV3.GuestCustomizationCloudInit{
614-
UserData: utils.StringPtr(bsdataEncoded),
615-
MetaData: utils.StringPtr(metadataEncoded),
616-
},
617-
},
618583
}
619584
vmSpec.ClusterReference = &nutanixClientV3.Reference{
620585
Kind: utils.StringPtr("cluster"),
621586
UUID: utils.StringPtr(peUUID),
622587
}
623588

589+
if err := r.addGuestCustomizationToVM(rctx, vmSpec); err != nil {
590+
errorMsg := fmt.Errorf("error occurred while adding guest customization to vm spec: %v", err)
591+
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
592+
return nil, err
593+
}
594+
624595
// Set BootType in VM Spec before creating VM
625596
err = r.addBootTypeToVM(rctx, vmSpec)
626597
if err != nil {
@@ -684,6 +655,100 @@ func (r *NutanixMachineReconciler) getOrCreateVM(rctx *nctx.MachineContext) (*nu
684655
return vm, nil
685656
}
686657

658+
func (r *NutanixMachineReconciler) addGuestCustomizationToVM(rctx *nctx.MachineContext, vmSpec *nutanixClientV3.VM) error {
659+
// Get the bootstrapData
660+
bootstrapRef := rctx.NutanixMachine.Spec.BootstrapRef
661+
if bootstrapRef.Kind == infrav1.NutanixMachineBootstrapRefKindSecret {
662+
bootstrapData, err := r.getBootstrapData(rctx)
663+
if err != nil {
664+
return err
665+
}
666+
667+
// Encode the bootstrapData by base64
668+
bsdataEncoded := base64.StdEncoding.EncodeToString(bootstrapData)
669+
metadata := fmt.Sprintf("{\"hostname\": \"%s\", \"uuid\": \"%s\"}", rctx.Machine.Name, uuid.New())
670+
metadataEncoded := base64.StdEncoding.EncodeToString([]byte(metadata))
671+
672+
vmSpec.Resources.GuestCustomization = &nutanixClientV3.GuestCustomization{
673+
IsOverridable: utils.BoolPtr(true),
674+
CloudInit: &nutanixClientV3.GuestCustomizationCloudInit{
675+
UserData: utils.StringPtr(bsdataEncoded),
676+
MetaData: utils.StringPtr(metadataEncoded),
677+
},
678+
}
679+
}
680+
681+
return nil
682+
}
683+
684+
func getDiskList(rctx *nctx.MachineContext) ([]*nutanixClientV3.VMDisk, error) {
685+
diskList := make([]*nutanixClientV3.VMDisk, 0)
686+
687+
systemDisk, err := getSystemDisk(rctx)
688+
if err != nil {
689+
return nil, err
690+
}
691+
diskList = append(diskList, systemDisk)
692+
693+
bootstrapRef := rctx.NutanixMachine.Spec.BootstrapRef
694+
if bootstrapRef.Kind == infrav1.NutanixMachineBootstrapRefKindImage {
695+
bootstrapDisk, err := getBootstrapDisk(rctx)
696+
if err != nil {
697+
return nil, err
698+
}
699+
700+
diskList = append(diskList, bootstrapDisk)
701+
}
702+
703+
return diskList, nil
704+
}
705+
706+
func getSystemDisk(rctx *nctx.MachineContext) (*nutanixClientV3.VMDisk, error) {
707+
nodeOSImageName := rctx.NutanixMachine.Spec.Image.Name
708+
nodeOSImageUUID, err := GetImageUUID(rctx.Context, rctx.NutanixClient, nodeOSImageName, rctx.NutanixMachine.Spec.Image.UUID)
709+
if err != nil {
710+
errorMsg := fmt.Errorf("failed to get the image UUID for image named %q: %w", *nodeOSImageName, err)
711+
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
712+
return nil, err
713+
}
714+
715+
systemDiskSizeMib := GetMibValueOfQuantity(rctx.NutanixMachine.Spec.SystemDiskSize)
716+
systemDisk, err := CreateSystemDiskSpec(nodeOSImageUUID, systemDiskSizeMib)
717+
if err != nil {
718+
errorMsg := fmt.Errorf("error occurred while creating system disk spec: %w", err)
719+
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
720+
return nil, err
721+
}
722+
723+
return systemDisk, nil
724+
}
725+
726+
func getBootstrapDisk(rctx *nctx.MachineContext) (*nutanixClientV3.VMDisk, error) {
727+
bootstrapImageName := rctx.NutanixMachine.Spec.BootstrapRef.Name
728+
bootstrapImageUUID, err := GetImageUUID(rctx.Context, rctx.NutanixClient, &bootstrapImageName, nil)
729+
if err != nil {
730+
errorMsg := fmt.Errorf("failed to get the image UUID for image named %q: %w", bootstrapImageName, err)
731+
rctx.SetFailureStatus(capierrors.CreateMachineError, errorMsg)
732+
return nil, err
733+
}
734+
735+
bootstrapDisk := &nutanixClientV3.VMDisk{
736+
DeviceProperties: &nutanixClientV3.VMDiskDeviceProperties{
737+
DeviceType: ptr.To(deviceTypeCDROM),
738+
DiskAddress: &nutanixClientV3.DiskAddress{
739+
AdapterType: ptr.To(adapterTypeIDE),
740+
DeviceIndex: ptr.To(int64(0)),
741+
},
742+
},
743+
DataSourceReference: &nutanixClientV3.Reference{
744+
Kind: ptr.To(strings.ToLower(infrav1.NutanixMachineBootstrapRefKindImage)),
745+
UUID: ptr.To(bootstrapImageUUID),
746+
},
747+
}
748+
749+
return bootstrapDisk, nil
750+
}
751+
687752
// getBootstrapData returns the Bootstrap data from the ref secret
688753
func (r *NutanixMachineReconciler) getBootstrapData(rctx *nctx.MachineContext) ([]byte, error) {
689754
if rctx.NutanixMachine.Spec.BootstrapRef == nil {

0 commit comments

Comments
 (0)