From 62f347d61c447ab1359b8d9f7f91194f163bd408 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Fri, 22 Nov 2024 15:11:23 -0600 Subject: [PATCH] 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 | 588 ++++++++++++---------- 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, 748 insertions(+), 448 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 77bdb2a5..2c0d36f6 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 33b6e5f3..dc26c0b8 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 e7963316..57584b6a 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" } } @@ -225,13 +223,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 b24e7f4b..742de6ba 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\_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 | | [task\_exec\_iam\_role\_max\_session\_duration](#input\_task\_exec\_iam\_role\_max\_session\_duration) | Maximum session duration (in seconds) for ECS task execution role. Default is 3600. | `number` | `null` | no | @@ -320,7 +323,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 | @@ -330,13 +333,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 | @@ -359,7 +364,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 5dba87fe..a8bc4de4 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -32,30 +32,33 @@ 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 = { for k, v in var.capacity_provider_strategy : k => v if !local.is_external_deployment && var.capacity_provider_strategy != null } + 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 +67,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 +79,22 @@ 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 = { for k, v in var.load_balancer : k => v if !local.is_external_deployment && var.load_balancer != null } + 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 +112,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 +158,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 +198,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 +209,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 +299,33 @@ 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 = { for k, v in var.capacity_provider_strategy : k => v if !local.is_external_deployment && var.capacity_provider_strategy != null } + 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 +334,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 +346,22 @@ 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 = { for k, v in var.load_balancer : k => v if !local.is_external_deployment && var.load_balancer != null } + 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 } } @@ -338,7 +369,7 @@ resource "aws_ecs_service" "ignore_task_definition" { dynamic "network_configuration" { # Set by task set if deployment controller is external - for_each = var.network_mode == "awsvpc" ? [{ for k, v in local.network_configuration : k => v if !local.is_external_deployment }] : [] + for_each = var.network_mode == "awsvpc" && !local.is_external_deployment ? [local.network_configuration] : [] content { assign_public_ip = network_configuration.value.assign_public_ip @@ -348,42 +379,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 +425,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 +465,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 +476,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 = var.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 +566,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 +620,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 +640,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 +649,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 +751,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 +762,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 +773,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 +787,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 +874,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 +988,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 +1008,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 +1017,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 +1107,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 +1125,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 +1145,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 +1154,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 +1199,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 +1280,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 +1465,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 +1478,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 +1517,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 +1563,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 +1598,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 31d3b619..185e9b77 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 } ################################################################################ @@ -535,8 +728,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 } ################################################################################ @@ -551,14 +764,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" { @@ -622,8 +832,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 } ################################################################################ @@ -654,10 +872,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 2d367a7b..374763a8 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_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) task_exec_iam_role_max_session_duration = try(each.value.task_exec_iam_role_max_session_duration, var.defaults.task_exec_iam_role_max_session_duration, null) @@ -115,7 +117,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) @@ -124,14 +126,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" } } }