From 544d83bfad86a7855c4dd89241824a12466c538e Mon Sep 17 00:00:00 2001 From: Mulham Raee Date: Wed, 4 Sep 2024 17:54:41 +0200 Subject: [PATCH] Add support to specifiy dedicated host ID and Affinity --- api/v1beta1/awscluster_conversion.go | 1 + api/v1beta1/awsmachine_conversion.go | 4 +++ api/v1beta1/zz_generated.conversion.go | 10 +++--- api/v1beta2/awsmachine_types.go | 30 +++++++++++++++- api/v1beta2/types.go | 6 +++- api/v1beta2/zz_generated.deepcopy.go | 35 +++++++++++++++++++ ...ster.x-k8s.io_awsmanagedcontrolplanes.yaml | 32 +++++++++++++++++ ...tructure.cluster.x-k8s.io_awsclusters.yaml | 16 +++++++++ ...tructure.cluster.x-k8s.io_awsmachines.yaml | 16 +++++++++ ....cluster.x-k8s.io_awsmachinetemplates.yaml | 16 +++++++++ pkg/cloud/services/ec2/instances.go | 8 ++++- 11 files changed, 167 insertions(+), 7 deletions(-) diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go index 954fea7a4c..4082a88b69 100644 --- a/api/v1beta1/awscluster_conversion.go +++ b/api/v1beta1/awscluster_conversion.go @@ -60,6 +60,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Bastion.PrivateDNSName = restored.Status.Bastion.PrivateDNSName dst.Status.Bastion.PublicIPOnLaunch = restored.Status.Bastion.PublicIPOnLaunch dst.Status.Bastion.CapacityReservationID = restored.Status.Bastion.CapacityReservationID + dst.Status.Bastion.DedicatedHostPlacement = restored.Status.Bastion.DedicatedHostPlacement } dst.Spec.Partition = restored.Spec.Partition diff --git a/api/v1beta1/awsmachine_conversion.go b/api/v1beta1/awsmachine_conversion.go index 6044416cdf..cb594ffd73 100644 --- a/api/v1beta1/awsmachine_conversion.go +++ b/api/v1beta1/awsmachine_conversion.go @@ -42,6 +42,8 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.PrivateDNSName = restored.Spec.PrivateDNSName dst.Spec.SecurityGroupOverrides = restored.Spec.SecurityGroupOverrides dst.Spec.CapacityReservationID = restored.Spec.CapacityReservationID + dst.Spec.DedicatedHostPlacement = restored.Spec.DedicatedHostPlacement + if restored.Spec.ElasticIPPool != nil { if dst.Spec.ElasticIPPool == nil { dst.Spec.ElasticIPPool = &infrav1.ElasticIPPool{} @@ -104,6 +106,8 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Template.Spec.PrivateDNSName = restored.Spec.Template.Spec.PrivateDNSName dst.Spec.Template.Spec.SecurityGroupOverrides = restored.Spec.Template.Spec.SecurityGroupOverrides dst.Spec.Template.Spec.CapacityReservationID = restored.Spec.Template.Spec.CapacityReservationID + dst.Spec.Template.Spec.DedicatedHostPlacement = restored.Spec.Template.Spec.DedicatedHostPlacement + if restored.Spec.Template.Spec.ElasticIPPool != nil { if dst.Spec.Template.Spec.ElasticIPPool == nil { dst.Spec.Template.Spec.ElasticIPPool = &infrav1.ElasticIPPool{} diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index a85eaf08d3..49f458ceee 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -1371,7 +1371,7 @@ func autoConvert_v1beta1_AWSMachineSpec_To_v1beta2_AWSMachineSpec(in *AWSMachine out.Ignition = nil } out.SpotMarketOptions = (*v1beta2.SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) - out.Tenancy = in.Tenancy + out.Tenancy = v1beta2.Tenancy(in.Tenancy) return nil } @@ -1431,7 +1431,8 @@ func autoConvert_v1beta2_AWSMachineSpec_To_v1beta1_AWSMachineSpec(in *v1beta2.AW out.SpotMarketOptions = (*SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) // WARNING: in.PlacementGroupName requires manual conversion: does not exist in peer-type // WARNING: in.PlacementGroupPartition requires manual conversion: does not exist in peer-type - out.Tenancy = in.Tenancy + out.Tenancy = string(in.Tenancy) + // WARNING: in.DedicatedHostPlacement requires manual conversion: does not exist in peer-type // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type // WARNING: in.CapacityReservationID requires manual conversion: does not exist in peer-type return nil @@ -1997,7 +1998,7 @@ func autoConvert_v1beta1_Instance_To_v1beta2_Instance(in *Instance, out *v1beta2 out.Tags = *(*map[string]string)(unsafe.Pointer(&in.Tags)) out.AvailabilityZone = in.AvailabilityZone out.SpotMarketOptions = (*v1beta2.SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) - out.Tenancy = in.Tenancy + out.Tenancy = v1beta2.Tenancy(in.Tenancy) out.VolumeIDs = *(*[]string)(unsafe.Pointer(&in.VolumeIDs)) return nil } @@ -2030,7 +2031,8 @@ func autoConvert_v1beta2_Instance_To_v1beta1_Instance(in *v1beta2.Instance, out out.SpotMarketOptions = (*SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) // WARNING: in.PlacementGroupName requires manual conversion: does not exist in peer-type // WARNING: in.PlacementGroupPartition requires manual conversion: does not exist in peer-type - out.Tenancy = in.Tenancy + out.Tenancy = string(in.Tenancy) + // WARNING: in.DedicatedHostPlacement requires manual conversion: does not exist in peer-type out.VolumeIDs = *(*[]string)(unsafe.Pointer(&in.VolumeIDs)) // WARNING: in.InstanceMetadataOptions requires manual conversion: does not exist in peer-type // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type diff --git a/api/v1beta2/awsmachine_types.go b/api/v1beta2/awsmachine_types.go index 39a649a0e5..15d02e1185 100644 --- a/api/v1beta2/awsmachine_types.go +++ b/api/v1beta2/awsmachine_types.go @@ -54,6 +54,18 @@ const ( IgnitionStorageTypeOptionUnencryptedUserData = IgnitionStorageTypeOption("UnencryptedUserData") ) +// Tenancy defines the different tenancy options for EC2 instance. +type Tenancy string + +const ( + // TenancyDefault means that the EC2 instance will be launched into a shared host. + TenancyDefault = Tenancy("default") + // TenancyDedicated means that AWS will create and allocate a physical host for the EC2 instance (1 instance per host). + TenancyDedicated = Tenancy("dedicated") + // TenancyHost means that the EC2 instance will be launched into one of the user's pre-allocated physical hosts (multiple instances per host). + TenancyHost = Tenancy("host") +) + // AWSMachineSpec defines the desired state of an Amazon EC2 instance. type AWSMachineSpec struct { // ProviderID is the unique identifier as specified by the cloud provider. @@ -188,7 +200,11 @@ type AWSMachineSpec struct { // Tenancy indicates if instance should run on shared or single-tenant hardware. // +optional // +kubebuilder:validation:Enum:=default;dedicated;host - Tenancy string `json:"tenancy,omitempty"` + Tenancy Tenancy `json:"tenancy,omitempty"` + + // DedicatedHostPlacement denotes the placement settings for the instance when tenancy=host + // +optional + DedicatedHostPlacement *DedicatedHostPlacement `json:"dedicatedHostPlacment,omitempty"` // PrivateDNSName is the options for the instance hostname. // +optional @@ -199,6 +215,18 @@ type AWSMachineSpec struct { CapacityReservationID *string `json:"capacityReservationId,omitempty"` } +// DedicatedHostPlacement denotes the placement settings for the instance when tenancy=host +type DedicatedHostPlacement struct { + // HostID pins the instance to a sepcific Dedicated Host. + // +optional + HostID *string `json:"hostID,omitempty"` + + // Affinity indicates the affinity setting between the instance and a Dedicated Host. + // +optional + // +kubebuilder:validation:Enum:=default;host + Affinity *string `json:"affinity,omitempty"` +} + // CloudInit defines options related to the bootstrapping systems where // CloudInit is used. type CloudInit struct { diff --git a/api/v1beta2/types.go b/api/v1beta2/types.go index 978d5310f2..37d308b716 100644 --- a/api/v1beta2/types.go +++ b/api/v1beta2/types.go @@ -240,7 +240,11 @@ type Instance struct { // Tenancy indicates if instance should run on shared or single-tenant hardware. // +optional - Tenancy string `json:"tenancy,omitempty"` + Tenancy Tenancy `json:"tenancy,omitempty"` + + // DedicatedHostPlacement denotes the placement settings for the instance when tenancy=host + // +optional + DedicatedHostPlacement *DedicatedHostPlacement `json:"dedicatedHostPlacment,omitempty"` // IDs of the instance's volumes // +optional diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index b3eaa6c08d..2389bf8f08 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -762,6 +762,11 @@ func (in *AWSMachineSpec) DeepCopyInto(out *AWSMachineSpec) { *out = new(SpotMarketOptions) (*in).DeepCopyInto(*out) } + if in.DedicatedHostPlacement != nil { + in, out := &in.DedicatedHostPlacement, &out.DedicatedHostPlacement + *out = new(DedicatedHostPlacement) + (*in).DeepCopyInto(*out) + } if in.PrivateDNSName != nil { in, out := &in.PrivateDNSName, &out.PrivateDNSName *out = new(PrivateDNSName) @@ -1291,6 +1296,31 @@ func (in *CloudInit) DeepCopy() *CloudInit { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DedicatedHostPlacement) DeepCopyInto(out *DedicatedHostPlacement) { + *out = *in + if in.HostID != nil { + in, out := &in.HostID, &out.HostID + *out = new(string) + **out = **in + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DedicatedHostPlacement. +func (in *DedicatedHostPlacement) DeepCopy() *DedicatedHostPlacement { + if in == nil { + return nil + } + out := new(DedicatedHostPlacement) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ElasticIPPool) DeepCopyInto(out *ElasticIPPool) { *out = *in @@ -1579,6 +1609,11 @@ func (in *Instance) DeepCopyInto(out *Instance) { *out = new(SpotMarketOptions) (*in).DeepCopyInto(*out) } + if in.DedicatedHostPlacement != nil { + in, out := &in.DedicatedHostPlacement, &out.DedicatedHostPlacement + *out = new(DedicatedHostPlacement) + (*in).DeepCopyInto(*out) + } if in.VolumeIDs != nil { in, out := &in.VolumeIDs, &out.VolumeIDs *out = make([]string, len(*in)) diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml index 345b3f4379..a5a817e44c 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -1125,6 +1125,22 @@ spec: description: CapacityReservationID specifies the target Capacity Reservation into which the instance should be launched. type: string + dedicatedHostPlacment: + description: DedicatedHostPlacement denotes the placement settings + for the instance when tenancy=host + properties: + affinity: + description: Affinity indicates the affinity setting between + the instance and a Dedicated Host. + enum: + - default + - host + type: string + hostID: + description: HostID pins the instance to a sepcific Dedicated + Host. + type: string + type: object ebsOptimized: description: Indicates whether the instance is optimized for Amazon EBS I/O. @@ -3169,6 +3185,22 @@ spec: description: CapacityReservationID specifies the target Capacity Reservation into which the instance should be launched. type: string + dedicatedHostPlacment: + description: DedicatedHostPlacement denotes the placement settings + for the instance when tenancy=host + properties: + affinity: + description: Affinity indicates the affinity setting between + the instance and a Dedicated Host. + enum: + - default + - host + type: string + hostID: + description: HostID pins the instance to a sepcific Dedicated + Host. + type: string + type: object ebsOptimized: description: Indicates whether the instance is optimized for Amazon EBS I/O. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml index f3eb3a2fc7..740d222a92 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml @@ -2110,6 +2110,22 @@ spec: description: CapacityReservationID specifies the target Capacity Reservation into which the instance should be launched. type: string + dedicatedHostPlacment: + description: DedicatedHostPlacement denotes the placement settings + for the instance when tenancy=host + properties: + affinity: + description: Affinity indicates the affinity setting between + the instance and a Dedicated Host. + enum: + - default + - host + type: string + hostID: + description: HostID pins the instance to a sepcific Dedicated + Host. + type: string + type: object ebsOptimized: description: Indicates whether the instance is optimized for Amazon EBS I/O. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml index c02466fa59..0cb67a3308 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml @@ -661,6 +661,22 @@ spec: - ssm-parameter-store type: string type: object + dedicatedHostPlacment: + description: DedicatedHostPlacement denotes the placement settings + for the instance when tenancy=host + properties: + affinity: + description: Affinity indicates the affinity setting between the + instance and a Dedicated Host. + enum: + - default + - host + type: string + hostID: + description: HostID pins the instance to a sepcific Dedicated + Host. + type: string + type: object elasticIpPool: description: ElasticIPPool is the configuration to allocate Public IPv4 address (Elastic IP/EIP) from user-defined pool. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml index 501a837555..643cc9e499 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml @@ -591,6 +591,22 @@ spec: - ssm-parameter-store type: string type: object + dedicatedHostPlacment: + description: DedicatedHostPlacement denotes the placement + settings for the instance when tenancy=host + properties: + affinity: + description: Affinity indicates the affinity setting between + the instance and a Dedicated Host. + enum: + - default + - host + type: string + hostID: + description: HostID pins the instance to a sepcific Dedicated + Host. + type: string + type: object elasticIpPool: description: ElasticIPPool is the configuration to allocate Public IPv4 address (Elastic IP/EIP) from user-defined pool. diff --git a/pkg/cloud/services/ec2/instances.go b/pkg/cloud/services/ec2/instances.go index ac11fea9fd..6d66b4626d 100644 --- a/pkg/cloud/services/ec2/instances.go +++ b/pkg/cloud/services/ec2/instances.go @@ -244,6 +244,7 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use input.InstanceMetadataOptions = scope.AWSMachine.Spec.InstanceMetadataOptions input.Tenancy = scope.AWSMachine.Spec.Tenancy + input.DedicatedHostPlacement = scope.AWSMachine.Spec.DedicatedHostPlacement input.PlacementGroupName = scope.AWSMachine.Spec.PlacementGroupName @@ -653,7 +654,12 @@ func (s *Service) runInstance(role string, i *infrav1.Instance) (*infrav1.Instan if i.Tenancy != "" { input.Placement = &ec2.Placement{ - Tenancy: &i.Tenancy, + Tenancy: ptr.To(string(i.Tenancy)), + } + + if i.Tenancy == infrav1.TenancyHost && i.DedicatedHostPlacement != nil { + input.Placement.Affinity = i.DedicatedHostPlacement.Affinity + input.Placement.HostId = i.DedicatedHostPlacement.HostID } }