From dc07755b9dd8633e419d7a4b88184058c532f708 Mon Sep 17 00:00:00 2001 From: Thirumalesh Aaraveti Date: Wed, 10 Jul 2024 11:39:26 +0530 Subject: [PATCH 1/2] Added the CapacityReservation support Fixed the lint Fixed the description Removed the API in v1 --- api/v1beta1/zz_generated.conversion.go | 2 ++ api/v1beta2/awsmachine_types.go | 5 +++ api/v1beta2/types.go | 5 +++ ...ster.x-k8s.io_awsmanagedcontrolplanes.yaml | 10 ++++++ ...tructure.cluster.x-k8s.io_awsclusters.yaml | 5 +++ ...tructure.cluster.x-k8s.io_awsmachines.yaml | 5 +++ ....cluster.x-k8s.io_awsmachinetemplates.yaml | 5 +++ pkg/cloud/services/ec2/instances.go | 19 +++++++++++ pkg/cloud/services/ec2/instances_test.go | 32 +++++++++++++++++++ 9 files changed, 88 insertions(+) diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index 565df1c3aa..64e6a9c946 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -1433,6 +1433,7 @@ func autoConvert_v1beta2_AWSMachineSpec_To_v1beta1_AWSMachineSpec(in *v1beta2.AW // WARNING: in.PlacementGroupPartition requires manual conversion: does not exist in peer-type out.Tenancy = in.Tenancy // 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 } @@ -2034,6 +2035,7 @@ func autoConvert_v1beta2_Instance_To_v1beta1_Instance(in *v1beta2.Instance, out // WARNING: in.InstanceMetadataOptions requires manual conversion: does not exist in peer-type // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type // WARNING: in.PublicIPOnLaunch requires manual conversion: does not exist in peer-type + // WARNING: in.CapacityReservationID requires manual conversion: does not exist in peer-type return nil } diff --git a/api/v1beta2/awsmachine_types.go b/api/v1beta2/awsmachine_types.go index 1a527f9991..83d5eb7a14 100644 --- a/api/v1beta2/awsmachine_types.go +++ b/api/v1beta2/awsmachine_types.go @@ -193,6 +193,11 @@ type AWSMachineSpec struct { // PrivateDNSName is the options for the instance hostname. // +optional PrivateDNSName *PrivateDNSName `json:"privateDnsName,omitempty"` + + // CapacityReservationID specifies the instance that should be launched in the + // reserved compute capacity. + // +optional + CapacityReservationID string `json:"capacityReservationId,omitempty"` } // CloudInit defines options related to the bootstrapping systems where diff --git a/api/v1beta2/types.go b/api/v1beta2/types.go index abf92ae4e0..6d2080e5d5 100644 --- a/api/v1beta2/types.go +++ b/api/v1beta2/types.go @@ -249,6 +249,11 @@ type Instance struct { // PublicIPOnLaunch is the option to associate a public IP on instance launch // +optional PublicIPOnLaunch *bool `json:"publicIPOnLaunch,omitempty"` + + // CapacityReservationID specifies the instance that should be launched in the + // reserved compute capacity. + // +optional + CapacityReservationID string `json:"capacityReservationId,omitempty"` } // InstanceMetadataState describes the state of InstanceMetadataOptions.HttpEndpoint and InstanceMetadataOptions.InstanceMetadataTags 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 7ab077b658..a217038cf0 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -1090,6 +1090,11 @@ spec: availabilityZone: description: Availability zone of instance type: string + capacityReservationId: + description: |- + CapacityReservationID specifies the instance that should be launched in the + reserved compute capacity. + type: string ebsOptimized: description: Indicates whether the instance is optimized for Amazon EBS I/O. @@ -3094,6 +3099,11 @@ spec: availabilityZone: description: Availability zone of instance type: string + capacityReservationId: + description: |- + CapacityReservationID specifies the instance that should be launched in the + reserved compute capacity. + type: string 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 cadff4f653..2c183e599d 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml @@ -2075,6 +2075,11 @@ spec: availabilityZone: description: Availability zone of instance type: string + capacityReservationId: + description: |- + CapacityReservationID specifies the instance that should be launched in the + reserved compute capacity. + type: string 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 5b3aba0f22..0325604ecd 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml @@ -624,6 +624,11 @@ spec: description: ID of resource type: string type: object + capacityReservationId: + description: |- + CapacityReservationID specifies the instance that should be launched in the + reserved compute capacity. + type: string cloudInit: description: |- CloudInit defines options related to the bootstrapping systems where 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 fc97c0757b..3d32e00845 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml @@ -554,6 +554,11 @@ spec: description: ID of resource type: string type: object + capacityReservationId: + description: |- + CapacityReservationID specifies the instance that should be launched in the + reserved compute capacity. + type: string cloudInit: description: |- CloudInit defines options related to the bootstrapping systems where diff --git a/pkg/cloud/services/ec2/instances.go b/pkg/cloud/services/ec2/instances.go index b6975c5309..89dfe00900 100644 --- a/pkg/cloud/services/ec2/instances.go +++ b/pkg/cloud/services/ec2/instances.go @@ -251,6 +251,8 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use input.PrivateDNSName = scope.AWSMachine.Spec.PrivateDNSName + input.CapacityReservationID = scope.AWSMachine.Spec.CapacityReservationID + s.scope.Debug("Running instance", "machine-role", scope.Role()) s.scope.Debug("Running instance with instance metadata options", "metadata options", input.InstanceMetadataOptions) out, err := s.runInstance(scope.Role(), input) @@ -636,6 +638,7 @@ func (s *Service) runInstance(role string, i *infrav1.Instance) (*infrav1.Instan input.InstanceMarketOptions = getInstanceMarketOptionsRequest(i.SpotMarketOptions) input.MetadataOptions = getInstanceMetadataOptionsRequest(i.InstanceMetadataOptions) input.PrivateDnsNameOptions = getPrivateDNSNameOptionsRequest(i.PrivateDNSName) + input.CapacityReservationSpecification = getCapacityReservationSpecification(i.CapacityReservationID) if i.Tenancy != "" { input.Placement = &ec2.Placement{ @@ -1119,6 +1122,22 @@ func filterGroups(list []string, strToFilter string) (newList []string) { return } +func getCapacityReservationSpecification(capacityReservationID string) *ec2.CapacityReservationSpecification { + if capacityReservationID == "" { + // Instance is not a CapacityReservation instance + return nil + } + + // Set required values for CapacityReservation + capacityReservationTargetOptions := &ec2.CapacityReservationTarget{} + capacityReservationTargetOptions.SetCapacityReservationId(capacityReservationID) + + capacityReservationSpecification := &ec2.CapacityReservationSpecification{} + capacityReservationSpecification.SetCapacityReservationTarget(capacityReservationTargetOptions) + + return capacityReservationSpecification +} + func getInstanceMarketOptionsRequest(spotMarketOptions *infrav1.SpotMarketOptions) *ec2.InstanceMarketOptionsRequest { if spotMarketOptions == nil { // Instance is not a Spot instance diff --git a/pkg/cloud/services/ec2/instances_test.go b/pkg/cloud/services/ec2/instances_test.go index 5fc267036b..876f6ed622 100644 --- a/pkg/cloud/services/ec2/instances_test.go +++ b/pkg/cloud/services/ec2/instances_test.go @@ -5320,3 +5320,35 @@ func mockedGetPrivateDNSDomainNameFromDHCPOptionsEmptyCalls(m *mocks.MockEC2APIM }, }, nil) } + +func TestGetCapacityReservationSpecification(t *testing.T) { + mockCapacityReservationID := "cr-123" + testCases := []struct { + name string + capacityReservationID string + expectedRequest *ec2.CapacityReservationSpecification + }{ + { + name: "with no CapacityReservationID options specified", + capacityReservationID: "", + expectedRequest: nil, + }, + { + name: "with an valid CapacityReservationID specified", + capacityReservationID: *aws.String(mockCapacityReservationID), + expectedRequest: &ec2.CapacityReservationSpecification{ + CapacityReservationTarget: &ec2.CapacityReservationTarget{ + CapacityReservationId: aws.String(mockCapacityReservationID), + }, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + request := getCapacityReservationSpecification(tc.capacityReservationID) + if !cmp.Equal(request, tc.expectedRequest) { + t.Errorf("Case: %s. Got: %v, expected: %v", tc.name, request, tc.expectedRequest) + } + }) + } +} From 5e44fa5724b038835cd44aaa51e851ccbbafffd6 Mon Sep 17 00:00:00 2001 From: Thirumalesh Aaraveti Date: Tue, 16 Jul 2024 11:19:56 +0530 Subject: [PATCH 2/2] Added the capacity reservation id Removed the tests by verify-gen --- api/v1beta1/awscluster_conversion.go | 1 + api/v1beta1/awsmachine_conversion.go | 2 ++ api/v1beta2/awsmachine_types.go | 5 ++--- api/v1beta2/types.go | 5 ++--- api/v1beta2/zz_generated.deepcopy.go | 10 ++++++++++ ...ster.x-k8s.io_awsmanagedcontrolplanes.yaml | 10 ++++------ ...tructure.cluster.x-k8s.io_awsclusters.yaml | 5 ++--- ...tructure.cluster.x-k8s.io_awsmachines.yaml | 5 ++--- ....cluster.x-k8s.io_awsmachinetemplates.yaml | 5 ++--- pkg/cloud/services/ec2/instances.go | 19 ++++++++----------- pkg/cloud/services/ec2/instances_test.go | 9 +++++---- 11 files changed, 40 insertions(+), 36 deletions(-) diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go index 65e797ffba..773962ad94 100644 --- a/api/v1beta1/awscluster_conversion.go +++ b/api/v1beta1/awscluster_conversion.go @@ -59,6 +59,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error { dst.Status.Bastion.PlacementGroupPartition = restored.Status.Bastion.PlacementGroupPartition 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.Spec.Partition = restored.Spec.Partition diff --git a/api/v1beta1/awsmachine_conversion.go b/api/v1beta1/awsmachine_conversion.go index 6ed2d50adc..6044416cdf 100644 --- a/api/v1beta1/awsmachine_conversion.go +++ b/api/v1beta1/awsmachine_conversion.go @@ -41,6 +41,7 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.PlacementGroupPartition = restored.Spec.PlacementGroupPartition dst.Spec.PrivateDNSName = restored.Spec.PrivateDNSName dst.Spec.SecurityGroupOverrides = restored.Spec.SecurityGroupOverrides + dst.Spec.CapacityReservationID = restored.Spec.CapacityReservationID if restored.Spec.ElasticIPPool != nil { if dst.Spec.ElasticIPPool == nil { dst.Spec.ElasticIPPool = &infrav1.ElasticIPPool{} @@ -102,6 +103,7 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Template.Spec.PlacementGroupPartition = restored.Spec.Template.Spec.PlacementGroupPartition 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 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/v1beta2/awsmachine_types.go b/api/v1beta2/awsmachine_types.go index 83d5eb7a14..39a649a0e5 100644 --- a/api/v1beta2/awsmachine_types.go +++ b/api/v1beta2/awsmachine_types.go @@ -194,10 +194,9 @@ type AWSMachineSpec struct { // +optional PrivateDNSName *PrivateDNSName `json:"privateDnsName,omitempty"` - // CapacityReservationID specifies the instance that should be launched in the - // reserved compute capacity. + // CapacityReservationID specifies the target Capacity Reservation into which the instance should be launched. // +optional - CapacityReservationID string `json:"capacityReservationId,omitempty"` + CapacityReservationID *string `json:"capacityReservationId,omitempty"` } // CloudInit defines options related to the bootstrapping systems where diff --git a/api/v1beta2/types.go b/api/v1beta2/types.go index 6d2080e5d5..a03d648385 100644 --- a/api/v1beta2/types.go +++ b/api/v1beta2/types.go @@ -250,10 +250,9 @@ type Instance struct { // +optional PublicIPOnLaunch *bool `json:"publicIPOnLaunch,omitempty"` - // CapacityReservationID specifies the instance that should be launched in the - // reserved compute capacity. + // CapacityReservationID specifies the target Capacity Reservation into which the instance should be launched. // +optional - CapacityReservationID string `json:"capacityReservationId,omitempty"` + CapacityReservationID *string `json:"capacityReservationId,omitempty"` } // InstanceMetadataState describes the state of InstanceMetadataOptions.HttpEndpoint and InstanceMetadataOptions.InstanceMetadataTags diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index d3e08bbb0c..515b6a20ac 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -767,6 +767,11 @@ func (in *AWSMachineSpec) DeepCopyInto(out *AWSMachineSpec) { *out = new(PrivateDNSName) (*in).DeepCopyInto(*out) } + if in.CapacityReservationID != nil { + in, out := &in.CapacityReservationID, &out.CapacityReservationID + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSMachineSpec. @@ -1594,6 +1599,11 @@ func (in *Instance) DeepCopyInto(out *Instance) { *out = new(bool) **out = **in } + if in.CapacityReservationID != nil { + in, out := &in.CapacityReservationID, &out.CapacityReservationID + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. 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 a217038cf0..4c0b00a0eb 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -1091,9 +1091,8 @@ spec: description: Availability zone of instance type: string capacityReservationId: - description: |- - CapacityReservationID specifies the instance that should be launched in the - reserved compute capacity. + description: CapacityReservationID specifies the target Capacity + Reservation into which the instance should be launched. type: string ebsOptimized: description: Indicates whether the instance is optimized for Amazon @@ -3100,9 +3099,8 @@ spec: description: Availability zone of instance type: string capacityReservationId: - description: |- - CapacityReservationID specifies the instance that should be launched in the - reserved compute capacity. + description: CapacityReservationID specifies the target Capacity + Reservation into which the instance should be launched. type: string ebsOptimized: description: Indicates whether the instance is optimized for Amazon 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 2c183e599d..ed850fd8b3 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml @@ -2076,9 +2076,8 @@ spec: description: Availability zone of instance type: string capacityReservationId: - description: |- - CapacityReservationID specifies the instance that should be launched in the - reserved compute capacity. + description: CapacityReservationID specifies the target Capacity + Reservation into which the instance should be launched. type: string ebsOptimized: description: Indicates whether the instance is optimized for Amazon 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 0325604ecd..c02466fa59 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml @@ -625,9 +625,8 @@ spec: type: string type: object capacityReservationId: - description: |- - CapacityReservationID specifies the instance that should be launched in the - reserved compute capacity. + description: CapacityReservationID specifies the target Capacity Reservation + into which the instance should be launched. type: string cloudInit: description: |- 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 3d32e00845..501a837555 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml @@ -555,9 +555,8 @@ spec: type: string type: object capacityReservationId: - description: |- - CapacityReservationID specifies the instance that should be launched in the - reserved compute capacity. + description: CapacityReservationID specifies the target Capacity + Reservation into which the instance should be launched. type: string cloudInit: description: |- diff --git a/pkg/cloud/services/ec2/instances.go b/pkg/cloud/services/ec2/instances.go index 89dfe00900..a9dec8eb92 100644 --- a/pkg/cloud/services/ec2/instances.go +++ b/pkg/cloud/services/ec2/instances.go @@ -1122,20 +1122,17 @@ func filterGroups(list []string, strToFilter string) (newList []string) { return } -func getCapacityReservationSpecification(capacityReservationID string) *ec2.CapacityReservationSpecification { - if capacityReservationID == "" { - // Instance is not a CapacityReservation instance +func getCapacityReservationSpecification(capacityReservationID *string) *ec2.CapacityReservationSpecification { + if capacityReservationID == nil { + // Not targeting any specific Capacity Reservation return nil } - // Set required values for CapacityReservation - capacityReservationTargetOptions := &ec2.CapacityReservationTarget{} - capacityReservationTargetOptions.SetCapacityReservationId(capacityReservationID) - - capacityReservationSpecification := &ec2.CapacityReservationSpecification{} - capacityReservationSpecification.SetCapacityReservationTarget(capacityReservationTargetOptions) - - return capacityReservationSpecification + return &ec2.CapacityReservationSpecification{ + CapacityReservationTarget: &ec2.CapacityReservationTarget{ + CapacityReservationId: capacityReservationID, + }, + } } func getInstanceMarketOptionsRequest(spotMarketOptions *infrav1.SpotMarketOptions) *ec2.InstanceMarketOptionsRequest { diff --git a/pkg/cloud/services/ec2/instances_test.go b/pkg/cloud/services/ec2/instances_test.go index 876f6ed622..932e297220 100644 --- a/pkg/cloud/services/ec2/instances_test.go +++ b/pkg/cloud/services/ec2/instances_test.go @@ -5323,19 +5323,20 @@ func mockedGetPrivateDNSDomainNameFromDHCPOptionsEmptyCalls(m *mocks.MockEC2APIM func TestGetCapacityReservationSpecification(t *testing.T) { mockCapacityReservationID := "cr-123" + mockCapacityReservationIDPtr := &mockCapacityReservationID testCases := []struct { name string - capacityReservationID string + capacityReservationID *string expectedRequest *ec2.CapacityReservationSpecification }{ { name: "with no CapacityReservationID options specified", - capacityReservationID: "", + capacityReservationID: nil, expectedRequest: nil, }, { - name: "with an valid CapacityReservationID specified", - capacityReservationID: *aws.String(mockCapacityReservationID), + name: "with a valid CapacityReservationID specified", + capacityReservationID: mockCapacityReservationIDPtr, expectedRequest: &ec2.CapacityReservationSpecification{ CapacityReservationTarget: &ec2.CapacityReservationTarget{ CapacityReservationId: aws.String(mockCapacityReservationID),