From 8d3bbd4999898c4b62b93e04952dfe027074dd63 Mon Sep 17 00:00:00 2001 From: Tommaso Date: Wed, 22 Oct 2025 09:57:30 -0500 Subject: [PATCH] Add flags to allow customization of CPU and memory shares, reservations and limits Signed-off-by: Tommaso --- apis/v1alpha3/vspheremachine_conversion.go | 1 + .../vspheremachinetemplate_conversion.go | 1 + apis/v1alpha3/vspherevm_conversion.go | 1 + apis/v1alpha3/zz_generated.conversion.go | 1 + apis/v1alpha4/vspheremachine_conversion.go | 1 + .../vspheremachinetemplate_conversion.go | 1 + apis/v1alpha4/vspherevm_conversion.go | 1 + apis/v1alpha4/zz_generated.conversion.go | 1 + apis/v1beta1/types.go | 52 ++++++++++++++ apis/v1beta1/zz_generated.deepcopy.go | 51 +++++++++++++ ...ture.cluster.x-k8s.io_vspheremachines.yaml | 71 +++++++++++++++++++ ...ster.x-k8s.io_vspheremachinetemplates.yaml | 71 +++++++++++++++++++ ...structure.cluster.x-k8s.io_vspherevms.yaml | 71 +++++++++++++++++++ pkg/services/govmomi/vcenter/clone.go | 54 ++++++++++++++ 14 files changed, 378 insertions(+) diff --git a/apis/v1alpha3/vspheremachine_conversion.go b/apis/v1alpha3/vspheremachine_conversion.go index eafef460fa..95056f4cba 100644 --- a/apis/v1alpha3/vspheremachine_conversion.go +++ b/apis/v1alpha3/vspheremachine_conversion.go @@ -36,6 +36,7 @@ func (src *VSphereMachine) ConvertTo(dstRaw conversion.Hub) error { return err } + dst.Spec.Resources = restored.Spec.Resources dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB dst.Spec.TagIDs = restored.Spec.TagIDs dst.Spec.PowerOffMode = restored.Spec.PowerOffMode diff --git a/apis/v1alpha3/vspheremachinetemplate_conversion.go b/apis/v1alpha3/vspheremachinetemplate_conversion.go index 02e5a9d80b..337d8428aa 100644 --- a/apis/v1alpha3/vspheremachinetemplate_conversion.go +++ b/apis/v1alpha3/vspheremachinetemplate_conversion.go @@ -39,6 +39,7 @@ func (src *VSphereMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err } + dst.Spec.Template.Spec.Resources = restored.Spec.Template.Spec.Resources dst.Spec.Template.Spec.TagIDs = restored.Spec.Template.Spec.TagIDs dst.Spec.Template.Spec.AdditionalDisksGiB = restored.Spec.Template.Spec.AdditionalDisksGiB dst.Spec.Template.Spec.PowerOffMode = restored.Spec.Template.Spec.PowerOffMode diff --git a/apis/v1alpha3/vspherevm_conversion.go b/apis/v1alpha3/vspherevm_conversion.go index e8ec172314..432900140f 100644 --- a/apis/v1alpha3/vspherevm_conversion.go +++ b/apis/v1alpha3/vspherevm_conversion.go @@ -35,6 +35,7 @@ func (src *VSphereVM) ConvertTo(dstRaw conversion.Hub) error { if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err } + dst.Spec.Resources = restored.Spec.Resources dst.Spec.TagIDs = restored.Spec.TagIDs dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB dst.Spec.PowerOffMode = restored.Spec.PowerOffMode diff --git a/apis/v1alpha3/zz_generated.conversion.go b/apis/v1alpha3/zz_generated.conversion.go index 489f69d30f..25afbe8820 100644 --- a/apis/v1alpha3/zz_generated.conversion.go +++ b/apis/v1alpha3/zz_generated.conversion.go @@ -1802,6 +1802,7 @@ func autoConvert_v1beta1_VirtualMachineCloneSpec_To_v1alpha3_VirtualMachineClone } out.NumCPUs = in.NumCPUs out.NumCoresPerSocket = in.NumCoresPerSocket + // WARNING: in.Resources requires manual conversion: does not exist in peer-type out.MemoryMiB = in.MemoryMiB out.DiskGiB = in.DiskGiB // WARNING: in.AdditionalDisksGiB requires manual conversion: does not exist in peer-type diff --git a/apis/v1alpha4/vspheremachine_conversion.go b/apis/v1alpha4/vspheremachine_conversion.go index 23e1d7269c..6be336e04d 100644 --- a/apis/v1alpha4/vspheremachine_conversion.go +++ b/apis/v1alpha4/vspheremachine_conversion.go @@ -36,6 +36,7 @@ func (src *VSphereMachine) ConvertTo(dstRaw conversion.Hub) error { return err } + dst.Spec.Resources = restored.Spec.Resources dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB dst.Spec.TagIDs = restored.Spec.TagIDs dst.Spec.PowerOffMode = restored.Spec.PowerOffMode diff --git a/apis/v1alpha4/vspheremachinetemplate_conversion.go b/apis/v1alpha4/vspheremachinetemplate_conversion.go index 6d94e1f5f8..afa865686d 100644 --- a/apis/v1alpha4/vspheremachinetemplate_conversion.go +++ b/apis/v1alpha4/vspheremachinetemplate_conversion.go @@ -39,6 +39,7 @@ func (src *VSphereMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err } + dst.Spec.Template.Spec.Resources = restored.Spec.Template.Spec.Resources dst.Spec.Template.Spec.TagIDs = restored.Spec.Template.Spec.TagIDs dst.Spec.Template.Spec.AdditionalDisksGiB = restored.Spec.Template.Spec.AdditionalDisksGiB dst.Spec.Template.Spec.PowerOffMode = restored.Spec.Template.Spec.PowerOffMode diff --git a/apis/v1alpha4/vspherevm_conversion.go b/apis/v1alpha4/vspherevm_conversion.go index d87f0969c8..c578547684 100644 --- a/apis/v1alpha4/vspherevm_conversion.go +++ b/apis/v1alpha4/vspherevm_conversion.go @@ -35,6 +35,7 @@ func (src *VSphereVM) ConvertTo(dstRaw conversion.Hub) error { if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok { return err } + dst.Spec.Resources = restored.Spec.Resources dst.Spec.TagIDs = restored.Spec.TagIDs dst.Spec.AdditionalDisksGiB = restored.Spec.AdditionalDisksGiB dst.Spec.PowerOffMode = restored.Spec.PowerOffMode diff --git a/apis/v1alpha4/zz_generated.conversion.go b/apis/v1alpha4/zz_generated.conversion.go index fd9ddcf91e..f77ac3db6d 100644 --- a/apis/v1alpha4/zz_generated.conversion.go +++ b/apis/v1alpha4/zz_generated.conversion.go @@ -1956,6 +1956,7 @@ func autoConvert_v1beta1_VirtualMachineCloneSpec_To_v1alpha4_VirtualMachineClone } out.NumCPUs = in.NumCPUs out.NumCoresPerSocket = in.NumCoresPerSocket + // WARNING: in.Resources requires manual conversion: does not exist in peer-type out.MemoryMiB = in.MemoryMiB out.DiskGiB = in.DiskGiB // WARNING: in.AdditionalDisksGiB requires manual conversion: does not exist in peer-type diff --git a/apis/v1beta1/types.go b/apis/v1beta1/types.go index cace8c445f..3f8c38b4d2 100644 --- a/apis/v1beta1/types.go +++ b/apis/v1beta1/types.go @@ -20,6 +20,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1" ) @@ -167,6 +168,12 @@ type VirtualMachineCloneSpec struct { // virtual machine is cloned. // +optional NumCoresPerSocket int32 `json:"numCoresPerSocket,omitempty"` + + // resources is the definition of the VM's cpu and memory + // reservations, limits and shares. + // +optional + Resources VirtualMachineResources `json:"resources,omitempty,omitzero"` + // MemoryMiB is the size of a virtual machine's memory, in MiB. // Defaults to the eponymous property value in the template from which the // virtual machine is cloned. @@ -211,6 +218,51 @@ type VirtualMachineCloneSpec struct { DataDisks []VSphereDisk `json:"dataDisks,omitempty"` } +// VirtualMachineResources is the definition of the VM's cpu and memory +// reservations, limits and shares. +// +kubebuilder:validation:MinProperties=1 +type VirtualMachineResources struct { + // requests is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + // and memory (in bytes, rounded up to the nearest MiB) reservations + // +optional + Requests VirtualMachineResourceSpec `json:"requests,omitempty,omitzero"` + // limits is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + // and memory (in bytes, rounded up to the nearest MiB) limits + // +optional + Limits VirtualMachineResourceSpec `json:"limits,omitempty,omitzero"` + // shares is the definition of the VM's cpu and memory shares + // +optional + Shares VirtualMachineResourceShares `json:"shares,omitempty,omitzero"` +} + +// VirtualMachineResourceSpec is the numerical definition of memory and cpu quantity for the +// given VM hardware policy. +// +kubebuilder:validation:MinProperties=1 +type VirtualMachineResourceSpec struct { + // cpu is the definition of the cpu quantity for the given VM hardware policy + // +optional + CPU resource.Quantity `json:"cpu,omitempty"` + + // memory is the definition of the memory quantity for the given VM hardware policy + // +optional + Memory resource.Quantity `json:"memory,omitempty"` +} + +// VirtualMachineResourceShares is the numerical definition of memory and cpu shares for the +// given VM +// +kubebuilder:validation:MinProperties=1 +type VirtualMachineResourceShares struct { + // cpu is the number of spu shares to assign to the VM + // +kubebuilder:validation:Minimum=1 + // +optional + CPU int32 `json:"cpu,omitempty"` + + // memory is the number of memory shares to assign to the VM + // +kubebuilder:validation:Minimum=1 + // +optional + Memory int32 `json:"memory,omitempty"` +} + // VSphereDisk is an additional disk to add to the VM that is not part of the VM OVA template. type VSphereDisk struct { // Name is used to identify the disk definition. Name is required and needs to be unique so that it can be used to diff --git a/apis/v1beta1/zz_generated.deepcopy.go b/apis/v1beta1/zz_generated.deepcopy.go index 1c12980758..e54eb3ea73 100644 --- a/apis/v1beta1/zz_generated.deepcopy.go +++ b/apis/v1beta1/zz_generated.deepcopy.go @@ -1531,6 +1531,7 @@ func (in *VirtualMachine) DeepCopy() *VirtualMachine { func (in *VirtualMachineCloneSpec) DeepCopyInto(out *VirtualMachineCloneSpec) { *out = *in in.Network.DeepCopyInto(&out.Network) + in.Resources.DeepCopyInto(&out.Resources) if in.AdditionalDisksGiB != nil { in, out := &in.AdditionalDisksGiB, &out.AdditionalDisksGiB *out = make([]int32, len(*in)) @@ -1571,3 +1572,53 @@ func (in *VirtualMachineCloneSpec) DeepCopy() *VirtualMachineCloneSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineResourceShares) DeepCopyInto(out *VirtualMachineResourceShares) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineResourceShares. +func (in *VirtualMachineResourceShares) DeepCopy() *VirtualMachineResourceShares { + if in == nil { + return nil + } + out := new(VirtualMachineResourceShares) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineResourceSpec) DeepCopyInto(out *VirtualMachineResourceSpec) { + *out = *in + out.CPU = in.CPU.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineResourceSpec. +func (in *VirtualMachineResourceSpec) DeepCopy() *VirtualMachineResourceSpec { + if in == nil { + return nil + } + out := new(VirtualMachineResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VirtualMachineResources) DeepCopyInto(out *VirtualMachineResources) { + *out = *in + in.Requests.DeepCopyInto(&out.Requests) + in.Limits.DeepCopyInto(&out.Limits) + out.Shares = in.Shares +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualMachineResources. +func (in *VirtualMachineResources) DeepCopy() *VirtualMachineResources { + if in == nil { + return nil + } + out := new(VirtualMachineResources) + in.DeepCopyInto(out) + return out +} diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml index b434afa852..d43e6feb5d 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachines.yaml @@ -1459,6 +1459,77 @@ spec: ResourcePool is the name, inventory path, managed object reference or the managed object ID in which the virtual machine is created/located. type: string + resources: + description: |- + resources is the definition of the VM's cpu and memory + reservations, limits and shares. + minProperties: 1 + properties: + limits: + description: |- + limits is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) limits + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity for + the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + description: |- + requests is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) reservations + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity for + the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + shares: + description: shares is the definition of the VM's cpu and memory + shares + minProperties: 1 + properties: + cpu: + description: cpu is the number of spu shares to assign to + the VM + format: int32 + minimum: 1 + type: integer + memory: + description: memory is the number of memory shares to assign + to the VM + format: int32 + minimum: 1 + type: integer + type: object + type: object server: description: |- Server is the IP address or FQDN of the vSphere server on which diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml index f9d73eaf30..fb1665bd9d 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspheremachinetemplates.yaml @@ -1335,6 +1335,77 @@ spec: ResourcePool is the name, inventory path, managed object reference or the managed object ID in which the virtual machine is created/located. type: string + resources: + description: |- + resources is the definition of the VM's cpu and memory + reservations, limits and shares. + minProperties: 1 + properties: + limits: + description: |- + limits is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) limits + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory + quantity for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + description: |- + requests is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) reservations + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory + quantity for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + shares: + description: shares is the definition of the VM's cpu + and memory shares + minProperties: 1 + properties: + cpu: + description: cpu is the number of spu shares to assign + to the VM + format: int32 + minimum: 1 + type: integer + memory: + description: memory is the number of memory shares + to assign to the VM + format: int32 + minimum: 1 + type: integer + type: object + type: object server: description: |- Server is the IP address or FQDN of the vSphere server on which diff --git a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml index 47e6599f07..e97855544a 100644 --- a/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml +++ b/config/default/crd/bases/infrastructure.cluster.x-k8s.io_vspherevms.yaml @@ -1517,6 +1517,77 @@ spec: ResourcePool is the name, inventory path, managed object reference or the managed object ID in which the virtual machine is created/located. type: string + resources: + description: |- + resources is the definition of the VM's cpu and memory + reservations, limits and shares. + minProperties: 1 + properties: + limits: + description: |- + limits is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) limits + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity for + the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + description: |- + requests is the definition of the VM's cpu (in hertz, rounded up to the nearest MHz) + and memory (in bytes, rounded up to the nearest MiB) reservations + minProperties: 1 + properties: + cpu: + anyOf: + - type: integer + - type: string + description: cpu is the definition of the cpu quantity for + the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + memory: + anyOf: + - type: integer + - type: string + description: memory is the definition of the memory quantity + for the given VM hardware policy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + shares: + description: shares is the definition of the VM's cpu and memory + shares + minProperties: 1 + properties: + cpu: + description: cpu is the number of spu shares to assign to + the VM + format: int32 + minimum: 1 + type: integer + memory: + description: memory is the number of memory shares to assign + to the VM + format: int32 + minimum: 1 + type: integer + type: object + type: object server: description: |- Server is the IP address or FQDN of the vSphere server on which diff --git a/pkg/services/govmomi/vcenter/clone.go b/pkg/services/govmomi/vcenter/clone.go index 47b11651db..19cd1636ff 100644 --- a/pkg/services/govmomi/vcenter/clone.go +++ b/pkg/services/govmomi/vcenter/clone.go @@ -20,6 +20,7 @@ package vcenter import ( "context" "fmt" + "math" "math/rand" "time" @@ -30,6 +31,7 @@ import ( "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/api/bootstrap/kubeadm/v1beta2" ctrl "sigs.k8s.io/controller-runtime" @@ -212,6 +214,48 @@ func Clone(ctx context.Context, vmCtx *capvcontext.VMContext, bootstrapData []by Snapshot: snapshotRef, } + // Set CPU reservations, limits and shares if specified + if !vmCtx.VSphereVM.Spec.Resources.Requests.CPU.IsZero() || !vmCtx.VSphereVM.Spec.Resources.Limits.CPU.IsZero() || vmCtx.VSphereVM.Spec.Resources.Shares.CPU > 0 { + cpuAllocation := types.ResourceAllocationInfo{} + if !vmCtx.VSphereVM.Spec.Resources.Requests.CPU.IsZero() { + cpuReservationMhz := convertQuantityToMhz(vmCtx.VSphereVM.Spec.Resources.Requests.CPU) + cpuAllocation.Reservation = ptr.To(cpuReservationMhz) + } + if !vmCtx.VSphereVM.Spec.Resources.Limits.CPU.IsZero() { + cpuLimitMhz := convertQuantityToMhz(vmCtx.VSphereVM.Spec.Resources.Limits.CPU) + cpuAllocation.Limit = ptr.To(cpuLimitMhz) + } + if vmCtx.VSphereVM.Spec.Resources.Shares.CPU > 0 { + cpuShares := types.SharesInfo{ + Shares: vmCtx.VSphereVM.Spec.Resources.Shares.CPU, + Level: types.SharesLevelCustom, + } + cpuAllocation.Shares = ptr.To(cpuShares) + } + spec.Config.CpuAllocation = ptr.To(cpuAllocation) + } + + // Set memory reservations, limits and shares if specified + if !vmCtx.VSphereVM.Spec.Resources.Requests.Memory.IsZero() || !vmCtx.VSphereVM.Spec.Resources.Limits.Memory.IsZero() || vmCtx.VSphereVM.Spec.Resources.Shares.Memory > 0 { + memoryAllocation := types.ResourceAllocationInfo{} + if !vmCtx.VSphereVM.Spec.Resources.Requests.Memory.IsZero() { + memoryReservationMiB := convertQuantityToMiB(vmCtx.VSphereVM.Spec.Resources.Requests.Memory) + memoryAllocation.Reservation = ptr.To(memoryReservationMiB) + } + if !vmCtx.VSphereVM.Spec.Resources.Limits.Memory.IsZero() { + memoryLimitMiB := convertQuantityToMiB(vmCtx.VSphereVM.Spec.Resources.Limits.Memory) + memoryAllocation.Limit = ptr.To(memoryLimitMiB) + } + if vmCtx.VSphereVM.Spec.Resources.Shares.Memory > 0 { + memoryShares := types.SharesInfo{ + Shares: vmCtx.VSphereVM.Spec.Resources.Shares.Memory, + Level: types.SharesLevelCustom, + } + memoryAllocation.Shares = ptr.To(memoryShares) + } + spec.Config.MemoryAllocation = ptr.To(memoryAllocation) + } + // For PCI devices, the memory for the VM needs to be reserved // We can replace this once we have another way of reserving memory option // exposed via the API types. @@ -503,6 +547,16 @@ func createDataDisks(ctx context.Context, dataDiskDefs []infrav1.VSphereDisk, de return additionalDisks, nil } +// convertQuantityToMhz converts a quantity to MHz, rounding up to the nearest MHz. +func convertQuantityToMhz(quantity resource.Quantity) int64 { + return int64(math.Ceil(float64(quantity.Value()) / float64(1000000))) +} + +// convertQuantityToMiB converts a quantity to MiB, rounding up to the nearest MiB. +func convertQuantityToMiB(quantity resource.Quantity) int64 { + return int64(math.Ceil(float64(quantity.Value()) / float64(1024) / float64(1024))) +} + type unitNumberAssigner struct { used []bool offset int32