Skip to content

Commit 7a53e16

Browse files
committed
feat(ecs): Mananged instances provider with infrastructure optimization
1 parent 344d18c commit 7a53e16

File tree

3 files changed

+169
-5
lines changed

3 files changed

+169
-5
lines changed

internal/service/ecs/capacity_provider.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,20 @@ func resourceCapacityProvider() *schema.Resource {
506506
Optional: true,
507507
ValidateDiagFunc: enum.Validate[awstypes.PropagateMITags](),
508508
},
509+
"infrastructure_optimization": {
510+
Type: schema.TypeList,
511+
MaxItems: 1,
512+
Optional: true,
513+
Elem: &schema.Resource{
514+
Schema: map[string]*schema.Schema{
515+
"scale_in_after": {
516+
Type: schema.TypeInt,
517+
Optional: true,
518+
ValidateFunc: validation.IntBetween(-1, 3600),
519+
},
520+
},
521+
},
522+
},
509523
},
510524
},
511525
},
@@ -930,6 +944,10 @@ func expandManagedInstancesProviderCreate(configured any) *awstypes.CreateManage
930944
apiObject.PropagateTags = awstypes.PropagateMITags(v)
931945
}
932946

947+
if v, ok := tfMap["infrastructure_optimization"].([]any); ok && len(v) > 0 {
948+
apiObject.InfrastructureOptimization = expandInfrastructureOptimization(v)
949+
}
950+
933951
return apiObject
934952
}
935953

@@ -957,6 +975,25 @@ func expandManagedInstancesProviderUpdate(configured any) *awstypes.UpdateManage
957975
apiObject.PropagateTags = awstypes.PropagateMITags(v)
958976
}
959977

978+
if v, ok := tfMap["infrastructure_optimization"].([]any); ok && len(v) > 0 {
979+
apiObject.InfrastructureOptimization = expandInfrastructureOptimization(v)
980+
}
981+
982+
return apiObject
983+
}
984+
985+
func expandInfrastructureOptimization(tfList []any) *awstypes.InfrastructureOptimization {
986+
if len(tfList) == 0 || tfList[0] == nil {
987+
return nil
988+
}
989+
990+
tfMap := tfList[0].(map[string]any)
991+
apiObject := &awstypes.InfrastructureOptimization{}
992+
993+
if v, ok := tfMap["scale_in_after"].(int); ok {
994+
apiObject.ScaleInAfter = aws.Int32(int32(v))
995+
}
996+
960997
return apiObject
961998
}
962999

@@ -1348,6 +1385,22 @@ func flattenManagedInstancesProvider(provider *awstypes.ManagedInstancesProvider
13481385
tfMap["instance_launch_template"] = flattenInstanceLaunchTemplate(provider.InstanceLaunchTemplate)
13491386
}
13501387

1388+
if provider.InfrastructureOptimization != nil {
1389+
tfMap["infrastructure_optimization"] = flattenInfrastructureOptimization(provider.InfrastructureOptimization)
1390+
}
1391+
1392+
return []map[string]any{tfMap}
1393+
}
1394+
1395+
func flattenInfrastructureOptimization(apiObject *awstypes.InfrastructureOptimization) []map[string]any {
1396+
if apiObject == nil {
1397+
return nil
1398+
}
1399+
1400+
tfMap := map[string]any{
1401+
"scale_in_after": aws.ToInt32(apiObject.ScaleInAfter),
1402+
}
1403+
13511404
return []map[string]any{tfMap}
13521405
}
13531406

internal/service/ecs/capacity_provider_test.go

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,52 @@ func TestAccECSCapacityProvider_updateManagedInstancesProvider(t *testing.T) {
416416
})
417417
}
418418

419+
func TestAccECSCapacityProvider_createManagedInstancesProvider_withInfrastructureOptimization(t *testing.T) {
420+
ctx := acctest.Context(t)
421+
var provider awstypes.CapacityProvider
422+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
423+
resourceName := "aws_ecs_capacity_provider.test"
424+
425+
resource.ParallelTest(t, resource.TestCase{
426+
PreCheck: func() { acctest.PreCheck(ctx, t) },
427+
ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID),
428+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
429+
CheckDestroy: testAccCheckCapacityProviderDestroy(ctx),
430+
Steps: []resource.TestStep{
431+
{
432+
Config: testAccCapacityProviderConfig_managedInstancesProvider_withInfrastructureOptimization(rName, 300),
433+
Check: resource.ComposeAggregateTestCheckFunc(
434+
testAccCheckCapacityProviderExists(ctx, resourceName, &provider),
435+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.#", "1"),
436+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.#", "1"),
437+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.0.scale_in_after", "300"),
438+
),
439+
},
440+
// {
441+
// ResourceName: resourceName,
442+
// ImportState: true,
443+
// ImportStateVerify: true,
444+
// },
445+
{
446+
Config: testAccCapacityProviderConfig_managedInstancesProvider_withInfrastructureOptimization(rName, 0),
447+
Check: resource.ComposeAggregateTestCheckFunc(
448+
testAccCheckCapacityProviderExists(ctx, resourceName, &provider),
449+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.#", "1"),
450+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.0.scale_in_after", "0"),
451+
),
452+
},
453+
{
454+
Config: testAccCapacityProviderConfig_managedInstancesProvider_withInfrastructureOptimization(rName, -1),
455+
Check: resource.ComposeAggregateTestCheckFunc(
456+
testAccCheckCapacityProviderExists(ctx, resourceName, &provider),
457+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.#", "1"),
458+
resource.TestCheckResourceAttr(resourceName, "managed_instances_provider.0.infrastructure_optimization.0.scale_in_after", "-1"),
459+
),
460+
},
461+
},
462+
})
463+
}
464+
419465
func testAccCheckCapacityProviderDestroy(ctx context.Context) resource.TestCheckFunc {
420466
return func(s *terraform.State) error {
421467
conn := acctest.Provider.Meta().(*conns.AWSClient).ECSClient(ctx)
@@ -434,7 +480,7 @@ func testAccCheckCapacityProviderDestroy(ctx context.Context) resource.TestCheck
434480
return err
435481
}
436482

437-
return fmt.Errorf("ECS Capacity Provider ID %s still exists", rs.Primary.ID)
483+
return fmt.Errorf("ECS Capacity ProviderID %s still exists", rs.Primary.ID)
438484
}
439485

440486
return nil
@@ -705,6 +751,22 @@ resource "aws_subnet" "test" {
705751
}
706752
}
707753
754+
resource "aws_security_group" "test" {
755+
name = %[1]q
756+
vpc_id = aws_vpc.test.id
757+
758+
egress {
759+
from_port = 0
760+
to_port = 0
761+
protocol = "-1"
762+
cidr_blocks = ["0.0.0.0/0"]
763+
}
764+
765+
tags = {
766+
Name = %[1]q
767+
}
768+
}
769+
708770
resource "aws_ecs_cluster" "test" {
709771
name = %[1]q
710772
}
@@ -771,7 +833,8 @@ resource "aws_ecs_capacity_provider" "test" {
771833
ec2_instance_profile_arn = aws_iam_instance_profile.test.arn
772834
773835
network_configuration {
774-
subnets = aws_subnet.test[*].id
836+
subnets = aws_subnet.test[*].id
837+
security_groups = [aws_security_group.test.id]
775838
}
776839
}
777840
}
@@ -793,7 +856,8 @@ resource "aws_ecs_capacity_provider" "test" {
793856
ec2_instance_profile_arn = aws_iam_instance_profile.test.arn
794857
795858
network_configuration {
796-
subnets = aws_subnet.test[*].id
859+
subnets = aws_subnet.test[*].id
860+
security_groups = [aws_security_group.test.id]
797861
}
798862
799863
instance_requirements {
@@ -831,7 +895,8 @@ resource "aws_ecs_capacity_provider" "test" {
831895
ec2_instance_profile_arn = aws_iam_instance_profile.test.arn
832896
833897
network_configuration {
834-
subnets = aws_subnet.test[*].id
898+
subnets = aws_subnet.test[*].id
899+
security_groups = [aws_security_group.test.id]
835900
}
836901
837902
storage_configuration {
@@ -867,7 +932,8 @@ resource "aws_ecs_capacity_provider" "test" {
867932
ec2_instance_profile_arn = aws_iam_instance_profile.test.arn
868933
869934
network_configuration {
870-
subnets = aws_subnet.test[*].id
935+
subnets = aws_subnet.test[*].id
936+
security_groups = [aws_security_group.test.id]
871937
}
872938
873939
instance_requirements {
@@ -884,3 +950,40 @@ resource "aws_ecs_capacity_provider" "test" {
884950
}
885951
`, rName))
886952
}
953+
954+
func testAccCapacityProviderConfig_managedInstancesProvider_withInfrastructureOptimization(rName string, scaleInAfter int) string {
955+
return acctest.ConfigCompose(testAccCapacityProviderConfig_managedInstancesProvider_base(rName), fmt.Sprintf(`
956+
resource "aws_ecs_capacity_provider" "test" {
957+
name = %[1]q
958+
cluster = aws_ecs_cluster.test.name
959+
960+
managed_instances_provider {
961+
infrastructure_role_arn = aws_iam_role.test.arn
962+
propagate_tags = "NONE"
963+
964+
instance_launch_template {
965+
ec2_instance_profile_arn = aws_iam_instance_profile.test.arn
966+
967+
network_configuration {
968+
subnets = aws_subnet.test[*].id
969+
security_groups = [aws_security_group.test.id]
970+
}
971+
972+
instance_requirements {
973+
vcpu_count {
974+
min = 1
975+
}
976+
977+
memory_mib {
978+
min = 1024
979+
}
980+
}
981+
}
982+
983+
infrastructure_optimization {
984+
scale_in_after = %[2]d
985+
}
986+
}
987+
}
988+
`, rName, scaleInAfter))
989+
}

website/docs/r/ecs_capacity_provider.html.markdown

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ This resource supports the following arguments:
122122
* `infrastructure_role_arn` - (Required) The Amazon Resource Name (ARN) of the infrastructure role that Amazon ECS uses to manage instances on your behalf. This role must have permissions to launch, terminate, and manage Amazon EC2 instances, as well as access to other AWS services required for Amazon ECS Managed Instances functionality. For more information, see [Amazon ECS infrastructure IAM role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/infrastructure_IAM_role.html) in the Amazon ECS Developer Guide.
123123
* `instance_launch_template` - (Required) The launch template configuration that specifies how Amazon ECS should launch Amazon EC2 instances. This includes the instance profile, network configuration, storage settings, and instance requirements for attribute-based instance type selection. For more information, see [Store instance launch parameters in Amazon EC2 launch templates](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html) in the Amazon EC2 User Guide. Detailed below.
124124
* `propagate_tags` - (Optional) Specifies whether to propagate tags from the capacity provider to the Amazon ECS Managed Instances. When enabled, tags applied to the capacity provider are automatically applied to all instances launched by this provider. Valid values are `CAPACITY_PROVIDER` and `NONE`.
125+
* `infrastructure_optimization` - (Optional) Defines how Amazon ECS Managed Instances optimizes the infrastastructure in your capacity provider. Configure it to turn on or off the infrastructure optimization in your capacity provider, and to control the idle EC2 instances optimization delay.
125126

126127
### `instance_launch_template`
127128

@@ -167,6 +168,13 @@ This resource supports the following arguments:
167168
* `total_local_storage_gb` - (Optional) The minimum and maximum total local storage in gigabytes (GB) for instance types with local storage.
168169
* `vcpu_count` - (Required) The minimum and maximum number of vCPUs for the instance types. Amazon ECS selects instance types that have vCPU counts within this range.
169170

171+
### `infrastructure_optimization`
172+
173+
* `scale_in_after` - (Optional) This parameter defines the number of seconds Amazon ECS Managed Instances waits before optimizing EC2 instances that have become idle or underutilized. A longer delay increases the likelihood of placing new tasks on idle instances, reducing startup time. A shorter delay helps reduce infrastructure costs by optimizing idle instances more quickly. Valid values are:
174+
* Not set (null) - Uses the default optimization behavior.
175+
* `-1` - Disables automatic infrastructure optimization.
176+
* `0` to `3600` (inclusive) - Specifies the number of seconds to wait before optimizing instances.
177+
170178
## Attribute Reference
171179

172180
This resource exports the following attributes in addition to the arguments above:

0 commit comments

Comments
 (0)