From e3f936b768e5b0e3d6469b6d6a2af42b39496a89 Mon Sep 17 00:00:00 2001 From: Rodrigo Torres Date: Tue, 18 Jun 2024 15:26:58 +0200 Subject: [PATCH 1/5] feat: Adding support for EBS volumes --- modules/service/main.tf | 107 +++++++++++++++++++++++++++++++++-- modules/service/variables.tf | 92 ++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 4 deletions(-) diff --git a/modules/service/main.tf b/modules/service/main.tf index a5e00761..b5e966b6 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -197,6 +197,30 @@ resource "aws_ecs_service" "this" { } } + dynamic "volume_configuration" { + for_each = var.volume_configuration + + content { + name = try(volume_configuration.value.name, volume_configuration.key) + + dynamic "managed_ebs_volume" { + for_each = try([volume_configuration.value.managed_ebs_volume], []) + + content { + role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) + encrypted = try(managed_ebs_volume.value.encrypted, null) + file_system_type = try(managed_ebs_volume.value.file_system_type, null) + iops = try(managed_ebs_volume.value.iops, null) + kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) + size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) + snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) + throughput = try(managed_ebs_volume.value.throughput, null) + volume_type = try(managed_ebs_volume.value.volume_type, null) + } + } + } + } + task_definition = local.task_definition triggers = var.triggers wait_for_steady_state = var.wait_for_steady_state @@ -211,7 +235,8 @@ resource "aws_ecs_service" "this" { } depends_on = [ - aws_iam_role_policy_attachment.service + aws_iam_role_policy_attachment.service, + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy ] lifecycle { @@ -394,6 +419,30 @@ resource "aws_ecs_service" "ignore_task_definition" { } } + dynamic "volume_configuration" { + for_each = var.volume_configuration + + content { + name = try(volume_configuration.value.name, volume_configuration.key) + + dynamic "managed_ebs_volume" { + for_each = try([volume_configuration.value.managed_ebs_volume], []) + + content { + role_arn = try(aws_iam_role.infrastructure_iam_role[0].arn, var.infrastructure_iam_role_arn) + encrypted = try(managed_ebs_volume.value.encrypted, null) + file_system_type = try(managed_ebs_volume.value.file_system_type, null) + iops = try(managed_ebs_volume.value.iops, null) + kms_key_id = try(managed_ebs_volume.value.kms_key_id, null) + size_in_gb = try(managed_ebs_volume.value.size_in_gb, null) + snapshot_id = try(managed_ebs_volume.value.snapshot_id, null) + throughput = try(managed_ebs_volume.value.throughput, null) + volume_type = try(managed_ebs_volume.value.volume_type, null) + } + } + } + } + task_definition = local.task_definition triggers = var.triggers wait_for_steady_state = var.wait_for_steady_state @@ -408,7 +457,8 @@ resource "aws_ecs_service" "ignore_task_definition" { } depends_on = [ - aws_iam_role_policy_attachment.service + aws_iam_role_policy_attachment.service, + aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy ] lifecycle { @@ -751,8 +801,9 @@ resource "aws_ecs_task_definition" "this" { } } - host_path = try(volume.value.host_path, null) - name = try(volume.value.name, volume.key) + host_path = try(volume.value.host_path, null) + configure_at_launch = try(volume.value.configure_at_launch, null) + name = try(volume.value.name, volume.key) } } @@ -1411,3 +1462,51 @@ resource "aws_security_group_rule" "this" { self = lookup(each.value, "self", null) source_security_group_id = lookup(each.value, "source_security_group_id", null) } + +############################################################################################ +# ECS infrastructure IAM role +# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/infrastructure_IAM_role.html +############################################################################################ + +locals { + needs_infrastructure_iam_role = var.create_infrastructure_iam_role && var.volume_configuration != null + create_infrastructure_iam_role = var.create && local.needs_infrastructure_iam_role + infrastructure_iam_role_name = try(coalesce(var.infrastructure_iam_role_name, var.name), "") +} + +data "aws_iam_policy_document" "infrastructure_iam_role" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + statement { + sid = "ECSServiceAssumeRole" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ecs.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "infrastructure_iam_role" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + name = var.infrastructure_iam_role_use_name_prefix ? null : local.infrastructure_iam_role_name + name_prefix = var.infrastructure_iam_role_use_name_prefix ? "${local.infrastructure_iam_role_name}-" : null + path = var.infrastructure_iam_role_path + description = coalesce(var.infrastructure_iam_role_description, "Amazon ECS infrastructure IAM role that is used to manage your infrastructure") + + assume_role_policy = data.aws_iam_policy_document.ecs_infrastructure_iam_role[0].json + permissions_boundary = var.infrastructure_iam_role_permissions_boundary + force_detach_policies = true + + tags = merge(var.tags, var.infrastructure_iam_role_tags) +} + +# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ebs-volumes.html#ebs-volume-considerations/ +resource "aws_iam_role_policy_attachment" "infrastructure_iam_role_ebs_policy" { + count = local.create_infrastructure_iam_role ? 1 : 0 + + role = aws_iam_role.infrastructure_iam_role[0].name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes" +} diff --git a/modules/service/variables.tf b/modules/service/variables.tf index 1c542e15..a5a820b0 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -659,3 +659,95 @@ variable "security_group_tags" { type = map(string) default = {} } + +################################################################################ +# Security Group +################################################################################ + +variable "create_security_group" { + description = "Determines if a security group is created" + type = bool + default = true +} + +variable "security_group_name" { + description = "Name to use on security group created" + type = string + default = null +} + +variable "security_group_use_name_prefix" { + description = "Determines whether the security group name (`security_group_name`) is used as a prefix" + type = bool + default = true +} + +variable "security_group_description" { + description = "Description of the security group created" + type = string + default = null +} + +variable "security_group_rules" { + description = "Security group rules to add to the security group created" + type = any + default = {} +} + +variable "security_group_tags" { + description = "A map of additional tags to add to the security group created" + type = map(string) + default = {} +} + +############################################################################################ +# ECS infrastructure IAM role +############################################################################################ + +variable "create_infrastructure_iam_role" { + description = "Determines whether the ECS infrastructure IAM role should be created" + type = bool + default = false +} + +variable "infrastructure_iam_role_arn" { + description = "Existing IAM role ARN" + type = string + default = null +} + +variable "infrastructure_iam_role_name" { + description = "Name to use on IAM role created" + type = string + default = null +} + +variable "infrastructure_iam_role_use_name_prefix" { + description = "Determines whether the IAM role name (`iam_role_name`) is used as a prefix" + type = bool + default = true +} + +variable "infrastructure_iam_role_path" { + description = "IAM role path" + type = string + default = null +} + +variable "infrastructure_iam_role_description" { + description = "Description of the role" + type = string + default = null +} + +variable "infrastructure_iam_role_permissions_boundary" { + description = "ARN of the policy that is used to set the permissions boundary for the IAM role" + type = string + default = null +} + +variable "infrastructure_iam_role_tags" { + description = "A map of additional tags to add to the IAM role created" + type = map(string) + default = {} +} From 0239f013feea10a37cf3df66a59e7d8d8ca9d57b Mon Sep 17 00:00:00 2001 From: Rodrigo Torres Date: Tue, 18 Jun 2024 15:41:14 +0200 Subject: [PATCH 2/5] feat: Adding support for EBS volumes --- modules/service/README.md | 12 ++++ modules/service/main.tf | 2 +- modules/service/variables.tf | 46 ++------------- wrappers/service/main.tf | 111 +++++++++++++++++++---------------- 4 files changed, 79 insertions(+), 92 deletions(-) diff --git a/modules/service/README.md b/modules/service/README.md index b24f2b2c..b1fa813d 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -195,10 +195,12 @@ module "ecs_service" { | [aws_ecs_task_set.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_set) | resource | | [aws_iam_policy.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | | [aws_iam_policy.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy.tasks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.infrastructure_iam_role_ebs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.task_exec_additional](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | @@ -207,6 +209,7 @@ module "ecs_service" { | [aws_security_group_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ecs_task_definition) | data source | +| [aws_iam_policy_document.infrastructure_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.service_assume](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.task_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -234,6 +237,7 @@ module "ecs_service" { | [cpu](#input\_cpu) | Number of cpu units used by the task. If the `requires_compatibilities` is `FARGATE` this field is required | `number` | `1024` | no | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | | [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no | +| [create\_infrastructure\_iam\_role](#input\_create\_infrastructure\_iam\_role) | Determines whether the ECS infrastructure IAM role should be created | `bool` | `false` | no | | [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `true` | no | | [create\_service](#input\_create\_service) | Determines whether service resource will be created (set to `false` in case you want to create task definition only) | `bool` | `true` | no | | [create\_task\_definition](#input\_create\_task\_definition) | Determines whether to create a task definition or use existing/provided | `bool` | `true` | no | @@ -264,6 +268,13 @@ module "ecs_service" { | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ignore\_task\_definition\_changes](#input\_ignore\_task\_definition\_changes) | Whether changes to service `task_definition` changes should be ignored | `bool` | `false` | no | | [inference\_accelerator](#input\_inference\_accelerator) | Configuration block(s) with Inference Accelerators settings | `any` | `{}` | no | +| [infrastructure\_iam\_role\_arn](#input\_infrastructure\_iam\_role\_arn) | Existing IAM role ARN | `string` | `null` | no | +| [infrastructure\_iam\_role\_description](#input\_infrastructure\_iam\_role\_description) | Description of the role | `string` | `null` | no | +| [infrastructure\_iam\_role\_name](#input\_infrastructure\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | +| [infrastructure\_iam\_role\_path](#input\_infrastructure\_iam\_role\_path) | IAM role path | `string` | `null` | no | +| [infrastructure\_iam\_role\_permissions\_boundary](#input\_infrastructure\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | +| [infrastructure\_iam\_role\_tags](#input\_infrastructure\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | +| [infrastructure\_iam\_role\_use\_name\_prefix](#input\_infrastructure\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name`) is used as a prefix | `bool` | `true` | no | | [ipc\_mode](#input\_ipc\_mode) | IPC resource namespace to be used for the containers in the task The valid values are `host`, `task`, and `none` | `string` | `null` | no | | [launch\_type](#input\_launch\_type) | Launch type on which to run your service. The valid values are `EC2`, `FARGATE`, and `EXTERNAL`. Defaults to `FARGATE` | `string` | `"FARGATE"` | no | | [load\_balancer](#input\_load\_balancer) | Configuration block for load balancers | `any` | `{}` | no | @@ -319,6 +330,7 @@ module "ecs_service" { | [timeouts](#input\_timeouts) | Create, update, and delete timeout configurations for the service | `map(string)` | `{}` | no | | [triggers](#input\_triggers) | Map of arbitrary keys and values that, when changed, will trigger an in-place update (redeployment). Useful with `timestamp()` | `any` | `{}` | no | | [volume](#input\_volume) | Configuration block for volumes that containers in your task may use | `any` | `{}` | no | +| [volume\_configuration](#input\_volume\_configuration) | Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume | `any` | `{}` | no | | [wait\_for\_steady\_state](#input\_wait\_for\_steady\_state) | If true, Terraform will wait for the service to reach a steady state before continuing. Default is `false` | `bool` | `null` | no | | [wait\_until\_stable](#input\_wait\_until\_stable) | Whether terraform should wait until the task set has reached `STEADY_STATE` | `bool` | `null` | no | | [wait\_until\_stable\_timeout](#input\_wait\_until\_stable\_timeout) | Wait timeout for task set to reach `STEADY_STATE`. Valid time units include `ns`, `us` (or µs), `ms`, `s`, `m`, and `h`. Default `10m` | `string` | `null` | no | diff --git a/modules/service/main.tf b/modules/service/main.tf index b5e966b6..248bf75b 100644 --- a/modules/service/main.tf +++ b/modules/service/main.tf @@ -1496,7 +1496,7 @@ resource "aws_iam_role" "infrastructure_iam_role" { path = var.infrastructure_iam_role_path description = coalesce(var.infrastructure_iam_role_description, "Amazon ECS infrastructure IAM role that is used to manage your infrastructure") - assume_role_policy = data.aws_iam_policy_document.ecs_infrastructure_iam_role[0].json + assume_role_policy = data.aws_iam_policy_document.infrastructure_iam_role[0].json permissions_boundary = var.infrastructure_iam_role_permissions_boundary force_detach_policies = true diff --git a/modules/service/variables.tf b/modules/service/variables.tf index a5a820b0..c516013b 100644 --- a/modules/service/variables.tf +++ b/modules/service/variables.tf @@ -373,6 +373,12 @@ variable "volume" { default = {} } +variable "volume_configuration" { + description = "Configuration for a volume specified in the task definition as a volume that is configured at launch time. Currently, the only supported volume type is an Amazon EBS volume" + type = any + default = {} +} + variable "task_tags" { description = "A map of additional tags to add to the task definition/set created" type = map(string) @@ -660,46 +666,6 @@ variable "security_group_tags" { default = {} } -################################################################################ -# Security Group -################################################################################ - -variable "create_security_group" { - description = "Determines if a security group is created" - type = bool - default = true -} - -variable "security_group_name" { - description = "Name to use on security group created" - type = string - default = null -} - -variable "security_group_use_name_prefix" { - description = "Determines whether the security group name (`security_group_name`) is used as a prefix" - type = bool - default = true -} - -variable "security_group_description" { - description = "Description of the security group created" - type = string - default = null -} - -variable "security_group_rules" { - description = "Security group rules to add to the security group created" - type = any - default = {} -} - -variable "security_group_tags" { - description = "A map of additional tags to add to the security group created" - type = map(string) - default = {} -} - ############################################################################################ # ECS infrastructure IAM role ############################################################################################ diff --git a/wrappers/service/main.tf b/wrappers/service/main.tf index 3dbd9e46..aaf8941a 100644 --- a/wrappers/service/main.tf +++ b/wrappers/service/main.tf @@ -27,57 +27,65 @@ module "wrapper" { } } }) - autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {}) - capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {}) - cluster_arn = try(each.value.cluster_arn, var.defaults.cluster_arn, "") - container_definition_defaults = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {}) - container_definitions = try(each.value.container_definitions, var.defaults.container_definitions, {}) - cpu = try(each.value.cpu, var.defaults.cpu, 1024) - create = try(each.value.create, var.defaults.create, true) - create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) - create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) - create_service = try(each.value.create_service, var.defaults.create_service, true) - create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true) - create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true) - create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) - create_tasks_iam_role = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true) - deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {}) - deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, {}) - deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200) - deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66) - desired_count = try(each.value.desired_count, var.defaults.desired_count, 1) - enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) - enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) - enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) - ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {}) - external_id = try(each.value.external_id, var.defaults.external_id, null) - family = try(each.value.family, var.defaults.family, null) - force_delete = try(each.value.force_delete, var.defaults.force_delete, null) - force_new_deployment = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true) - health_check_grace_period_seconds = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null) - iam_role_arn = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null) - iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) - iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) - iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) - iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) - iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {}) - iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) - iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) - ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) - inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {}) - ipc_mode = try(each.value.ipc_mode, var.defaults.ipc_mode, null) - launch_type = try(each.value.launch_type, var.defaults.launch_type, "FARGATE") - load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, {}) - memory = try(each.value.memory, var.defaults.memory, 2048) - name = try(each.value.name, var.defaults.name, null) - network_mode = try(each.value.network_mode, var.defaults.network_mode, "awsvpc") - ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {}) - pid_mode = try(each.value.pid_mode, var.defaults.pid_mode, null) - placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, {}) - platform_version = try(each.value.platform_version, var.defaults.platform_version, null) - propagate_tags = try(each.value.propagate_tags, var.defaults.propagate_tags, null) - proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {}) - requires_compatibilities = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"]) + autoscaling_scheduled_actions = try(each.value.autoscaling_scheduled_actions, var.defaults.autoscaling_scheduled_actions, {}) + capacity_provider_strategy = try(each.value.capacity_provider_strategy, var.defaults.capacity_provider_strategy, {}) + cluster_arn = try(each.value.cluster_arn, var.defaults.cluster_arn, "") + container_definition_defaults = try(each.value.container_definition_defaults, var.defaults.container_definition_defaults, {}) + container_definitions = try(each.value.container_definitions, var.defaults.container_definitions, {}) + cpu = try(each.value.cpu, var.defaults.cpu, 1024) + create = try(each.value.create, var.defaults.create, true) + create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true) + create_infrastructure_iam_role = try(each.value.create_infrastructure_iam_role, var.defaults.create_infrastructure_iam_role, false) + create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true) + create_service = try(each.value.create_service, var.defaults.create_service, true) + create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true) + create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true) + create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true) + create_tasks_iam_role = try(each.value.create_tasks_iam_role, var.defaults.create_tasks_iam_role, true) + deployment_circuit_breaker = try(each.value.deployment_circuit_breaker, var.defaults.deployment_circuit_breaker, {}) + deployment_controller = try(each.value.deployment_controller, var.defaults.deployment_controller, {}) + deployment_maximum_percent = try(each.value.deployment_maximum_percent, var.defaults.deployment_maximum_percent, 200) + deployment_minimum_healthy_percent = try(each.value.deployment_minimum_healthy_percent, var.defaults.deployment_minimum_healthy_percent, 66) + desired_count = try(each.value.desired_count, var.defaults.desired_count, 1) + enable_autoscaling = try(each.value.enable_autoscaling, var.defaults.enable_autoscaling, true) + enable_ecs_managed_tags = try(each.value.enable_ecs_managed_tags, var.defaults.enable_ecs_managed_tags, true) + enable_execute_command = try(each.value.enable_execute_command, var.defaults.enable_execute_command, false) + ephemeral_storage = try(each.value.ephemeral_storage, var.defaults.ephemeral_storage, {}) + external_id = try(each.value.external_id, var.defaults.external_id, null) + family = try(each.value.family, var.defaults.family, null) + force_delete = try(each.value.force_delete, var.defaults.force_delete, null) + force_new_deployment = try(each.value.force_new_deployment, var.defaults.force_new_deployment, true) + health_check_grace_period_seconds = try(each.value.health_check_grace_period_seconds, var.defaults.health_check_grace_period_seconds, null) + iam_role_arn = try(each.value.iam_role_arn, var.defaults.iam_role_arn, null) + iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) + iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) + iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) + iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) + iam_role_statements = try(each.value.iam_role_statements, var.defaults.iam_role_statements, {}) + iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) + iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) + ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, var.defaults.ignore_task_definition_changes, false) + inference_accelerator = try(each.value.inference_accelerator, var.defaults.inference_accelerator, {}) + infrastructure_iam_role_arn = try(each.value.infrastructure_iam_role_arn, var.defaults.infrastructure_iam_role_arn, null) + infrastructure_iam_role_description = try(each.value.infrastructure_iam_role_description, var.defaults.infrastructure_iam_role_description, null) + infrastructure_iam_role_name = try(each.value.infrastructure_iam_role_name, var.defaults.infrastructure_iam_role_name, null) + infrastructure_iam_role_path = try(each.value.infrastructure_iam_role_path, var.defaults.infrastructure_iam_role_path, null) + infrastructure_iam_role_permissions_boundary = try(each.value.infrastructure_iam_role_permissions_boundary, var.defaults.infrastructure_iam_role_permissions_boundary, null) + infrastructure_iam_role_tags = try(each.value.infrastructure_iam_role_tags, var.defaults.infrastructure_iam_role_tags, {}) + infrastructure_iam_role_use_name_prefix = try(each.value.infrastructure_iam_role_use_name_prefix, var.defaults.infrastructure_iam_role_use_name_prefix, true) + ipc_mode = try(each.value.ipc_mode, var.defaults.ipc_mode, null) + launch_type = try(each.value.launch_type, var.defaults.launch_type, "FARGATE") + load_balancer = try(each.value.load_balancer, var.defaults.load_balancer, {}) + memory = try(each.value.memory, var.defaults.memory, 2048) + name = try(each.value.name, var.defaults.name, null) + network_mode = try(each.value.network_mode, var.defaults.network_mode, "awsvpc") + ordered_placement_strategy = try(each.value.ordered_placement_strategy, var.defaults.ordered_placement_strategy, {}) + pid_mode = try(each.value.pid_mode, var.defaults.pid_mode, null) + placement_constraints = try(each.value.placement_constraints, var.defaults.placement_constraints, {}) + platform_version = try(each.value.platform_version, var.defaults.platform_version, null) + propagate_tags = try(each.value.propagate_tags, var.defaults.propagate_tags, null) + proxy_configuration = try(each.value.proxy_configuration, var.defaults.proxy_configuration, {}) + requires_compatibilities = try(each.value.requires_compatibilities, var.defaults.requires_compatibilities, ["FARGATE"]) runtime_platform = try(each.value.runtime_platform, var.defaults.runtime_platform, { operating_system_family = "LINUX" cpu_architecture = "X86_64" @@ -123,6 +131,7 @@ module "wrapper" { timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) triggers = try(each.value.triggers, var.defaults.triggers, {}) volume = try(each.value.volume, var.defaults.volume, {}) + volume_configuration = try(each.value.volume_configuration, var.defaults.volume_configuration, {}) wait_for_steady_state = try(each.value.wait_for_steady_state, var.defaults.wait_for_steady_state, null) wait_until_stable = try(each.value.wait_until_stable, var.defaults.wait_until_stable, null) wait_until_stable_timeout = try(each.value.wait_until_stable_timeout, var.defaults.wait_until_stable_timeout, null) From 25efac1739958c7fe73cf9d5040e46a02a200c60 Mon Sep 17 00:00:00 2001 From: Rodrigo Torres Date: Wed, 19 Jun 2024 17:06:38 +0200 Subject: [PATCH 3/5] feat: Add support for EBS volumes --- examples/ec2-autoscaling/main.tf | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/examples/ec2-autoscaling/main.tf b/examples/ec2-autoscaling/main.tf index 35e6249f..30bcb6ad 100644 --- a/examples/ec2-autoscaling/main.tf +++ b/examples/ec2-autoscaling/main.tf @@ -95,8 +95,24 @@ module "ecs_service" { } } + create_infrastructure_iam_role = true + volume_configuration = { + ebs-volume = { + managed_ebs_volume = { + encrypted = true + file_system_type = "xfs" + size_in_gb = 5 + volume_type = "gp3" + } + } + } + volume = { - my-vol = {} + my-vol = {}, + ebs-volume = { + name = "ebs-volume" + configure_at_launch = true + } } # Container definition(s) @@ -115,6 +131,10 @@ module "ecs_service" { { sourceVolume = "my-vol", containerPath = "/var/www/my-vol" + }, + { + containerPath = "/ebs/data" + sourceVolume = "ebs-volume" } ] From 6c52d9bd8ff8483e9e440f479d3c9ed614c9ac30 Mon Sep 17 00:00:00 2001 From: Rodrigo Torres Date: Wed, 19 Jun 2024 17:36:28 +0200 Subject: [PATCH 4/5] feat: Add support for EBS volumes --- examples/ec2-autoscaling/README.md | 2 ++ examples/ec2-autoscaling/outputs.tf | 10 ++++++++++ modules/service/README.md | 2 ++ modules/service/outputs.tf | 14 ++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index d5288ec5..c95634c1 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -73,6 +73,8 @@ No inputs. | [service\_iam\_role\_name](#output\_service\_iam\_role\_name) | Service IAM role name | | [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role | | [service\_id](#output\_service\_id) | ARN that identifies the service | +| [service\_infrastructure\_iam\_role\_arn](#output\_service\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN | +| [service\_infrastructure\_iam\_role\_name](#output\_service\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name | | [service\_name](#output\_service\_name) | Name of the service | | [service\_task\_definition\_arn](#output\_service\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) | | [service\_task\_definition\_revision](#output\_service\_task\_definition\_revision) | Revision of the task in a particular family | diff --git a/examples/ec2-autoscaling/outputs.tf b/examples/ec2-autoscaling/outputs.tf index 2f6f85a7..128fd2f7 100644 --- a/examples/ec2-autoscaling/outputs.tf +++ b/examples/ec2-autoscaling/outputs.tf @@ -130,3 +130,13 @@ output "service_autoscaling_scheduled_actions" { description = "Map of autoscaling scheduled actions and their attributes" value = module.ecs_service.autoscaling_scheduled_actions } + +output "service_infrastructure_iam_role_arn" { + description = "Infrastructure IAM role ARN" + value = module.ecs_service.infrastructure_iam_role_arn +} + +output "service_infrastructure_iam_role_name" { + description = "Infrastructure IAM role name" + value = module.ecs_service.infrastructure_iam_role_name +} diff --git a/modules/service/README.md b/modules/service/README.md index b1fa813d..63d29d7f 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -346,6 +346,8 @@ module "ecs_service" { | [iam\_role\_name](#output\_iam\_role\_name) | Service IAM role name | | [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role | | [id](#output\_id) | ARN that identifies the service | +| [infrastructure\_iam\_role\_arn](#output\_infrastructure\_iam\_role\_arn) | Infrastructure IAM role ARN | +| [infrastructure\_iam\_role\_name](#output\_infrastructure\_iam\_role\_name) | Infrastructure IAM role name | | [name](#output\_name) | Name of the service | | [security\_group\_arn](#output\_security\_group\_arn) | Amazon Resource Name (ARN) of the security group | | [security\_group\_id](#output\_security\_group\_id) | ID of the security group | diff --git a/modules/service/outputs.tf b/modules/service/outputs.tf index 1eaa8510..2ca89ce8 100644 --- a/modules/service/outputs.tf +++ b/modules/service/outputs.tf @@ -155,3 +155,17 @@ output "security_group_id" { description = "ID of the security group" value = try(aws_security_group.this[0].id, null) } + +############################################################################################ +# ECS infrastructure IAM role +############################################################################################ + +output "infrastructure_iam_role_arn" { + description = "Infrastructure IAM role ARN" + value = try(aws_iam_role.infrastructure_iam_role[0].arn, null) +} + +output "infrastructure_iam_role_name" { + description = "Infrastructure IAM role name" + value = try(aws_iam_role.infrastructure_iam_role[0].name, null) +} From 42bac0f5548b4cf447ac776dac87fd5579407a06 Mon Sep 17 00:00:00 2001 From: Bryant Biggs Date: Wed, 24 Jul 2024 19:41:57 -0400 Subject: [PATCH 5/5] chore: Update min required AWS provider version --- README.md | 2 +- examples/complete/README.md | 4 ++-- examples/complete/versions.tf | 2 +- examples/ec2-autoscaling/README.md | 4 ++-- examples/ec2-autoscaling/versions.tf | 2 +- examples/fargate/README.md | 4 ++-- examples/fargate/versions.tf | 2 +- modules/cluster/README.md | 4 ++-- modules/cluster/versions.tf | 2 +- modules/container-definition/README.md | 4 ++-- modules/container-definition/versions.tf | 2 +- modules/service/README.md | 4 ++-- modules/service/versions.tf | 2 +- versions.tf | 2 +- wrappers/README.md | 6 +++--- wrappers/cluster/README.md | 6 +++--- wrappers/cluster/versions.tf | 2 +- wrappers/container-definition/README.md | 6 +++--- wrappers/container-definition/versions.tf | 2 +- wrappers/service/README.md | 6 +++--- wrappers/service/versions.tf | 2 +- wrappers/versions.tf | 2 +- 22 files changed, 36 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 301a713b..b2cbef86 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ module "ecs" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers diff --git a/examples/complete/README.md b/examples/complete/README.md index a3de37cf..edffba88 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/examples/ec2-autoscaling/README.md b/examples/ec2-autoscaling/README.md index c95634c1..1ca87e47 100644 --- a/examples/ec2-autoscaling/README.md +++ b/examples/ec2-autoscaling/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/examples/ec2-autoscaling/versions.tf b/examples/ec2-autoscaling/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/ec2-autoscaling/versions.tf +++ b/examples/ec2-autoscaling/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index deb8f958..183616e9 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -27,13 +27,13 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index 5f6e023e..dc999065 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/cluster/README.md b/modules/cluster/README.md index 27e5217c..5f1d8289 100644 --- a/modules/cluster/README.md +++ b/modules/cluster/README.md @@ -137,13 +137,13 @@ module "ecs_cluster" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/modules/cluster/versions.tf b/modules/cluster/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/cluster/versions.tf +++ b/modules/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/container-definition/README.md b/modules/container-definition/README.md index 2b7cc211..48aa292e 100644 --- a/modules/container-definition/README.md +++ b/modules/container-definition/README.md @@ -116,13 +116,13 @@ module "example_ecs_container_definition" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/modules/container-definition/versions.tf b/modules/container-definition/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/container-definition/versions.tf +++ b/modules/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/modules/service/README.md b/modules/service/README.md index 63d29d7f..365791df 100644 --- a/modules/service/README.md +++ b/modules/service/README.md @@ -167,13 +167,13 @@ module "ecs_service" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3 | -| [aws](#requirement\_aws) | >= 5.37 | +| [aws](#requirement\_aws) | >= 5.59 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.37 | +| [aws](#provider\_aws) | >= 5.59 | ## Modules diff --git a/modules/service/versions.tf b/modules/service/versions.tf index 5f6e023e..dc999065 100644 --- a/modules/service/versions.tf +++ b/modules/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/versions.tf b/versions.tf index 5f6e023e..dc999065 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/README.md b/wrappers/README.md index 4d232b92..449acd8a 100644 --- a/wrappers/README.md +++ b/wrappers/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers" + source = "terraform-aws-modules/ecs/aws//wrappers" defaults = { # Default values create = true diff --git a/wrappers/cluster/README.md b/wrappers/cluster/README.md index 724fc78d..1a795281 100644 --- a/wrappers/cluster/README.md +++ b/wrappers/cluster/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/cluster" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/cluster?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/cluster?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/cluster" + source = "terraform-aws-modules/ecs/aws//wrappers/cluster" defaults = { # Default values create = true diff --git a/wrappers/cluster/versions.tf b/wrappers/cluster/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/cluster/versions.tf +++ b/wrappers/cluster/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/container-definition/README.md b/wrappers/container-definition/README.md index 7fec4239..4731aa9a 100644 --- a/wrappers/container-definition/README.md +++ b/wrappers/container-definition/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/container-definition" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/container-definition?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/container-definition?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/container-definition" + source = "terraform-aws-modules/ecs/aws//wrappers/container-definition" defaults = { # Default values create = true diff --git a/wrappers/container-definition/versions.tf b/wrappers/container-definition/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/container-definition/versions.tf +++ b/wrappers/container-definition/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/service/README.md b/wrappers/service/README.md index 0704f3ba..219da916 100644 --- a/wrappers/service/README.md +++ b/wrappers/service/README.md @@ -12,9 +12,9 @@ This wrapper does not implement any extra functionality. ```hcl terraform { - source = "tfr:///terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" + source = "tfr:///terraform-aws-modules/ecs/aws//wrappers/service" # Alternative source: - # source = "git::git@github.com:terraform-aws-modules/terraform-aws-feature-svc-connect-timeout.git//wrappers/service?ref=master" + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ecs.git//wrappers/service?ref=master" } inputs = { @@ -42,7 +42,7 @@ inputs = { ```hcl module "wrapper" { - source = "terraform-aws-modules/feature-svc-connect-timeout/aws//wrappers/service" + source = "terraform-aws-modules/ecs/aws//wrappers/service" defaults = { # Default values create = true diff --git a/wrappers/service/versions.tf b/wrappers/service/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/service/versions.tf +++ b/wrappers/service/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 5f6e023e..dc999065 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.37" + version = ">= 5.59" } } }