From 1efb36dcbce474a1a03bdce3f9be337b8500e576 Mon Sep 17 00:00:00 2001 From: Ivan Sukhomlyn Date: Mon, 12 Feb 2024 17:43:42 +0200 Subject: [PATCH 01/17] feat: Support `managed_draining` argument at `aws_ecs_capacity_provider` (#158) * feat: Support manged_draining argument for aws_ecs_capacity_provider * bump required AWS provider version to 5.34 * align AWS provider version across the project * feat: Update MSTV to 1.3 to support state migrations, align provider version on minor version --------- Co-authored-by: Bryant Biggs --- README.md | 4 ++-- examples/complete/README.md | 6 +++--- examples/complete/versions.tf | 4 ++-- examples/ec2-autoscaling/README.md | 6 +++--- examples/ec2-autoscaling/main.tf | 2 ++ examples/ec2-autoscaling/versions.tf | 4 ++-- examples/fargate/README.md | 6 +++--- examples/fargate/versions.tf | 4 ++-- modules/cluster/README.md | 8 +++++--- modules/cluster/main.tf | 1 + modules/cluster/versions.tf | 4 ++-- modules/container-definition/README.md | 6 +++--- modules/container-definition/versions.tf | 4 ++-- modules/service/README.md | 6 +++--- modules/service/versions.tf | 4 ++-- versions.tf | 4 ++-- 16 files changed, 39 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 8e20fbc0..a45968d3 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ module "ecs" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index 9d20e63d..5b73cfcb 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 682191e7..63e9319d 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index ff7a998d..75f12070 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf index cef24c97..35e6249f 100644 --- a/examples/ec2-autoscaling/main.tf +++ b/examples/ec2-autoscaling/main.tf @@ -36,6 +36,7 @@ module "ecs_cluster" { # On-demand instances ex_1 = { auto_scaling_group_arn = module.autoscaling["ex_1"].autoscaling_group_arn + managed_draining = "ENABLED" managed_termination_protection = "ENABLED" managed_scaling = { @@ -53,6 +54,7 @@ module "ecs_cluster" { # Spot instances ex_2 = { auto_scaling_group_arn = module.autoscaling["ex_2"].autoscaling_group_arn + managed_draining = "ENABLED" managed_termination_protection = "ENABLED" managed_scaling = { diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index 682191e7..63e9319d 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 49d4697d..34f26c96 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index 682191e7..63e9319d 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/modules/cluster/README.md b/modules/cluster/README.md index 282943b5..8e8ac5eb 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -70,6 +70,7 @@ module "ecs_cluster" { autoscaling_capacity_providers = { one = { auto_scaling_group_arn = "arn:aws:autoscaling:eu-west-1:012345678901:autoScalingGroup:08419a61:autoScalingGroupName/ecs-ec2-one-20220603194933774300000011" + managed_draining = "DISABLED" managed_termination_protection = "ENABLED" managed_scaling = { @@ -86,6 +87,7 @@ module "ecs_cluster" { } two = { auto_scaling_group_arn = "arn:aws:autoscaling:eu-west-1:012345678901:autoScalingGroup:08419a61:autoScalingGroupName/ecs-ec2-two-20220603194933774300000022" + managed_draining = "ENABLED" managed_termination_protection = "ENABLED" managed_scaling = { @@ -134,14 +136,14 @@ module "ecs_cluster" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/modules/cluster/main.tf b/modules/cluster/main.tf index cecf7e44..9ed117eb 100644 --- a/modules/cluster/main.tf +++ b/modules/cluster/main.tf @@ -151,6 +151,7 @@ resource "aws_ecs_capacity_provider" "this" { auto_scaling_group_provider { auto_scaling_group_arn = each.value.auto_scaling_group_arn + managed_draining = try(each.value.managed_draining, "ENABLED") # When you use managed termination protection, you must also use managed scaling otherwise managed termination protection won't work managed_termination_protection = length(try([each.value.managed_scaling], [])) == 0 ? "DISABLED" : try(each.value.managed_termination_protection, null) diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index 682191e7..63e9319d 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index 6ed52ac7..150f2f5c 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -115,14 +115,14 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index 682191e7..63e9319d 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/modules/service/README.md b/modules/service/README.md index 4faaf8f1..a498a9e9 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -166,14 +166,14 @@ module "ecs_service" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.66.1 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 5.34 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.66.1 | +| [aws](#provider\_aws) | >= 5.34 | ## Modules diff --git a/modules/service/versions.tf b/modules/service/versions.tf index 682191e7..63e9319d 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/versions.tf b/versions.tf index 682191e7..63e9319d 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } From 83b79cd3efaf535d4ca658b1aaf4f0a9b51ace89 Mon Sep 17 00:00:00 2001 From: "H.Saki" <44340370+saki-engineering@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:48:36 +0900 Subject: [PATCH 02/17] feat: Add support for multiple `service`s inside `service_connect_configuration` (#123) feat: Add support for multiple service inside service_connect_configuration Co-authored-by: Bryant Biggs --- examples/complete/main.tf | 16 +++++++++------- examples/fargate/main.tf | 16 +++++++++------- modules/service/main.tf | 4 ++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/complete/main.tf b/examples/complete/main.tf index b7353bbd..114f5aa1 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -107,14 +107,16 @@ module "ecs" { service_connect_configuration = { namespace = aws_service_discovery_http_namespace.this.arn - service = { - client_alias = { - port = local.container_port - dns_name = local.container_name + service = [ + { + client_alias = { + port = local.container_port + dns_name = local.container_name + } + port_name = local.container_name + discovery_name = local.container_name } - port_name = local.container_name - discovery_name = local.container_name - } + ] } load_balancer = { diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index 7cae2e0c..9aaa1226 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -133,14 +133,16 @@ module "ecs_service" { service_connect_configuration = { namespace = aws_service_discovery_http_namespace.this.arn - service = { - client_alias = { - port = local.container_port - dns_name = local.container_name + service = [ + { + client_alias = { + port = local.container_port + dns_name = local.container_name + } + port_name = local.container_name + discovery_name = local.container_name } - port_name = local.container_name - discovery_name = local.container_name - } + ] } load_balancer = { diff --git a/modules/service/main.tf b/modules/service/main.tf index c69c12da..8b2a1ed8 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -155,7 +155,7 @@ resource "aws_ecs_service" "this" { namespace = lookup(service_connect_configuration.value, "namespace", null) dynamic "service" { - for_each = try([service_connect_configuration.value.service], []) + for_each = try(service_connect_configuration.value.service, []) content { @@ -343,7 +343,7 @@ resource "aws_ecs_service" "ignore_task_definition" { namespace = lookup(service_connect_configuration.value, "namespace", null) dynamic "service" { - for_each = try([service_connect_configuration.value.service], []) + for_each = try(service_connect_configuration.value.service, []) content { From c83dc9e810cdd1df65b861572f2170e505380510 Mon Sep 17 00:00:00 2001 From: matt <97546619+mattaltberg@users.noreply.github.com> Date: Fri, 31 May 2024 13:28:06 -0400 Subject: [PATCH 03/17] feat: Add support for custom metric queries in customized_metric_spec (#196) * feat: add support for custom metric queries in customized metric spec * fix: Update and run pre-commit checks to format --------- Co-authored-by: Bryant Biggs --- modules/service/main.tf | 37 +++++++++++++++++++++-- wrappers/cluster/versions.tf | 4 +-- wrappers/container-definition/versions.tf | 4 +-- wrappers/service/versions.tf | 8 +++++ wrappers/versions.tf | 4 +-- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/modules/service/main.tf b/modules/service/main.tf index 8b2a1ed8..7050c949 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -1257,6 +1257,37 @@ resource "aws_appautoscaling_policy" "this" { for_each = try([target_tracking_scaling_policy_configuration.value.customized_metric_specification], []) content { + dynamic "metrics" { + for_each = try(customized_metric_specification.value.metrics, []) + content { + id = metrics.value.id + label = try(metrics.value.label, null) + return_data = try(metrics.value.return_data, true) + expression = try(metrics.value.expression, null) + + + dynamic "metric_stat" { + for_each = try([metrics.value.metric_stat], []) + content { + stat = metric_stat.value.stat + dynamic "metric" { + for_each = try([metric_stat.value.metric], []) + content { + namespace = metric.value.namespace + metric_name = metric.value.metric_name + dynamic "dimensions" { + for_each = try(metric.value.dimensions, []) + content { + name = dimensions.value.name + value = dimensions.value.value + } + } + } + } + } + } + } + } dynamic "dimensions" { for_each = try(customized_metric_specification.value.dimensions, []) @@ -1266,9 +1297,9 @@ resource "aws_appautoscaling_policy" "this" { } } - metric_name = customized_metric_specification.value.metric_name - namespace = customized_metric_specification.value.namespace - statistic = customized_metric_specification.value.statistic + metric_name = try(customized_metric_specification.value.metric_name, null) + namespace = try(customized_metric_specification.value.namespace, null) + statistic = try(customized_metric_specification.value.statistic, null) unit = try(customized_metric_specification.value.unit, null) } } diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index 682191e7..63e9319d 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index 682191e7..63e9319d 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index 682191e7..fa179650 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -1,10 +1,18 @@ terraform { +<<<<<<< HEAD required_version = ">= 1.0" +======= + required_version = ">= 1.3" +>>>>>>> edf0446 (feat: Add support for custom metric queries in customized_metric_spec (#196)) required_providers { aws = { source = "hashicorp/aws" +<<<<<<< HEAD version = ">= 4.66.1" +======= + version = ">= 5.34" +>>>>>>> edf0446 (feat: Add support for custom metric queries in customized_metric_spec (#196)) } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 682191e7..63e9319d 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.66.1" + version = ">= 5.34" } } } From 73fce3ceea018ccd3fc5a83e0fec9a92685b564f Mon Sep 17 00:00:00 2001 From: Sal Sodano Date: Wed, 24 Jul 2024 19:32:28 -0400 Subject: [PATCH 04/17] feat: Add support for service connect timeout settings (#212) * feat: add service connect timeout support * chore: Update required min versions * chore: Fix merge conflicts --------- Co-authored-by: Bryant Biggs --- README.md | 2 +- examples/complete/README.md | 4 ++-- examples/complete/main.tf | 6 ++++++ examples/complete/versions.tf | 2 +- examples/ec2-autoscaling/README.md | 4 ++-- examples/ec2-autoscaling/versions.tf | 2 +- examples/fargate/README.md | 4 ++-- examples/fargate/versions.tf | 2 +- modules/cluster/README.md | 4 ++-- modules/cluster/versions.tf | 2 +- modules/container-definition/README.md | 4 ++-- modules/container-definition/versions.tf | 2 +- modules/service/README.md | 4 ++-- modules/service/main.tf | 18 ++++++++++++++++++ modules/service/versions.tf | 2 +- versions.tf | 2 +- wrappers/README.md | 6 +++--- wrappers/cluster/README.md | 6 +++--- wrappers/cluster/versions.tf | 2 +- wrappers/container-definition/README.md | 6 +++--- wrappers/container-definition/versions.tf | 2 +- wrappers/service/README.md | 6 +++--- wrappers/service/versions.tf | 10 +--------- wrappers/versions.tf | 2 +- 24 files changed, 60 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a45968d3..ff003918 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ module "ecs" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index 5b73cfcb..2bd7088b 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 114f5aa1..191ad114 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -113,6 +113,12 @@ module "ecs" { port = local.container_port dns_name = local.container_name } + + timeout = { + idle_timeout_seconds = 20 + per_request_timeout_seconds = 30 + } + port_name = local.container_name discovery_name = local.container_name } diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 63e9319d..5f6e023e 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index 75f12070..31b43ab0 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index 63e9319d..5f6e023e 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 34f26c96..c209fa4a 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index 63e9319d..5f6e023e 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/modules/cluster/README.md b/modules/cluster/README.md index 8e8ac5eb..2216a567 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -137,13 +137,13 @@ module "ecs_cluster" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index 63e9319d..5f6e023e 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index 150f2f5c..c35dadf1 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -116,13 +116,13 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index 63e9319d..5f6e023e 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/modules/service/README.md b/modules/service/README.md index a498a9e9..95032012 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -167,13 +167,13 @@ module "ecs_service" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.34 | +| [aws](#requirement\_aws) | >= 5.37 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.34 | +| [aws](#provider\_aws) | >= 5.37 | ## Modules diff --git a/modules/service/main.tf b/modules/service/main.tf index 7050c949..51f6c634 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -168,6 +168,15 @@ resource "aws_ecs_service" "this" { } } + dynamic "timeout" { + for_each = try([service.value.timeout], []) + + content { + idle_timeout_seconds = try(timeout.value.idle_timeout_seconds, null) + per_request_timeout_seconds = try(timeout.value.per_request_timeout_seconds, null) + } + } + discovery_name = try(service.value.discovery_name, null) ingress_port_override = try(service.value.ingress_port_override, null) port_name = service.value.port_name @@ -356,6 +365,15 @@ resource "aws_ecs_service" "ignore_task_definition" { } } + dynamic "timeout" { + for_each = try([service.value.timeout], []) + + content { + idle_timeout_seconds = try(timeout.value.idle_timeout_seconds, null) + per_request_timeout_seconds = try(timeout.value.per_request_timeout_seconds, null) + } + } + discovery_name = try(service.value.discovery_name, null) ingress_port_override = try(service.value.ingress_port_override, null) port_name = service.value.port_name diff --git a/modules/service/versions.tf b/modules/service/versions.tf index 63e9319d..5f6e023e 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/versions.tf b/versions.tf index 63e9319d..5f6e023e 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/wrappers/README.md b/wrappers/README.md index 449acd8a..4d232b92 100644 --- a/wrappers/README.md +++ b/wrappers/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/ecs/aws//wrappers" + source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/ecs/aws//wrappers" + source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" defaults = { # Default values create = true diff --git a/wrappers/cluster/README.md b/wrappers/cluster/README.md index 1a795281..724fc78d 100644 --- a/wrappers/cluster/README.md +++ b/wrappers/cluster/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/cluster" + source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/cluster?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/cluster?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/ecs/aws//wrappers/cluster" + source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" defaults = { # Default values create = true diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index 63e9319d..5f6e023e 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/wrappers/container-definition/README.md b/wrappers/container-definition/README.md index 4731aa9a..7fec4239 100644 --- a/wrappers/container-definition/README.md +++ b/wrappers/container-definition/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/container-definition" + source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/container-definition?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/container-definition?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/ecs/aws//wrappers/container-definition" + source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" defaults = { # Default values create = true diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index 63e9319d..5f6e023e 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } diff --git a/wrappers/service/README.md b/wrappers/service/README.md index 219da916..0704f3ba 100644 --- a/wrappers/service/README.md +++ b/wrappers/service/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/service" + source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/service?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/service?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/ecs/aws//wrappers/service" + source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" defaults = { # Default values create = true diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index fa179650..5f6e023e 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -1,18 +1,10 @@ terraform { -<<<<<<< HEAD - required_version = ">= 1.0" -======= required_version = ">= 1.3" ->>>>>>> edf0446 (feat: Add support for custom metric queries in customized_metric_spec (#196)) required_providers { aws = { source = "hashicorp/aws" -<<<<<<< HEAD - version = ">= 4.66.1" -======= - version = ">= 5.34" ->>>>>>> edf0446 (feat: Add support for custom metric queries in customized_metric_spec (#196)) + version = ">= 5.37" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 63e9319d..5f6e023e 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.34" + version = ">= 5.37" } } } From 472aad99fd4af56dcf8fd68efd9b7d49a730a106 Mon Sep 17 00:00:00 2001 From: Rodrigo Torres Date: Thu, 25 Jul 2024 01:43:58 +0200 Subject: [PATCH 05/17] feat: Add support for EBS volumes (#205) * feat: Adding support for EBS volumes * feat: Adding support for EBS volumes * feat: Add support for EBS volumes * feat: Add support for EBS volumes * chore: Update min required AWS provider version --------- Co-authored-by: Bryant Biggs --- README.md | 2 +- examples/complete/README.md | 4 +- examples/complete/versions.tf | 2 +- examples/ec2-autoscaling/README.md | 6 +- examples/ec2-autoscaling/main.tf | 22 ++++- examples/ec2-autoscaling/outputs.tf | 10 ++ examples/ec2-autoscaling/versions.tf | 2 +- examples/fargate/README.md | 4 +- examples/fargate/versions.tf | 2 +- modules/cluster/README.md | 4 +- modules/cluster/versions.tf | 2 +- modules/container-definition/README.md | 4 +- modules/container-definition/versions.tf | 2 +- modules/service/README.md | 18 +++- modules/service/main.tf | 107 +++++++++++++++++++- modules/service/outputs.tf | 14 +++ modules/service/variables.tf | 58 +++++++++++ modules/service/versions.tf | 2 +- versions.tf | 2 +- wrappers/README.md | 6 +- wrappers/cluster/README.md | 6 +- wrappers/cluster/versions.tf | 2 +- wrappers/container-definition/README.md | 6 +- wrappers/container-definition/versions.tf | 2 +- wrappers/service/README.md | 6 +- wrappers/service/main.tf | 113 ++++++++++++---------- wrappers/service/versions.tf | 2 +- wrappers/versions.tf | 2 +- 28 files changed, 319 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index ff003918..d5f08583 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ module "ecs" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index 2bd7088b..b6bfa6e5 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index 31b43ab0..02553d5b 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules @@ -74,6 +74,8 @@ No inputs. | [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | Service IAM role name | | [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role | | [service\_id](#output\_service\_id) | ARN that identifies the service | +| [service\_infrastructure\_iam\_role\_arn](#output\_service\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN | +| [service\_infrastructure\_iam\_role\_name](#output\_service\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name | | [service\_name](#output\_service\_name) | Name of the service | | [service\_task\_definition\_arn](#output\_service\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) | | [service\_task\_definition\_revision](#output\_service\_task\_definition\_revision) | Revision of the task in a particular family | diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf index 35e6249f..30bcb6ad 100644 --- a/examples/ec2-autoscaling/main.tf +++ b/examples/ec2-autoscaling/main.tf @@ -95,8 +95,24 @@ module "ecs_service" { } } + create_infrastructure_iam_role = true + volume_configuration = { + ebs-volume = { + managed_ebs_volume = { + encrypted = true + file_system_type = "xfs" + size_in_gb = 5 + volume_type = "gp3" + } + } + } + volume = { - my-vol = {} + my-vol = {}, + ebs-volume = { + name = "ebs-volume" + configure_at_launch = true + } } # Container definition(s) @@ -115,6 +131,10 @@ module "ecs_service" { { sourceVolume = "my-vol", containerPath = "/var/www/my-vol" + }, + { + containerPath = "/ebs/data" + sourceVolume = "ebs-volume" } ] diff --git a/examples/ec2-autoscaling/outputs.tf b/examples/ec2-autoscaling/outputs.tf index 80903ad5..3ad62947 100644 --- a/examples/ec2-autoscaling/outputs.tf +++ b/examples/ec2-autoscaling/outputs.tf @@ -131,6 +131,16 @@ output "service_autoscaling_scheduled_actions" { value = module.ecs_service.autoscaling_scheduled_actions } +output "service_infrastructure_iam_role_arn" { + description = "Infrastructure IAM role ARN" + value = module.ecs_service.infrastructure_iam_role_arn +} + +output "service_infrastructure_iam_role_name" { + description = "Infrastructure IAM role name" + value = module.ecs_service.infrastructure_iam_role_name +} + ################################################################################ # Application Load Balancer ################################################################################ diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index c209fa4a..72b9cc9f 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/cluster/README.md b/modules/cluster/README.md index 2216a567..b8e5f946 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -137,13 +137,13 @@ module "ecs_cluster" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index c35dadf1..c2e01db1 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -116,13 +116,13 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/service/README.md b/modules/service/README.md index 95032012..4dab3d31 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -167,13 +167,13 @@ module "ecs_service" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules @@ -195,10 +195,12 @@ module "ecs_service" { | [aws_ecs_task_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_set) | resource | | [aws_iam_policy.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | @@ -207,6 +209,7 @@ module "ecs_service" { | [aws_security_group_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecs_task_definition) | data source | +| [aws_iam_policy_document.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -234,6 +237,7 @@ module "ecs_service" { | [cpu](#input\_cpu) | Number of cpu units used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `1024` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no | +| [create\_infrastructure\_iam\_role](#input\_create\_infrastructure\_iam\_role) | Determines whether the ECS infrastructure IAM role should be created | `bool` | `false` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `true` | no | | [create\_service](#input\_create\_service) | Determines whether service resource will be created (set to `false` in case you want to create task definition only) | `bool` | `true` | no | | [create\_task\_definition](#input\_create\_task\_definition) | Determines whether to create a task definition or use existing/provided | `bool` | `true` | no | @@ -264,6 +268,13 @@ module "ecs_service" { | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ignore\_task\_definition\_changes](#input\_ignore\_task\_definition\_changes) | Whether changes to service `task_definition` changes should be ignored | `bool` | `false` | no | | [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings | `any` | `{}` | no | +| [infrastructure\_iam\_role\_arn](#input\_infrastructure\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | +| [infrastructure\_iam\_role\_description](#input\_infrastructure\_iam\_role\_description) | Description of the role | `string` | `null` | no | +| [infrastructure\_iam\_role\_name](#input\_infrastructure\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | +| [infrastructure\_iam\_role\_path](#input\_infrastructure\_iam\_role\_path) | IAM role path | `string` | `null` | no | +| [infrastructure\_iam\_role\_permissions\_boundary](#input\_infrastructure\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | +| [infrastructure\_iam\_role\_tags](#input\_infrastructure\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | +| [infrastructure\_iam\_role\_use\_name\_prefix](#input\_infrastructure\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ipc\_mode](#input\_ipc\_mode) | IPC resource namespace to be used for the containers in the task The valid values are `host`, `task`, and `none` | `string` | `null` | no | | [launch\_type](#input\_launch\_type) | Launch type on which to run your service. The valid values are `EC2`, `FARGATE`, and `EXTERNAL`. Defaults to `FARGATE` | `string` | `"FARGATE"` | no | | [load\_balancer](#input\_load\_balancer) | Configuration block for load balancers | `any` | `{}` | no | @@ -320,6 +331,7 @@ module "ecs_service" { | [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the service | `map(string)` | `{}` | no | | [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `any` | `{}` | no | | [volume](#input\_volume) | Configuration block for volumes that containers in your task may use | `any` | `{}` | no | +| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume | `any` | `{}` | no | | [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no | | [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no | | [wait\_until\_stable\_timeout](#input\_wait\_until\_stable\_timeout) | Wait timeout for task set to reach `STEADY_STATE`. Valid time units include `ns`, `us` (or µs), `ms`, `s`, `m`, and `h`. Default `10m` | `string` | `null` | no | @@ -335,6 +347,8 @@ module "ecs_service" { | [iam\_role\_name](#output\_iam\_role\_name) | Service IAM role name | | [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role | | [id](#output\_id) | ARN that identifies the service | +| [infrastructure\_iam\_role\_arn](#output\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN | +| [infrastructure\_iam\_role\_name](#output\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name | | [name](#output\_name) | Name of the service | | [security\_group\_arn](#output\_security\_group\_arn) | Amazon Resource Name (ARN) of the security group | | [security\_group\_id](#output\_security\_group\_id) | ID of the security group | diff --git a/modules/service/main.tf b/modules/service/main.tf index 51f6c634..960b0b6c 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -197,6 +197,30 @@ resource "aws_ecs_service" "this" { } } + dynamic "volume_configuration" { + for_each = var.volume_configuration + + content { + name = try(volume_configuration.value.name, volume_configuration.key) + + dynamic "managed_ebs_volume" { + for_each = try([volume_configuration.value.managed_ebs_volume], []) + + content { + role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) + encrypted = try(managed_ebs_volume.value.encrypted, null) + file_system_type = try(managed_ebs_volume.value.file_system_type, null) + iops = try(managed_ebs_volume.value.iops, null) + kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) + size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) + snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) + throughput = try(managed_ebs_volume.value.throughput, null) + volume_type = try(managed_ebs_volume.value.volume_type, null) + } + } + } + } + task_definition = local.task_definition triggers = var.triggers wait_for_steady_state = var.wait_for_steady_state @@ -211,7 +235,8 @@ resource "aws_ecs_service" "this" { } depends_on = [ - aws_iam_role_policy_attachment.service + aws_iam_role_policy_attachment.service, + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy ] lifecycle { @@ -394,6 +419,30 @@ resource "aws_ecs_service" "ignore_task_definition" { } } + dynamic "volume_configuration" { + for_each = var.volume_configuration + + content { + name = try(volume_configuration.value.name, volume_configuration.key) + + dynamic "managed_ebs_volume" { + for_each = try([volume_configuration.value.managed_ebs_volume], []) + + content { + role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) + encrypted = try(managed_ebs_volume.value.encrypted, null) + file_system_type = try(managed_ebs_volume.value.file_system_type, null) + iops = try(managed_ebs_volume.value.iops, null) + kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) + size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) + snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) + throughput = try(managed_ebs_volume.value.throughput, null) + volume_type = try(managed_ebs_volume.value.volume_type, null) + } + } + } + } + task_definition = local.task_definition triggers = var.triggers wait_for_steady_state = var.wait_for_steady_state @@ -408,7 +457,8 @@ resource "aws_ecs_service" "ignore_task_definition" { } depends_on = [ - aws_iam_role_policy_attachment.service + aws_iam_role_policy_attachment.service, + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy ] lifecycle { @@ -751,8 +801,9 @@ resource "aws_ecs_task_definition" "this" { } } - host_path = try(volume.value.host_path, null) - name = try(volume.value.name, volume.key) + host_path = try(volume.value.host_path, null) + configure_at_launch = try(volume.value.configure_at_launch, null) + name = try(volume.value.name, volume.key) } } @@ -1411,3 +1462,51 @@ resource "aws_security_group_rule" "this" { self = lookup(each.value, "self", null) source_security_group_id = lookup(each.value, "source_security_group_id", null) } + +############################################################################################ +# ECS infrastructure IAM role +# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/infrastructure_IAM_role.html +############################################################################################ + +locals { + needs_infrastructure_iam_role = var.create_infrastructure_iam_role && var.volume_configuration != null + create_infrastructure_iam_role = var.create && local.needs_infrastructure_iam_role + infrastructure_iam_role_name = try(coalesce(var.infrastructure_iam_role_name, var.name), "") +} + +data "aws_iam_policy_document" "infrastructure_iam_role" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + statement { + sid = "ECSServiceAssumeRole" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "infrastructure_iam_role" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + name = var.infrastructure_iam_role_use_name_prefix ? null : local.infrastructure_iam_role_name + name_prefix = var.infrastructure_iam_role_use_name_prefix ? "${local.infrastructure_iam_role_name}-" : null + path = var.infrastructure_iam_role_path + description = coalesce(var.infrastructure_iam_role_description, "Amazon ECS infrastructure IAM role that is used to manage your infrastructure") + + assume_role_policy = data.aws_iam_policy_document.infrastructure_iam_role[0].json + permissions_boundary = var.infrastructure_iam_role_permissions_boundary + force_detach_policies = true + + tags = merge(var.tags, var.infrastructure_iam_role_tags) +} + +# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ebs-volumes.html#ebs-volume-considerations/ +resource "aws_iam_role_policy_attachment" "infrastructure_iam_role_ebs_policy" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + role = aws_iam_role.infrastructure_iam_role[0].name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" +} diff --git a/modules/service/outputs.tf b/modules/service/outputs.tf index 1eaa8510..2ca89ce8 100644 --- a/modules/service/outputs.tf +++ b/modules/service/outputs.tf @@ -155,3 +155,17 @@ output "security_group_id" { description = "ID of the security group" value = try(aws_security_group.this[0].id, null) } + +############################################################################################ +# ECS infrastructure IAM role +############################################################################################ + +output "infrastructure_iam_role_arn" { + description = "Infrastructure IAM role ARN" + value = try(aws_iam_role.infrastructure_iam_role[0].arn, null) +} + +output "infrastructure_iam_role_name" { + description = "Infrastructure IAM role name" + value = try(aws_iam_role.infrastructure_iam_role[0].name, null) +} diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 9a55e989..08ee0c4f 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -373,6 +373,12 @@ variable "volume" { default = {} } +variable "volume_configuration" { + description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume" + type = any + default = {} +} + variable "task_tags" { description = "A map of additional tags to add to the task definition/set created" type = map(string) @@ -665,3 +671,55 @@ variable "security_group_tags" { type = map(string) default = {} } + +############################################################################################ +# ECS infrastructure IAM role +############################################################################################ + +variable "create_infrastructure_iam_role" { + description = "Determines whether the ECS infrastructure IAM role should be created" + type = bool + default = false +} + +variable "infrastructure_iam_role_arn" { + description = "Existing IAM role ARN" + type = string + default = null +} + +variable "infrastructure_iam_role_name" { + description = "Name to use on IAM role created" + type = string + default = null +} + +variable "infrastructure_iam_role_use_name_prefix" { + description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix" + type = bool + default = true +} + +variable "infrastructure_iam_role_path" { + description = "IAM role path" + type = string + default = null +} + +variable "infrastructure_iam_role_description" { + description = "Description of the role" + type = string + default = null +} + +variable "infrastructure_iam_role_permissions_boundary" { + description = "ARN of the policy that is used to set the permissions boundary for the IAM role" + type = string + default = null +} + +variable "infrastructure_iam_role_tags" { + description = "A map of additional tags to add to the IAM role created" + type = map(string) + default = {} +} diff --git a/modules/service/versions.tf b/modules/service/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/versions.tf b/versions.tf index 5f6e023e..dc999065 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/README.md b/wrappers/README.md index 4d232b92..449acd8a 100644 --- a/wrappers/README.md +++ b/wrappers/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" + source = "terraform-aws-modules/ecs/aws//wrappers" defaults = { # Default values create = true diff --git a/wrappers/cluster/README.md b/wrappers/cluster/README.md index 724fc78d..1a795281 100644 --- a/wrappers/cluster/README.md +++ b/wrappers/cluster/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/cluster" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/cluster?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/cluster?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" + source = "terraform-aws-modules/ecs/aws//wrappers/cluster" defaults = { # Default values create = true diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/container-definition/README.md b/wrappers/container-definition/README.md index 7fec4239..4731aa9a 100644 --- a/wrappers/container-definition/README.md +++ b/wrappers/container-definition/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/container-definition" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/container-definition?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/container-definition?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" + source = "terraform-aws-modules/ecs/aws//wrappers/container-definition" defaults = { # Default values create = true diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/service/README.md b/wrappers/service/README.md index 0704f3ba..219da916 100644 --- a/wrappers/service/README.md +++ b/wrappers/service/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/service" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/service?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/service?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" + source = "terraform-aws-modules/ecs/aws//wrappers/service" defaults = { # Default values create = true diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 9a7d6aec..70941642 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -27,57 +27,65 @@ module "wrapper" { } } }) - autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {}) - capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {}) - cluster_arn = try(each.value.cluster_arn, var.defaults.cluster_arn, "") - container_definition_defaults = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {}) - container_definitions = try(each.value.container_definitions, var.defaults.container_definitions, {}) - cpu = try(each.value.cpu, var.defaults.cpu, 1024) - create = try(each.value.create, var.defaults.create, true) - create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) - create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) - create_service = try(each.value.create_service, var.defaults.create_service, true) - create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true) - create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true) - create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) - create_tasks_iam_role = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true) - deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {}) - deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, {}) - deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200) - deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66) - desired_count = try(each.value.desired_count, var.defaults.desired_count, 1) - enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) - enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) - enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) - ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {}) - external_id = try(each.value.external_id, var.defaults.external_id, null) - family = try(each.value.family, var.defaults.family, null) - force_delete = try(each.value.force_delete, var.defaults.force_delete, null) - force_new_deployment = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true) - health_check_grace_period_seconds = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null) - iam_role_arn = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null) - iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) - iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) - iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) - iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) - iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {}) - iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) - iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) - ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) - inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {}) - ipc_mode = try(each.value.ipc_mode, var.defaults.ipc_mode, null) - launch_type = try(each.value.launch_type, var.defaults.launch_type, "FARGATE") - load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, {}) - memory = try(each.value.memory, var.defaults.memory, 2048) - name = try(each.value.name, var.defaults.name, null) - network_mode = try(each.value.network_mode, var.defaults.network_mode, "awsvpc") - ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {}) - pid_mode = try(each.value.pid_mode, var.defaults.pid_mode, null) - placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, {}) - platform_version = try(each.value.platform_version, var.defaults.platform_version, null) - propagate_tags = try(each.value.propagate_tags, var.defaults.propagate_tags, null) - proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {}) - requires_compatibilities = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"]) + autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {}) + capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {}) + cluster_arn = try(each.value.cluster_arn, var.defaults.cluster_arn, "") + container_definition_defaults = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {}) + container_definitions = try(each.value.container_definitions, var.defaults.container_definitions, {}) + cpu = try(each.value.cpu, var.defaults.cpu, 1024) + create = try(each.value.create, var.defaults.create, true) + create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, var.defaults.create_infrastructure_iam_role, false) + create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) + create_service = try(each.value.create_service, var.defaults.create_service, true) + create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true) + create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true) + create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) + create_tasks_iam_role = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true) + deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {}) + deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, {}) + deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200) + deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66) + desired_count = try(each.value.desired_count, var.defaults.desired_count, 1) + enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) + enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) + enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) + ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {}) + external_id = try(each.value.external_id, var.defaults.external_id, null) + family = try(each.value.family, var.defaults.family, null) + force_delete = try(each.value.force_delete, var.defaults.force_delete, null) + force_new_deployment = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true) + health_check_grace_period_seconds = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null) + iam_role_arn = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null) + iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) + iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) + iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) + iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) + iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {}) + iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) + iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) + ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) + inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {}) + infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, var.defaults.infrastructure_iam_role_arn, null) + infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, var.defaults.infrastructure_iam_role_description, null) + infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, var.defaults.infrastructure_iam_role_name, null) + infrastructure_iam_role_path = try(each.value.infrastructure_iam_role_path, var.defaults.infrastructure_iam_role_path, null) + infrastructure_iam_role_permissions_boundary = try(each.value.infrastructure_iam_role_permissions_boundary, var.defaults.infrastructure_iam_role_permissions_boundary, null) + infrastructure_iam_role_tags = try(each.value.infrastructure_iam_role_tags, var.defaults.infrastructure_iam_role_tags, {}) + infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, var.defaults.infrastructure_iam_role_use_name_prefix, true) + ipc_mode = try(each.value.ipc_mode, var.defaults.ipc_mode, null) + launch_type = try(each.value.launch_type, var.defaults.launch_type, "FARGATE") + load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, {}) + memory = try(each.value.memory, var.defaults.memory, 2048) + name = try(each.value.name, var.defaults.name, null) + network_mode = try(each.value.network_mode, var.defaults.network_mode, "awsvpc") + ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {}) + pid_mode = try(each.value.pid_mode, var.defaults.pid_mode, null) + placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, {}) + platform_version = try(each.value.platform_version, var.defaults.platform_version, null) + propagate_tags = try(each.value.propagate_tags, var.defaults.propagate_tags, null) + proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {}) + requires_compatibilities = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"]) runtime_platform = try(each.value.runtime_platform, var.defaults.runtime_platform, { operating_system_family = "LINUX" cpu_architecture = "X86_64" @@ -111,7 +119,6 @@ module "wrapper" { task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, {}) task_exec_secret_arns = try(each.value.task_exec_secret_arns, var.defaults.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"]) task_exec_ssm_param_arns = try(each.value.task_exec_ssm_param_arns, var.defaults.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"]) - task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) tasks_iam_role_arn = try(each.value.tasks_iam_role_arn, var.defaults.tasks_iam_role_arn, null) tasks_iam_role_description = try(each.value.tasks_iam_role_description, var.defaults.tasks_iam_role_description, null) tasks_iam_role_name = try(each.value.tasks_iam_role_name, var.defaults.tasks_iam_role_name, null) @@ -121,9 +128,11 @@ module "wrapper" { tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, {}) tasks_iam_role_tags = try(each.value.tasks_iam_role_tags, var.defaults.tasks_iam_role_tags, {}) tasks_iam_role_use_name_prefix = try(each.value.tasks_iam_role_use_name_prefix, var.defaults.tasks_iam_role_use_name_prefix, true) + task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) triggers = try(each.value.triggers, var.defaults.triggers, {}) volume = try(each.value.volume, var.defaults.volume, {}) + volume_configuration = try(each.value.volume_configuration, var.defaults.volume_configuration, {}) wait_for_steady_state = try(each.value.wait_for_steady_state, var.defaults.wait_for_steady_state, null) wait_until_stable = try(each.value.wait_until_stable, var.defaults.wait_until_stable, null) wait_until_stable_timeout = try(each.value.wait_until_stable_timeout, var.defaults.wait_until_stable_timeout, null) diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } From 12b2f404280afe80e3224e6caffdefbbd52b8c91 Mon Sep 17 00:00:00 2001 From: Kevin Ouellet <43302866+kevouellet@users.noreply.github.com> Date: Mon, 5 Aug 2024 15:07:40 -0400 Subject: [PATCH 06/17] feat: Add support for service connect tls settings (#216) * add dynamic tls block for service connect service * set aws_pca_authority_arn to required * also apply fix to ecs service without ignore_task_def * formatting --------- Co-authored-by: Kevin Ouellet --- modules/service/main.tf | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/modules/service/main.tf b/modules/service/main.tf index 960b0b6c..0b78d44b 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -177,6 +177,24 @@ resource "aws_ecs_service" "this" { } } + dynamic "tls" { + for_each = try([service.value.tls], []) + + content { + + dynamic "issuer_cert_authority" { + for_each = tls.value.issuer_cert_authority + + content { + aws_pca_authority_arn = issuer_cert_authority.value.aws_pca_authority_arn + } + } + + kms_key = try(tls.value.kms_key, null) + role_arn = try(tls.value.role_arn, null) + } + } + discovery_name = try(service.value.discovery_name, null) ingress_port_override = try(service.value.ingress_port_override, null) port_name = service.value.port_name @@ -399,6 +417,24 @@ resource "aws_ecs_service" "ignore_task_definition" { } } + dynamic "tls" { + for_each = try([service.value.tls], []) + + content { + + dynamic "issuer_cert_authority" { + for_each = tls.value.issuer_cert_authority + + content { + aws_pca_authority_arn = issuer_cert_authority.value.aws_pca_authority_arn + } + } + + kms_key = try(tls.value.kms_key, null) + role_arn = try(tls.value.role_arn, null) + } + } + discovery_name = try(service.value.discovery_name, null) ingress_port_override = try(service.value.ingress_port_override, null) port_name = service.value.port_name From bd6cffabd66f0b6aeda9425d9fa97a0d7658dc7a Mon Sep 17 00:00:00 2001 From: Thomas Montague Date: Tue, 3 Sep 2024 15:37:21 -0500 Subject: [PATCH 07/17] fix: Propagate support for EBS volumes to the root module (#223) * Add missing support for EBS volumes. The PR https://github.com/terraform-aws-modules/terraform-aws-ecs/pull/205 failed to update the main module triggered when using the Terraform Registry as the module source. * Set default to true * Correct infra iam role logic. --- main.tf | 11 +++++++++++ modules/service/main.tf | 4 ++-- modules/service/variables.tf | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/main.tf b/main.tf index 5e380de7..1b885684 100644 --- a/main.tf +++ b/main.tf @@ -85,6 +85,7 @@ module "service" { service_registries = lookup(each.value, "service_registries", {}) timeouts = try(each.value.timeouts, {}) triggers = try(each.value.triggers, {}) + volume_configuration = try(each.value.volume_configuration, {}) wait_for_steady_state = try(each.value.wait_for_steady_state, null) # Service IAM role @@ -98,6 +99,16 @@ module "service" { iam_role_tags = try(each.value.iam_role_tags, {}) iam_role_statements = lookup(each.value, "iam_role_statements", {}) + # ECS infrastructure IAM role + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, false) + infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, null) + infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, null) + infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, true) + infrastructure_iam_role_path = try(each.value.infrastructure_iam_role_path, null) + infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, null) + infrastructure_iam_role_permissions_boundary = try(each.value.infrastructure_iam_role_permissions_boundary, null) + infrastructure_iam_role_tags = try(each.value.infrastructure_iam_role_tags, {}) + # Task definition create_task_definition = try(each.value.create_task_definition, true) task_definition_arn = lookup(each.value, "task_definition_arn", null) diff --git a/modules/service/main.tf b/modules/service/main.tf index 0b78d44b..dad4b050 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -1505,8 +1505,8 @@ resource "aws_security_group_rule" "this" { ############################################################################################ locals { - needs_infrastructure_iam_role = var.create_infrastructure_iam_role && var.volume_configuration != null - create_infrastructure_iam_role = var.create && local.needs_infrastructure_iam_role + needs_infrastructure_iam_role = var.volume_configuration != null + create_infrastructure_iam_role = var.create && var.create_infrastructure_iam_role && local.needs_infrastructure_iam_role infrastructure_iam_role_name = try(coalesce(var.infrastructure_iam_role_name, var.name), "") } diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 08ee0c4f..fad1c11a 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -679,7 +679,7 @@ variable "security_group_tags" { variable "create_infrastructure_iam_role" { description = "Determines whether the ECS infrastructure IAM role should be created" type = bool - default = false + default = true } variable "infrastructure_iam_role_arn" { From 6bc8138dfb92ea61d56fcad23bf8874ed6c0f74e Mon Sep 17 00:00:00 2001 From: Thomas Montague Date: Tue, 3 Sep 2024 16:29:32 -0500 Subject: [PATCH 08/17] fix: Correct logic for local `needs_infrastructure_iam_role` check (#224) * Fix need infrastructure role check. * try adjusting logic. * explicit dep * forgot this default * update example. --- examples/ec2-autoscaling/main.tf | 1 - main.tf | 2 +- modules/service/main.tf | 8 +++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf index 30bcb6ad..2fe2a62f 100644 --- a/examples/ec2-autoscaling/main.tf +++ b/examples/ec2-autoscaling/main.tf @@ -95,7 +95,6 @@ module "ecs_service" { } } - create_infrastructure_iam_role = true volume_configuration = { ebs-volume = { managed_ebs_volume = { diff --git a/main.tf b/main.tf index 1b885684..6261f433 100644 --- a/main.tf +++ b/main.tf @@ -100,7 +100,7 @@ module "service" { iam_role_statements = lookup(each.value, "iam_role_statements", {}) # ECS infrastructure IAM role - create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, false) + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, true) infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, null) infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, null) infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, true) diff --git a/modules/service/main.tf b/modules/service/main.tf index dad4b050..c5cf0561 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -225,7 +225,7 @@ resource "aws_ecs_service" "this" { for_each = try([volume_configuration.value.managed_ebs_volume], []) content { - role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) + role_arn = local.infrastructure_iam_role_arn encrypted = try(managed_ebs_volume.value.encrypted, null) file_system_type = try(managed_ebs_volume.value.file_system_type, null) iops = try(managed_ebs_volume.value.iops, null) @@ -254,7 +254,8 @@ resource "aws_ecs_service" "this" { depends_on = [ aws_iam_role_policy_attachment.service, - aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy, + aws_iam_role.infrastructure_iam_role, ] lifecycle { @@ -1505,8 +1506,9 @@ resource "aws_security_group_rule" "this" { ############################################################################################ locals { - needs_infrastructure_iam_role = var.volume_configuration != null + needs_infrastructure_iam_role = length(var.volume_configuration) > 0 create_infrastructure_iam_role = var.create && var.create_infrastructure_iam_role && local.needs_infrastructure_iam_role + infrastructure_iam_role_arn = local.needs_infrastructure_iam_role ? try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) : null infrastructure_iam_role_name = try(coalesce(var.infrastructure_iam_role_name, var.name), "") } From 664bb44222dbb17c9e27559e32218872bb7aaf22 Mon Sep 17 00:00:00 2001 From: Paul SANTUS Date: Mon, 16 Sep 2024 16:55:46 +0200 Subject: [PATCH 09/17] feat: Add support for restartPolicy (#231) * feat: Add support for restartPolicy (#230) * fix precommit error * fix: Correct defaults and remove redundant validation --------- Co-authored-by: Bryant Biggs --- README.md | 2 +- examples/complete/README.md | 4 ++-- examples/complete/main.tf | 6 ++++++ examples/complete/versions.tf | 2 +- examples/ec2-autoscaling/README.md | 4 ++-- examples/ec2-autoscaling/versions.tf | 2 +- examples/fargate/README.md | 4 ++-- examples/fargate/main.tf | 6 ++++++ examples/fargate/versions.tf | 2 +- main.tf | 14 +++++++------- modules/cluster/README.md | 4 ++-- modules/cluster/versions.tf | 2 +- modules/container-definition/README.md | 5 +++-- modules/container-definition/main.tf | 1 + modules/container-definition/variables.tf | 10 ++++++++++ modules/container-definition/versions.tf | 2 +- modules/service/README.md | 12 +++++++++--- modules/service/main.tf | 1 + modules/service/versions.tf | 2 +- versions.tf | 2 +- wrappers/cluster/versions.tf | 2 +- wrappers/container-definition/main.tf | 1 + wrappers/container-definition/versions.tf | 2 +- wrappers/service/main.tf | 2 +- wrappers/service/versions.tf | 2 +- wrappers/versions.tf | 2 +- 26 files changed, 65 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index d5f08583..89757647 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ module "ecs" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index b6bfa6e5..205f4563 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 191ad114..5b2100e0 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -102,6 +102,12 @@ module "ecs" { } } memory_reservation = 100 + + restart_policy = { + enabled = true + ignoredExitCodes = [1] + restartAttemptPeriod = 60 + } } } diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index dc999065..790c7ad1 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index 02553d5b..2b135751 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index dc999065..790c7ad1 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 72b9cc9f..19ed8cf3 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index 9aaa1226..1b92fd5c 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -121,6 +121,12 @@ module "ecs_service" { } } + restart_policy = { + enabled = true + ignoredExitCodes = [1] + restartAttemptPeriod = 60 + } + # Not required for fluent-bit, just an example volumes_from = [{ sourceContainer = "fluent-bit" diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index dc999065..790c7ad1 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/main.tf b/main.tf index 6261f433..682251d7 100644 --- a/main.tf +++ b/main.tf @@ -100,14 +100,14 @@ module "service" { iam_role_statements = lookup(each.value, "iam_role_statements", {}) # ECS infrastructure IAM role - create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, true) - infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, null) - infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, null) - infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, true) - infrastructure_iam_role_path = try(each.value.infrastructure_iam_role_path, null) - infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, null) + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, true) + infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, null) + infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, null) + infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, true) + infrastructure_iam_role_path = try(each.value.infrastructure_iam_role_path, null) + infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, null) infrastructure_iam_role_permissions_boundary = try(each.value.infrastructure_iam_role_permissions_boundary, null) - infrastructure_iam_role_tags = try(each.value.infrastructure_iam_role_tags, {}) + infrastructure_iam_role_tags = try(each.value.infrastructure_iam_role_tags, {}) # Task definition create_task_definition = try(each.value.create_task_definition, true) diff --git a/modules/cluster/README.md b/modules/cluster/README.md index b8e5f946..f098eb37 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -137,13 +137,13 @@ module "ecs_cluster" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index dc999065..790c7ad1 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index c2e01db1..d96ed6ef 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -116,13 +116,13 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules @@ -178,6 +178,7 @@ No modules. | [readonly\_root\_filesystem](#input\_readonly\_root\_filesystem) | When this parameter is true, the container is given read-only access to its root file system | `bool` | `true` | no | | [repository\_credentials](#input\_repository\_credentials) | Container repository credentials; required when using a private repo. This map currently supports a single key; "credentialsParameter", which should be the ARN of a Secrets Manager's secret holding the credentials | `map(string)` | `{}` | no | | [resource\_requirements](#input\_resource\_requirements) | The type and amount of a resource to assign to a container. The only supported resource is a GPU |
list(object({
type = string
value = string
}))
| `[]` | no | +| [restart\_policy](#input\_restart\_policy) | Container restart policy; helps overcome transient failures faster and maintain task availability |
object({
enabled = optional(bool)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
})
| `null` | no | | [secrets](#input\_secrets) | The secrets to pass to the container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the Amazon Elastic Container Service Developer Guide |
list(object({
name = string
valueFrom = string
}))
| `[]` | no | | [service](#input\_service) | The name of the service that the container definition is associated with | `string` | `""` | no | | [start\_timeout](#input\_start\_timeout) | Time duration (in seconds) to wait before giving up on resolving dependencies for a container | `number` | `30` | no | diff --git a/modules/container-definition/main.tf b/modules/container-definition/main.tf index 682fc94c..8982d148 100644 --- a/modules/container-definition/main.tf +++ b/modules/container-definition/main.tf @@ -54,6 +54,7 @@ locals { portMappings = var.port_mappings privileged = local.is_not_windows ? var.privileged : null pseudoTerminal = var.pseudo_terminal + restartPolicy = var.restart_policy readonlyRootFilesystem = local.is_not_windows ? var.readonly_root_filesystem : null repositoryCredentials = length(var.repository_credentials) > 0 ? var.repository_credentials : null resourceRequirements = length(var.resource_requirements) > 0 ? var.resource_requirements : null diff --git a/modules/container-definition/variables.tf b/modules/container-definition/variables.tf index 0f88b9de..a1349ba2 100644 --- a/modules/container-definition/variables.tf +++ b/modules/container-definition/variables.tf @@ -215,6 +215,16 @@ variable "resource_requirements" { default = [] } +variable "restart_policy" { + description = "Container restart policy; helps overcome transient failures faster and maintain task availability" + type = object({ + enabled = optional(bool) + ignoredExitCodes = optional(list(number)) + restartAttemptPeriod = optional(number) + }) + default = null +} + variable "secrets" { description = "The secrets to pass to the container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the Amazon Elastic Container Service Developer Guide" type = list(object({ diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index dc999065..790c7ad1 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/modules/service/README.md b/modules/service/README.md index 4dab3d31..d32e1bfe 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -70,6 +70,12 @@ module "ecs_service" { } } memory_reservation = 100 + + restart_policy = { + enabled = true + ignoredExitCodes = [1] + restartAttemptPeriod = 60 + } } } @@ -167,13 +173,13 @@ module "ecs_service" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.59 | +| [aws](#requirement\_aws) | >= 5.63 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.59 | +| [aws](#provider\_aws) | >= 5.63 | ## Modules @@ -237,7 +243,7 @@ module "ecs_service" { | [cpu](#input\_cpu) | Number of cpu units used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `1024` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no | -| [create\_infrastructure\_iam\_role](#input\_create\_infrastructure\_iam\_role) | Determines whether the ECS infrastructure IAM role should be created | `bool` | `false` | no | +| [create\_infrastructure\_iam\_role](#input\_create\_infrastructure\_iam\_role) | Determines whether the ECS infrastructure IAM role should be created | `bool` | `true` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `true` | no | | [create\_service](#input\_create\_service) | Determines whether service resource will be created (set to `false` in case you want to create task definition only) | `bool` | `true` | no | | [create\_task\_definition](#input\_create\_task\_definition) | Determines whether to create a task definition or use existing/provided | `bool` | `true` | no | diff --git a/modules/service/main.tf b/modules/service/main.tf index c5cf0561..0c5435ff 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -670,6 +670,7 @@ module "container_definition" { readonly_root_filesystem = try(each.value.readonly_root_filesystem, var.container_definition_defaults.readonly_root_filesystem, true) repository_credentials = try(each.value.repository_credentials, var.container_definition_defaults.repository_credentials, {}) resource_requirements = try(each.value.resource_requirements, var.container_definition_defaults.resource_requirements, []) + restart_policy = try(each.value.restart_policy, var.container_definition_defaults.restart_policy, { enabled = false }) secrets = try(each.value.secrets, var.container_definition_defaults.secrets, []) start_timeout = try(each.value.start_timeout, var.container_definition_defaults.start_timeout, 30) stop_timeout = try(each.value.stop_timeout, var.container_definition_defaults.stop_timeout, 120) diff --git a/modules/service/versions.tf b/modules/service/versions.tf index dc999065..790c7ad1 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/versions.tf b/versions.tf index dc999065..790c7ad1 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index dc999065..790c7ad1 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/wrappers/container-definition/main.tf b/wrappers/container-definition/main.tf index 7bcba25d..e5644f81 100644 --- a/wrappers/container-definition/main.tf +++ b/wrappers/container-definition/main.tf @@ -42,6 +42,7 @@ module "wrapper" { readonly_root_filesystem = try(each.value.readonly_root_filesystem, var.defaults.readonly_root_filesystem, true) repository_credentials = try(each.value.repository_credentials, var.defaults.repository_credentials, {}) resource_requirements = try(each.value.resource_requirements, var.defaults.resource_requirements, []) + restart_policy = try(each.value.restart_policy, var.defaults.restart_policy, null) secrets = try(each.value.secrets, var.defaults.secrets, []) service = try(each.value.service, var.defaults.service, "") start_timeout = try(each.value.start_timeout, var.defaults.start_timeout, 30) diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index dc999065..790c7ad1 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 70941642..5885f3d9 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -35,7 +35,7 @@ module "wrapper" { cpu = try(each.value.cpu, var.defaults.cpu, 1024) create = try(each.value.create, var.defaults.create, true) create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) - create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, var.defaults.create_infrastructure_iam_role, false) + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, var.defaults.create_infrastructure_iam_role, true) create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) create_service = try(each.value.create_service, var.defaults.create_service, true) create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true) diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index dc999065..790c7ad1 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index dc999065..790c7ad1 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.59" + version = ">= 5.63" } } } From 75f3e7d310ba85e5ffbc249a7e9d150e1596086d Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 22 Nov 2024 15:11:23 -0600 Subject: [PATCH 10/17] refactor: Initial pass at variable type definitions for service module' --- README.md | 4 +- examples/complete/README.md | 6 +- examples/complete/versions.tf | 4 +- examples/ec2-autoscaling/README.md | 6 +- examples/ec2-autoscaling/versions.tf | 4 +- examples/fargate/README.md | 7 +- examples/fargate/main.tf | 24 +- examples/fargate/outputs.tf | 7 +- examples/fargate/versions.tf | 4 +- main.tf | 3 +- modules/cluster/README.md | 6 +- modules/cluster/versions.tf | 4 +- modules/container-definition/README.md | 6 +- modules/container-definition/versions.tf | 4 +- modules/service/README.md | 70 +-- modules/service/main.tf | 582 ++++++++++++---------- modules/service/outputs.tf | 5 - modules/service/variables.tf | 366 +++++++++++--- modules/service/versions.tf | 4 +- versions.tf | 4 +- wrappers/cluster/versions.tf | 4 +- wrappers/container-definition/versions.tf | 4 +- wrappers/service/main.tf | 54 +- wrappers/service/versions.tf | 4 +- wrappers/versions.tf | 4 +- 25 files changed, 743 insertions(+), 447 deletions(-) diff --git a/README.md b/README.md index 89757647..1b3ec800 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ module "ecs" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index 205f4563..525f122c 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 790c7ad1..aebe26a1 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index 2b135751..d9a430a5 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index 790c7ad1..aebe26a1 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 19ed8cf3..242d59e6 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -26,14 +26,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules @@ -78,7 +78,6 @@ No inputs. | [service\_security\_group\_id](#output\_service\_security\_group\_id) | ID of the security group | | [service\_task\_definition\_arn](#output\_service\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) | | [service\_task\_definition\_family](#output\_service\_task\_definition\_family) | The unique name of the task definition | -| [service\_task\_definition\_family\_revision](#output\_service\_task\_definition\_family\_revision) | The family and revision (family:revision) of the task definition | | [service\_task\_definition\_revision](#output\_service\_task\_definition\_revision) | Revision of the task in a particular family | | [service\_task\_exec\_iam\_role\_arn](#output\_service\_task\_exec\_iam\_role\_arn) | Task execution IAM role ARN | | [service\_task\_exec\_iam\_role\_name](#output\_service\_task\_exec\_iam\_role\_name) | Task execution IAM role name | diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index 1b92fd5c..0cde7c8b 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -160,21 +160,19 @@ module "ecs_service" { } subnet_ids = module.vpc.private_subnets - security_group_rules = { + security_group_ingress_rules = { alb_ingress_3000 = { - type = "ingress" - from_port = local.container_port - to_port = local.container_port - protocol = "tcp" description = "Service port" + from_port = local.container_port + ip_protocol = "tcp" source_security_group_id = module.alb.security_group_id } + } + security_group_egress_rules = { egress_all = { - type = "egress" - from_port = 0 to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + ip_protocol = "-1" + cidr_ipv4 = "0.0.0.0/0" } } @@ -226,13 +224,11 @@ module "ecs_task_definition" { subnet_ids = module.vpc.private_subnets - security_group_rules = { + security_group_egress_rules = { egress_all = { - type = "egress" - from_port = 0 to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + ip_protocol = "-1" + cidr_ipv4 = "0.0.0.0/0" } } diff --git a/examples/fargate/outputs.tf b/examples/fargate/outputs.tf index 6c77f7ba..6f33f2f1 100644 --- a/examples/fargate/outputs.tf +++ b/examples/fargate/outputs.tf @@ -76,11 +76,6 @@ output "service_task_definition_family" { value = module.ecs_service.task_definition_family } -output "service_task_definition_family_revision" { - description = "The family and revision (family:revision) of the task definition" - value = module.ecs_service.task_definition_family_revision -} - output "service_task_exec_iam_role_name" { description = "Task execution IAM role name" value = module.ecs_service.task_exec_iam_role_name @@ -159,7 +154,7 @@ output "task_definition_run_task_command" { description = "awscli command to run the standalone task" value = < [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index 790c7ad1..aebe26a1 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index d96ed6ef..d2c0521a 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -115,14 +115,14 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index 790c7ad1..aebe26a1 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/modules/service/README.md b/modules/service/README.md index d32e1bfe..ef9545de 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -172,14 +172,14 @@ module "ecs_service" { | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.63 | +| [terraform](#requirement\_terraform) | >= 1.3.10 | +| [aws](#requirement\_aws) | >= 5.77 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.63 | +| [aws](#provider\_aws) | >= 5.77 | ## Modules @@ -207,14 +207,15 @@ module "ecs_service" { | [aws_iam_role.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.infrastructure_iam_role_vpc_lattice_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | -| [aws_security_group_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | +| [aws_vpc_security_group_egress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource | +| [aws_vpc_security_group_ingress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | -| [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecs_task_definition) | data source | | [aws_iam_policy_document.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -230,13 +231,14 @@ module "ecs_service" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [alarms](#input\_alarms) | Information about the CloudWatch alarms | `any` | `{}` | no | +| [alarms](#input\_alarms) | Information about the CloudWatch alarms |
object({
alarm_names = list(string)
enable = optional(bool, true)
rollback = optional(bool, true)
})
| `null` | no | | [assign\_public\_ip](#input\_assign\_public\_ip) | Assign a public IP address to the ENI (Fargate launch type only) | `bool` | `false` | no | | [autoscaling\_max\_capacity](#input\_autoscaling\_max\_capacity) | Maximum number of tasks to run in your service | `number` | `10` | no | | [autoscaling\_min\_capacity](#input\_autoscaling\_min\_capacity) | Minimum number of tasks to run in your service | `number` | `1` | no | | [autoscaling\_policies](#input\_autoscaling\_policies) | Map of autoscaling policies to create for the service | `any` |
{
"cpu": {
"policy_type": "TargetTrackingScaling",
"target_tracking_scaling_policy_configuration": {
"predefined_metric_specification": {
"predefined_metric_type": "ECSServiceAverageCPUUtilization"
}
}
},
"memory": {
"policy_type": "TargetTrackingScaling",
"target_tracking_scaling_policy_configuration": {
"predefined_metric_specification": {
"predefined_metric_type": "ECSServiceAverageMemoryUtilization"
}
}
}
}
| no | -| [autoscaling\_scheduled\_actions](#input\_autoscaling\_scheduled\_actions) | Map of autoscaling scheduled actions to create for the service | `any` | `{}` | no | -| [capacity\_provider\_strategy](#input\_capacity\_provider\_strategy) | Capacity provider strategies to use for the service. Can be one or more | `any` | `{}` | no | +| [autoscaling\_scheduled\_actions](#input\_autoscaling\_scheduled\_actions) | Map of autoscaling scheduled actions to create for the service |
map(object({
name = optional(string)
min_capacity = number
max_capacity = number
schedule = string
start_time = optional(string)
end_time = optional(string)
timezone = optional(string)
}))
| `null` | no | +| [availability\_zone\_rebalancing](#input\_availability\_zone\_rebalancing) | ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. Defaults to `DISABLED` | `string` | `null` | no | +| [capacity\_provider\_strategy](#input\_capacity\_provider\_strategy) | Capacity provider strategies to use for the service. Can be one or more |
map(object({
base = optional(number)
capacity_provider = string
weight = optional(number)
}))
| `null` | no | | [cluster\_arn](#input\_cluster\_arn) | ARN of the ECS cluster where the resources will be provisioned | `string` | `""` | no | | [container\_definition\_defaults](#input\_container\_definition\_defaults) | A map of default values for [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html) created by `container_definitions` | `any` | `{}` | no | | [container\_definitions](#input\_container\_definitions) | A map of valid [container definitions](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html). Please note that you should only provide values that are part of the container definition document | `any` | `{}` | no | @@ -250,18 +252,18 @@ module "ecs_service" { | [create\_task\_exec\_iam\_role](#input\_create\_task\_exec\_iam\_role) | Determines whether the ECS task definition IAM role should be created | `bool` | `true` | no | | [create\_task\_exec\_policy](#input\_create\_task\_exec\_policy) | Determines whether the ECS task definition IAM policy should be created. This includes permissions included in AmazonECSTaskExecutionRolePolicy as well as access to secrets and SSM parameters | `bool` | `true` | no | | [create\_tasks\_iam\_role](#input\_create\_tasks\_iam\_role) | Determines whether the ECS tasks IAM role should be created | `bool` | `true` | no | -| [deployment\_circuit\_breaker](#input\_deployment\_circuit\_breaker) | Configuration block for deployment circuit breaker | `any` | `{}` | no | -| [deployment\_controller](#input\_deployment\_controller) | Configuration block for deployment controller configuration | `any` | `{}` | no | -| [deployment\_maximum\_percent](#input\_deployment\_maximum\_percent) | Upper limit (as a percentage of the service's `desired_count`) of the number of running tasks that can be running in a service during a deployment | `number` | `200` | no | -| [deployment\_minimum\_healthy\_percent](#input\_deployment\_minimum\_healthy\_percent) | Lower limit (as a percentage of the service's `desired_count`) of the number of running tasks that must remain running and healthy in a service during a deployment | `number` | `66` | no | +| [deployment\_circuit\_breaker](#input\_deployment\_circuit\_breaker) | Configuration block for deployment circuit breaker |
object({
enable = bool
rollback = bool
})
| `null` | no | +| [deployment\_controller](#input\_deployment\_controller) | Configuration block for deployment controller configuration |
object({
type = optional(string)
})
| `null` | no | +| [deployment\_maximum\_percent](#input\_deployment\_maximum\_percent) | Upper limit (as a percentage of the service's `desired_count`) of the number of running tasks that can be running in a service during a deployment | `number` | `null` | no | +| [deployment\_minimum\_healthy\_percent](#input\_deployment\_minimum\_healthy\_percent) | Lower limit (as a percentage of the service's `desired_count`) of the number of running tasks that must remain running and healthy in a service during a deployment | `number` | `null` | no | | [desired\_count](#input\_desired\_count) | Number of instances of the task definition to place and keep running | `number` | `1` | no | | [enable\_autoscaling](#input\_enable\_autoscaling) | Determines whether to enable autoscaling for the service | `bool` | `true` | no | | [enable\_ecs\_managed\_tags](#input\_enable\_ecs\_managed\_tags) | Specifies whether to enable Amazon ECS managed tags for the tasks within the service | `bool` | `true` | no | | [enable\_execute\_command](#input\_enable\_execute\_command) | Specifies whether to enable Amazon ECS Exec for the tasks within the service | `bool` | `false` | no | -| [ephemeral\_storage](#input\_ephemeral\_storage) | The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate | `any` | `{}` | no | +| [ephemeral\_storage](#input\_ephemeral\_storage) | The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate |
object({
size_in_gib = number
})
| `null` | no | | [external\_id](#input\_external\_id) | The external ID associated with the task set | `string` | `null` | no | | [family](#input\_family) | A unique name for your task definition | `string` | `null` | no | -| [force\_delete](#input\_force\_delete) | Whether to allow deleting the task set without waiting for scaling down to 0 | `bool` | `null` | no | +| [force\_delete](#input\_force\_delete) | Enable to delete a service even if it wasn't scaled down to zero tasks. It's only necessary to use this if the service uses the `REPLICA` scheduling strategy | `bool` | `null` | no | | [force\_new\_deployment](#input\_force\_new\_deployment) | Enable to force a new task deployment of the service. This can be used to update tasks to use a newer Docker image with same image/tag combination, roll Fargate tasks onto a newer platform version, or immediately deploy `ordered_placement_strategy` and `placement_constraints` updates | `bool` | `true` | no | | [health\_check\_grace\_period\_seconds](#input\_health\_check\_grace\_period\_seconds) | Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown, up to 2147483647. Only valid for services configured to use load balancers | `number` | `null` | no | | [iam\_role\_arn](#input\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | @@ -269,11 +271,11 @@ module "ecs_service" { | [iam\_role\_name](#input\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | | [iam\_role\_path](#input\_iam\_role\_path) | IAM role path | `string` | `null` | no | | [iam\_role\_permissions\_boundary](#input\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | -| [iam\_role\_statements](#input\_iam\_role\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no | +| [iam\_role\_statements](#input\_iam\_role\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [iam\_role\_tags](#input\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ignore\_task\_definition\_changes](#input\_ignore\_task\_definition\_changes) | Whether changes to service `task_definition` changes should be ignored | `bool` | `false` | no | -| [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings | `any` | `{}` | no | +| [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings |
object({
device_name = string
device_type = string
})
| `null` | no | | [infrastructure\_iam\_role\_arn](#input\_infrastructure\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | | [infrastructure\_iam\_role\_description](#input\_infrastructure\_iam\_role\_description) | Description of the role | `string` | `null` | no | | [infrastructure\_iam\_role\_name](#input\_infrastructure\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | @@ -283,34 +285,35 @@ module "ecs_service" { | [infrastructure\_iam\_role\_use\_name\_prefix](#input\_infrastructure\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ipc\_mode](#input\_ipc\_mode) | IPC resource namespace to be used for the containers in the task The valid values are `host`, `task`, and `none` | `string` | `null` | no | | [launch\_type](#input\_launch\_type) | Launch type on which to run your service. The valid values are `EC2`, `FARGATE`, and `EXTERNAL`. Defaults to `FARGATE` | `string` | `"FARGATE"` | no | -| [load\_balancer](#input\_load\_balancer) | Configuration block for load balancers | `any` | `{}` | no | +| [load\_balancer](#input\_load\_balancer) | Configuration block for load balancers |
map(object({
container_name = string
container_port = number
elb_name = optional(string)
target_group_arn = optional(string)
}))
| `null` | no | | [memory](#input\_memory) | Amount (in MiB) of memory used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `2048` | no | | [name](#input\_name) | Name of the service (up to 255 letters, numbers, hyphens, and underscores) | `string` | `null` | no | | [network\_mode](#input\_network\_mode) | Docker networking mode to use for the containers in the task. Valid values are `none`, `bridge`, `awsvpc`, and `host` | `string` | `"awsvpc"` | no | -| [ordered\_placement\_strategy](#input\_ordered\_placement\_strategy) | Service level strategy rules that are taken into consideration during task placement. List from top to bottom in order of precedence | `any` | `{}` | no | +| [ordered\_placement\_strategy](#input\_ordered\_placement\_strategy) | Service level strategy rules that are taken into consideration during task placement. List from top to bottom in order of precedence |
map(object({
field = optional(string)
type = string
}))
| `null` | no | | [pid\_mode](#input\_pid\_mode) | Process namespace to use for the containers in the task. The valid values are `host` and `task` | `string` | `null` | no | -| [placement\_constraints](#input\_placement\_constraints) | Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the service, see `task_definition_placement_constraints` for setting at the task definition | `any` | `{}` | no | +| [placement\_constraints](#input\_placement\_constraints) | Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the service, see `task_definition_placement_constraints` for setting at the task definition |
map(object({
expression = optional(string)
type = string
}))
| `null` | no | | [platform\_version](#input\_platform\_version) | Platform version on which to run your service. Only applicable for `launch_type` set to `FARGATE`. Defaults to `LATEST` | `string` | `null` | no | | [propagate\_tags](#input\_propagate\_tags) | Specifies whether to propagate the tags from the task definition or the service to the tasks. The valid values are `SERVICE` and `TASK_DEFINITION` | `string` | `null` | no | -| [proxy\_configuration](#input\_proxy\_configuration) | Configuration block for the App Mesh proxy | `any` | `{}` | no | +| [proxy\_configuration](#input\_proxy\_configuration) | Configuration block for the App Mesh proxy |
object({
container_name = string
properties = optional(map(string))
type = optional(string)
})
| `null` | no | | [requires\_compatibilities](#input\_requires\_compatibilities) | Set of launch types required by the task. The valid values are `EC2` and `FARGATE` | `list(string)` |
[
"FARGATE"
]
| no | -| [runtime\_platform](#input\_runtime\_platform) | Configuration block for `runtime_platform` that containers in your task may use | `any` |
{
"cpu_architecture": "X86_64",
"operating_system_family": "LINUX"
}
| no | -| [scale](#input\_scale) | A floating-point percentage of the desired number of tasks to place and keep running in the task set | `any` | `{}` | no | +| [runtime\_platform](#input\_runtime\_platform) | Configuration block for `runtime_platform` that containers in your task may use |
object({
cpu_architecture = optional(string, "X86_64")
operating_system_family = optional(string, "LINUX")
})
|
{
"cpu_architecture": "X86_64",
"operating_system_family": "LINUX"
}
| no | +| [scale](#input\_scale) | A floating-point percentage of the desired number of tasks to place and keep running in the task set |
object({
unit = optional(string)
value = optional(number)
})
| `null` | no | | [scheduling\_strategy](#input\_scheduling\_strategy) | Scheduling strategy to use for the service. The valid values are `REPLICA` and `DAEMON`. Defaults to `REPLICA` | `string` | `null` | no | | [security\_group\_description](#input\_security\_group\_description) | Description of the security group created | `string` | `null` | no | +| [security\_group\_egress\_rules](#input\_security\_group\_egress\_rules) | Security group egress rules to add to the security group created |
map(object({
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(string)
ip_protocol = optional(string)
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(string)
}))
| `null` | no | | [security\_group\_ids](#input\_security\_group\_ids) | List of security groups to associate with the task or service | `list(string)` | `[]` | no | +| [security\_group\_ingress\_rules](#input\_security\_group\_ingress\_rules) | Security group ingress rules to add to the security group created |
map(object({
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = optional(string)
from_port = optional(string)
ip_protocol = optional(string)
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
tags = optional(map(string), {})
to_port = optional(string)
}))
| `null` | no | | [security\_group\_name](#input\_security\_group\_name) | Name to use on security group created | `string` | `null` | no | -| [security\_group\_rules](#input\_security\_group\_rules) | Security group rules to add to the security group created | `any` | `{}` | no | | [security\_group\_tags](#input\_security\_group\_tags) | A map of additional tags to add to the security group created | `map(string)` | `{}` | no | | [security\_group\_use\_name\_prefix](#input\_security\_group\_use\_name\_prefix) | Determines whether the security group name (`security_group_name`) is used as a prefix | `bool` | `true` | no | -| [service\_connect\_configuration](#input\_service\_connect\_configuration) | The ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace | `any` | `{}` | no | -| [service\_registries](#input\_service\_registries) | Service discovery registries for the service | `any` | `{}` | no | +| [service\_connect\_configuration](#input\_service\_connect\_configuration) | The ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace |
object({
enabled = optional(bool, true)
log_configuration = optional(object({
log_driver = string
options = optional(map(string))
secret_option = optional(object({
name = string
value_from = string
}))
}))
namespace = optional(string)
service = optional(list(object({
client_alias = optional(object({
dns_name = optional(string)
port = number
}))
discovery_name = optional(string)
ingress_port_override = optional(number)
port_name = string
timeout = optional(object({
idle_timeout_seconds = optional(number)
per_request_timeout_seconds = optional(number)
}))
tls = optional(object({
issuer_cert_authority = optional(object({
aws_pca_authority_arn = string
}))
kms_key = optional(string)
role_arn = optional(string)
}))
})))
})
| `null` | no | +| [service\_registries](#input\_service\_registries) | Service discovery registries for the service |
object({
container_name = optional(string)
container_port = optional(number)
port = optional(number)
registry_arn = string
})
| `null` | no | | [service\_tags](#input\_service\_tags) | A map of additional tags to add to the service | `map(string)` | `{}` | no | | [skip\_destroy](#input\_skip\_destroy) | If true, the task is not deleted when the service is deleted | `bool` | `null` | no | | [subnet\_ids](#input\_subnet\_ids) | List of subnets to associate with the task or service | `list(string)` | `[]` | no | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | | [task\_definition\_arn](#input\_task\_definition\_arn) | Existing task definition ARN. Required when `create_task_definition` is `false` | `string` | `null` | no | -| [task\_definition\_placement\_constraints](#input\_task\_definition\_placement\_constraints) | Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the task definition, see `placement_constraints` for setting at the service | `any` | `{}` | no | +| [task\_definition\_placement\_constraints](#input\_task\_definition\_placement\_constraints) | Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the task definition, see `placement_constraints` for setting at the service |
map(object({
expression = optional(string)
type = string
}))
| `null` | no | | [task\_exec\_iam\_policy\_path](#input\_task\_exec\_iam\_policy\_path) | Path for the iam role | `string` | `null` | no | | [task\_exec\_iam\_role\_arn](#input\_task\_exec\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | | [task\_exec\_iam\_role\_description](#input\_task\_exec\_iam\_role\_description) | Description of the role | `string` | `null` | no | @@ -321,7 +324,7 @@ module "ecs_service" { | [task\_exec\_iam\_role\_policies](#input\_task\_exec\_iam\_role\_policies) | Map of IAM role policy ARNs to attach to the IAM role | `map(string)` | `{}` | no | | [task\_exec\_iam\_role\_tags](#input\_task\_exec\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [task\_exec\_iam\_role\_use\_name\_prefix](#input\_task\_exec\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`task_exec_iam_role_name`) is used as a prefix | `bool` | `true` | no | -| [task\_exec\_iam\_statements](#input\_task\_exec\_iam\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no | +| [task\_exec\_iam\_statements](#input\_task\_exec\_iam\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [task\_exec\_secret\_arns](#input\_task\_exec\_secret\_arns) | List of SecretsManager secret ARNs the task execution role will be permitted to get/read | `list(string)` |
[
"arn:aws:secretsmanager:*:*:secret:*"
]
| no | | [task\_exec\_ssm\_param\_arns](#input\_task\_exec\_ssm\_param\_arns) | List of SSM parameter ARNs the task execution role will be permitted to get/read | `list(string)` |
[
"arn:aws:ssm:*:*:parameter/*"
]
| no | | [task\_tags](#input\_task\_tags) | A map of additional tags to add to the task definition/set created | `map(string)` | `{}` | no | @@ -331,13 +334,15 @@ module "ecs_service" { | [tasks\_iam\_role\_path](#input\_tasks\_iam\_role\_path) | IAM role path | `string` | `null` | no | | [tasks\_iam\_role\_permissions\_boundary](#input\_tasks\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | | [tasks\_iam\_role\_policies](#input\_tasks\_iam\_role\_policies) | Map of IAM role policy ARNs to attach to the IAM role | `map(string)` | `{}` | no | -| [tasks\_iam\_role\_statements](#input\_tasks\_iam\_role\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no | +| [tasks\_iam\_role\_statements](#input\_tasks\_iam\_role\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [tasks\_iam\_role\_tags](#input\_tasks\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [tasks\_iam\_role\_use\_name\_prefix](#input\_tasks\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`tasks_iam_role_name`) is used as a prefix | `bool` | `true` | no | -| [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the service | `map(string)` | `{}` | no | -| [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `any` | `{}` | no | -| [volume](#input\_volume) | Configuration block for volumes that containers in your task may use | `any` | `{}` | no | -| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume | `any` | `{}` | no | +| [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the service |
object({
create = optional(string)
update = optional(string)
delete = optional(string)
})
| `null` | no | +| [track\_latest](#input\_track\_latest) | Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource | `bool` | `true` | no | +| [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `map(string)` | `null` | no | +| [volume](#input\_volume) | Configuration block for volumes that containers in your task may use |
map(object({
configure_at_launch = optional(bool)
docker_volume_configuration = optional(object({
autoprovision = optional(bool)
driver = optional(string)
driver_opts = optional(map(string))
labels = optional(map(string))
scope = optional(string)
}))
efs_volume_configuration = optional(object({
authorization_config = optional(object({
access_point_id = optional(string)
iam = optional(string)
}))
file_system_id = string
root_directory = optional(string)
transit_encryption = optional(string)
transit_encryption_port = optional(number)
}))
fsx_windows_file_server_volume_configuration = optional(object({
authorization_config = optional(object({
credentials_parameter = string
domain = string
}))
file_system_id = string
root_directory = string
}))
host_path = optional(string)
name = optional(string)
}))
| `null` | no | +| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time |
object({
name = string
managed_ebs_volume = list(object({
encrypted = optional(bool)
file_system_type = optional(string)
iops = optional(number)
kms_key_id = optional(string)
size_in_gb = optional(number)
snapshot_id = optional(string)
throughput = optional(number)
volume_type = optional(string)
tag_specification = optional(list(object({
resource_type = string
propagate_tags = optional(string, "TASK_DEFINITION")
tags = optional(map(string))
})))
}))
})
| `null` | no | +| [vpc\_lattice\_configurations](#input\_vpc\_lattice\_configurations) | The VPC Lattice configuration for your service that allows Lattice to connect, secure, and monitor your service across multiple accounts and VPCs |
object({
role_arn = string
target_group_arn = string
port_name = string
})
| `null` | no | | [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no | | [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no | | [wait\_until\_stable\_timeout](#input\_wait\_until\_stable\_timeout) | Wait timeout for task set to reach `STEADY_STATE`. Valid time units include `ns`, `us` (or µs), `ms`, `s`, `m`, and `h`. Default `10m` | `string` | `null` | no | @@ -360,7 +365,6 @@ module "ecs_service" { | [security\_group\_id](#output\_security\_group\_id) | ID of the security group | | [task\_definition\_arn](#output\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) | | [task\_definition\_family](#output\_task\_definition\_family) | The unique name of the task definition | -| [task\_definition\_family\_revision](#output\_task\_definition\_family\_revision) | The family and revision (family:revision) of the task definition | | [task\_definition\_revision](#output\_task\_definition\_revision) | Revision of the task in a particular family | | [task\_exec\_iam\_role\_arn](#output\_task\_exec\_iam\_role\_arn) | Task execution IAM role ARN | | [task\_exec\_iam\_role\_name](#output\_task\_exec\_iam\_role\_name) | Task execution IAM role name | diff --git a/modules/service/main.tf b/modules/service/main.tf index 0c5435ff..0e08c6e5 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -32,30 +32,32 @@ resource "aws_ecs_service" "this" { count = local.create_service && !var.ignore_task_definition_changes ? 1 : 0 dynamic "alarms" { - for_each = length(var.alarms) > 0 ? [var.alarms] : [] + for_each = var.alarms != null ? [var.alarms] : [] content { alarm_names = alarms.value.alarm_names - enable = try(alarms.value.enable, true) - rollback = try(alarms.value.rollback, true) + enable = alarms.value.enable + rollback = alarms.value.rollback } } + availability_zone_rebalancing = var.availability_zone_rebalancing + dynamic "capacity_provider_strategy" { # Set by task set if deployment controller is external - for_each = { for k, v in var.capacity_provider_strategy : k => v if !local.is_external_deployment } + for_each = !local.is_external_deployment && var.capacity_provider_strategy != null ? var.capacity_provider_strategy : {} content { - base = try(capacity_provider_strategy.value.base, null) + base = capacity_provider_strategy.value.base capacity_provider = capacity_provider_strategy.value.capacity_provider - weight = try(capacity_provider_strategy.value.weight, null) + weight = capacity_provider_strategy.value.weight } } cluster = var.cluster_arn dynamic "deployment_circuit_breaker" { - for_each = length(var.deployment_circuit_breaker) > 0 ? [var.deployment_circuit_breaker] : [] + for_each = var.deployment_circuit_breaker != null ? [var.deployment_circuit_breaker] : [] content { enable = deployment_circuit_breaker.value.enable @@ -64,10 +66,10 @@ resource "aws_ecs_service" "this" { } dynamic "deployment_controller" { - for_each = length(var.deployment_controller) > 0 ? [var.deployment_controller] : [] + for_each = var.deployment_controller != null ? [var.deployment_controller] : [] content { - type = try(deployment_controller.value.type, null) + type = deployment_controller.value.type } } @@ -76,20 +78,21 @@ resource "aws_ecs_service" "this" { desired_count = local.is_daemon || local.is_external_deployment ? null : var.desired_count enable_ecs_managed_tags = var.enable_ecs_managed_tags enable_execute_command = var.enable_execute_command + force_delete = var.force_delete force_new_deployment = local.is_external_deployment ? null : var.force_new_deployment health_check_grace_period_seconds = var.health_check_grace_period_seconds iam_role = local.iam_role_arn - launch_type = local.is_external_deployment || length(var.capacity_provider_strategy) > 0 ? null : var.launch_type + launch_type = local.is_external_deployment || var.capacity_provider_strategy != null ? null : var.launch_type dynamic "load_balancer" { # Set by task set if deployment controller is external - for_each = { for k, v in var.load_balancer : k => v if !local.is_external_deployment } + for_each = var.load_balancer != null ? var.load_balancer : {} content { container_name = load_balancer.value.container_name container_port = load_balancer.value.container_port - elb_name = try(load_balancer.value.elb_name, null) - target_group_arn = try(load_balancer.value.target_group_arn, null) + elb_name = load_balancer.value.elb_name + target_group_arn = load_balancer.value.target_group_arn } } @@ -107,42 +110,43 @@ resource "aws_ecs_service" "this" { } dynamic "ordered_placement_strategy" { - for_each = var.ordered_placement_strategy + for_each = var.ordered_placement_strategy != null ? var.ordered_placement_strategy : {} content { - field = try(ordered_placement_strategy.value.field, null) + field = ordered_placement_strategy.value.field type = ordered_placement_strategy.value.type } } dynamic "placement_constraints" { - for_each = var.placement_constraints + for_each = var.placement_constraints != null ? var.placement_constraints : {} content { - expression = try(placement_constraints.value.expression, null) + expression = placement_constraints.value.expression type = placement_constraints.value.type } } # Set by task set if deployment controller is external platform_version = local.is_fargate && !local.is_external_deployment ? var.platform_version : null + propagate_tags = var.propagate_tags scheduling_strategy = local.is_fargate ? "REPLICA" : var.scheduling_strategy dynamic "service_connect_configuration" { - for_each = length(var.service_connect_configuration) > 0 ? [var.service_connect_configuration] : [] + for_each = var.service_connect_configuration != null ? [var.service_connect_configuration] : [] content { - enabled = try(service_connect_configuration.value.enabled, true) + enabled = service_connect_configuration.value.enabled dynamic "log_configuration" { - for_each = try([service_connect_configuration.value.log_configuration], []) + for_each = service_connect_configuration.value.log_configuration != null ? [service_connect_configuration.value.log_configuration] : [] content { - log_driver = try(log_configuration.value.log_driver, null) - options = try(log_configuration.value.options, null) + log_driver = log_configuration.value.log_driver + options = log_configuration.value.options dynamic "secret_option" { - for_each = try(log_configuration.value.secret_option, []) + for_each = log_configuration.value.secret_option != null ? [log_configuration.value.secret_option] : [] content { name = secret_option.value.name @@ -152,36 +156,38 @@ resource "aws_ecs_service" "this" { } } - namespace = lookup(service_connect_configuration.value, "namespace", null) + namespace = service_connect_configuration.value.namespace dynamic "service" { - for_each = try(service_connect_configuration.value.service, []) + for_each = service_connect_configuration.value.service != null ? service_connect_configuration.value.service : [] content { - dynamic "client_alias" { - for_each = try([service.value.client_alias], []) + for_each = service.value.client_alias != null ? [service.value.client_alias] : [] content { - dns_name = try(client_alias.value.dns_name, null) + dns_name = client_alias.value.dns_name port = client_alias.value.port } } + discovery_name = service.value.discovery_name + ingress_port_override = service.value.ingress_port_override + port_name = service.value.port_name + dynamic "timeout" { - for_each = try([service.value.timeout], []) + for_each = service.value.timeout != null ? [service.value.timeout] : [] content { - idle_timeout_seconds = try(timeout.value.idle_timeout_seconds, null) - per_request_timeout_seconds = try(timeout.value.per_request_timeout_seconds, null) + idle_timeout_seconds = timeout.value.idle_timeout_seconds + per_request_timeout_seconds = timeout.value.per_request_timeout_seconds } } dynamic "tls" { - for_each = try([service.value.tls], []) + for_each = service.value.tls != null ? [service.value.tls] : [] content { - dynamic "issuer_cert_authority" { for_each = tls.value.issuer_cert_authority @@ -190,14 +196,10 @@ resource "aws_ecs_service" "this" { } } - kms_key = try(tls.value.kms_key, null) - role_arn = try(tls.value.role_arn, null) + kms_key = tls.value.kms_key + role_arn = tls.value.role_arn } } - - discovery_name = try(service.value.discovery_name, null) - ingress_port_override = try(service.value.ingress_port_override, null) - port_name = service.value.port_name } } } @@ -205,57 +207,79 @@ resource "aws_ecs_service" "this" { dynamic "service_registries" { # Set by task set if deployment controller is external - for_each = length(var.service_registries) > 0 ? [{ for k, v in var.service_registries : k => v if !local.is_external_deployment }] : [] + for_each = var.service_registries != null && !local.is_external_deployment ? [var.service_registries] : [] content { - container_name = try(service_registries.value.container_name, null) - container_port = try(service_registries.value.container_port, null) - port = try(service_registries.value.port, null) + container_name = service_registries.value.container_name + container_port = service_registries.value.container_port + port = service_registries.value.port registry_arn = service_registries.value.registry_arn } } + tags = merge(var.tags, var.service_tags) + task_definition = local.task_definition + triggers = var.triggers + dynamic "volume_configuration" { - for_each = var.volume_configuration + for_each = var.volume_configuration != null ? [var.volume_configuration] : [] content { - name = try(volume_configuration.value.name, volume_configuration.key) + name = volume_configuration.value.name dynamic "managed_ebs_volume" { - for_each = try([volume_configuration.value.managed_ebs_volume], []) + for_each = volume_configuration.value.managed_ebs_volume content { + encrypted = managed_ebs_volume.value.encrypted + file_system_type = managed_ebs_volume.value.file_system_type + iops = managed_ebs_volume.value.iops + kms_key_id = managed_ebs_volume.value.kms_key_id role_arn = local.infrastructure_iam_role_arn - encrypted = try(managed_ebs_volume.value.encrypted, null) - file_system_type = try(managed_ebs_volume.value.file_system_type, null) - iops = try(managed_ebs_volume.value.iops, null) - kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) - size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) - snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) - throughput = try(managed_ebs_volume.value.throughput, null) - volume_type = try(managed_ebs_volume.value.volume_type, null) + size_in_gb = managed_ebs_volume.value.size_in_gb + snapshot_id = managed_ebs_volume.value.snapshot_id + throughput = managed_ebs_volume.value.throughput + volume_type = managed_ebs_volume.value.volume_type + + dynamic "tag_specifications" { + for_each = managed_ebs_volume.value.tag_specifications != null ? managed_ebs_volume.value.tag_specifications : [] + + content { + resource_type = tag_specifications.value.resource_type + propagate_tags = tag_specifications.value.propagate_tags + tags = tag_specifications.value.tags + } + } } } } } - task_definition = local.task_definition - triggers = var.triggers + dynamic "vpc_lattice_configurations" { + for_each = var.vpc_lattice_configurations != null ? [var.vpc_lattice_configurations] : [] + + content { + role_arn = local.infrastructure_iam_role_arn + target_group_arn = vpc_lattice_configurations.value.target_group_arn + port_name = vpc_lattice_configurations.value.port_name + } + } + wait_for_steady_state = var.wait_for_steady_state - propagate_tags = var.propagate_tags - tags = merge(var.tags, var.service_tags) + dynamic "timeouts" { + for_each = var.timeouts != null ? [var.timeouts] : [] - timeouts { - create = try(var.timeouts.create, null) - update = try(var.timeouts.update, null) - delete = try(var.timeouts.delete, null) + content { + create = timeouts.value.create + update = timeouts.value.update + delete = timeouts.value.delete + } } depends_on = [ aws_iam_role_policy_attachment.service, aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy, - aws_iam_role.infrastructure_iam_role, ] lifecycle { @@ -273,30 +297,32 @@ resource "aws_ecs_service" "ignore_task_definition" { count = local.create_service && var.ignore_task_definition_changes ? 1 : 0 dynamic "alarms" { - for_each = length(var.alarms) > 0 ? [var.alarms] : [] + for_each = var.alarms != null ? [var.alarms] : [] content { alarm_names = alarms.value.alarm_names - enable = try(alarms.value.enable, true) - rollback = try(alarms.value.rollback, true) + enable = alarms.value.enable + rollback = alarms.value.rollback } } + availability_zone_rebalancing = var.availability_zone_rebalancing + dynamic "capacity_provider_strategy" { # Set by task set if deployment controller is external - for_each = { for k, v in var.capacity_provider_strategy : k => v if !local.is_external_deployment } + for_each = !local.is_external_deployment && var.capacity_provider_strategy != null ? var.capacity_provider_strategy : {} content { - base = try(capacity_provider_strategy.value.base, null) + base = capacity_provider_strategy.value.base capacity_provider = capacity_provider_strategy.value.capacity_provider - weight = try(capacity_provider_strategy.value.weight, null) + weight = capacity_provider_strategy.value.weight } } cluster = var.cluster_arn dynamic "deployment_circuit_breaker" { - for_each = length(var.deployment_circuit_breaker) > 0 ? [var.deployment_circuit_breaker] : [] + for_each = var.deployment_circuit_breaker != null ? [var.deployment_circuit_breaker] : [] content { enable = deployment_circuit_breaker.value.enable @@ -305,10 +331,10 @@ resource "aws_ecs_service" "ignore_task_definition" { } dynamic "deployment_controller" { - for_each = length(var.deployment_controller) > 0 ? [var.deployment_controller] : [] + for_each = var.deployment_controller != null ? [var.deployment_controller] : [] content { - type = try(deployment_controller.value.type, null) + type = deployment_controller.value.type } } @@ -317,20 +343,21 @@ resource "aws_ecs_service" "ignore_task_definition" { desired_count = local.is_daemon || local.is_external_deployment ? null : var.desired_count enable_ecs_managed_tags = var.enable_ecs_managed_tags enable_execute_command = var.enable_execute_command + force_delete = var.force_delete force_new_deployment = local.is_external_deployment ? null : var.force_new_deployment health_check_grace_period_seconds = var.health_check_grace_period_seconds iam_role = local.iam_role_arn - launch_type = local.is_external_deployment || length(var.capacity_provider_strategy) > 0 ? null : var.launch_type + launch_type = local.is_external_deployment || var.capacity_provider_strategy != null ? null : var.launch_type dynamic "load_balancer" { # Set by task set if deployment controller is external - for_each = { for k, v in var.load_balancer : k => v if !local.is_external_deployment } + for_each = var.load_balancer != null ? var.load_balancer : {} content { container_name = load_balancer.value.container_name container_port = load_balancer.value.container_port - elb_name = try(load_balancer.value.elb_name, null) - target_group_arn = try(load_balancer.value.target_group_arn, null) + elb_name = load_balancer.value.elb_name + target_group_arn = load_balancer.value.target_group_arn } } @@ -348,42 +375,43 @@ resource "aws_ecs_service" "ignore_task_definition" { } dynamic "ordered_placement_strategy" { - for_each = var.ordered_placement_strategy + for_each = var.ordered_placement_strategy != null ? var.ordered_placement_strategy : {} content { - field = try(ordered_placement_strategy.value.field, null) + field = ordered_placement_strategy.value.field type = ordered_placement_strategy.value.type } } dynamic "placement_constraints" { - for_each = var.placement_constraints + for_each = var.placement_constraints != null ? var.placement_constraints : {} content { - expression = try(placement_constraints.value.expression, null) + expression = placement_constraints.value.expression type = placement_constraints.value.type } } # Set by task set if deployment controller is external platform_version = local.is_fargate && !local.is_external_deployment ? var.platform_version : null + propagate_tags = var.propagate_tags scheduling_strategy = local.is_fargate ? "REPLICA" : var.scheduling_strategy dynamic "service_connect_configuration" { - for_each = length(var.service_connect_configuration) > 0 ? [var.service_connect_configuration] : [] + for_each = var.service_connect_configuration != null ? [var.service_connect_configuration] : [] content { - enabled = try(service_connect_configuration.value.enabled, true) + enabled = service_connect_configuration.value.enabled dynamic "log_configuration" { - for_each = try([service_connect_configuration.value.log_configuration], []) + for_each = service_connect_configuration.value.log_configuration != null ? [service_connect_configuration.value.log_configuration] : [] content { - log_driver = try(log_configuration.value.log_driver, null) - options = try(log_configuration.value.options, null) + log_driver = log_configuration.value.log_driver + options = log_configuration.value.options dynamic "secret_option" { - for_each = try(log_configuration.value.secret_option, []) + for_each = log_configuration.value.secret_option != null ? [log_configuration.value.secret_option] : [] content { name = secret_option.value.name @@ -393,36 +421,38 @@ resource "aws_ecs_service" "ignore_task_definition" { } } - namespace = lookup(service_connect_configuration.value, "namespace", null) + namespace = service_connect_configuration.value.namespace dynamic "service" { - for_each = try(service_connect_configuration.value.service, []) + for_each = service_connect_configuration.value.service != null ? service_connect_configuration.value.service : [] content { - dynamic "client_alias" { - for_each = try([service.value.client_alias], []) + for_each = service.value.client_alias != null ? [service.value.client_alias] : [] content { - dns_name = try(client_alias.value.dns_name, null) + dns_name = client_alias.value.dns_name port = client_alias.value.port } } + discovery_name = service.value.discovery_name + ingress_port_override = service.value.ingress_port_override + port_name = service.value.port_name + dynamic "timeout" { - for_each = try([service.value.timeout], []) + for_each = service.value.timeout != null ? [service.value.timeout] : [] content { - idle_timeout_seconds = try(timeout.value.idle_timeout_seconds, null) - per_request_timeout_seconds = try(timeout.value.per_request_timeout_seconds, null) + idle_timeout_seconds = timeout.value.idle_timeout_seconds + per_request_timeout_seconds = timeout.value.per_request_timeout_seconds } } dynamic "tls" { - for_each = try([service.value.tls], []) + for_each = service.value.tls != null ? [service.value.tls] : [] content { - dynamic "issuer_cert_authority" { for_each = tls.value.issuer_cert_authority @@ -431,14 +461,10 @@ resource "aws_ecs_service" "ignore_task_definition" { } } - kms_key = try(tls.value.kms_key, null) - role_arn = try(tls.value.role_arn, null) + kms_key = tls.value.kms_key + role_arn = tls.value.role_arn } } - - discovery_name = try(service.value.discovery_name, null) - ingress_port_override = try(service.value.ingress_port_override, null) - port_name = service.value.port_name } } } @@ -446,56 +472,79 @@ resource "aws_ecs_service" "ignore_task_definition" { dynamic "service_registries" { # Set by task set if deployment controller is external - for_each = length(var.service_registries) > 0 ? [{ for k, v in var.service_registries : k => v if !local.is_external_deployment }] : [] + for_each = var.service_registries != null && !local.is_external_deployment ? [var.service_registries] : [] content { - container_name = try(service_registries.value.container_name, null) - container_port = try(service_registries.value.container_port, null) - port = try(service_registries.value.port, null) + container_name = service_registries.value.container_name + container_port = service_registries.value.container_port + port = service_registries.value.port registry_arn = service_registries.value.registry_arn } } + tags = merge(var.tags, var.service_tags) + task_definition = local.task_definition + triggers = var.triggers + dynamic "volume_configuration" { - for_each = var.volume_configuration + for_each = var.volume_configuration != null ? [var.volume_configuration] : [] content { - name = try(volume_configuration.value.name, volume_configuration.key) + name = volume_configuration.value.name dynamic "managed_ebs_volume" { - for_each = try([volume_configuration.value.managed_ebs_volume], []) + for_each = volume_configuration.value.managed_ebs_volume content { - role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) - encrypted = try(managed_ebs_volume.value.encrypted, null) - file_system_type = try(managed_ebs_volume.value.file_system_type, null) - iops = try(managed_ebs_volume.value.iops, null) - kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) - size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) - snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) - throughput = try(managed_ebs_volume.value.throughput, null) - volume_type = try(managed_ebs_volume.value.volume_type, null) + encrypted = managed_ebs_volume.value.encrypted + file_system_type = managed_ebs_volume.value.file_system_type + iops = managed_ebs_volume.value.iops + kms_key_id = managed_ebs_volume.value.kms_key_id + role_arn = local.infrastructure_iam_role_arn + size_in_gb = managed_ebs_volume.value.size_in_gb + snapshot_id = managed_ebs_volume.value.snapshot_id + throughput = managed_ebs_volume.value.throughput + volume_type = managed_ebs_volume.value.volume_type + + dynamic "tag_specifications" { + for_each = managed_ebs_volume.value.tag_specifications != null ? managed_ebs_volume.value.tag_specifications : [] + + content { + resource_type = tag_specifications.value.resource_type + propagate_tags = tag_specifications.value.propagate_tags + tags = tag_specifications.value.tags + } + } } } } } - task_definition = local.task_definition - triggers = var.triggers + dynamic "vpc_lattice_configurations" { + for_each = var.vpc_lattice_configurations != null ? [var.vpc_lattice_configurations] : [] + + content { + role_arn = local.infrastructure_iam_role_arn + target_group_arn = vpc_lattice_configurations.value.target_group_arn + port_name = vpc_lattice_configurations.value.port_name + } + } + wait_for_steady_state = var.wait_for_steady_state - propagate_tags = var.propagate_tags - tags = merge(var.tags, var.service_tags) + dynamic "timeouts" { + for_each = var.timeouts != null ? [var.timeouts] : [] - timeouts { - create = try(var.timeouts.create, null) - update = try(var.timeouts.update, null) - delete = try(var.timeouts.delete, null) + content { + create = timeouts.value.create + update = timeouts.value.update + delete = timeouts.value.delete + } } depends_on = [ aws_iam_role_policy_attachment.service, - aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy, ] lifecycle { @@ -513,7 +562,7 @@ resource "aws_ecs_service" "ignore_task_definition" { locals { # Role is not required if task definition uses `awsvpc` network mode or if a load balancer is not used - needs_iam_role = var.network_mode != "awsvpc" && length(var.load_balancer) > 0 + needs_iam_role = var.network_mode != "awsvpc" && var.load_balancer != null create_iam_role = var.create && var.create_iam_role && local.needs_iam_role iam_role_arn = local.needs_iam_role ? try(aws_iam_role.service[0].arn, var.iam_role_arn) : null @@ -567,18 +616,18 @@ data "aws_iam_policy_document" "service" { } dynamic "statement" { - for_each = var.iam_role_statements + for_each = var.iam_role_statements != null ? var.iam_role_statements : [] content { - sid = try(statement.value.sid, null) - actions = try(statement.value.actions, null) - not_actions = try(statement.value.not_actions, null) - effect = try(statement.value.effect, null) - resources = try(statement.value.resources, null) - not_resources = try(statement.value.not_resources, null) + sid = statement.value.sid + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources dynamic "principals" { - for_each = try(statement.value.principals, []) + for_each = statement.value.principals != null ? statement.value.principals : [] content { type = principals.value.type @@ -587,7 +636,7 @@ data "aws_iam_policy_document" "service" { } dynamic "not_principals" { - for_each = try(statement.value.not_principals, []) + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] content { type = not_principals.value.type @@ -596,7 +645,7 @@ data "aws_iam_policy_document" "service" { } dynamic "condition" { - for_each = try(statement.value.conditions, []) + for_each = statement.value.conditions != null ? statement.value.conditions : [] content { test = condition.value.test @@ -698,26 +747,7 @@ module "container_definition" { locals { create_task_definition = var.create && var.create_task_definition - - # This allows us to query both the existing as well as Terraform's state and get - # and get the max version of either source, useful for when external resources - # update the container definition - max_task_def_revision = local.create_task_definition ? max(aws_ecs_task_definition.this[0].revision, data.aws_ecs_task_definition.this[0].revision) : 0 - task_definition = local.create_task_definition ? "${aws_ecs_task_definition.this[0].family}:${local.max_task_def_revision}" : var.task_definition_arn -} - -# This allows us to query both the existing as well as Terraform's state and get -# and get the max version of either source, useful for when external resources -# update the container definition -data "aws_ecs_task_definition" "this" { - count = local.create_task_definition ? 1 : 0 - - task_definition = aws_ecs_task_definition.this[0].family - - depends_on = [ - # Needs to exist first on first deployment - aws_ecs_task_definition.this - ] + task_definition = local.create_task_definition ? aws_ecs_task_definition.this[0].arn : var.task_definition_arn } resource "aws_ecs_task_definition" "this" { @@ -728,7 +758,7 @@ resource "aws_ecs_task_definition" "this" { cpu = var.cpu dynamic "ephemeral_storage" { - for_each = length(var.ephemeral_storage) > 0 ? [var.ephemeral_storage] : [] + for_each = var.ephemeral_storage != null ? [var.ephemeral_storage] : [] content { size_in_gib = ephemeral_storage.value.size_in_gib @@ -739,7 +769,7 @@ resource "aws_ecs_task_definition" "this" { family = coalesce(var.family, var.name) dynamic "inference_accelerator" { - for_each = var.inference_accelerator + for_each = var.inference_accelerator != null ? [var.inference_accelerator] : [] content { device_name = inference_accelerator.value.device_name @@ -753,80 +783,81 @@ resource "aws_ecs_task_definition" "this" { pid_mode = var.pid_mode dynamic "placement_constraints" { - for_each = var.task_definition_placement_constraints + for_each = var.task_definition_placement_constraints != null ? var.task_definition_placement_constraints : {} content { - expression = try(placement_constraints.value.expression, null) + expression = placement_constraints.value.expression type = placement_constraints.value.type } } dynamic "proxy_configuration" { - for_each = length(var.proxy_configuration) > 0 ? [var.proxy_configuration] : [] + for_each = var.proxy_configuration != null ? [var.proxy_configuration] : [] content { container_name = proxy_configuration.value.container_name - properties = try(proxy_configuration.value.properties, null) - type = try(proxy_configuration.value.type, null) + properties = proxy_configuration.value.properties + type = proxy_configuration.value.type } } requires_compatibilities = var.requires_compatibilities dynamic "runtime_platform" { - for_each = length(var.runtime_platform) > 0 ? [var.runtime_platform] : [] + for_each = var.runtime_platform != null ? [var.runtime_platform] : [] content { - cpu_architecture = try(runtime_platform.value.cpu_architecture, null) - operating_system_family = try(runtime_platform.value.operating_system_family, null) + cpu_architecture = runtime_platform.value.cpu_architecture + operating_system_family = runtime_platform.value.operating_system_family } } skip_destroy = var.skip_destroy task_role_arn = try(aws_iam_role.tasks[0].arn, var.tasks_iam_role_arn) + track_latest = var.track_latest dynamic "volume" { - for_each = var.volume + for_each = var.volume != null ? var.volume : {} content { dynamic "docker_volume_configuration" { - for_each = try([volume.value.docker_volume_configuration], []) + for_each = volume.value.docker_volume_configuration != null ? [volume.value.docker_volume_configuration] : [] content { - autoprovision = try(docker_volume_configuration.value.autoprovision, null) - driver = try(docker_volume_configuration.value.driver, null) - driver_opts = try(docker_volume_configuration.value.driver_opts, null) - labels = try(docker_volume_configuration.value.labels, null) - scope = try(docker_volume_configuration.value.scope, null) + autoprovision = docker_volume_configuration.value.autoprovision + driver = docker_volume_configuration.value.driver + driver_opts = docker_volume_configuration.value.driver_opts + labels = docker_volume_configuration.value.labels + scope = docker_volume_configuration.value.scope } } dynamic "efs_volume_configuration" { - for_each = try([volume.value.efs_volume_configuration], []) + for_each = volume.value.efs_volume_configuration != null ? [volume.value.efs_volume_configuration] : [] content { dynamic "authorization_config" { - for_each = try([efs_volume_configuration.value.authorization_config], []) + for_each = efs_volume_configuration.value.authorization_config != null ? [efs_volume_configuration.value.authorization_config] : [] content { - access_point_id = try(authorization_config.value.access_point_id, null) - iam = try(authorization_config.value.iam, null) + access_point_id = authorization_config.value.access_point_id + iam = authorization_config.value.iam } } file_system_id = efs_volume_configuration.value.file_system_id - root_directory = try(efs_volume_configuration.value.root_directory, null) - transit_encryption = try(efs_volume_configuration.value.transit_encryption, null) - transit_encryption_port = try(efs_volume_configuration.value.transit_encryption_port, null) + root_directory = efs_volume_configuration.value.root_directory + transit_encryption = efs_volume_configuration.value.transit_encryption + transit_encryption_port = efs_volume_configuration.value.transit_encryption_port } } dynamic "fsx_windows_file_server_volume_configuration" { - for_each = try([volume.value.fsx_windows_file_server_volume_configuration], []) + for_each = volume.value.fsx_windows_file_server_volume_configuration != null ? [volume.value.fsx_windows_file_server_volume_configuration] : [] content { dynamic "authorization_config" { - for_each = try([fsx_windows_file_server_volume_configuration.value.authorization_config], []) + for_each = fsx_windows_file_server_volume_configuration.value.authorization_config != null ? [fsx_windows_file_server_volume_configuration.value.authorization_config] : [] content { credentials_parameter = authorization_config.value.credentials_parameter @@ -839,8 +870,8 @@ resource "aws_ecs_task_definition" "this" { } } - host_path = try(volume.value.host_path, null) - configure_at_launch = try(volume.value.configure_at_launch, null) + host_path = volume.value.host_path + configure_at_launch = volume.value.configure_at_launch name = try(volume.value.name, volume.key) } } @@ -953,18 +984,18 @@ data "aws_iam_policy_document" "task_exec" { } dynamic "statement" { - for_each = var.task_exec_iam_statements + for_each = var.task_exec_iam_statements != null ? var.task_exec_iam_statements : [] content { - sid = try(statement.value.sid, null) - actions = try(statement.value.actions, null) - not_actions = try(statement.value.not_actions, null) - effect = try(statement.value.effect, null) - resources = try(statement.value.resources, null) - not_resources = try(statement.value.not_resources, null) + sid = statement.value.sid + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources dynamic "principals" { - for_each = try(statement.value.principals, []) + for_each = statement.value.principals != null ? statement.value.principals : [] content { type = principals.value.type @@ -973,7 +1004,7 @@ data "aws_iam_policy_document" "task_exec" { } dynamic "not_principals" { - for_each = try(statement.value.not_principals, []) + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] content { type = not_principals.value.type @@ -982,7 +1013,7 @@ data "aws_iam_policy_document" "task_exec" { } dynamic "condition" { - for_each = try(statement.value.conditions, []) + for_each = statement.value.conditions != null ? statement.value.conditions : [] content { test = condition.value.test @@ -1072,7 +1103,7 @@ resource "aws_iam_role_policy_attachment" "tasks" { } data "aws_iam_policy_document" "tasks" { - count = local.create_tasks_iam_role && (length(var.tasks_iam_role_statements) > 0 || var.enable_execute_command) ? 1 : 0 + count = local.create_tasks_iam_role && (var.tasks_iam_role_statements != null || var.enable_execute_command) ? 1 : 0 dynamic "statement" { for_each = var.enable_execute_command ? [1] : [] @@ -1090,18 +1121,18 @@ data "aws_iam_policy_document" "tasks" { } dynamic "statement" { - for_each = var.tasks_iam_role_statements + for_each = var.tasks_iam_role_statements != null ? var.tasks_iam_role_statements : [] content { - sid = try(statement.value.sid, null) - actions = try(statement.value.actions, null) - not_actions = try(statement.value.not_actions, null) - effect = try(statement.value.effect, null) - resources = try(statement.value.resources, null) - not_resources = try(statement.value.not_resources, null) + sid = statement.value.sid + actions = statement.value.actions + not_actions = statement.value.not_actions + effect = statement.value.effect + resources = statement.value.resources + not_resources = statement.value.not_resources dynamic "principals" { - for_each = try(statement.value.principals, []) + for_each = statement.value.principals != null ? statement.value.principals : [] content { type = principals.value.type @@ -1110,7 +1141,7 @@ data "aws_iam_policy_document" "tasks" { } dynamic "not_principals" { - for_each = try(statement.value.not_principals, []) + for_each = statement.value.not_principals != null ? statement.value.not_principals : [] content { type = not_principals.value.type @@ -1119,7 +1150,7 @@ data "aws_iam_policy_document" "tasks" { } dynamic "condition" { - for_each = try(statement.value.conditions, []) + for_each = statement.value.conditions != null ? statement.value.conditions : [] content { test = condition.value.test @@ -1164,47 +1195,47 @@ resource "aws_ecs_task_set" "this" { } dynamic "load_balancer" { - for_each = var.load_balancer + for_each = var.load_balancer != null ? var.load_balancer : {} content { - load_balancer_name = try(load_balancer.value.load_balancer_name, null) - target_group_arn = try(load_balancer.value.target_group_arn, null) + load_balancer_name = load_balancer.value.load_balancer_name + target_group_arn = load_balancer.value.target_group_arn container_name = load_balancer.value.container_name - container_port = try(load_balancer.value.container_port, null) + container_port = load_balancer.value.container_port } } dynamic "service_registries" { - for_each = length(var.service_registries) > 0 ? [var.service_registries] : [] + for_each = var.service_registries != null ? [var.service_registries] : [] content { - container_name = try(service_registries.value.container_name, null) - container_port = try(service_registries.value.container_port, null) - port = try(service_registries.value.port, null) + container_name = service_registries.value.container_name + container_port = service_registries.value.container_port + port = service_registries.value.port registry_arn = service_registries.value.registry_arn } } - launch_type = length(var.capacity_provider_strategy) > 0 ? null : var.launch_type + launch_type = var.capacity_provider_strategy != null ? null : var.launch_type dynamic "capacity_provider_strategy" { - for_each = var.capacity_provider_strategy + for_each = var.capacity_provider_strategy != null ? var.capacity_provider_strategy : {} content { - base = try(capacity_provider_strategy.value.base, null) + base = capacity_provider_strategy.value.base capacity_provider = capacity_provider_strategy.value.capacity_provider - weight = try(capacity_provider_strategy.value.weight, null) + weight = capacity_provider_strategy.value.weight } } platform_version = local.is_fargate ? var.platform_version : null dynamic "scale" { - for_each = length(var.scale) > 0 ? [var.scale] : [] + for_each = var.scale != null ? [var.scale] : [] content { - unit = try(scale.value.unit, null) - value = try(scale.value.value, null) + unit = scale.value.unit + value = scale.value.value } } @@ -1245,47 +1276,47 @@ resource "aws_ecs_task_set" "ignore_task_definition" { } dynamic "load_balancer" { - for_each = var.load_balancer + for_each = var.load_balancer != null ? var.load_balancer : {} content { - load_balancer_name = try(load_balancer.value.load_balancer_name, null) - target_group_arn = try(load_balancer.value.target_group_arn, null) + load_balancer_name = load_balancer.value.load_balancer_name + target_group_arn = load_balancer.value.target_group_arn container_name = load_balancer.value.container_name - container_port = try(load_balancer.value.container_port, null) + container_port = load_balancer.value.container_port } } dynamic "service_registries" { - for_each = length(var.service_registries) > 0 ? [var.service_registries] : [] + for_each = var.service_registries != null ? [var.service_registries] : [] content { - container_name = try(service_registries.value.container_name, null) - container_port = try(service_registries.value.container_port, null) - port = try(service_registries.value.port, null) + container_name = service_registries.value.container_name + container_port = service_registries.value.container_port + port = service_registries.value.port registry_arn = service_registries.value.registry_arn } } - launch_type = length(var.capacity_provider_strategy) > 0 ? null : var.launch_type + launch_type = var.capacity_provider_strategy != null ? null : var.launch_type dynamic "capacity_provider_strategy" { - for_each = var.capacity_provider_strategy + for_each = var.capacity_provider_strategy != null ? var.capacity_provider_strategy : {} content { - base = try(capacity_provider_strategy.value.base, null) + base = capacity_provider_strategy.value.base capacity_provider = capacity_provider_strategy.value.capacity_provider - weight = try(capacity_provider_strategy.value.weight, null) + weight = capacity_provider_strategy.value.weight } } platform_version = local.is_fargate ? var.platform_version : null dynamic "scale" { - for_each = length(var.scale) > 0 ? [var.scale] : [] + for_each = var.scale != null ? [var.scale] : [] content { - unit = try(scale.value.unit, null) - value = try(scale.value.value, null) + unit = scale.value.unit + value = scale.value.value } } @@ -1430,7 +1461,7 @@ resource "aws_appautoscaling_policy" "this" { } resource "aws_appautoscaling_scheduled_action" "this" { - for_each = { for k, v in var.autoscaling_scheduled_actions : k => v if local.enable_autoscaling } + for_each = local.enable_autoscaling && var.autoscaling_scheduled_actions != null ? var.autoscaling_scheduled_actions : {} name = try(each.value.name, each.key) service_namespace = aws_appautoscaling_target.this[0].service_namespace @@ -1443,9 +1474,9 @@ resource "aws_appautoscaling_scheduled_action" "this" { } schedule = each.value.schedule - start_time = try(each.value.start_time, null) - end_time = try(each.value.end_time, null) - timezone = try(each.value.timezone, null) + start_time = each.value.start_time + end_time = each.value.end_time + timezone = each.value.timezone } ################################################################################ @@ -1482,23 +1513,44 @@ resource "aws_security_group" "this" { } } -resource "aws_security_group_rule" "this" { - for_each = { for k, v in var.security_group_rules : k => v if local.create_security_group } - - # Required - security_group_id = aws_security_group.this[0].id - protocol = each.value.protocol - from_port = each.value.from_port - to_port = each.value.to_port - type = each.value.type - - # Optional - description = lookup(each.value, "description", null) - cidr_blocks = lookup(each.value, "cidr_blocks", null) - ipv6_cidr_blocks = lookup(each.value, "ipv6_cidr_blocks", null) - prefix_list_ids = lookup(each.value, "prefix_list_ids", null) - self = lookup(each.value, "self", null) - source_security_group_id = lookup(each.value, "source_security_group_id", null) +resource "aws_vpc_security_group_ingress_rule" "this" { + for_each = var.security_group_ingress_rules != null && local.create_security_group ? var.security_group_ingress_rules : {} + + cidr_ipv4 = each.value.cidr_ipv4 + cidr_ipv6 = each.value.cidr_ipv6 + description = each.value.description + from_port = each.value.from_port + ip_protocol = each.value.ip_protocol + prefix_list_id = each.value.prefix_list_id + referenced_security_group_id = each.value.referenced_security_group_id + security_group_id = aws_security_group.this[0].id + tags = merge( + var.tags, + { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, + var.security_group_tags, + each.value.tags + ) + to_port = try(each.value.to_port, each.value.from_port) +} + +resource "aws_vpc_security_group_egress_rule" "this" { + for_each = var.security_group_egress_rules != null && local.create_security_group ? var.security_group_egress_rules : {} + + cidr_ipv4 = each.value.cidr_ipv4 + cidr_ipv6 = each.value.cidr_ipv6 + description = each.value.description + from_port = try(each.value.from_port, each.value.to_port) + ip_protocol = each.value.ip_protocol + prefix_list_id = each.value.prefix_list_id + referenced_security_group_id = each.value.referenced_security_group_id + security_group_id = aws_security_group.this[0].id + tags = merge( + var.tags, + { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, + var.security_group_tags, + each.value.tags + ) + to_port = each.value.to_port } ############################################################################################ @@ -1507,7 +1559,7 @@ resource "aws_security_group_rule" "this" { ############################################################################################ locals { - needs_infrastructure_iam_role = length(var.volume_configuration) > 0 + needs_infrastructure_iam_role = var.volume_configuration != null || var.vpc_lattice_configurations != null create_infrastructure_iam_role = var.create && var.create_infrastructure_iam_role && local.needs_infrastructure_iam_role infrastructure_iam_role_arn = local.needs_infrastructure_iam_role ? try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) : null infrastructure_iam_role_name = try(coalesce(var.infrastructure_iam_role_name, var.name), "") @@ -1542,10 +1594,16 @@ resource "aws_iam_role" "infrastructure_iam_role" { tags = merge(var.tags, var.infrastructure_iam_role_tags) } -# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ebs-volumes.html#ebs-volume-considerations/ resource "aws_iam_role_policy_attachment" "infrastructure_iam_role_ebs_policy" { - count = local.create_infrastructure_iam_role ? 1 : 0 + count = local.create_infrastructure_iam_role && var.volume_configuration != null ? 1 : 0 + + role = aws_iam_role.infrastructure_iam_role[0].name + policy_arn = "arn:${local.partition}:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" +} + +resource "aws_iam_role_policy_attachment" "infrastructure_iam_role_vpc_lattice_policy" { + count = local.create_infrastructure_iam_role && var.vpc_lattice_configurations != null ? 1 : 0 role = aws_iam_role.infrastructure_iam_role[0].name - policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" + policy_arn = "arn:${local.partition}:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVpcLattice" } diff --git a/modules/service/outputs.tf b/modules/service/outputs.tf index 2ca89ce8..0d81c8f9 100644 --- a/modules/service/outputs.tf +++ b/modules/service/outputs.tf @@ -59,11 +59,6 @@ output "task_definition_family" { value = try(aws_ecs_task_definition.this[0].family, null) } -output "task_definition_family_revision" { - description = "The family and revision (family:revision) of the task definition" - value = "${try(aws_ecs_task_definition.this[0].family, "")}:${local.max_task_def_revision}" -} - ################################################################################ # Task Execution - IAM Role # https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html diff --git a/modules/service/variables.tf b/modules/service/variables.tf index fad1c11a..0f29e49c 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -28,14 +28,28 @@ variable "ignore_task_definition_changes" { variable "alarms" { description = "Information about the CloudWatch alarms" - type = any - default = {} + type = object({ + alarm_names = list(string) + enable = optional(bool, true) + rollback = optional(bool, true) + }) + default = null +} + +variable "availability_zone_rebalancing" { + description = " ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. Defaults to `DISABLED`" + type = string + default = null } variable "capacity_provider_strategy" { description = "Capacity provider strategies to use for the service. Can be one or more" - type = any - default = {} + type = map(object({ + base = optional(number) + capacity_provider = string + weight = optional(number) + })) + default = null } variable "cluster_arn" { @@ -46,26 +60,31 @@ variable "cluster_arn" { variable "deployment_circuit_breaker" { description = "Configuration block for deployment circuit breaker" - type = any - default = {} + type = object({ + enable = bool + rollback = bool + }) + default = null } variable "deployment_controller" { description = "Configuration block for deployment controller configuration" - type = any - default = {} + type = object({ + type = optional(string) + }) + default = null } variable "deployment_maximum_percent" { description = "Upper limit (as a percentage of the service's `desired_count`) of the number of running tasks that can be running in a service during a deployment" type = number - default = 200 + default = null } variable "deployment_minimum_healthy_percent" { description = "Lower limit (as a percentage of the service's `desired_count`) of the number of running tasks that must remain running and healthy in a service during a deployment" type = number - default = 66 + default = null } variable "desired_count" { @@ -86,6 +105,12 @@ variable "enable_execute_command" { default = false } +variable "force_delete" { + description = "Enable to delete a service even if it wasn't scaled down to zero tasks. It's only necessary to use this if the service uses the `REPLICA` scheduling strategy" + type = bool + default = null +} + variable "force_new_deployment" { description = "Enable to force a new task deployment of the service. This can be used to update tasks to use a newer Docker image with same image/tag combination, roll Fargate tasks onto a newer platform version, or immediately deploy `ordered_placement_strategy` and `placement_constraints` updates" type = bool @@ -106,8 +131,13 @@ variable "launch_type" { variable "load_balancer" { description = "Configuration block for load balancers" - type = any - default = {} + type = map(object({ + container_name = string + container_port = number + elb_name = optional(string) + target_group_arn = optional(string) + })) + default = null } variable "name" { @@ -136,14 +166,20 @@ variable "subnet_ids" { variable "ordered_placement_strategy" { description = "Service level strategy rules that are taken into consideration during task placement. List from top to bottom in order of precedence" - type = any - default = {} + type = map(object({ + field = optional(string) + type = string + })) + default = null } variable "placement_constraints" { description = "Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the service, see `task_definition_placement_constraints` for setting at the task definition" - type = any - default = {} + type = map(object({ + expression = optional(string) + type = string + })) + default = null } variable "platform_version" { @@ -166,26 +202,66 @@ variable "scheduling_strategy" { variable "service_connect_configuration" { description = "The ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace" - type = any - default = {} + type = object({ + enabled = optional(bool, true) + log_configuration = optional(object({ + log_driver = string + options = optional(map(string)) + secret_option = optional(object({ + name = string + value_from = string + })) + })) + namespace = optional(string) + service = optional(list(object({ + client_alias = optional(object({ + dns_name = optional(string) + port = number + })) + discovery_name = optional(string) + ingress_port_override = optional(number) + port_name = string + timeout = optional(object({ + idle_timeout_seconds = optional(number) + per_request_timeout_seconds = optional(number) + })) + tls = optional(object({ + issuer_cert_authority = optional(object({ + aws_pca_authority_arn = string + })) + kms_key = optional(string) + role_arn = optional(string) + })) + }))) + }) + default = null } variable "service_registries" { description = "Service discovery registries for the service" - type = any - default = {} + type = object({ + container_name = optional(string) + container_port = optional(number) + port = optional(number) + registry_arn = string + }) + default = null } variable "timeouts" { description = "Create, update, and delete timeout configurations for the service" - type = map(string) - default = {} + type = object({ + create = optional(string) + update = optional(string) + delete = optional(string) + }) + default = null } variable "triggers" { description = "Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()`" - type = any - default = {} + type = map(string) + default = null } variable "wait_for_steady_state" { @@ -194,6 +270,39 @@ variable "wait_for_steady_state" { default = null } +variable "volume_configuration" { + description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time" + type = object({ + name = string + managed_ebs_volume = list(object({ + encrypted = optional(bool) + file_system_type = optional(string) + iops = optional(number) + kms_key_id = optional(string) + size_in_gb = optional(number) + snapshot_id = optional(string) + throughput = optional(number) + volume_type = optional(string) + tag_specification = optional(list(object({ + resource_type = string + propagate_tags = optional(string, "TASK_DEFINITION") + tags = optional(map(string)) + }))) + })) + }) + default = null +} + +variable "vpc_lattice_configurations" { + description = "The VPC Lattice configuration for your service that allows Lattice to connect, secure, and monitor your service across multiple accounts and VPCs" + type = object({ + role_arn = string + target_group_arn = string + port_name = string + }) + default = null +} + variable "service_tags" { description = "A map of additional tags to add to the service" type = map(string) @@ -254,8 +363,28 @@ variable "iam_role_tags" { variable "iam_role_statements" { description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" - type = any - default = {} + type = list(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string) + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + values = list(string) + variable = string + }))) + })) + default = null } ################################################################################ @@ -294,8 +423,10 @@ variable "cpu" { variable "ephemeral_storage" { description = "The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate" - type = any - default = {} + type = object({ + size_in_gib = number + }) + default = null } variable "family" { @@ -306,8 +437,11 @@ variable "family" { variable "inference_accelerator" { description = "Configuration block(s) with Inference Accelerators settings" - type = any - default = {} + type = object({ + device_name = string + device_type = string + }) + default = null } variable "ipc_mode" { @@ -336,14 +470,21 @@ variable "pid_mode" { variable "task_definition_placement_constraints" { description = "Configuration block for rules that are taken into consideration during task placement (up to max of 10). This is set at the task definition, see `placement_constraints` for setting at the service" - type = any - default = {} + type = map(object({ + expression = optional(string) + type = string + })) + default = null } variable "proxy_configuration" { description = "Configuration block for the App Mesh proxy" - type = any - default = {} + type = object({ + container_name = string + properties = optional(map(string)) + type = optional(string) + }) + default = null } variable "requires_compatibilities" { @@ -354,13 +495,22 @@ variable "requires_compatibilities" { variable "runtime_platform" { description = "Configuration block for `runtime_platform` that containers in your task may use" - type = any + type = object({ + cpu_architecture = optional(string, "X86_64") + operating_system_family = optional(string, "LINUX") + }) default = { operating_system_family = "LINUX" cpu_architecture = "X86_64" } } +variable "track_latest" { + description = "Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource" + type = bool + default = true +} + variable "skip_destroy" { description = "If true, the task is not deleted when the service is deleted" type = bool @@ -369,14 +519,37 @@ variable "skip_destroy" { variable "volume" { description = "Configuration block for volumes that containers in your task may use" - type = any - default = {} -} - -variable "volume_configuration" { - description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume" - type = any - default = {} + type = map(object({ + configure_at_launch = optional(bool) + docker_volume_configuration = optional(object({ + autoprovision = optional(bool) + driver = optional(string) + driver_opts = optional(map(string)) + labels = optional(map(string)) + scope = optional(string) + })) + efs_volume_configuration = optional(object({ + authorization_config = optional(object({ + access_point_id = optional(string) + iam = optional(string) + })) + file_system_id = string + root_directory = optional(string) + transit_encryption = optional(string) + transit_encryption_port = optional(number) + })) + fsx_windows_file_server_volume_configuration = optional(object({ + authorization_config = optional(object({ + credentials_parameter = string + domain = string + })) + file_system_id = string + root_directory = string + })) + host_path = optional(string) + name = optional(string) + })) + default = null } variable "task_tags" { @@ -470,8 +643,28 @@ variable "task_exec_secret_arns" { variable "task_exec_iam_statements" { description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" - type = any - default = {} + type = list(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string) + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + values = list(string) + variable = string + }))) + })) + default = null } variable "task_exec_iam_policy_path" { @@ -541,8 +734,28 @@ variable "tasks_iam_role_policies" { variable "tasks_iam_role_statements" { description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" - type = any - default = {} + type = list(object({ + sid = optional(string) + actions = optional(list(string)) + not_actions = optional(list(string)) + effect = optional(string) + resources = optional(list(string)) + not_resources = optional(list(string)) + principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + not_principals = optional(list(object({ + type = string + identifiers = list(string) + }))) + condition = optional(list(object({ + test = string + values = list(string) + variable = string + }))) + })) + default = null } ################################################################################ @@ -557,14 +770,11 @@ variable "external_id" { variable "scale" { description = "A floating-point percentage of the desired number of tasks to place and keep running in the task set" - type = any - default = {} -} - -variable "force_delete" { - description = "Whether to allow deleting the task set without waiting for scaling down to 0" - type = bool - default = null + type = object({ + unit = optional(string) + value = optional(number) + }) + default = null } variable "wait_until_stable" { @@ -628,8 +838,16 @@ variable "autoscaling_policies" { variable "autoscaling_scheduled_actions" { description = "Map of autoscaling scheduled actions to create for the service" - type = any - default = {} + type = map(object({ + name = optional(string) + min_capacity = number + max_capacity = number + schedule = string + start_time = optional(string) + end_time = optional(string) + timezone = optional(string) + })) + default = null } ################################################################################ @@ -660,10 +878,36 @@ variable "security_group_description" { default = null } -variable "security_group_rules" { - description = "Security group rules to add to the security group created" - type = any - default = {} +variable "security_group_ingress_rules" { + description = "Security group ingress rules to add to the security group created" + type = map(object({ + cidr_ipv4 = optional(string) + cidr_ipv6 = optional(string) + description = optional(string) + from_port = optional(string) + ip_protocol = optional(string) + prefix_list_id = optional(string) + referenced_security_group_id = optional(string) + tags = optional(map(string), {}) + to_port = optional(string) + })) + default = null +} + +variable "security_group_egress_rules" { + description = "Security group egress rules to add to the security group created" + type = map(object({ + cidr_ipv4 = optional(string) + cidr_ipv6 = optional(string) + description = optional(string) + from_port = optional(string) + ip_protocol = optional(string) + prefix_list_id = optional(string) + referenced_security_group_id = optional(string) + tags = optional(map(string), {}) + to_port = optional(string) + })) + default = null } variable "security_group_tags" { diff --git a/modules/service/versions.tf b/modules/service/versions.tf index 790c7ad1..aebe26a1 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/versions.tf b/versions.tf index 790c7ad1..aebe26a1 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index 790c7ad1..aebe26a1 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index 790c7ad1..aebe26a1 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 5885f3d9..981b62e2 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -3,7 +3,7 @@ module "wrapper" { for_each = var.items - alarms = try(each.value.alarms, var.defaults.alarms, {}) + alarms = try(each.value.alarms, var.defaults.alarms, null) assign_public_ip = try(each.value.assign_public_ip, var.defaults.assign_public_ip, false) autoscaling_max_capacity = try(each.value.autoscaling_max_capacity, var.defaults.autoscaling_max_capacity, 10) autoscaling_min_capacity = try(each.value.autoscaling_min_capacity, var.defaults.autoscaling_min_capacity, 1) @@ -27,8 +27,9 @@ module "wrapper" { } } }) - autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {}) - capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {}) + autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, null) + availability_zone_rebalancing = try(each.value.availability_zone_rebalancing, var.defaults.availability_zone_rebalancing, null) + capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, null) cluster_arn = try(each.value.cluster_arn, var.defaults.cluster_arn, "") container_definition_defaults = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {}) container_definitions = try(each.value.container_definitions, var.defaults.container_definitions, {}) @@ -42,15 +43,15 @@ module "wrapper" { create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true) create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) create_tasks_iam_role = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true) - deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {}) - deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, {}) - deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200) - deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66) + deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, null) + deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, null) + deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, null) + deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, null) desired_count = try(each.value.desired_count, var.defaults.desired_count, 1) enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) - ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {}) + ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, null) external_id = try(each.value.external_id, var.defaults.external_id, null) family = try(each.value.family, var.defaults.family, null) force_delete = try(each.value.force_delete, var.defaults.force_delete, null) @@ -61,11 +62,11 @@ module "wrapper" { iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) - iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {}) + iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, null) iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) - inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {}) + inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, null) infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, var.defaults.infrastructure_iam_role_arn, null) infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, var.defaults.infrastructure_iam_role_description, null) infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, var.defaults.infrastructure_iam_role_name, null) @@ -75,37 +76,38 @@ module "wrapper" { infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, var.defaults.infrastructure_iam_role_use_name_prefix, true) ipc_mode = try(each.value.ipc_mode, var.defaults.ipc_mode, null) launch_type = try(each.value.launch_type, var.defaults.launch_type, "FARGATE") - load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, {}) + load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, null) memory = try(each.value.memory, var.defaults.memory, 2048) name = try(each.value.name, var.defaults.name, null) network_mode = try(each.value.network_mode, var.defaults.network_mode, "awsvpc") - ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {}) + ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, null) pid_mode = try(each.value.pid_mode, var.defaults.pid_mode, null) - placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, {}) + placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, null) platform_version = try(each.value.platform_version, var.defaults.platform_version, null) propagate_tags = try(each.value.propagate_tags, var.defaults.propagate_tags, null) - proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {}) + proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, null) requires_compatibilities = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"]) runtime_platform = try(each.value.runtime_platform, var.defaults.runtime_platform, { operating_system_family = "LINUX" cpu_architecture = "X86_64" }) - scale = try(each.value.scale, var.defaults.scale, {}) + scale = try(each.value.scale, var.defaults.scale, null) scheduling_strategy = try(each.value.scheduling_strategy, var.defaults.scheduling_strategy, null) security_group_description = try(each.value.security_group_description, var.defaults.security_group_description, null) + security_group_egress_rules = try(each.value.security_group_egress_rules, var.defaults.security_group_egress_rules, null) security_group_ids = try(each.value.security_group_ids, var.defaults.security_group_ids, []) + security_group_ingress_rules = try(each.value.security_group_ingress_rules, var.defaults.security_group_ingress_rules, null) security_group_name = try(each.value.security_group_name, var.defaults.security_group_name, null) - security_group_rules = try(each.value.security_group_rules, var.defaults.security_group_rules, {}) security_group_tags = try(each.value.security_group_tags, var.defaults.security_group_tags, {}) security_group_use_name_prefix = try(each.value.security_group_use_name_prefix, var.defaults.security_group_use_name_prefix, true) - service_connect_configuration = try(each.value.service_connect_configuration, var.defaults.service_connect_configuration, {}) - service_registries = try(each.value.service_registries, var.defaults.service_registries, {}) + service_connect_configuration = try(each.value.service_connect_configuration, var.defaults.service_connect_configuration, null) + service_registries = try(each.value.service_registries, var.defaults.service_registries, null) service_tags = try(each.value.service_tags, var.defaults.service_tags, {}) skip_destroy = try(each.value.skip_destroy, var.defaults.skip_destroy, null) subnet_ids = try(each.value.subnet_ids, var.defaults.subnet_ids, []) tags = try(each.value.tags, var.defaults.tags, {}) task_definition_arn = try(each.value.task_definition_arn, var.defaults.task_definition_arn, null) - task_definition_placement_constraints = try(each.value.task_definition_placement_constraints, var.defaults.task_definition_placement_constraints, {}) + task_definition_placement_constraints = try(each.value.task_definition_placement_constraints, var.defaults.task_definition_placement_constraints, null) task_exec_iam_policy_path = try(each.value.task_exec_iam_policy_path, var.defaults.task_exec_iam_policy_path, null) task_exec_iam_role_arn = try(each.value.task_exec_iam_role_arn, var.defaults.task_exec_iam_role_arn, null) task_exec_iam_role_description = try(each.value.task_exec_iam_role_description, var.defaults.task_exec_iam_role_description, null) @@ -116,7 +118,7 @@ module "wrapper" { task_exec_iam_role_policies = try(each.value.task_exec_iam_role_policies, var.defaults.task_exec_iam_role_policies, {}) task_exec_iam_role_tags = try(each.value.task_exec_iam_role_tags, var.defaults.task_exec_iam_role_tags, {}) task_exec_iam_role_use_name_prefix = try(each.value.task_exec_iam_role_use_name_prefix, var.defaults.task_exec_iam_role_use_name_prefix, true) - task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, {}) + task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, null) task_exec_secret_arns = try(each.value.task_exec_secret_arns, var.defaults.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"]) task_exec_ssm_param_arns = try(each.value.task_exec_ssm_param_arns, var.defaults.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"]) tasks_iam_role_arn = try(each.value.tasks_iam_role_arn, var.defaults.tasks_iam_role_arn, null) @@ -125,14 +127,16 @@ module "wrapper" { tasks_iam_role_path = try(each.value.tasks_iam_role_path, var.defaults.tasks_iam_role_path, null) tasks_iam_role_permissions_boundary = try(each.value.tasks_iam_role_permissions_boundary, var.defaults.tasks_iam_role_permissions_boundary, null) tasks_iam_role_policies = try(each.value.tasks_iam_role_policies, var.defaults.tasks_iam_role_policies, {}) - tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, {}) + tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, null) tasks_iam_role_tags = try(each.value.tasks_iam_role_tags, var.defaults.tasks_iam_role_tags, {}) tasks_iam_role_use_name_prefix = try(each.value.tasks_iam_role_use_name_prefix, var.defaults.tasks_iam_role_use_name_prefix, true) task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) - timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) - triggers = try(each.value.triggers, var.defaults.triggers, {}) - volume = try(each.value.volume, var.defaults.volume, {}) - volume_configuration = try(each.value.volume_configuration, var.defaults.volume_configuration, {}) + timeouts = try(each.value.timeouts, var.defaults.timeouts, null) + track_latest = try(each.value.track_latest, var.defaults.track_latest, true) + triggers = try(each.value.triggers, var.defaults.triggers, null) + volume = try(each.value.volume, var.defaults.volume, null) + volume_configuration = try(each.value.volume_configuration, var.defaults.volume_configuration, null) + vpc_lattice_configurations = try(each.value.vpc_lattice_configurations, var.defaults.vpc_lattice_configurations, null) wait_for_steady_state = try(each.value.wait_for_steady_state, var.defaults.wait_for_steady_state, null) wait_until_stable = try(each.value.wait_until_stable, var.defaults.wait_until_stable, null) wait_until_stable_timeout = try(each.value.wait_until_stable_timeout, var.defaults.wait_until_stable_timeout, null) diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index 790c7ad1..aebe26a1 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 790c7ad1..aebe26a1 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.3" + required_version = ">= 1.3.10" required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.63" + version = ">= 5.77" } } } From 4f98ff1299b291e79a7e57ffe0a3bfccf5fe6701 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Sat, 23 Nov 2024 14:14:18 -0600 Subject: [PATCH 11/17] refactor: Initial pass at variable type definitions for container definition module --- .pre-commit-config.yaml | 2 +- examples/fargate/main.tf | 10 +- modules/container-definition/README.md | 63 ++++---- modules/container-definition/main.tf | 73 +++++----- modules/container-definition/variables.tf | 167 ++++++++++++++-------- modules/service/main.tf | 91 ++++++------ wrappers/container-definition/main.tf | 81 ++++++----- 7 files changed, 271 insertions(+), 216 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7900442e..fb99ea11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - '--args=--only=terraform_documented_variables' - '--args=--only=terraform_typed_variables' - '--args=--only=terraform_module_pinned_source' - - '--args=--only=terraform_naming_convention' + # - '--args=--only=terraform_naming_convention' # Disabled due to container definition variables requiring camelCase - '--args=--only=terraform_required_version' - '--args=--only=terraform_required_providers' - '--args=--only=terraform_standard_module_structure' diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index 0cde7c8b..d9b45a48 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -162,15 +162,14 @@ module "ecs_service" { subnet_ids = module.vpc.private_subnets security_group_ingress_rules = { alb_ingress_3000 = { - description = "Service port" - from_port = local.container_port - ip_protocol = "tcp" - source_security_group_id = module.alb.security_group_id + description = "Service port" + from_port = local.container_port + ip_protocol = "tcp" + referenced_security_group_id = module.alb.security_group_id } } security_group_egress_rules = { egress_all = { - to_port = 0 ip_protocol = "-1" cidr_ipv4 = "0.0.0.0/0" } @@ -226,7 +225,6 @@ module "ecs_task_definition" { security_group_egress_rules = { egress_all = { - to_port = 0 ip_protocol = "-1" cidr_ipv4 = "0.0.0.0/0" } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index d2c0521a..0f1d8cc2 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -139,56 +139,57 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [cloudwatch\_log\_group\_class](#input\_cloudwatch\_log\_group\_class) | Specified the log class of the log group. Possible values are: `STANDARD` or `INFREQUENT_ACCESS` | `string` | `null` | no | | [cloudwatch\_log\_group\_kms\_key\_id](#input\_cloudwatch\_log\_group\_kms\_key\_id) | If a KMS Key ARN is set, this key will be used to encrypt the corresponding log group. Please be sure that the KMS Key has an appropriate key policy (https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html) | `string` | `null` | no | | [cloudwatch\_log\_group\_name](#input\_cloudwatch\_log\_group\_name) | Custom name of CloudWatch log group for a service associated with the container definition | `string` | `null` | no | | [cloudwatch\_log\_group\_retention\_in\_days](#input\_cloudwatch\_log\_group\_retention\_in\_days) | Number of days to retain log events. Default is 30 days | `number` | `30` | no | | [cloudwatch\_log\_group\_use\_name\_prefix](#input\_cloudwatch\_log\_group\_use\_name\_prefix) | Determines whether the log group name should be used as a prefix | `bool` | `false` | no | -| [command](#input\_command) | The command that's passed to the container | `list(string)` | `[]` | no | +| [command](#input\_command) | The command that's passed to the container | `list(string)` | `null` | no | | [cpu](#input\_cpu) | The number of cpu units to reserve for the container. This is optional for tasks using Fargate launch type and the total amount of `cpu` of all containers in a task will need to be lower than the task-level cpu value | `number` | `null` | no | | [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Determines whether a log group is created by this module. If not, AWS will automatically create one if logging is enabled | `bool` | `true` | no | -| [dependencies](#input\_dependencies) | The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. The condition can be one of START, COMPLETE, SUCCESS or HEALTHY |
list(object({
condition = string
containerName = string
}))
| `[]` | no | -| [disable\_networking](#input\_disable\_networking) | When this parameter is true, networking is disabled within the container | `bool` | `null` | no | -| [dns\_search\_domains](#input\_dns\_search\_domains) | Container DNS search domains. A list of DNS search domains that are presented to the container | `list(string)` | `[]` | no | -| [dns\_servers](#input\_dns\_servers) | Container DNS servers. This is a list of strings specifying the IP addresses of the DNS servers | `list(string)` | `[]` | no | -| [docker\_labels](#input\_docker\_labels) | A key/value map of labels to add to the container | `map(string)` | `{}` | no | -| [docker\_security\_options](#input\_docker\_security\_options) | A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn't valid for containers in tasks using the Fargate launch type | `list(string)` | `[]` | no | +| [dependsOn](#input\_dependsOn) | The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. The condition can be one of START, COMPLETE, SUCCESS or HEALTHY |
list(object({
condition = string
containerName = string
}))
| `null` | no | +| [disableNetworking](#input\_disableNetworking) | When this parameter is true, networking is disabled within the container | `bool` | `null` | no | +| [dnsSearchDomains](#input\_dnsSearchDomains) | Container DNS search domains. A list of DNS search domains that are presented to the container | `list(string)` | `null` | no | +| [dnsServers](#input\_dnsServers) | Container DNS servers. This is a list of strings specifying the IP addresses of the DNS servers | `list(string)` | `null` | no | +| [dockerLabels](#input\_dockerLabels) | A key/value map of labels to add to the container | `map(string)` | `null` | no | +| [dockerSecurityOptions](#input\_dockerSecurityOptions) | A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn't valid for containers in tasks using the Fargate launch type | `list(string)` | `null` | no | | [enable\_cloudwatch\_logging](#input\_enable\_cloudwatch\_logging) | Determines whether CloudWatch logging is configured for this container definition. Set to `false` to use other logging drivers | `bool` | `true` | no | | [enable\_execute\_command](#input\_enable\_execute\_command) | Specifies whether to enable Amazon ECS Exec for the tasks within the service | `bool` | `false` | no | -| [entrypoint](#input\_entrypoint) | The entry point that is passed to the container | `list(string)` | `[]` | no | -| [environment](#input\_environment) | The environment variables to pass to the container |
list(object({
name = string
value = string
}))
| `[]` | no | -| [environment\_files](#input\_environment\_files) | A list of files containing the environment variables to pass to a container |
list(object({
value = string
type = string
}))
| `[]` | no | +| [entrypoint](#input\_entrypoint) | The entry point that is passed to the container | `list(string)` | `null` | no | +| [environment](#input\_environment) | The environment variables to pass to the container |
list(object({
name = string
value = string
}))
| `null` | no | +| [environmentFiles](#input\_environmentFiles) | A list of files containing the environment variables to pass to a container |
list(object({
value = string
type = string
}))
| `null` | no | | [essential](#input\_essential) | If the `essential` parameter of a container is marked as `true`, and that container fails or stops for any reason, all other containers that are part of the task are stopped | `bool` | `null` | no | -| [extra\_hosts](#input\_extra\_hosts) | A list of hostnames and IP address mappings to append to the `/etc/hosts` file on the container |
list(object({
hostname = string
ipAddress = string
}))
| `[]` | no | -| [firelens\_configuration](#input\_firelens\_configuration) | The FireLens configuration for the container. This is used to specify and configure a log router for container logs. For more information, see [Custom Log Routing](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_firelens.html) in the Amazon Elastic Container Service Developer Guide | `any` | `{}` | no | -| [health\_check](#input\_health\_check) | The container health check command and associated configuration parameters for the container. See [HealthCheck](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_HealthCheck.html) | `any` | `{}` | no | +| [extraHosts](#input\_extraHosts) | A list of hostnames and IP address mappings to append to the `/etc/hosts` file on the container |
list(object({
hostname = string
ipAddress = string
}))
| `null` | no | +| [firelensConfiguration](#input\_firelensConfiguration) | The FireLens configuration for the container. This is used to specify and configure a log router for container logs. For more information, see [Custom Log Routing](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_firelens.html) in the Amazon Elastic Container Service Developer Guide |
object({
options = optional(map(string), {})
type = optional(string)
})
| `null` | no | +| [healthCheck](#input\_healthCheck) | The container health check command and associated configuration parameters for the container. See [HealthCheck](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_HealthCheck.html) |
object({
command = optional(list(string), [])
interval = optional(number, 30)
retries = optional(number, 3)
startPeriod = optional(number)
timeout = optional(number, 5)
})
| `null` | no | | [hostname](#input\_hostname) | The hostname to use for your container | `string` | `null` | no | | [image](#input\_image) | The image used to start a container. This string is passed directly to the Docker daemon. By default, images in the Docker Hub registry are available. Other repositories are specified with either `repository-url/image:tag` or `repository-url/image@digest` | `string` | `null` | no | | [interactive](#input\_interactive) | When this parameter is `true`, you can deploy containerized applications that require `stdin` or a `tty` to be allocated | `bool` | `false` | no | -| [links](#input\_links) | The links parameter allows containers to communicate with each other without the need for port mappings. This parameter is only supported if the network mode of a task definition is `bridge` | `list(string)` | `[]` | no | -| [linux\_parameters](#input\_linux\_parameters) | Linux-specific modifications that are applied to the container, such as Linux kernel capabilities. For more information see [KernelCapabilities](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_KernelCapabilities.html) | `any` | `{}` | no | -| [log\_configuration](#input\_log\_configuration) | The log configuration for the container. For more information see [LogConfiguration](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html) | `any` | `{}` | no | +| [links](#input\_links) | The links parameter allows containers to communicate with each other without the need for port mappings. This parameter is only supported if the network mode of a task definition is `bridge` | `list(string)` | `null` | no | +| [linuxParameters](#input\_linuxParameters) | Linux-specific modifications that are applied to the container, such as Linux kernel capabilities. For more information see [KernelCapabilities](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_KernelCapabilities.html) |
object({
capabilities = optional(object({
add = optional(list(string))
drop = optional(list(string))
}))
devices = optional(list(object({
containerPath = optional(string)
hostPath = optional(string)
permissions = optional(list(string))
})))
initProcessEnabled = optional(bool, false)
maxSwap = optional(number)
sharedMemorySize = optional(number)
swappiness = optional(number)
tmpfs = optional(list(object({
containerPath = string
mountOptions = optional(list(string))
size = number
})))
})
|
{
"initProcessEnabled": false
}
| no | +| [logConfiguration](#input\_logConfiguration) | The log configuration for the container. For more information see [LogConfiguration](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html) | `any` | `{}` | no | | [memory](#input\_memory) | The amount (in MiB) of memory to present to the container. If your container attempts to exceed the memory specified here, the container is killed. The total amount of memory reserved for all containers within a task must be lower than the task `memory` value, if one is specified | `number` | `null` | no | -| [memory\_reservation](#input\_memory\_reservation) | The soft limit (in MiB) of memory to reserve for the container. When system memory is under heavy contention, Docker attempts to keep the container memory to this soft limit. However, your container can consume more memory when it needs to, up to either the hard limit specified with the `memory` parameter (if applicable), or all of the available memory on the container instance | `number` | `null` | no | -| [mount\_points](#input\_mount\_points) | The mount points for data volumes in your container | `list(any)` | `[]` | no | +| [memoryReservation](#input\_memoryReservation) | The soft limit (in MiB) of memory to reserve for the container. When system memory is under heavy contention, Docker attempts to keep the container memory to this soft limit. However, your container can consume more memory when it needs to, up to either the hard limit specified with the `memory` parameter (if applicable), or all of the available memory on the container instance | `number` | `null` | no | +| [mountPoints](#input\_mountPoints) | The mount points for data volumes in your container | `list(any)` | `null` | no | | [name](#input\_name) | The name of a container. If you're linking multiple containers together in a task definition, the name of one container can be entered in the links of another container to connect the containers. Up to 255 letters (uppercase and lowercase), numbers, underscores, and hyphens are allowed | `string` | `null` | no | | [operating\_system\_family](#input\_operating\_system\_family) | The OS family for task | `string` | `"LINUX"` | no | -| [port\_mappings](#input\_port\_mappings) | The list of port mappings for the container. Port mappings allow containers to access ports on the host container instance to send or receive traffic. For task definitions that use the awsvpc network mode, only specify the containerPort. The hostPort can be left blank or it must be the same value as the containerPort | `list(any)` | `[]` | no | +| [portMappings](#input\_portMappings) | The list of port mappings for the container. Port mappings allow containers to access ports on the host container instance to send or receive traffic. For task definitions that use the awsvpc network mode, only specify the containerPort. The hostPort can be left blank or it must be the same value as the containerPort |
list(object({
appProtocol = optional(string)
containerPort = number
hostPort = optional(number)
name = string
protocol = optional(string)
}))
| `null` | no | | [privileged](#input\_privileged) | When this parameter is true, the container is given elevated privileges on the host container instance (similar to the root user) | `bool` | `false` | no | -| [pseudo\_terminal](#input\_pseudo\_terminal) | When this parameter is true, a `TTY` is allocated | `bool` | `false` | no | -| [readonly\_root\_filesystem](#input\_readonly\_root\_filesystem) | When this parameter is true, the container is given read-only access to its root file system | `bool` | `true` | no | -| [repository\_credentials](#input\_repository\_credentials) | Container repository credentials; required when using a private repo. This map currently supports a single key; "credentialsParameter", which should be the ARN of a Secrets Manager's secret holding the credentials | `map(string)` | `{}` | no | -| [resource\_requirements](#input\_resource\_requirements) | The type and amount of a resource to assign to a container. The only supported resource is a GPU |
list(object({
type = string
value = string
}))
| `[]` | no | -| [restart\_policy](#input\_restart\_policy) | Container restart policy; helps overcome transient failures faster and maintain task availability |
object({
enabled = optional(bool)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
})
| `null` | no | -| [secrets](#input\_secrets) | The secrets to pass to the container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the Amazon Elastic Container Service Developer Guide |
list(object({
name = string
valueFrom = string
}))
| `[]` | no | +| [pseudoTerminal](#input\_pseudoTerminal) | When this parameter is true, a `TTY` is allocated | `bool` | `false` | no | +| [readonlyRootFilesystem](#input\_readonlyRootFilesystem) | When this parameter is true, the container is given read-only access to its root file system | `bool` | `true` | no | +| [repositoryCredentials](#input\_repositoryCredentials) | Container repository credentials; required when using a private repo. This map currently supports a single key; "credentialsParameter", which should be the ARN of a Secrets Manager's secret holding the credentials | `map(string)` | `null` | no | +| [resourceRequirements](#input\_resourceRequirements) | The type and amount of a resource to assign to a container. The only supported resource is a GPU |
list(object({
type = string
value = string
}))
| `null` | no | +| [restartPolicy](#input\_restartPolicy) | Container restart policy; helps overcome transient failures faster and maintain task availability |
object({
enabled = optional(bool, true)
ignoredExitCodes = optional(list(number))
restartAttemptPeriod = optional(number)
})
|
{
"enabled": true
}
| no | +| [secrets](#input\_secrets) | The secrets to pass to the container. For more information, see [Specifying Sensitive Data](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/specifying-sensitive-data.html) in the Amazon Elastic Container Service Developer Guide |
list(object({
name = string
valueFrom = string
}))
| `null` | no | | [service](#input\_service) | The name of the service that the container definition is associated with | `string` | `""` | no | -| [start\_timeout](#input\_start\_timeout) | Time duration (in seconds) to wait before giving up on resolving dependencies for a container | `number` | `30` | no | -| [stop\_timeout](#input\_stop\_timeout) | Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own | `number` | `120` | no | -| [system\_controls](#input\_system\_controls) | A list of namespaced kernel parameters to set in the container | `list(map(string))` | `[]` | no | +| [startTimeout](#input\_startTimeout) | Time duration (in seconds) to wait before giving up on resolving dependencies for a container | `number` | `30` | no | +| [stopTimeout](#input\_stopTimeout) | Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own | `number` | `120` | no | +| [systemControls](#input\_systemControls) | A list of namespaced kernel parameters to set in the container | `list(map(string))` | `null` | no | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | -| [ulimits](#input\_ulimits) | A list of ulimits to set in the container. If a ulimit value is specified in a task definition, it overrides the default values set by Docker |
list(object({
hardLimit = number
name = string
softLimit = number
}))
| `[]` | no | +| [ulimits](#input\_ulimits) | A list of ulimits to set in the container. If a ulimit value is specified in a task definition, it overrides the default values set by Docker |
list(object({
hardLimit = number
name = string
softLimit = number
}))
| `null` | no | | [user](#input\_user) | The user to run as inside the container. Can be any of these formats: user, user:group, uid, uid:gid, user:gid, uid:group. The default (null) will use the container's configured `USER` directive or root if not set | `string` | `null` | no | -| [volumes\_from](#input\_volumes\_from) | Data volumes to mount from another container | `list(any)` | `[]` | no | -| [working\_directory](#input\_working\_directory) | The working directory to run commands inside the container | `string` | `null` | no | +| [volumesFrom](#input\_volumesFrom) | Data volumes to mount from another container |
list(object({
readOnly = bool
sourceContainer = string
}))
| `null` | no | +| [workingDirectory](#input\_workingDirectory) | The working directory to run commands inside the container | `string` | `null` | no | ## Outputs diff --git a/modules/container-definition/main.tf b/modules/container-definition/main.tf index 8982d148..9d6258db 100644 --- a/modules/container-definition/main.tf +++ b/modules/container-definition/main.tf @@ -5,7 +5,7 @@ locals { log_group_name = try(coalesce(var.cloudwatch_log_group_name, "/aws/ecs/${var.service}/${var.name}"), "") - log_configuration = merge( + logConfiguration = merge( { for k, v in { logDriver = "awslogs", options = { @@ -14,58 +14,52 @@ locals { awslogs-stream-prefix = "ecs" }, } : k => v if var.enable_cloudwatch_logging }, - var.log_configuration + var.logConfiguration ) - linux_parameters = var.enable_execute_command ? merge({ "initProcessEnabled" : true }, var.linux_parameters) : merge({ "initProcessEnabled" : false }, var.linux_parameters) - - health_check = length(var.health_check) > 0 ? merge({ - interval = 30, - retries = 3, - timeout = 5 - }, var.health_check) : null + linuxParameters = var.enable_execute_command ? merge(var.linuxParameters, { "initProcessEnabled" : true }) : var.linuxParameters definition = { - command = length(var.command) > 0 ? var.command : null + command = var.command cpu = var.cpu - dependsOn = length(var.dependencies) > 0 ? var.dependencies : null # depends_on is a reserved word - disableNetworking = local.is_not_windows ? var.disable_networking : null - dnsSearchDomains = local.is_not_windows && length(var.dns_search_domains) > 0 ? var.dns_search_domains : null - dnsServers = local.is_not_windows && length(var.dns_servers) > 0 ? var.dns_servers : null - dockerLabels = length(var.docker_labels) > 0 ? var.docker_labels : null - dockerSecurityOptions = length(var.docker_security_options) > 0 ? var.docker_security_options : null - entrypoint = length(var.entrypoint) > 0 ? var.entrypoint : null + dependsOn = var.dependsOn + disableNetworking = local.is_not_windows ? var.disableNetworking : null + dnsSearchDomains = local.is_not_windows ? var.dnsSearchDomains : null + dnsServers = local.is_not_windows ? var.dnsServers : null + dockerLabels = var.dockerLabels + dockerSecurityOptions = var.dockerSecurityOptions + entrypoint = var.entrypoint environment = var.environment - environmentFiles = length(var.environment_files) > 0 ? var.environment_files : null + environmentFiles = var.environmentFiles essential = var.essential - extraHosts = local.is_not_windows && length(var.extra_hosts) > 0 ? var.extra_hosts : null - firelensConfiguration = length(var.firelens_configuration) > 0 ? var.firelens_configuration : null - healthCheck = local.health_check + extraHosts = local.is_not_windows ? var.extraHosts : null + firelensConfiguration = var.firelensConfiguration + healthCheck = var.healthCheck hostname = var.hostname image = var.image interactive = var.interactive - links = local.is_not_windows && length(var.links) > 0 ? var.links : null - linuxParameters = local.is_not_windows && length(local.linux_parameters) > 0 ? local.linux_parameters : null - logConfiguration = length(local.log_configuration) > 0 ? local.log_configuration : null + links = local.is_not_windows ? var.links : null + linuxParameters = local.is_not_windows ? local.linuxParameters : null + logConfiguration = length(local.logConfiguration) > 0 ? local.logConfiguration : null memory = var.memory - memoryReservation = var.memory_reservation - mountPoints = var.mount_points + memoryReservation = var.memoryReservation + mountPoints = var.mountPoints name = var.name - portMappings = var.port_mappings + portMappings = var.portMappings privileged = local.is_not_windows ? var.privileged : null - pseudoTerminal = var.pseudo_terminal - restartPolicy = var.restart_policy - readonlyRootFilesystem = local.is_not_windows ? var.readonly_root_filesystem : null - repositoryCredentials = length(var.repository_credentials) > 0 ? var.repository_credentials : null - resourceRequirements = length(var.resource_requirements) > 0 ? var.resource_requirements : null - secrets = length(var.secrets) > 0 ? var.secrets : null - startTimeout = var.start_timeout - stopTimeout = var.stop_timeout - systemControls = length(var.system_controls) > 0 ? var.system_controls : [] - ulimits = local.is_not_windows && length(var.ulimits) > 0 ? var.ulimits : null + pseudoTerminal = var.pseudoTerminal + restartPolicy = var.restartPolicy + readonlyRootFilesystem = local.is_not_windows ? var.readonlyRootFilesystem : null + repositoryCredentials = var.repositoryCredentials + resourceRequirements = var.resourceRequirements + secrets = var.secrets + startTimeout = var.startTimeout + stopTimeout = var.stopTimeout + systemControls = var.systemControls + ulimits = local.is_not_windows ? var.ulimits : null user = local.is_not_windows ? var.user : null - volumesFrom = var.volumes_from - workingDirectory = var.working_directory + volumesFrom = var.volumesFrom + workingDirectory = var.workingDirectory } # Strip out all null values, ECS API will provide defaults in place of null/empty values @@ -77,6 +71,7 @@ resource "aws_cloudwatch_log_group" "this" { name = var.cloudwatch_log_group_use_name_prefix ? null : local.log_group_name name_prefix = var.cloudwatch_log_group_use_name_prefix ? "${local.log_group_name}-" : null + log_group_class = var.cloudwatch_log_group_class retention_in_days = var.cloudwatch_log_group_retention_in_days kms_key_id = var.cloudwatch_log_group_kms_key_id diff --git a/modules/container-definition/variables.tf b/modules/container-definition/variables.tf index a1349ba2..c99b1295 100644 --- a/modules/container-definition/variables.tf +++ b/modules/container-definition/variables.tf @@ -11,7 +11,7 @@ variable "operating_system_family" { variable "command" { description = "The command that's passed to the container" type = list(string) - default = [] + default = null } variable "cpu" { @@ -20,43 +20,43 @@ variable "cpu" { default = null } -variable "dependencies" { +variable "dependsOn" { description = "The dependencies defined for container startup and shutdown. A container can contain multiple dependencies. When a dependency is defined for container startup, for container shutdown it is reversed. The condition can be one of START, COMPLETE, SUCCESS or HEALTHY" type = list(object({ condition = string containerName = string })) - default = [] + default = null } -variable "disable_networking" { +variable "disableNetworking" { description = "When this parameter is true, networking is disabled within the container" type = bool default = null } -variable "dns_search_domains" { +variable "dnsSearchDomains" { description = "Container DNS search domains. A list of DNS search domains that are presented to the container" type = list(string) - default = [] + default = null } -variable "dns_servers" { +variable "dnsServers" { description = "Container DNS servers. This is a list of strings specifying the IP addresses of the DNS servers" type = list(string) - default = [] + default = null } -variable "docker_labels" { +variable "dockerLabels" { description = "A key/value map of labels to add to the container" type = map(string) - default = {} + default = null } -variable "docker_security_options" { +variable "dockerSecurityOptions" { description = "A list of strings to provide custom labels for SELinux and AppArmor multi-level security systems. This field isn't valid for containers in tasks using the Fargate launch type" type = list(string) - default = [] + default = null } variable "enable_execute_command" { @@ -68,7 +68,7 @@ variable "enable_execute_command" { variable "entrypoint" { description = "The entry point that is passed to the container" type = list(string) - default = [] + default = null } variable "environment" { @@ -77,16 +77,16 @@ variable "environment" { name = string value = string })) - default = [] + default = null } -variable "environment_files" { +variable "environmentFiles" { description = "A list of files containing the environment variables to pass to a container" type = list(object({ value = string type = string })) - default = [] + default = null } variable "essential" { @@ -95,25 +95,34 @@ variable "essential" { default = null } -variable "extra_hosts" { +variable "extraHosts" { description = "A list of hostnames and IP address mappings to append to the `/etc/hosts` file on the container" type = list(object({ hostname = string ipAddress = string })) - default = [] + default = null } -variable "firelens_configuration" { +variable "firelensConfiguration" { description = "The FireLens configuration for the container. This is used to specify and configure a log router for container logs. For more information, see [Custom Log Routing](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_firelens.html) in the Amazon Elastic Container Service Developer Guide" - type = any - default = {} + type = object({ + options = optional(map(string), {}) + type = optional(string) + }) + default = null } -variable "health_check" { +variable "healthCheck" { description = "The container health check command and associated configuration parameters for the container. See [HealthCheck](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_HealthCheck.html)" - type = any - default = {} + type = object({ + command = optional(list(string), []) + interval = optional(number, 30) + retries = optional(number, 3) + startPeriod = optional(number) + timeout = optional(number, 5) + }) + default = null } variable "hostname" { @@ -137,19 +146,48 @@ variable "interactive" { variable "links" { description = "The links parameter allows containers to communicate with each other without the need for port mappings. This parameter is only supported if the network mode of a task definition is `bridge`" type = list(string) - default = [] + default = null } -variable "linux_parameters" { +variable "linuxParameters" { description = "Linux-specific modifications that are applied to the container, such as Linux kernel capabilities. For more information see [KernelCapabilities](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_KernelCapabilities.html)" - type = any - default = {} + type = object({ + capabilities = optional(object({ + add = optional(list(string)) + drop = optional(list(string)) + })) + devices = optional(list(object({ + containerPath = optional(string) + hostPath = optional(string) + permissions = optional(list(string)) + }))) + initProcessEnabled = optional(bool, false) + maxSwap = optional(number) + sharedMemorySize = optional(number) + swappiness = optional(number) + tmpfs = optional(list(object({ + containerPath = string + mountOptions = optional(list(string)) + size = number + }))) + }) + default = { + initProcessEnabled = false + } } -variable "log_configuration" { +variable "logConfiguration" { description = "The log configuration for the container. For more information see [LogConfiguration](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html)" - type = any - default = {} + # type = object({ + # logDriver = optional(string) + # options = optional(map(string)) + # secretOptions = optional(list(object({ + # name = string + # valueFrom = string + # }))) + # }) + type = any + default = {} } variable "memory" { @@ -158,16 +196,16 @@ variable "memory" { default = null } -variable "memory_reservation" { +variable "memoryReservation" { description = "The soft limit (in MiB) of memory to reserve for the container. When system memory is under heavy contention, Docker attempts to keep the container memory to this soft limit. However, your container can consume more memory when it needs to, up to either the hard limit specified with the `memory` parameter (if applicable), or all of the available memory on the container instance" type = number default = null } -variable "mount_points" { +variable "mountPoints" { description = "The mount points for data volumes in your container" type = list(any) - default = [] + default = null } variable "name" { @@ -176,10 +214,16 @@ variable "name" { default = null } -variable "port_mappings" { +variable "portMappings" { description = "The list of port mappings for the container. Port mappings allow containers to access ports on the host container instance to send or receive traffic. For task definitions that use the awsvpc network mode, only specify the containerPort. The hostPort can be left blank or it must be the same value as the containerPort" - type = list(any) - default = [] + type = list(object({ + appProtocol = optional(string) + containerPort = number + hostPort = optional(number) + name = string + protocol = optional(string) + })) + default = null } variable "privileged" { @@ -188,41 +232,43 @@ variable "privileged" { default = false } -variable "pseudo_terminal" { +variable "pseudoTerminal" { description = "When this parameter is true, a `TTY` is allocated" type = bool default = false } -variable "readonly_root_filesystem" { +variable "readonlyRootFilesystem" { description = "When this parameter is true, the container is given read-only access to its root file system" type = bool default = true } -variable "repository_credentials" { +variable "repositoryCredentials" { description = "Container repository credentials; required when using a private repo. This map currently supports a single key; \"credentialsParameter\", which should be the ARN of a Secrets Manager's secret holding the credentials" type = map(string) - default = {} + default = null } -variable "resource_requirements" { +variable "resourceRequirements" { description = "The type and amount of a resource to assign to a container. The only supported resource is a GPU" type = list(object({ type = string value = string })) - default = [] + default = null } -variable "restart_policy" { +variable "restartPolicy" { description = "Container restart policy; helps overcome transient failures faster and maintain task availability" type = object({ - enabled = optional(bool) + enabled = optional(bool, true) ignoredExitCodes = optional(list(number)) restartAttemptPeriod = optional(number) }) - default = null + default = { + enabled = true + } } variable "secrets" { @@ -231,25 +277,25 @@ variable "secrets" { name = string valueFrom = string })) - default = [] + default = null } -variable "start_timeout" { +variable "startTimeout" { description = "Time duration (in seconds) to wait before giving up on resolving dependencies for a container" type = number default = 30 } -variable "stop_timeout" { +variable "stopTimeout" { description = "Time duration (in seconds) to wait before the container is forcefully killed if it doesn't exit normally on its own" type = number default = 120 } -variable "system_controls" { +variable "systemControls" { description = "A list of namespaced kernel parameters to set in the container" type = list(map(string)) - default = [] + default = null } variable "ulimits" { @@ -259,7 +305,7 @@ variable "ulimits" { name = string softLimit = number })) - default = [] + default = null } variable "user" { @@ -268,13 +314,16 @@ variable "user" { default = null } -variable "volumes_from" { +variable "volumesFrom" { description = "Data volumes to mount from another container" - type = list(any) - default = [] + type = list(object({ + readOnly = bool + sourceContainer = string + })) + default = null } -variable "working_directory" { +variable "workingDirectory" { description = "The working directory to run commands inside the container" type = string default = null @@ -314,6 +363,12 @@ variable "cloudwatch_log_group_use_name_prefix" { default = false } +variable "cloudwatch_log_group_class" { + description = "Specified the log class of the log group. Possible values are: `STANDARD` or `INFREQUENT_ACCESS`" + type = string + default = null +} + variable "cloudwatch_log_group_retention_in_days" { description = "Number of days to retain log events. Default is 30 days" type = number diff --git a/modules/service/main.tf b/modules/service/main.tf index 0e08c6e5..acee6584 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -687,47 +687,47 @@ module "container_definition" { operating_system_family = try(var.runtime_platform.operating_system_family, "LINUX") # Container Definition - command = try(each.value.command, var.container_definition_defaults.command, []) - cpu = try(each.value.cpu, var.container_definition_defaults.cpu, null) - dependencies = try(each.value.dependencies, var.container_definition_defaults.dependencies, []) # depends_on is a reserved word - disable_networking = try(each.value.disable_networking, var.container_definition_defaults.disable_networking, null) - dns_search_domains = try(each.value.dns_search_domains, var.container_definition_defaults.dns_search_domains, []) - dns_servers = try(each.value.dns_servers, var.container_definition_defaults.dns_servers, []) - docker_labels = try(each.value.docker_labels, var.container_definition_defaults.docker_labels, {}) - docker_security_options = try(each.value.docker_security_options, var.container_definition_defaults.docker_security_options, []) - enable_execute_command = try(each.value.enable_execute_command, var.container_definition_defaults.enable_execute_command, var.enable_execute_command) - entrypoint = try(each.value.entrypoint, var.container_definition_defaults.entrypoint, []) - environment = try(each.value.environment, var.container_definition_defaults.environment, []) - environment_files = try(each.value.environment_files, var.container_definition_defaults.environment_files, []) - essential = try(each.value.essential, var.container_definition_defaults.essential, null) - extra_hosts = try(each.value.extra_hosts, var.container_definition_defaults.extra_hosts, []) - firelens_configuration = try(each.value.firelens_configuration, var.container_definition_defaults.firelens_configuration, {}) - health_check = try(each.value.health_check, var.container_definition_defaults.health_check, {}) - hostname = try(each.value.hostname, var.container_definition_defaults.hostname, null) - image = try(each.value.image, var.container_definition_defaults.image, null) - interactive = try(each.value.interactive, var.container_definition_defaults.interactive, false) - links = try(each.value.links, var.container_definition_defaults.links, []) - linux_parameters = try(each.value.linux_parameters, var.container_definition_defaults.linux_parameters, {}) - log_configuration = try(each.value.log_configuration, var.container_definition_defaults.log_configuration, {}) - memory = try(each.value.memory, var.container_definition_defaults.memory, null) - memory_reservation = try(each.value.memory_reservation, var.container_definition_defaults.memory_reservation, null) - mount_points = try(each.value.mount_points, var.container_definition_defaults.mount_points, []) - name = try(each.value.name, each.key) - port_mappings = try(each.value.port_mappings, var.container_definition_defaults.port_mappings, []) - privileged = try(each.value.privileged, var.container_definition_defaults.privileged, false) - pseudo_terminal = try(each.value.pseudo_terminal, var.container_definition_defaults.pseudo_terminal, false) - readonly_root_filesystem = try(each.value.readonly_root_filesystem, var.container_definition_defaults.readonly_root_filesystem, true) - repository_credentials = try(each.value.repository_credentials, var.container_definition_defaults.repository_credentials, {}) - resource_requirements = try(each.value.resource_requirements, var.container_definition_defaults.resource_requirements, []) - restart_policy = try(each.value.restart_policy, var.container_definition_defaults.restart_policy, { enabled = false }) - secrets = try(each.value.secrets, var.container_definition_defaults.secrets, []) - start_timeout = try(each.value.start_timeout, var.container_definition_defaults.start_timeout, 30) - stop_timeout = try(each.value.stop_timeout, var.container_definition_defaults.stop_timeout, 120) - system_controls = try(each.value.system_controls, var.container_definition_defaults.system_controls, []) - ulimits = try(each.value.ulimits, var.container_definition_defaults.ulimits, []) - user = try(each.value.user, var.container_definition_defaults.user, 0) - volumes_from = try(each.value.volumes_from, var.container_definition_defaults.volumes_from, []) - working_directory = try(each.value.working_directory, var.container_definition_defaults.working_directory, null) + command = try(each.value.command, var.container_definition_defaults.command, null) + cpu = try(each.value.cpu, var.container_definition_defaults.cpu, null) + dependsOn = try(each.value.dependsOn, var.container_definition_defaults.dependsOn, null) + disableNetworking = try(each.value.disableNetworking, var.container_definition_defaults.disableNetworking, null) + dnsSearchDomains = try(each.value.dnsSearchDomains, var.container_definition_defaults.dnsSearchDomains, null) + dnsServers = try(each.value.dnsServers, var.container_definition_defaults.dnsServers, null) + dockerLabels = try(each.value.dockerLabels, var.container_definition_defaults.dockerLabels, null) + dockerSecurityOptions = try(each.value.dockerSecurityOptions, var.container_definition_defaults.dockerSecurityOptions, null) + enable_execute_command = try(each.value.enable_execute_command, var.container_definition_defaults.enable_execute_command, var.enable_execute_command) + entrypoint = try(each.value.entrypoint, var.container_definition_defaults.entrypoint, null) + environment = try(each.value.environment, var.container_definition_defaults.environment, null) + environmentFiles = try(each.value.environmentFiles, var.container_definition_defaults.environmentFiles, null) + essential = try(each.value.essential, var.container_definition_defaults.essential, null) + extraHosts = try(each.value.extraHosts, var.container_definition_defaults.extraHosts, null) + firelensConfiguration = try(each.value.firelensConfiguration, var.container_definition_defaults.firelensConfiguration, null) + healthCheck = try(each.value.healthCheck, var.container_definition_defaults.healthCheck, null) + hostname = try(each.value.hostname, var.container_definition_defaults.hostname, null) + image = try(each.value.image, var.container_definition_defaults.image, null) + interactive = try(each.value.interactive, var.container_definition_defaults.interactive, false) + links = try(each.value.links, var.container_definition_defaults.links, null) + linuxParameters = try(each.value.linuxParameters, var.container_definition_defaults.linuxParameters, { initProcessEnabled = false }) + logConfiguration = try(each.value.logConfiguration, var.container_definition_defaults.logConfiguration, {}) + memory = try(each.value.memory, var.container_definition_defaults.memory, null) + memoryReservation = try(each.value.memory_reservation, var.container_definition_defaults.memoryReservation, null) + mountPoints = try(each.value.mount_points, var.container_definition_defaults.mountPoints, null) + name = try(each.value.name, each.key) + portMappings = try(each.value.port_mappings, var.container_definition_defaults.portMappings, null) + privileged = try(each.value.privileged, var.container_definition_defaults.privileged, false) + pseudoTerminal = try(each.value.pseudoTerminal, var.container_definition_defaults.pseudoTerminal, false) + readonlyRootFilesystem = try(each.value.readonlyRootFilesystem, var.container_definition_defaults.readonlyRootFilesystem, true) + repositoryCredentials = try(each.value.repositoryCredentials, var.container_definition_defaults.repositoryCredentials, null) + resourceRequirements = try(each.value.resourceRequirements, var.container_definition_defaults.resourceRequirements, null) + restartPolicy = try(each.value.restartPolicy, var.container_definition_defaults.restartPolicy, { enabled = true }) + secrets = try(each.value.secrets, var.container_definition_defaults.secrets, null) + startTimeout = try(each.value.startTimeout, var.container_definition_defaults.startTimeout, 30) + stopTimeout = try(each.value.stopTimeout, var.container_definition_defaults.stopTimeout, 120) + systemControls = try(each.value.systemControls, var.container_definition_defaults.systemControls, null) + ulimits = try(each.value.ulimits, var.container_definition_defaults.ulimits, null) + user = try(each.value.user, var.container_definition_defaults.user, null) + volumesFrom = try(each.value.volumesFrom, var.container_definition_defaults.volumesFrom, null) + workingDirectory = try(each.value.workingDirectory, var.container_definition_defaults.workingDirectory, null) # CloudWatch Log Group service = var.name @@ -735,6 +735,7 @@ module "container_definition" { create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.container_definition_defaults.create_cloudwatch_log_group, true) cloudwatch_log_group_name = try(each.value.cloudwatch_log_group_name, var.container_definition_defaults.cloudwatch_log_group_name, null) cloudwatch_log_group_use_name_prefix = try(each.value.cloudwatch_log_group_use_name_prefix, var.container_definition_defaults.cloudwatch_log_group_use_name_prefix, false) + cloudwatch_log_group_class = try(each.value.cloudwatch_log_group_class, var.container_definition_defaults.cloudwatch_log_group_class, null) cloudwatch_log_group_retention_in_days = try(each.value.cloudwatch_log_group_retention_in_days, var.container_definition_defaults.cloudwatch_log_group_retention_in_days, 14) cloudwatch_log_group_kms_key_id = try(each.value.cloudwatch_log_group_kms_key_id, var.container_definition_defaults.cloudwatch_log_group_kms_key_id, null) @@ -872,7 +873,7 @@ resource "aws_ecs_task_definition" "this" { host_path = volume.value.host_path configure_at_launch = volume.value.configure_at_launch - name = try(volume.value.name, volume.key) + name = coalesce(volume.value.name, volume.key) } } @@ -1163,7 +1164,7 @@ data "aws_iam_policy_document" "tasks" { } resource "aws_iam_role_policy" "tasks" { - count = local.create_tasks_iam_role && (length(var.tasks_iam_role_statements) > 0 || var.enable_execute_command) ? 1 : 0 + count = local.create_tasks_iam_role && (var.tasks_iam_role_statements != null || var.enable_execute_command) ? 1 : 0 name = var.tasks_iam_role_use_name_prefix ? null : local.tasks_iam_role_name name_prefix = var.tasks_iam_role_use_name_prefix ? "${local.tasks_iam_role_name}-" : null @@ -1530,7 +1531,7 @@ resource "aws_vpc_security_group_ingress_rule" "this" { var.security_group_tags, each.value.tags ) - to_port = try(each.value.to_port, each.value.from_port) + to_port = try(coalesce(each.value.to_port, each.value.from_port), null) } resource "aws_vpc_security_group_egress_rule" "this" { @@ -1539,7 +1540,7 @@ resource "aws_vpc_security_group_egress_rule" "this" { cidr_ipv4 = each.value.cidr_ipv4 cidr_ipv6 = each.value.cidr_ipv6 description = each.value.description - from_port = try(each.value.from_port, each.value.to_port) + from_port = try(coalesce(each.value.from_port, each.value.to_port), null) ip_protocol = each.value.ip_protocol prefix_list_id = each.value.prefix_list_id referenced_security_group_id = each.value.referenced_security_group_id diff --git a/wrappers/container-definition/main.tf b/wrappers/container-definition/main.tf index e5644f81..bd077d01 100644 --- a/wrappers/container-definition/main.tf +++ b/wrappers/container-definition/main.tf @@ -3,54 +3,59 @@ module "wrapper" { for_each = var.items + cloudwatch_log_group_class = try(each.value.cloudwatch_log_group_class, var.defaults.cloudwatch_log_group_class, null) cloudwatch_log_group_kms_key_id = try(each.value.cloudwatch_log_group_kms_key_id, var.defaults.cloudwatch_log_group_kms_key_id, null) cloudwatch_log_group_name = try(each.value.cloudwatch_log_group_name, var.defaults.cloudwatch_log_group_name, null) cloudwatch_log_group_retention_in_days = try(each.value.cloudwatch_log_group_retention_in_days, var.defaults.cloudwatch_log_group_retention_in_days, 30) cloudwatch_log_group_use_name_prefix = try(each.value.cloudwatch_log_group_use_name_prefix, var.defaults.cloudwatch_log_group_use_name_prefix, false) - command = try(each.value.command, var.defaults.command, []) + command = try(each.value.command, var.defaults.command, null) cpu = try(each.value.cpu, var.defaults.cpu, null) create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.defaults.create_cloudwatch_log_group, true) - dependencies = try(each.value.dependencies, var.defaults.dependencies, []) - disable_networking = try(each.value.disable_networking, var.defaults.disable_networking, null) - dns_search_domains = try(each.value.dns_search_domains, var.defaults.dns_search_domains, []) - dns_servers = try(each.value.dns_servers, var.defaults.dns_servers, []) - docker_labels = try(each.value.docker_labels, var.defaults.docker_labels, {}) - docker_security_options = try(each.value.docker_security_options, var.defaults.docker_security_options, []) + dependsOn = try(each.value.dependsOn, var.defaults.dependsOn, null) + disableNetworking = try(each.value.disableNetworking, var.defaults.disableNetworking, null) + dnsSearchDomains = try(each.value.dnsSearchDomains, var.defaults.dnsSearchDomains, null) + dnsServers = try(each.value.dnsServers, var.defaults.dnsServers, null) + dockerLabels = try(each.value.dockerLabels, var.defaults.dockerLabels, null) + dockerSecurityOptions = try(each.value.dockerSecurityOptions, var.defaults.dockerSecurityOptions, null) enable_cloudwatch_logging = try(each.value.enable_cloudwatch_logging, var.defaults.enable_cloudwatch_logging, true) enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) - entrypoint = try(each.value.entrypoint, var.defaults.entrypoint, []) - environment = try(each.value.environment, var.defaults.environment, []) - environment_files = try(each.value.environment_files, var.defaults.environment_files, []) + entrypoint = try(each.value.entrypoint, var.defaults.entrypoint, null) + environment = try(each.value.environment, var.defaults.environment, null) + environmentFiles = try(each.value.environmentFiles, var.defaults.environmentFiles, null) essential = try(each.value.essential, var.defaults.essential, null) - extra_hosts = try(each.value.extra_hosts, var.defaults.extra_hosts, []) - firelens_configuration = try(each.value.firelens_configuration, var.defaults.firelens_configuration, {}) - health_check = try(each.value.health_check, var.defaults.health_check, {}) + extraHosts = try(each.value.extraHosts, var.defaults.extraHosts, null) + firelensConfiguration = try(each.value.firelensConfiguration, var.defaults.firelensConfiguration, null) + healthCheck = try(each.value.healthCheck, var.defaults.healthCheck, null) hostname = try(each.value.hostname, var.defaults.hostname, null) image = try(each.value.image, var.defaults.image, null) interactive = try(each.value.interactive, var.defaults.interactive, false) - links = try(each.value.links, var.defaults.links, []) - linux_parameters = try(each.value.linux_parameters, var.defaults.linux_parameters, {}) - log_configuration = try(each.value.log_configuration, var.defaults.log_configuration, {}) - memory = try(each.value.memory, var.defaults.memory, null) - memory_reservation = try(each.value.memory_reservation, var.defaults.memory_reservation, null) - mount_points = try(each.value.mount_points, var.defaults.mount_points, []) - name = try(each.value.name, var.defaults.name, null) - operating_system_family = try(each.value.operating_system_family, var.defaults.operating_system_family, "LINUX") - port_mappings = try(each.value.port_mappings, var.defaults.port_mappings, []) - privileged = try(each.value.privileged, var.defaults.privileged, false) - pseudo_terminal = try(each.value.pseudo_terminal, var.defaults.pseudo_terminal, false) - readonly_root_filesystem = try(each.value.readonly_root_filesystem, var.defaults.readonly_root_filesystem, true) - repository_credentials = try(each.value.repository_credentials, var.defaults.repository_credentials, {}) - resource_requirements = try(each.value.resource_requirements, var.defaults.resource_requirements, []) - restart_policy = try(each.value.restart_policy, var.defaults.restart_policy, null) - secrets = try(each.value.secrets, var.defaults.secrets, []) - service = try(each.value.service, var.defaults.service, "") - start_timeout = try(each.value.start_timeout, var.defaults.start_timeout, 30) - stop_timeout = try(each.value.stop_timeout, var.defaults.stop_timeout, 120) - system_controls = try(each.value.system_controls, var.defaults.system_controls, []) - tags = try(each.value.tags, var.defaults.tags, {}) - ulimits = try(each.value.ulimits, var.defaults.ulimits, []) - user = try(each.value.user, var.defaults.user, null) - volumes_from = try(each.value.volumes_from, var.defaults.volumes_from, []) - working_directory = try(each.value.working_directory, var.defaults.working_directory, null) + links = try(each.value.links, var.defaults.links, null) + linuxParameters = try(each.value.linuxParameters, var.defaults.linuxParameters, { + initProcessEnabled = false + }) + logConfiguration = try(each.value.logConfiguration, var.defaults.logConfiguration, {}) + memory = try(each.value.memory, var.defaults.memory, null) + memoryReservation = try(each.value.memoryReservation, var.defaults.memoryReservation, null) + mountPoints = try(each.value.mountPoints, var.defaults.mountPoints, null) + name = try(each.value.name, var.defaults.name, null) + operating_system_family = try(each.value.operating_system_family, var.defaults.operating_system_family, "LINUX") + portMappings = try(each.value.portMappings, var.defaults.portMappings, null) + privileged = try(each.value.privileged, var.defaults.privileged, false) + pseudoTerminal = try(each.value.pseudoTerminal, var.defaults.pseudoTerminal, false) + readonlyRootFilesystem = try(each.value.readonlyRootFilesystem, var.defaults.readonlyRootFilesystem, true) + repositoryCredentials = try(each.value.repositoryCredentials, var.defaults.repositoryCredentials, null) + resourceRequirements = try(each.value.resourceRequirements, var.defaults.resourceRequirements, null) + restartPolicy = try(each.value.restartPolicy, var.defaults.restartPolicy, { + enabled = true + }) + secrets = try(each.value.secrets, var.defaults.secrets, null) + service = try(each.value.service, var.defaults.service, "") + startTimeout = try(each.value.startTimeout, var.defaults.startTimeout, 30) + stopTimeout = try(each.value.stopTimeout, var.defaults.stopTimeout, 120) + systemControls = try(each.value.systemControls, var.defaults.systemControls, null) + tags = try(each.value.tags, var.defaults.tags, {}) + ulimits = try(each.value.ulimits, var.defaults.ulimits, null) + user = try(each.value.user, var.defaults.user, null) + volumesFrom = try(each.value.volumesFrom, var.defaults.volumesFrom, null) + workingDirectory = try(each.value.workingDirectory, var.defaults.workingDirectory, null) } From 5d7c29e36f5692aac1eac87992cf15760c9cca5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Vald=C3=A9s?= Date: Thu, 9 Jan 2025 12:28:39 -0300 Subject: [PATCH 12/17] chore: Update variable name to tag_specifications (#251) Update variable name In main.tf it is used a plural tag_specifications name for the attribute --- modules/service/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 0f29e49c..6b833812 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -283,7 +283,7 @@ variable "volume_configuration" { snapshot_id = optional(string) throughput = optional(number) volume_type = optional(string) - tag_specification = optional(list(object({ + tag_specifications = optional(list(object({ resource_type = string propagate_tags = optional(string, "TASK_DEFINITION") tags = optional(map(string)) From fb5bcc4b3851d39703ac15851accbe4eb3d25a64 Mon Sep 17 00:00:00 2001 From: "Keisuke.Matsuda" <32216421+keisukematsuda19921106@users.noreply.github.com> Date: Fri, 21 Mar 2025 21:38:47 +0900 Subject: [PATCH 13/17] feat: Add support for availability zone rebalancing (#262) (#269) * feat: Add support for availability zone rebalancing (#262) * revert default value of availability zone rebalancing --- examples/complete/main.tf | 3 ++- main.tf | 1 + modules/service/README.md | 2 +- wrappers/service/main.tf | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 5b2100e0..0bd43e54 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -151,7 +151,8 @@ module "ecs" { } ] - subnet_ids = module.vpc.private_subnets + subnet_ids = module.vpc.private_subnets + availability_zone_rebalancing = "ENABLED" security_group_rules = { alb_ingress_3000 = { type = "ingress" diff --git a/main.tf b/main.tf index 8b976573..0dfe8a17 100644 --- a/main.tf +++ b/main.tf @@ -59,6 +59,7 @@ module "service" { # Service ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, false) alarms = try(each.value.alarms, {}) + availability_zone_rebalancing = try(each.value.availability_zone_rebalancing, "null") capacity_provider_strategy = try(each.value.capacity_provider_strategy, {}) cluster_arn = module.cluster.arn deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, {}) diff --git a/modules/service/README.md b/modules/service/README.md index ef9545de..0e5e1e4e 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -341,7 +341,7 @@ module "ecs_service" { | [track\_latest](#input\_track\_latest) | Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource | `bool` | `true` | no | | [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `map(string)` | `null` | no | | [volume](#input\_volume) | Configuration block for volumes that containers in your task may use |
map(object({
configure_at_launch = optional(bool)
docker_volume_configuration = optional(object({
autoprovision = optional(bool)
driver = optional(string)
driver_opts = optional(map(string))
labels = optional(map(string))
scope = optional(string)
}))
efs_volume_configuration = optional(object({
authorization_config = optional(object({
access_point_id = optional(string)
iam = optional(string)
}))
file_system_id = string
root_directory = optional(string)
transit_encryption = optional(string)
transit_encryption_port = optional(number)
}))
fsx_windows_file_server_volume_configuration = optional(object({
authorization_config = optional(object({
credentials_parameter = string
domain = string
}))
file_system_id = string
root_directory = string
}))
host_path = optional(string)
name = optional(string)
}))
| `null` | no | -| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time |
object({
name = string
managed_ebs_volume = list(object({
encrypted = optional(bool)
file_system_type = optional(string)
iops = optional(number)
kms_key_id = optional(string)
size_in_gb = optional(number)
snapshot_id = optional(string)
throughput = optional(number)
volume_type = optional(string)
tag_specification = optional(list(object({
resource_type = string
propagate_tags = optional(string, "TASK_DEFINITION")
tags = optional(map(string))
})))
}))
})
| `null` | no | +| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time |
object({
name = string
managed_ebs_volume = list(object({
encrypted = optional(bool)
file_system_type = optional(string)
iops = optional(number)
kms_key_id = optional(string)
size_in_gb = optional(number)
snapshot_id = optional(string)
throughput = optional(number)
volume_type = optional(string)
tag_specifications = optional(list(object({
resource_type = string
propagate_tags = optional(string, "TASK_DEFINITION")
tags = optional(map(string))
})))
}))
})
| `null` | no | | [vpc\_lattice\_configurations](#input\_vpc\_lattice\_configurations) | The VPC Lattice configuration for your service that allows Lattice to connect, secure, and monitor your service across multiple accounts and VPCs |
object({
role_arn = string
target_group_arn = string
port_name = string
})
| `null` | no | | [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no | | [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no | diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 981b62e2..5f337a42 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -121,6 +121,7 @@ module "wrapper" { task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, null) task_exec_secret_arns = try(each.value.task_exec_secret_arns, var.defaults.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"]) task_exec_ssm_param_arns = try(each.value.task_exec_ssm_param_arns, var.defaults.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"]) + task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) tasks_iam_role_arn = try(each.value.tasks_iam_role_arn, var.defaults.tasks_iam_role_arn, null) tasks_iam_role_description = try(each.value.tasks_iam_role_description, var.defaults.tasks_iam_role_description, null) tasks_iam_role_name = try(each.value.tasks_iam_role_name, var.defaults.tasks_iam_role_name, null) @@ -130,7 +131,6 @@ module "wrapper" { tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, null) tasks_iam_role_tags = try(each.value.tasks_iam_role_tags, var.defaults.tasks_iam_role_tags, {}) tasks_iam_role_use_name_prefix = try(each.value.tasks_iam_role_use_name_prefix, var.defaults.tasks_iam_role_use_name_prefix, true) - task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) timeouts = try(each.value.timeouts, var.defaults.timeouts, null) track_latest = try(each.value.track_latest, var.defaults.track_latest, true) triggers = try(each.value.triggers, var.defaults.triggers, null) From 27d93bccfddd5bc8a9b3d6b79508fc667bb8c338 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 1 Apr 2025 16:15:06 -0500 Subject: [PATCH 14/17] chore: Raise MSV of AWS provider --- README.md | 2 +- examples/complete/README.md | 4 ++-- examples/complete/versions.tf | 2 +- examples/ec2-autoscaling/README.md | 4 ++-- examples/ec2-autoscaling/versions.tf | 2 +- examples/fargate/README.md | 4 ++-- examples/fargate/versions.tf | 2 +- main.tf | 6 +++--- modules/cluster/README.md | 4 ++-- modules/cluster/versions.tf | 2 +- modules/container-definition/README.md | 4 ++-- modules/container-definition/versions.tf | 2 +- modules/service/README.md | 4 ++-- modules/service/variables.tf | 2 +- modules/service/versions.tf | 2 +- versions.tf | 2 +- wrappers/cluster/versions.tf | 2 +- wrappers/container-definition/versions.tf | 2 +- wrappers/service/main.tf | 2 +- wrappers/service/versions.tf | 2 +- wrappers/versions.tf | 2 +- 21 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 1b3ec800..bd3f3a39 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ module "ecs" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index 525f122c..43f7a7c0 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index aebe26a1..a4c98511 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index d9a430a5..640ca600 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index aebe26a1..a4c98511 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 242d59e6..38703fe7 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index aebe26a1..a4c98511 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/main.tf b/main.tf index 0dfe8a17..fb0c0986 100644 --- a/main.tf +++ b/main.tf @@ -59,7 +59,7 @@ module "service" { # Service ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, false) alarms = try(each.value.alarms, {}) - availability_zone_rebalancing = try(each.value.availability_zone_rebalancing, "null") + availability_zone_rebalancing = try(each.value.availability_zone_rebalancing, null) capacity_provider_strategy = try(each.value.capacity_provider_strategy, {}) cluster_arn = module.cluster.arn deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, {}) @@ -201,8 +201,8 @@ module "service" { security_group_name = try(each.value.security_group_name, null) security_group_use_name_prefix = try(each.value.security_group_use_name_prefix, true) security_group_description = try(each.value.security_group_description, null) - security_group_ingress_rules = lookup(each.value, "security_group_ingress_rules", {}) - security_group_egress_rules = lookup(each.value, "security_group_egress_rules", {}) + security_group_ingress_rules = try(each.value.security_group_ingress_rules, null) + security_group_egress_rules = try(each.value.security_group_egress_rules, null) security_group_tags = try(each.value.security_group_tags, {}) tags = merge(var.tags, try(each.value.tags, {})) diff --git a/modules/cluster/README.md b/modules/cluster/README.md index e2cdc9b1..7f8f2b1f 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -137,13 +137,13 @@ module "ecs_cluster" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index aebe26a1..a4c98511 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index 0f1d8cc2..42e3255f 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -116,13 +116,13 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index aebe26a1..a4c98511 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/modules/service/README.md b/modules/service/README.md index 0e5e1e4e..089535c3 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -173,13 +173,13 @@ module "ecs_service" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.10 | -| [aws](#requirement\_aws) | >= 5.77 | +| [aws](#requirement\_aws) | >= 5.93 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.77 | +| [aws](#provider\_aws) | >= 5.93 | ## Modules diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 6b833812..1ca66fb4 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -37,7 +37,7 @@ variable "alarms" { } variable "availability_zone_rebalancing" { - description = " ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. Defaults to `DISABLED`" + description = "ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. Defaults to `DISABLED`" type = string default = null } diff --git a/modules/service/versions.tf b/modules/service/versions.tf index aebe26a1..a4c98511 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/versions.tf b/versions.tf index aebe26a1..a4c98511 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index aebe26a1..a4c98511 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index aebe26a1..a4c98511 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 5f337a42..981b62e2 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -121,7 +121,6 @@ module "wrapper" { task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, null) task_exec_secret_arns = try(each.value.task_exec_secret_arns, var.defaults.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"]) task_exec_ssm_param_arns = try(each.value.task_exec_ssm_param_arns, var.defaults.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"]) - task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) tasks_iam_role_arn = try(each.value.tasks_iam_role_arn, var.defaults.tasks_iam_role_arn, null) tasks_iam_role_description = try(each.value.tasks_iam_role_description, var.defaults.tasks_iam_role_description, null) tasks_iam_role_name = try(each.value.tasks_iam_role_name, var.defaults.tasks_iam_role_name, null) @@ -131,6 +130,7 @@ module "wrapper" { tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, null) tasks_iam_role_tags = try(each.value.tasks_iam_role_tags, var.defaults.tasks_iam_role_tags, {}) tasks_iam_role_use_name_prefix = try(each.value.tasks_iam_role_use_name_prefix, var.defaults.tasks_iam_role_use_name_prefix, true) + task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) timeouts = try(each.value.timeouts, var.defaults.timeouts, null) track_latest = try(each.value.track_latest, var.defaults.track_latest, true) triggers = try(each.value.triggers, var.defaults.triggers, null) diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index aebe26a1..a4c98511 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index aebe26a1..a4c98511 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.77" + version = ">= 5.93" } } } From 4a0b133574d93f0a9f3f809f96743abe06884ed2 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 1 Apr 2025 16:24:05 -0500 Subject: [PATCH 15/17] feat: Use policy for tasks role instead of inline policy --- modules/service/README.md | 5 +++-- modules/service/main.tf | 27 ++++++++++++++++++--------- modules/service/variables.tf | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/modules/service/README.md b/modules/service/README.md index 089535c3..0c52f293 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -201,17 +201,18 @@ module "ecs_service" { | [aws_ecs_task_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_set) | resource | | [aws_iam_policy.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_role.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.infrastructure_iam_role_vpc_lattice_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.tasks_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_security_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | | [aws_vpc_security_group_egress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource | | [aws_vpc_security_group_ingress_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | @@ -333,7 +334,7 @@ module "ecs_service" { | [tasks\_iam\_role\_name](#input\_tasks\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | | [tasks\_iam\_role\_path](#input\_tasks\_iam\_role\_path) | IAM role path | `string` | `null` | no | | [tasks\_iam\_role\_permissions\_boundary](#input\_tasks\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | -| [tasks\_iam\_role\_policies](#input\_tasks\_iam\_role\_policies) | Map of IAM role policy ARNs to attach to the IAM role | `map(string)` | `{}` | no | +| [tasks\_iam\_role\_policies](#input\_tasks\_iam\_role\_policies) | Map of additioanl IAM role policy ARNs to attach to the IAM role | `map(string)` | `{}` | no | | [tasks\_iam\_role\_statements](#input\_tasks\_iam\_role\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage |
list(object({
sid = optional(string)
actions = optional(list(string))
not_actions = optional(list(string))
effect = optional(string)
resources = optional(list(string))
not_resources = optional(list(string))
principals = optional(list(object({
type = string
identifiers = list(string)
})))
not_principals = optional(list(object({
type = string
identifiers = list(string)
})))
condition = optional(list(object({
test = string
values = list(string)
variable = string
})))
}))
| `null` | no | | [tasks\_iam\_role\_tags](#input\_tasks\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [tasks\_iam\_role\_use\_name\_prefix](#input\_tasks\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`tasks_iam_role_name`) is used as a prefix | `bool` | `true` | no | diff --git a/modules/service/main.tf b/modules/service/main.tf index acee6584..4e08156e 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -1096,13 +1096,6 @@ resource "aws_iam_role" "tasks" { tags = merge(var.tags, var.tasks_iam_role_tags) } -resource "aws_iam_role_policy_attachment" "tasks" { - for_each = { for k, v in var.tasks_iam_role_policies : k => v if local.create_tasks_iam_role } - - role = aws_iam_role.tasks[0].name - policy_arn = each.value -} - data "aws_iam_policy_document" "tasks" { count = local.create_tasks_iam_role && (var.tasks_iam_role_statements != null || var.enable_execute_command) ? 1 : 0 @@ -1163,13 +1156,29 @@ data "aws_iam_policy_document" "tasks" { } } -resource "aws_iam_role_policy" "tasks" { +resource "aws_iam_policy" "tasks" { count = local.create_tasks_iam_role && (var.tasks_iam_role_statements != null || var.enable_execute_command) ? 1 : 0 name = var.tasks_iam_role_use_name_prefix ? null : local.tasks_iam_role_name name_prefix = var.tasks_iam_role_use_name_prefix ? "${local.tasks_iam_role_name}-" : null + description = coalesce(var.tasks_iam_role_description, "Task role IAM policy") policy = data.aws_iam_policy_document.tasks[0].json - role = aws_iam_role.tasks[0].id + path = var.tasks_iam_role_path + tags = merge(var.tags, var.tasks_iam_role_tags) +} + +resource "aws_iam_role_policy_attachment" "tasks" { + count = local.create_tasks_iam_role && (length(var.tasks_iam_role_statements) > 0 || var.enable_execute_command) ? 1 : 0 + + role = aws_iam_role.tasks[0].name + policy_arn = aws_iam_policy.tasks[0].arn +} + +resource "aws_iam_role_policy_attachment" "tasks_additional" { + for_each = { for k, v in var.tasks_iam_role_policies : k => v if local.create_tasks_iam_role } + + role = aws_iam_role.tasks[0].name + policy_arn = each.value } ################################################################################ diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 1ca66fb4..11cdfdd4 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -727,7 +727,7 @@ variable "tasks_iam_role_tags" { } variable "tasks_iam_role_policies" { - description = "Map of IAM role policy ARNs to attach to the IAM role" + description = "Map of additioanl IAM role policy ARNs to attach to the IAM role" type = map(string) default = {} } From b0914fec2d8b35e0c2b786372ea24eb99c7a2453 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 1 Apr 2025 17:31:12 -0500 Subject: [PATCH 16/17] feat: Add FIS param and remove inference accelerator from `service` module --- main.tf | 1 - modules/service/README.md | 6 ++-- modules/service/main.tf | 65 ++++++++++++++++++------------------ modules/service/variables.tf | 45 ++++++++++++------------- wrappers/service/main.tf | 2 +- 5 files changed, 58 insertions(+), 61 deletions(-) diff --git a/main.tf b/main.tf index fb0c0986..99ce984d 100644 --- a/main.tf +++ b/main.tf @@ -118,7 +118,6 @@ module "service" { cpu = try(each.value.cpu, 1024) ephemeral_storage = try(each.value.ephemeral_storage, {}) family = try(each.value.family, null) - inference_accelerator = try(each.value.inference_accelerator, {}) ipc_mode = try(each.value.ipc_mode, null) memory = try(each.value.memory, 2048) network_mode = try(each.value.network_mode, "awsvpc") diff --git a/modules/service/README.md b/modules/service/README.md index 0c52f293..a5c3ed12 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -261,6 +261,7 @@ module "ecs_service" { | [enable\_autoscaling](#input\_enable\_autoscaling) | Determines whether to enable autoscaling for the service | `bool` | `true` | no | | [enable\_ecs\_managed\_tags](#input\_enable\_ecs\_managed\_tags) | Specifies whether to enable Amazon ECS managed tags for the tasks within the service | `bool` | `true` | no | | [enable\_execute\_command](#input\_enable\_execute\_command) | Specifies whether to enable Amazon ECS Exec for the tasks within the service | `bool` | `false` | no | +| [enable\_fault\_injection](#input\_enable\_fault\_injection) | Enables fault injection and allows for fault injection requests to be accepted from the task's containers. Default is `false` | `bool` | `null` | no | | [ephemeral\_storage](#input\_ephemeral\_storage) | The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate |
object({
size_in_gib = number
})
| `null` | no | | [external\_id](#input\_external\_id) | The external ID associated with the task set | `string` | `null` | no | | [family](#input\_family) | A unique name for your task definition | `string` | `null` | no | @@ -276,7 +277,6 @@ module "ecs_service" { | [iam\_role\_tags](#input\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ignore\_task\_definition\_changes](#input\_ignore\_task\_definition\_changes) | Whether changes to service `task_definition` changes should be ignored | `bool` | `false` | no | -| [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings |
object({
device_name = string
device_type = string
})
| `null` | no | | [infrastructure\_iam\_role\_arn](#input\_infrastructure\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | | [infrastructure\_iam\_role\_description](#input\_infrastructure\_iam\_role\_description) | Description of the role | `string` | `null` | no | | [infrastructure\_iam\_role\_name](#input\_infrastructure\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | @@ -307,7 +307,7 @@ module "ecs_service" { | [security\_group\_name](#input\_security\_group\_name) | Name to use on security group created | `string` | `null` | no | | [security\_group\_tags](#input\_security\_group\_tags) | A map of additional tags to add to the security group created | `map(string)` | `{}` | no | | [security\_group\_use\_name\_prefix](#input\_security\_group\_use\_name\_prefix) | Determines whether the security group name (`security_group_name`) is used as a prefix | `bool` | `true` | no | -| [service\_connect\_configuration](#input\_service\_connect\_configuration) | The ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace |
object({
enabled = optional(bool, true)
log_configuration = optional(object({
log_driver = string
options = optional(map(string))
secret_option = optional(object({
name = string
value_from = string
}))
}))
namespace = optional(string)
service = optional(list(object({
client_alias = optional(object({
dns_name = optional(string)
port = number
}))
discovery_name = optional(string)
ingress_port_override = optional(number)
port_name = string
timeout = optional(object({
idle_timeout_seconds = optional(number)
per_request_timeout_seconds = optional(number)
}))
tls = optional(object({
issuer_cert_authority = optional(object({
aws_pca_authority_arn = string
}))
kms_key = optional(string)
role_arn = optional(string)
}))
})))
})
| `null` | no | +| [service\_connect\_configuration](#input\_service\_connect\_configuration) | The ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace |
object({
enabled = optional(bool, true)
log_configuration = optional(object({
log_driver = string
options = optional(map(string))
secret_option = optional(list(object({
name = string
value_from = string
})))
}))
namespace = optional(string)
service = optional(list(object({
client_alias = optional(object({
dns_name = optional(string)
port = number
}))
discovery_name = optional(string)
ingress_port_override = optional(number)
port_name = string
timeout = optional(object({
idle_timeout_seconds = optional(number)
per_request_timeout_seconds = optional(number)
}))
tls = optional(object({
issuer_cert_authority = object({
aws_pca_authority_arn = string
})
kms_key = optional(string)
role_arn = optional(string)
}))
})))
})
| `null` | no | | [service\_registries](#input\_service\_registries) | Service discovery registries for the service |
object({
container_name = optional(string)
container_port = optional(number)
port = optional(number)
registry_arn = string
})
| `null` | no | | [service\_tags](#input\_service\_tags) | A map of additional tags to add to the service | `map(string)` | `{}` | no | | [skip\_destroy](#input\_skip\_destroy) | If true, the task is not deleted when the service is deleted | `bool` | `null` | no | @@ -342,7 +342,7 @@ module "ecs_service" { | [track\_latest](#input\_track\_latest) | Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource | `bool` | `true` | no | | [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `map(string)` | `null` | no | | [volume](#input\_volume) | Configuration block for volumes that containers in your task may use |
map(object({
configure_at_launch = optional(bool)
docker_volume_configuration = optional(object({
autoprovision = optional(bool)
driver = optional(string)
driver_opts = optional(map(string))
labels = optional(map(string))
scope = optional(string)
}))
efs_volume_configuration = optional(object({
authorization_config = optional(object({
access_point_id = optional(string)
iam = optional(string)
}))
file_system_id = string
root_directory = optional(string)
transit_encryption = optional(string)
transit_encryption_port = optional(number)
}))
fsx_windows_file_server_volume_configuration = optional(object({
authorization_config = optional(object({
credentials_parameter = string
domain = string
}))
file_system_id = string
root_directory = string
}))
host_path = optional(string)
name = optional(string)
}))
| `null` | no | -| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time |
object({
name = string
managed_ebs_volume = list(object({
encrypted = optional(bool)
file_system_type = optional(string)
iops = optional(number)
kms_key_id = optional(string)
size_in_gb = optional(number)
snapshot_id = optional(string)
throughput = optional(number)
volume_type = optional(string)
tag_specifications = optional(list(object({
resource_type = string
propagate_tags = optional(string, "TASK_DEFINITION")
tags = optional(map(string))
})))
}))
})
| `null` | no | +| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time |
object({
name = string
managed_ebs_volume = object({
encrypted = optional(bool)
file_system_type = optional(string)
iops = optional(number)
kms_key_id = optional(string)
size_in_gb = optional(number)
snapshot_id = optional(string)
tag_specifications = optional(list(object({
propagate_tags = optional(string, "TASK_DEFINITION")
resource_type = string
tags = optional(map(string))
})))
throughput = optional(number)
volume_type = optional(string)
})
})
| `null` | no | | [vpc\_lattice\_configurations](#input\_vpc\_lattice\_configurations) | The VPC Lattice configuration for your service that allows Lattice to connect, secure, and monitor your service across multiple accounts and VPCs |
object({
role_arn = string
target_group_arn = string
port_name = string
})
| `null` | no | | [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no | | [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no | diff --git a/modules/service/main.tf b/modules/service/main.tf index 4e08156e..fe535905 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -1,11 +1,17 @@ -data "aws_region" "current" {} -data "aws_partition" "current" {} -data "aws_caller_identity" "current" {} +data "aws_region" "current" { + count = var.create ? 1 : 0 +} +data "aws_partition" "current" { + count = var.create ? 1 : 0 +} +data "aws_caller_identity" "current" { + count = var.create ? 1 : 0 +} locals { - account_id = data.aws_caller_identity.current.account_id - partition = data.aws_partition.current.partition - region = data.aws_region.current.name + account_id = try(data.aws_caller_identity.current[0].account_id, "") + partition = try(data.aws_partition.current[0].partition, "") + region = try(data.aws_region.current[0].name, "") } ################################################################################ @@ -146,7 +152,7 @@ resource "aws_ecs_service" "this" { options = log_configuration.value.options dynamic "secret_option" { - for_each = log_configuration.value.secret_option != null ? [log_configuration.value.secret_option] : [] + for_each = log_configuration.value.secret_option != null ? log_configuration.value.secret_option : [] content { name = secret_option.value.name @@ -228,7 +234,7 @@ resource "aws_ecs_service" "this" { name = volume_configuration.value.name dynamic "managed_ebs_volume" { - for_each = volume_configuration.value.managed_ebs_volume + for_each = [volume_configuration.value.managed_ebs_volume] content { encrypted = managed_ebs_volume.value.encrypted @@ -238,8 +244,6 @@ resource "aws_ecs_service" "this" { role_arn = local.infrastructure_iam_role_arn size_in_gb = managed_ebs_volume.value.size_in_gb snapshot_id = managed_ebs_volume.value.snapshot_id - throughput = managed_ebs_volume.value.throughput - volume_type = managed_ebs_volume.value.volume_type dynamic "tag_specifications" { for_each = managed_ebs_volume.value.tag_specifications != null ? managed_ebs_volume.value.tag_specifications : [] @@ -250,6 +254,9 @@ resource "aws_ecs_service" "this" { tags = tag_specifications.value.tags } } + + throughput = managed_ebs_volume.value.throughput + volume_type = managed_ebs_volume.value.volume_type } } } @@ -411,7 +418,7 @@ resource "aws_ecs_service" "ignore_task_definition" { options = log_configuration.value.options dynamic "secret_option" { - for_each = log_configuration.value.secret_option != null ? [log_configuration.value.secret_option] : [] + for_each = log_configuration.value.secret_option != null ? log_configuration.value.secret_option : [] content { name = secret_option.value.name @@ -493,7 +500,7 @@ resource "aws_ecs_service" "ignore_task_definition" { name = volume_configuration.value.name dynamic "managed_ebs_volume" { - for_each = volume_configuration.value.managed_ebs_volume + for_each = [volume_configuration.value.managed_ebs_volume] content { encrypted = managed_ebs_volume.value.encrypted @@ -503,8 +510,6 @@ resource "aws_ecs_service" "ignore_task_definition" { role_arn = local.infrastructure_iam_role_arn size_in_gb = managed_ebs_volume.value.size_in_gb snapshot_id = managed_ebs_volume.value.snapshot_id - throughput = managed_ebs_volume.value.throughput - volume_type = managed_ebs_volume.value.volume_type dynamic "tag_specifications" { for_each = managed_ebs_volume.value.tag_specifications != null ? managed_ebs_volume.value.tag_specifications : [] @@ -515,6 +520,9 @@ resource "aws_ecs_service" "ignore_task_definition" { tags = tag_specifications.value.tags } } + + throughput = managed_ebs_volume.value.throughput + volume_type = managed_ebs_volume.value.volume_type } } } @@ -755,8 +763,9 @@ resource "aws_ecs_task_definition" "this" { count = local.create_task_definition ? 1 : 0 # Convert map of maps to array of maps before JSON encoding - container_definitions = jsonencode([for k, v in module.container_definition : v.container_definition]) - cpu = var.cpu + container_definitions = jsonencode([for k, v in module.container_definition : v.container_definition]) + cpu = var.cpu + enable_fault_injection = var.enable_fault_injection dynamic "ephemeral_storage" { for_each = var.ephemeral_storage != null ? [var.ephemeral_storage] : [] @@ -769,15 +778,6 @@ resource "aws_ecs_task_definition" "this" { execution_role_arn = try(aws_iam_role.task_exec[0].arn, var.task_exec_iam_role_arn) family = coalesce(var.family, var.name) - dynamic "inference_accelerator" { - for_each = var.inference_accelerator != null ? [var.inference_accelerator] : [] - - content { - device_name = inference_accelerator.value.device_name - device_type = inference_accelerator.value.device_type - } - } - ipc_mode = var.ipc_mode memory = var.memory network_mode = var.network_mode @@ -821,6 +821,8 @@ resource "aws_ecs_task_definition" "this" { for_each = var.volume != null ? var.volume : {} content { + configure_at_launch = volume.value.configure_at_launch + dynamic "docker_volume_configuration" { for_each = volume.value.docker_volume_configuration != null ? [volume.value.docker_volume_configuration] : [] @@ -871,9 +873,8 @@ resource "aws_ecs_task_definition" "this" { } } - host_path = volume.value.host_path - configure_at_launch = volume.value.configure_at_launch - name = coalesce(volume.value.name, volume.key) + host_path = volume.value.host_path + name = coalesce(volume.value.name, volume.key) } } @@ -1524,7 +1525,7 @@ resource "aws_security_group" "this" { } resource "aws_vpc_security_group_ingress_rule" "this" { - for_each = var.security_group_ingress_rules != null && local.create_security_group ? var.security_group_ingress_rules : {} + for_each = { for k, v in var.security_group_ingress_rules : k => v if var.security_group_ingress_rules != null && local.create_security_group } cidr_ipv4 = each.value.cidr_ipv4 cidr_ipv6 = each.value.cidr_ipv6 @@ -1536,15 +1537,15 @@ resource "aws_vpc_security_group_ingress_rule" "this" { security_group_id = aws_security_group.this[0].id tags = merge( var.tags, - { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, var.security_group_tags, + { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, each.value.tags ) to_port = try(coalesce(each.value.to_port, each.value.from_port), null) } resource "aws_vpc_security_group_egress_rule" "this" { - for_each = var.security_group_egress_rules != null && local.create_security_group ? var.security_group_egress_rules : {} + for_each = { for k, v in var.security_group_egress_rules : k => v if var.security_group_egress_rules != null && local.create_security_group } cidr_ipv4 = each.value.cidr_ipv4 cidr_ipv6 = each.value.cidr_ipv6 @@ -1556,8 +1557,8 @@ resource "aws_vpc_security_group_egress_rule" "this" { security_group_id = aws_security_group.this[0].id tags = merge( var.tags, - { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, var.security_group_tags, + { "Name" = try(each.value.name, "${local.security_group_name}-${each.key}") }, each.value.tags ) to_port = each.value.to_port diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 11cdfdd4..7a62922d 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -207,10 +207,10 @@ variable "service_connect_configuration" { log_configuration = optional(object({ log_driver = string options = optional(map(string)) - secret_option = optional(object({ + secret_option = optional(list(object({ name = string value_from = string - })) + }))) })) namespace = optional(string) service = optional(list(object({ @@ -226,9 +226,9 @@ variable "service_connect_configuration" { per_request_timeout_seconds = optional(number) })) tls = optional(object({ - issuer_cert_authority = optional(object({ + issuer_cert_authority = object({ aws_pca_authority_arn = string - })) + }) kms_key = optional(string) role_arn = optional(string) })) @@ -274,21 +274,21 @@ variable "volume_configuration" { description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time" type = object({ name = string - managed_ebs_volume = list(object({ + managed_ebs_volume = object({ encrypted = optional(bool) file_system_type = optional(string) iops = optional(number) kms_key_id = optional(string) size_in_gb = optional(number) snapshot_id = optional(string) - throughput = optional(number) - volume_type = optional(string) tag_specifications = optional(list(object({ - resource_type = string propagate_tags = optional(string, "TASK_DEFINITION") + resource_type = string tags = optional(map(string)) }))) - })) + throughput = optional(number) + volume_type = optional(string) + }) }) default = null } @@ -421,6 +421,12 @@ variable "cpu" { default = 1024 } +variable "enable_fault_injection" { + description = "Enables fault injection and allows for fault injection requests to be accepted from the task's containers. Default is `false`" + type = bool + default = null +} + variable "ephemeral_storage" { description = "The amount of ephemeral storage to allocate for the task. This parameter is used to expand the total amount of ephemeral storage available, beyond the default amount, for tasks hosted on AWS Fargate" type = object({ @@ -435,15 +441,6 @@ variable "family" { default = null } -variable "inference_accelerator" { - description = "Configuration block(s) with Inference Accelerators settings" - type = object({ - device_name = string - device_type = string - }) - default = null -} - variable "ipc_mode" { description = "IPC resource namespace to be used for the containers in the task The valid values are `host`, `task`, and `none`" type = string @@ -505,18 +502,18 @@ variable "runtime_platform" { } } -variable "track_latest" { - description = "Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource" - type = bool - default = true -} - variable "skip_destroy" { description = "If true, the task is not deleted when the service is deleted" type = bool default = null } +variable "track_latest" { + description = "Whether should track latest `ACTIVE` task definition on AWS or the one created with the resource stored in state. Default is `false`. Useful in the event the task definition is modified outside of this resource" + type = bool + default = true +} + variable "volume" { description = "Configuration block for volumes that containers in your task may use" type = map(object({ diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 981b62e2..38bdf262 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -51,6 +51,7 @@ module "wrapper" { enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) + enable_fault_injection = try(each.value.enable_fault_injection, var.defaults.enable_fault_injection, null) ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, null) external_id = try(each.value.external_id, var.defaults.external_id, null) family = try(each.value.family, var.defaults.family, null) @@ -66,7 +67,6 @@ module "wrapper" { iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) - inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, null) infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, var.defaults.infrastructure_iam_role_arn, null) infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, var.defaults.infrastructure_iam_role_description, null) infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, var.defaults.infrastructure_iam_role_name, null) From ed296d1257769e30844bca800b984be0cb8508be Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Tue, 1 Apr 2025 18:36:03 -0500 Subject: [PATCH 17/17] feat: Update cluster variable definitions; drop `cluster_` prefix --- examples/ec2-autoscaling/main.tf | 19 ++++----- examples/fargate/main.tf | 2 +- main.tf | 8 ++-- modules/cluster/README.md | 8 ++-- modules/cluster/main.tf | 71 +++++++++++--------------------- modules/cluster/variables.tf | 51 +++++++++++++++++------ modules/service/main.tf | 2 +- wrappers/cluster/main.tf | 26 +++++++----- wrappers/service/main.tf | 2 +- 9 files changed, 97 insertions(+), 92 deletions(-) diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf index 2fe2a62f..b1f5258f 100644 --- a/examples/ec2-autoscaling/main.tf +++ b/examples/ec2-autoscaling/main.tf @@ -28,7 +28,7 @@ locals { module "ecs_cluster" { source = "../../modules/cluster" - cluster_name = local.name + name = local.name # Capacity provider - autoscaling groups default_capacity_provider_use_fargate = false @@ -96,13 +96,12 @@ module "ecs_service" { } volume_configuration = { - ebs-volume = { - managed_ebs_volume = { - encrypted = true - file_system_type = "xfs" - size_in_gb = 5 - volume_type = "gp3" - } + name = "ebs-volume" + managed_ebs_volume = { + encrypted = true + file_system_type = "xfs" + size_in_gb = 5 + volume_type = "gp3" } } @@ -162,11 +161,9 @@ module "ecs_service" { } subnet_ids = module.vpc.private_subnets - security_group_rules = { + security_group_ingress_rules = { alb_http_ingress = { - type = "ingress" from_port = local.container_port - to_port = local.container_port protocol = "tcp" description = "Service port" source_security_group_id = module.alb.security_group_id diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index d9b45a48..362310b8 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -28,7 +28,7 @@ locals { module "ecs_cluster" { source = "../../modules/cluster" - cluster_name = local.name + name = local.name # Capacity provider fargate_capacity_providers = { diff --git a/main.tf b/main.tf index 99ce984d..3d92b03e 100644 --- a/main.tf +++ b/main.tf @@ -8,10 +8,10 @@ module "cluster" { create = var.create # Cluster - cluster_name = var.cluster_name - cluster_configuration = var.cluster_configuration - cluster_settings = var.cluster_settings - cluster_service_connect_defaults = var.cluster_service_connect_defaults + name = var.cluster_name + configuration = var.cluster_configuration + settings = var.cluster_settings + service_connect_defaults = var.cluster_service_connect_defaults # Cluster Cloudwatch log group create_cloudwatch_log_group = var.create_cloudwatch_log_group diff --git a/modules/cluster/README.md b/modules/cluster/README.md index 7f8f2b1f..7904a2a7 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -173,16 +173,16 @@ No modules. | [cloudwatch\_log\_group\_name](#input\_cloudwatch\_log\_group\_name) | Custom name of CloudWatch Log Group for ECS cluster | `string` | `null` | no | | [cloudwatch\_log\_group\_retention\_in\_days](#input\_cloudwatch\_log\_group\_retention\_in\_days) | Number of days to retain log events | `number` | `90` | no | | [cloudwatch\_log\_group\_tags](#input\_cloudwatch\_log\_group\_tags) | A map of additional tags to add to the log group created | `map(string)` | `{}` | no | -| [cluster\_configuration](#input\_cluster\_configuration) | The execute command configuration for the cluster | `any` | `{}` | no | -| [cluster\_name](#input\_cluster\_name) | Name of the cluster (up to 255 letters, numbers, hyphens, and underscores) | `string` | `""` | no | -| [cluster\_service\_connect\_defaults](#input\_cluster\_service\_connect\_defaults) | Configures a default Service Connect namespace | `map(string)` | `{}` | no | -| [cluster\_settings](#input\_cluster\_settings) | List of configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster | `any` |
[
{
"name": "containerInsights",
"value": "enabled"
}
]
| no | +| [configuration](#input\_configuration) | The execute command configuration for the cluster |
object({
execute_command_configuration = optional(object({
kms_key_id = optional(string)
log_configuration = optional(object({
cloud_watch_encryption_enabled = optional(bool)
cloud_watch_log_group_name = optional(string)
s3_bucket_encryption_enabled = optional(bool)
s3_bucket_name = optional(string)
s3_kms_key_id = optional(string)
}))
logging = optional(string, "OVERRIDE")
}))
managed_storage_configuration = optional(object({
fargate_ephemeral_storage_kms_key_id = optional(string)
kms_key_id = optional(string)
}))
})
|
{
"execute_command_configuration": {
"log_configuration": {
"cloud_watch_log_group_name": "placeholder"
}
}
}
| no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_cloudwatch\_log\_group](#input\_create\_cloudwatch\_log\_group) | Determines whether a log group is created by this module for the cluster logs. If not, AWS will automatically create one if logging is enabled | `bool` | `true` | no | | [create\_task\_exec\_iam\_role](#input\_create\_task\_exec\_iam\_role) | Determines whether the ECS task definition IAM role should be created | `bool` | `false` | no | | [create\_task\_exec\_policy](#input\_create\_task\_exec\_policy) | Determines whether the ECS task definition IAM policy should be created. This includes permissions included in AmazonECSTaskExecutionRolePolicy as well as access to secrets and SSM parameters | `bool` | `true` | no | | [default\_capacity\_provider\_use\_fargate](#input\_default\_capacity\_provider\_use\_fargate) | Determines whether to use Fargate or autoscaling for default capacity provider strategy | `bool` | `true` | no | | [fargate\_capacity\_providers](#input\_fargate\_capacity\_providers) | Map of Fargate capacity provider definitions to use for the cluster | `any` | `{}` | no | +| [name](#input\_name) | Name of the cluster (up to 255 letters, numbers, hyphens, and underscores) | `string` | `""` | no | +| [service\_connect\_defaults](#input\_service\_connect\_defaults) | Configures a default Service Connect namespace |
object({
namespace = string
})
| `null` | no | +| [settings](#input\_settings) | List of configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster |
list(object({
name = string
value = string
}))
|
[
{
"name": "containerInsights",
"value": "enabled"
}
]
| no | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | | [task\_exec\_iam\_role\_description](#input\_task\_exec\_iam\_role\_description) | Description of the role | `string` | `null` | no | | [task\_exec\_iam\_role\_name](#input\_task\_exec\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | diff --git a/modules/cluster/main.tf b/modules/cluster/main.tf index 9ed117eb..96d84b00 100644 --- a/modules/cluster/main.tf +++ b/modules/cluster/main.tf @@ -2,76 +2,50 @@ # Cluster ################################################################################ -locals { - execute_command_configuration = { - logging = "OVERRIDE" - log_configuration = { - cloud_watch_log_group_name = try(aws_cloudwatch_log_group.this[0].name, null) - } - } -} - resource "aws_ecs_cluster" "this" { count = var.create ? 1 : 0 - name = var.cluster_name - dynamic "configuration" { - for_each = var.create_cloudwatch_log_group ? [var.cluster_configuration] : [] + for_each = var.configuration != null ? [var.configuration] : [] content { dynamic "execute_command_configuration" { - for_each = try([merge(local.execute_command_configuration, configuration.value.execute_command_configuration)], [{}]) + for_each = configuration.value.execute_command_configuration != null ? [configuration.value.execute_command_configuration] : [] content { - kms_key_id = try(execute_command_configuration.value.kms_key_id, null) - logging = try(execute_command_configuration.value.logging, "DEFAULT") + kms_key_id = execute_command_configuration.value.kms_key_id dynamic "log_configuration" { - for_each = try([execute_command_configuration.value.log_configuration], []) + for_each = execute_command_configuration.value.log_configuration != null ? [execute_command_configuration.value.log_configuration] : [] content { - cloud_watch_encryption_enabled = try(log_configuration.value.cloud_watch_encryption_enabled, null) - cloud_watch_log_group_name = try(log_configuration.value.cloud_watch_log_group_name, null) - s3_bucket_name = try(log_configuration.value.s3_bucket_name, null) - s3_bucket_encryption_enabled = try(log_configuration.value.s3_bucket_encryption_enabled, null) - s3_key_prefix = try(log_configuration.value.s3_key_prefix, null) + cloud_watch_encryption_enabled = log_configuration.value.cloud_watch_encryption_enabled + cloud_watch_log_group_name = try(aws_cloudwatch_log_group.this[0].name, log_configuration.value.cloud_watch_log_group_name) + s3_bucket_encryption_enabled = log_configuration.value.s3_bucket_encryption_enabled + s3_bucket_name = log_configuration.value.s3_bucket_name + s3_key_prefix = log_configuration.value.s3_key_prefix } } + + logging = try(execute_command_configuration.value.logging, "DEFAULT") } } - } - } - dynamic "configuration" { - for_each = !var.create_cloudwatch_log_group && length(var.cluster_configuration) > 0 ? [var.cluster_configuration] : [] - - content { - dynamic "execute_command_configuration" { - for_each = try([configuration.value.execute_command_configuration], [{}]) + dynamic "managed_storage_configuration" { + for_each = configuration.value.managed_storage_configuration != null ? [configuration.value.managed_storage_configuration] : [] content { - kms_key_id = try(execute_command_configuration.value.kms_key_id, null) - logging = try(execute_command_configuration.value.logging, "DEFAULT") - - dynamic "log_configuration" { - for_each = try([execute_command_configuration.value.log_configuration], []) - - content { - cloud_watch_encryption_enabled = try(log_configuration.value.cloud_watch_encryption_enabled, null) - cloud_watch_log_group_name = try(log_configuration.value.cloud_watch_log_group_name, null) - s3_bucket_name = try(log_configuration.value.s3_bucket_name, null) - s3_bucket_encryption_enabled = try(log_configuration.value.s3_bucket_encryption_enabled, null) - s3_key_prefix = try(log_configuration.value.s3_key_prefix, null) - } - } + fargate_ephemeral_storage_kms_key_id = managed_storage_configuration.value.fargate_ephemeral_storage_kms_key_id + kms_key_id = managed_storage_configuration.value.kms_key_id } } } } + name = var.name + dynamic "service_connect_defaults" { - for_each = length(var.cluster_service_connect_defaults) > 0 ? [var.cluster_service_connect_defaults] : [] + for_each = var.service_connect_defaults != null ? [var.service_connect_defaults] : [] content { namespace = service_connect_defaults.value.namespace @@ -79,7 +53,7 @@ resource "aws_ecs_cluster" "this" { } dynamic "setting" { - for_each = flatten([var.cluster_settings]) + for_each = var.settings != null ? var.settings : [] content { name = setting.value.name @@ -93,10 +67,11 @@ resource "aws_ecs_cluster" "this" { ################################################################################ # CloudWatch Log Group ################################################################################ + resource "aws_cloudwatch_log_group" "this" { count = var.create && var.create_cloudwatch_log_group ? 1 : 0 - name = try(coalesce(var.cloudwatch_log_group_name, "/aws/ecs/${var.cluster_name}"), "") + name = try(coalesce(var.cloudwatch_log_group_name, "/aws/ecs/${var.name}"), "") retention_in_days = var.cloudwatch_log_group_retention_in_days kms_key_id = var.cloudwatch_log_group_kms_key_id @@ -177,7 +152,7 @@ resource "aws_ecs_capacity_provider" "this" { ################################################################################ locals { - task_exec_iam_role_name = try(coalesce(var.task_exec_iam_role_name, var.cluster_name), "") + task_exec_iam_role_name = try(coalesce(var.task_exec_iam_role_name, var.name), "") create_task_exec_iam_role = var.create && var.create_task_exec_iam_role create_task_exec_policy = local.create_task_exec_iam_role && var.create_task_exec_policy @@ -203,7 +178,7 @@ resource "aws_iam_role" "task_exec" { name = var.task_exec_iam_role_use_name_prefix ? null : local.task_exec_iam_role_name name_prefix = var.task_exec_iam_role_use_name_prefix ? "${local.task_exec_iam_role_name}-" : null path = var.task_exec_iam_role_path - description = coalesce(var.task_exec_iam_role_description, "Task execution role for ${var.cluster_name}") + description = coalesce(var.task_exec_iam_role_description, "Task execution role for ${var.name}") assume_role_policy = data.aws_iam_policy_document.task_exec_assume[0].json permissions_boundary = var.task_exec_iam_role_permissions_boundary diff --git a/modules/cluster/variables.tf b/modules/cluster/variables.tf index 6629743c..e53884bc 100644 --- a/modules/cluster/variables.tf +++ b/modules/cluster/variables.tf @@ -14,21 +14,54 @@ variable "tags" { # Cluster ################################################################################ -variable "cluster_name" { +variable "name" { description = "Name of the cluster (up to 255 letters, numbers, hyphens, and underscores)" type = string default = "" } -variable "cluster_configuration" { +variable "configuration" { description = "The execute command configuration for the cluster" - type = any - default = {} + type = object({ + execute_command_configuration = optional(object({ + kms_key_id = optional(string) + log_configuration = optional(object({ + cloud_watch_encryption_enabled = optional(bool) + cloud_watch_log_group_name = optional(string) + s3_bucket_encryption_enabled = optional(bool) + s3_bucket_name = optional(string) + s3_kms_key_id = optional(string) + })) + logging = optional(string, "OVERRIDE") + })) + managed_storage_configuration = optional(object({ + fargate_ephemeral_storage_kms_key_id = optional(string) + kms_key_id = optional(string) + })) + }) + default = { + execute_command_configuration = { + log_configuration = { + cloud_watch_log_group_name = "placeholder" # will use CloudWatch log group created by module + } + } + } +} + +variable "service_connect_defaults" { + description = "Configures a default Service Connect namespace" + type = object({ + namespace = string + }) + default = null } -variable "cluster_settings" { +variable "settings" { description = "List of configuration block(s) with cluster settings. For example, this can be used to enable CloudWatch Container Insights for a cluster" - type = any + type = list(object({ + name = string + value = string + })) default = [ { name = "containerInsights" @@ -37,12 +70,6 @@ variable "cluster_settings" { ] } -variable "cluster_service_connect_defaults" { - description = "Configures a default Service Connect namespace" - type = map(string) - default = {} -} - ################################################################################ # CloudWatch Log Group ################################################################################ diff --git a/modules/service/main.tf b/modules/service/main.tf index fe535905..bd6fd897 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -231,7 +231,7 @@ resource "aws_ecs_service" "this" { for_each = var.volume_configuration != null ? [var.volume_configuration] : [] content { - name = volume_configuration.value.name + name = try(volume_configuration.value.name, volume_configuration.key) dynamic "managed_ebs_volume" { for_each = [volume_configuration.value.managed_ebs_volume] diff --git a/wrappers/cluster/main.tf b/wrappers/cluster/main.tf index 91f929d7..3b2f92a5 100644 --- a/wrappers/cluster/main.tf +++ b/wrappers/cluster/main.tf @@ -8,21 +8,27 @@ module "wrapper" { cloudwatch_log_group_name = try(each.value.cloudwatch_log_group_name, var.defaults.cloudwatch_log_group_name, null) cloudwatch_log_group_retention_in_days = try(each.value.cloudwatch_log_group_retention_in_days, var.defaults.cloudwatch_log_group_retention_in_days, 90) cloudwatch_log_group_tags = try(each.value.cloudwatch_log_group_tags, var.defaults.cloudwatch_log_group_tags, {}) - cluster_configuration = try(each.value.cluster_configuration, var.defaults.cluster_configuration, {}) - cluster_name = try(each.value.cluster_name, var.defaults.cluster_name, "") - cluster_service_connect_defaults = try(each.value.cluster_service_connect_defaults, var.defaults.cluster_service_connect_defaults, {}) - cluster_settings = try(each.value.cluster_settings, var.defaults.cluster_settings, [ + configuration = try(each.value.configuration, var.defaults.configuration, { + execute_command_configuration = { + log_configuration = { + cloud_watch_log_group_name = "placeholder" + } + } + }) + create = try(each.value.create, var.defaults.create, true) + create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.defaults.create_cloudwatch_log_group, true) + create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, false) + create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) + default_capacity_provider_use_fargate = try(each.value.default_capacity_provider_use_fargate, var.defaults.default_capacity_provider_use_fargate, true) + fargate_capacity_providers = try(each.value.fargate_capacity_providers, var.defaults.fargate_capacity_providers, {}) + name = try(each.value.name, var.defaults.name, "") + service_connect_defaults = try(each.value.service_connect_defaults, var.defaults.service_connect_defaults, null) + settings = try(each.value.settings, var.defaults.settings, [ { name = "containerInsights" value = "enabled" } ]) - create = try(each.value.create, var.defaults.create, true) - create_cloudwatch_log_group = try(each.value.create_cloudwatch_log_group, var.defaults.create_cloudwatch_log_group, true) - create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, false) - create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) - default_capacity_provider_use_fargate = try(each.value.default_capacity_provider_use_fargate, var.defaults.default_capacity_provider_use_fargate, true) - fargate_capacity_providers = try(each.value.fargate_capacity_providers, var.defaults.fargate_capacity_providers, {}) tags = try(each.value.tags, var.defaults.tags, {}) task_exec_iam_role_description = try(each.value.task_exec_iam_role_description, var.defaults.task_exec_iam_role_description, null) task_exec_iam_role_name = try(each.value.task_exec_iam_role_name, var.defaults.task_exec_iam_role_name, null) diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 38bdf262..d051e5e8 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -121,6 +121,7 @@ module "wrapper" { task_exec_iam_statements = try(each.value.task_exec_iam_statements, var.defaults.task_exec_iam_statements, null) task_exec_secret_arns = try(each.value.task_exec_secret_arns, var.defaults.task_exec_secret_arns, ["arn:aws:secretsmanager:*:*:secret:*"]) task_exec_ssm_param_arns = try(each.value.task_exec_ssm_param_arns, var.defaults.task_exec_ssm_param_arns, ["arn:aws:ssm:*:*:parameter/*"]) + task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) tasks_iam_role_arn = try(each.value.tasks_iam_role_arn, var.defaults.tasks_iam_role_arn, null) tasks_iam_role_description = try(each.value.tasks_iam_role_description, var.defaults.tasks_iam_role_description, null) tasks_iam_role_name = try(each.value.tasks_iam_role_name, var.defaults.tasks_iam_role_name, null) @@ -130,7 +131,6 @@ module "wrapper" { tasks_iam_role_statements = try(each.value.tasks_iam_role_statements, var.defaults.tasks_iam_role_statements, null) tasks_iam_role_tags = try(each.value.tasks_iam_role_tags, var.defaults.tasks_iam_role_tags, {}) tasks_iam_role_use_name_prefix = try(each.value.tasks_iam_role_use_name_prefix, var.defaults.tasks_iam_role_use_name_prefix, true) - task_tags = try(each.value.task_tags, var.defaults.task_tags, {}) timeouts = try(each.value.timeouts, var.defaults.timeouts, null) track_latest = try(each.value.track_latest, var.defaults.track_latest, true) triggers = try(each.value.triggers, var.defaults.triggers, null)