diff --git a/docs/data-sources/hcp_machine_pool.md b/docs/data-sources/hcp_machine_pool.md index d50d355b..97d03489 100644 --- a/docs/data-sources/hcp_machine_pool.md +++ b/docs/data-sources/hcp_machine_pool.md @@ -65,6 +65,7 @@ Read-Only: Optional: - `additional_security_group_ids` (List of String) Additional security group ids. After the creation of the resource, it is not possible to update the attribute value. +- `capacity_reservation_id` (String) The ID of the AWS Capacity Reservation used for the node pool. - `disk_size` (Number) The root disk size, in GiB. - `ec2_metadata_http_tokens` (String) This value determines which EC2 Instance Metadata Service mode to use for EC2 instances in the nodes.This can be set as `optional` (IMDS v1 or v2) or `required` (IMDSv2 only). This feature is available from After the creation of the resource, it is not possible to update the attribute value. - `tags` (Map of String) Apply user defined tags to all machine pool resources created in AWS. After the creation of the resource, it is not possible to update the attribute value. diff --git a/docs/resources/hcp_machine_pool.md b/docs/resources/hcp_machine_pool.md index 73e72eb5..98727843 100644 --- a/docs/resources/hcp_machine_pool.md +++ b/docs/resources/hcp_machine_pool.md @@ -81,6 +81,7 @@ Required: Optional: - `additional_security_group_ids` (List of String) Additional security group ids. After the creation of the resource, it is not possible to update the attribute value. +- `capacity_reservation_id` (String) The ID of the AWS Capacity Reservation to use for the node pool. Cannot be set when autoscaling is enabled. After the creation of the resource, it is not possible to update the attribute value. - `disk_size` (Number) Root disk size, in GiB. After the creation of the resource, it is not possible to update the attribute value. - `ec2_metadata_http_tokens` (String) This value determines which EC2 Instance Metadata Service mode to use for EC2 instances in the nodes.This can be set as `optional` (IMDS v1 or v2) or `required` (IMDSv2 only). This feature is available from After the creation of the resource, it is not possible to update the attribute value. - `tags` (Map of String) Apply user defined tags to all machine pool resources created in AWS.After the creation of the resource, it is not possible to update the attribute value. diff --git a/provider/machinepool/hcp/aws_node_pool.go b/provider/machinepool/hcp/aws_node_pool.go index 1131cc22..3a37424c 100644 --- a/provider/machinepool/hcp/aws_node_pool.go +++ b/provider/machinepool/hcp/aws_node_pool.go @@ -23,6 +23,7 @@ type AWSNodePool struct { AdditionalSecurityGroupIds types.List `tfsdk:"additional_security_group_ids"` Ec2MetadataHttpTokens types.String `tfsdk:"ec2_metadata_http_tokens"` DiskSize types.Int64 `tfsdk:"disk_size"` + CapacityReservationId types.String `tfsdk:"capacity_reservation_id"` } func AwsNodePoolResource() map[string]schema.Attribute { @@ -73,6 +74,14 @@ func AwsNodePoolResource() map[string]schema.Attribute { int64planmodifier.UseStateForUnknown(), }, }, + "capacity_reservation_id": schema.StringAttribute{ + Description: "The ID of the AWS Capacity Reservation to use for the node pool. " + + "Cannot be set when autoscaling is enabled. " + common.ValueCannotBeChangedStringDescription, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, } } @@ -109,5 +118,10 @@ func AwsNodePoolDatasource() map[string]dsschema.Attribute { Optional: true, Computed: true, }, + "capacity_reservation_id": schema.StringAttribute{ + Description: "The ID of the AWS Capacity Reservation used for the node pool.", + Optional: true, + Computed: true, + }, } } diff --git a/provider/machinepool/hcp/machine_pool_resource.go b/provider/machinepool/hcp/machine_pool_resource.go index 4fac161b..bfe2e628 100644 --- a/provider/machinepool/hcp/machine_pool_resource.go +++ b/provider/machinepool/hcp/machine_pool_resource.go @@ -226,6 +226,8 @@ func (r *HcpMachinePoolResource) ConfigValidators(context.Context) []resource.Co resourcevalidator.RequiredTogether(path.MatchRoot("autoscaling").AtName("min_replicas"), path.MatchRoot("autoscaling").AtName("max_replicas")), resourcevalidator.Conflicting(path.MatchRoot("replicas"), path.MatchRoot("autoscaling").AtName("min_replicas")), resourcevalidator.Conflicting(path.MatchRoot("replicas"), path.MatchRoot("autoscaling").AtName("max_replicas")), + resourcevalidator.Conflicting(path.MatchRoot("aws_node_pool").AtName("capacity_reservation_id"), path.MatchRoot("autoscaling").AtName("min_replicas")), + resourcevalidator.Conflicting(path.MatchRoot("aws_node_pool").AtName("capacity_reservation_id"), path.MatchRoot("autoscaling").AtName("max_replicas")), } } @@ -334,6 +336,12 @@ func (r *HcpMachinePoolResource) Create(ctx context.Context, req resource.Create awsNodePoolBuilder.RootVolume(cmv1.NewAWSVolume().Size(int(*workerDiskSize))) } + if !common.IsStringAttributeUnknownOrEmpty(plan.AWSNodePool.CapacityReservationId) { + capacityReservationBuilder := cmv1.NewAWSCapacityReservation() + capacityReservationBuilder.Id(plan.AWSNodePool.CapacityReservationId.ValueString()) + awsNodePoolBuilder.CapacityReservation(capacityReservationBuilder) + } + builder.AWSNodePool(awsNodePoolBuilder) } @@ -621,6 +629,7 @@ func validateNoImmutableAttChange(state, plan *HcpMachinePoolState) diag.Diagnos validateStateAndPlanEquals(state.AWSNodePool.Ec2MetadataHttpTokens, plan.AWSNodePool.Ec2MetadataHttpTokens, "aws_node_pool.ec2_metadata_http_tokens", &diags) validateStateAndPlanEquals(state.AWSNodePool.DiskSize, plan.AWSNodePool.DiskSize, "aws_node_pool.disk_size", &diags) + validateStateAndPlanEquals(state.AWSNodePool.CapacityReservationId, plan.AWSNodePool.CapacityReservationId, "aws_node_pool.capacity_reservation_id", &diags) } return diags } @@ -1217,6 +1226,14 @@ func populateState(ctx context.Context, object *cmv1.NodePool, state *HcpMachine state.AWSNodePool.DiskSize = types.Int64Value(int64(size)) } } + + if capacityReservation, ok := awsNodePool.GetCapacityReservation(); ok { + if capacityReservationId, ok := capacityReservation.GetId(); ok { + state.AWSNodePool.CapacityReservationId = types.StringValue(capacityReservationId) + } + } else { + state.AWSNodePool.CapacityReservationId = types.StringNull() + } } autoscaling, ok := object.GetAutoscaling() diff --git a/subsystem/hcp/machine_pool_resource_test.go b/subsystem/hcp/machine_pool_resource_test.go index c1d5910e..90b94bdd 100644 --- a/subsystem/hcp/machine_pool_resource_test.go +++ b/subsystem/hcp/machine_pool_resource_test.go @@ -2226,6 +2226,88 @@ var _ = Describe("Hcp Machine pool", func() { Expect(runOutput.ExitCode).ToNot(BeZero()) runOutput.VerifyErrorContainsSubstring("Invalid root disk size") }) + + It("Can create machine pool with capacity reservation ID", func() { + // Prepare the server: + TestServer.AppendHandlers( + CombineHandlers( + VerifyRequest( + http.MethodPost, + "/api/clusters_mgmt/v1/clusters/123/node_pools", + ), + RespondWithJSON(http.StatusCreated, `{ + "id":"my-pool", + "aws_node_pool":{ + "instance_type":"r5.xlarge", + "instance_profile": "bla", + "capacity_reservation": { + "id": "cr-1234567890abcdef0" + } + }, + "auto_repair": true, + "replicas":2, + "subnet":"id-1", + "availability_zone":"us-east-1a", + "version": { + "raw_id": "4.14.10" + } + }`), + ), + ) + + // Run the apply command: + Terraform.Source(` + resource "rhcs_hcp_machine_pool" "my_pool" { + cluster = "123" + name = "my-pool" + aws_node_pool = { + instance_type = "r5.xlarge", + capacity_reservation_id = "cr-1234567890abcdef0" + } + autoscaling = { + enabled = false, + } + subnet_id = "id-1" + replicas = 2 + auto_repair = true + version = "4.14.10" + }`) + runOutput := Terraform.Apply() + Expect(runOutput.ExitCode).To(BeZero()) + + // Check the state: + resource := Terraform.Resource("rhcs_hcp_machine_pool", "my_pool") + Expect(resource).To(MatchJQ(".attributes.cluster", "123")) + Expect(resource).To(MatchJQ(".attributes.id", "my-pool")) + Expect(resource).To(MatchJQ(".attributes.name", "my-pool")) + Expect(resource).To(MatchJQ(".attributes.aws_node_pool.instance_type", "r5.xlarge")) + Expect(resource).To(MatchJQ(".attributes.aws_node_pool.capacity_reservation_id", "cr-1234567890abcdef0")) + Expect(resource).To(MatchJQ(".attributes.replicas", 2.0)) + }) + + It("Cannot create machine pool with capacity reservation ID when autoscaling is enabled", func() { + // Run the apply command: + Terraform.Source(` + resource "rhcs_hcp_machine_pool" "my_pool" { + cluster = "123" + name = "my-pool" + aws_node_pool = { + instance_type = "r5.xlarge", + capacity_reservation_id = "cr-1234567890abcdef0" + } + autoscaling = { + enabled = true, + min_replicas = 1, + max_replicas = 3 + } + subnet_id = "id-1" + auto_repair = true + version = "4.14.10" + }`) + runOutput := Terraform.Validate() + Expect(runOutput.ExitCode).ToNot(BeZero()) + runOutput.VerifyErrorContainsSubstring("Invalid Attribute Combination") + }) }) Context("Standard workers machine pool", func() {