diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a6cd369..b348aea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.96.1 + rev: v1.96.2 hooks: - id: terraform_fmt - id: terraform_docs diff --git a/README.md b/README.md index e190380..1d8fc68 100644 --- a/README.md +++ b/README.md @@ -163,14 +163,14 @@ Examples codified under the [`examples`](https://github.com/terraform-aws-module | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.0 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 6.0 ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.0 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules @@ -207,7 +207,7 @@ No modules. | [create\_job\_queues](#input\_create\_job\_queues) | Determines whether to create job queues | `bool` | `true` | no | | [create\_service\_iam\_role](#input\_create\_service\_iam\_role) | Determines whether a an IAM role is created or to use an existing IAM role | `bool` | `true` | no | | [create\_spot\_fleet\_iam\_role](#input\_create\_spot\_fleet\_iam\_role) | Determines whether a an IAM role is created or to use an existing IAM role | `bool` | `false` | no | -| [instance\_iam\_role\_additional\_policies](#input\_instance\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `list(string)` | `[]` | no | +| [instance\_iam\_role\_additional\_policies](#input\_instance\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | | [instance\_iam\_role\_description](#input\_instance\_iam\_role\_description) | Cluster instance IAM role description | `string` | `null` | no | | [instance\_iam\_role\_name](#input\_instance\_iam\_role\_name) | Cluster instance IAM role name | `string` | `null` | no | | [instance\_iam\_role\_path](#input\_instance\_iam\_role\_path) | Cluster instance IAM role path | `string` | `null` | no | @@ -216,14 +216,14 @@ No modules. | [instance\_iam\_role\_use\_name\_prefix](#input\_instance\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`instance_iam_role_name`) is used as a prefix | `string` | `true` | no | | [job\_definitions](#input\_job\_definitions) | Map of job definitions to create | `any` | `{}` | no | | [job\_queues](#input\_job\_queues) | Map of job queue and scheduling policy defintions to create | `any` | `{}` | no | -| [service\_iam\_role\_additional\_policies](#input\_service\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `list(string)` | `[]` | no | +| [service\_iam\_role\_additional\_policies](#input\_service\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | | [service\_iam\_role\_description](#input\_service\_iam\_role\_description) | Batch service IAM role description | `string` | `null` | no | | [service\_iam\_role\_name](#input\_service\_iam\_role\_name) | Batch service IAM role name | `string` | `null` | no | | [service\_iam\_role\_path](#input\_service\_iam\_role\_path) | Batch service IAM role path | `string` | `null` | no | | [service\_iam\_role\_permissions\_boundary](#input\_service\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | | [service\_iam\_role\_tags](#input\_service\_iam\_role\_tags) | A map of additional tags to add to the IAM role created | `map(string)` | `{}` | no | | [service\_iam\_role\_use\_name\_prefix](#input\_service\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`service_iam_role_name`) is used as a prefix | `bool` | `true` | no | -| [spot\_fleet\_iam\_role\_additional\_policies](#input\_spot\_fleet\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `list(string)` | `[]` | no | +| [spot\_fleet\_iam\_role\_additional\_policies](#input\_spot\_fleet\_iam\_role\_additional\_policies) | Additional policies to be added to the IAM role | `map(string)` | `{}` | no | | [spot\_fleet\_iam\_role\_description](#input\_spot\_fleet\_iam\_role\_description) | Spot fleet IAM role description | `string` | `null` | no | | [spot\_fleet\_iam\_role\_name](#input\_spot\_fleet\_iam\_role\_name) | Spot fleet IAM role name | `string` | `null` | no | | [spot\_fleet\_iam\_role\_path](#input\_spot\_fleet\_iam\_role\_path) | Spot fleet IAM role path | `string` | `null` | no | diff --git a/examples/ec2/README.md b/examples/ec2/README.md index d6160a1..a4923c9 100644 --- a/examples/ec2/README.md +++ b/examples/ec2/README.md @@ -24,14 +24,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.0 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 6.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.0 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules @@ -39,16 +39,15 @@ Note that this example may create resources which will incur monetary charges on |------|--------|---------| | [batch](#module\_batch) | ../.. | n/a | | [batch\_disabled](#module\_batch\_disabled) | ../.. | n/a | -| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 4.0 | -| [vpc\_endpoint\_security\_group](#module\_vpc\_endpoint\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | -| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 4.0 | +| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | +| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 | ## Resources | Name | Type | |------|------| | [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | ## Inputs diff --git a/examples/ec2/main.tf b/examples/ec2/main.tf index fc328d7..5d25f11 100644 --- a/examples/ec2/main.tf +++ b/examples/ec2/main.tf @@ -2,9 +2,14 @@ provider "aws" { region = local.region } +data "aws_availability_zones" "available" {} + locals { region = "us-east-1" - name = "batch-ex-${replace(basename(path.cwd), "_", "-")}" + name = "batch-ex-${basename(path.cwd)}" + + vpc_cidr = "10.0.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) tags = { Name = local.name @@ -13,8 +18,6 @@ locals { } } -data "aws_region" "current" {} - ################################################################################ # Batch Module ################################################################################ @@ -31,9 +34,9 @@ module "batch" { instance_iam_role_name = "${local.name}-ecs-instance" instance_iam_role_path = "/batch/" instance_iam_role_description = "IAM instance role/profile for AWS Batch ECS instance(s)" - instance_iam_role_additional_policies = [ - "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" - ] + instance_iam_role_additional_policies = { + AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" + } instance_iam_role_tags = { ModuleCreatedRole = "Yes" } @@ -64,7 +67,7 @@ module "batch" { desired_vcpus = 4 instance_types = ["m5.large", "r5.large"] - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] + security_group_ids = [module.vpc_endpoints.security_group_id] subnets = module.vpc.private_subnets # Note - any tag changes here will force compute environment replacement @@ -91,7 +94,7 @@ module "batch" { desired_vcpus = 4 instance_types = ["m4.large", "m3.large", "r4.large", "r3.large"] - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] + security_group_ids = [module.vpc_endpoints.security_group_id] subnets = module.vpc.private_subnets # Note - any tag changes here will force compute environment replacement @@ -201,92 +204,63 @@ module "batch" { module "vpc" { source = "terraform-aws-modules/vpc/aws" - version = "~> 4.0" + version = "~> 5.0" name = local.name - cidr = "10.99.0.0/18" + cidr = local.vpc_cidr - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - public_subnets = ["10.99.0.0/24", "10.99.1.0/24", "10.99.2.0/24"] - private_subnets = ["10.99.3.0/24", "10.99.4.0/24", "10.99.5.0/24"] + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] + public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] enable_nat_gateway = true single_nat_gateway = true - public_route_table_tags = { Name = "${local.name}-public" } - public_subnet_tags = { Name = "${local.name}-public" } - private_route_table_tags = { Name = "${local.name}-private" } - private_subnet_tags = { Name = "${local.name}-private" } - - enable_dhcp_options = true - enable_dns_hostnames = true - dhcp_options_domain_name = data.aws_region.current.name == "us-east-1" ? "ec2.internal" : "${data.aws_region.current.name}.compute.internal" - tags = local.tags } module "vpc_endpoints" { source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" - version = "~> 4.0" - - vpc_id = module.vpc.vpc_id - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] - - endpoints = { - ecr_api = { - service = "ecr.api" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - ecr_dkr = { - service = "ecr.dkr" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - ecs = { - service = "ecs" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - ssm = { - service = "ssm" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - s3 = { - service = "s3" - service_type = "Gateway" - route_table_ids = module.vpc.private_route_table_ids + version = "~> 5.0" + + vpc_id = module.vpc.vpc_id + + # Security group + create_security_group = true + security_group_name_prefix = "${local.name}-vpc-endpoints-" + security_group_description = "VPC endpoint security group" + security_group_rules = { + ingress_https = { + description = "HTTPS from VPC" + cidr_blocks = [module.vpc.vpc_cidr_block] } } - tags = local.tags -} - -module "vpc_endpoint_security_group" { - source = "terraform-aws-modules/security-group/aws" - version = "~> 4.0" - - name = "${local.name}-vpc-endpoint" - description = "Security group for VPC endpoints" - vpc_id = module.vpc.vpc_id - - ingress_with_self = [ + endpoints = merge( { - from_port = 443 - to_port = 443 - protocol = "tcp" - description = "Container to VPC endpoint service" - self = true + s3 = { + service = "s3" + service_type = "Gateway" + route_table_ids = module.vpc.private_route_table_ids + tags = { + Name = "${local.name}-s3" + } + } }, - ] - - egress_cidr_blocks = ["0.0.0.0/0"] - egress_rules = ["https-443-tcp"] + { + for service in toset(["ecr.api", "ecr.dkr", "ecs", "ssm"]) : + replace(service, ".", "_") => + { + service = service + subnet_ids = module.vpc.private_subnets + private_dns_enabled = true + tags = { Name = "${local.name}-${service}" } + } + } + ) tags = local.tags } - resource "aws_cloudwatch_log_group" "this" { name = "/aws/batch/${local.name}" retention_in_days = 1 diff --git a/examples/ec2/versions.tf b/examples/ec2/versions.tf index d8dd1a4..88fefa8 100644 --- a/examples/ec2/versions.tf +++ b/examples/ec2/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0" + version = ">= 6.0" } } } diff --git a/examples/fargate/README.md b/examples/fargate/README.md index 266ef70..b1a1eeb 100644 --- a/examples/fargate/README.md +++ b/examples/fargate/README.md @@ -24,14 +24,14 @@ Note that this example may create resources which will incur monetary charges on | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.0 | +| [terraform](#requirement\_terraform) | >= 1.3 | +| [aws](#requirement\_aws) | >= 6.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.0 | +| [aws](#provider\_aws) | >= 6.0 | ## Modules @@ -39,9 +39,8 @@ Note that this example may create resources which will incur monetary charges on |------|--------|---------| | [batch](#module\_batch) | ../.. | n/a | | [batch\_disabled](#module\_batch\_disabled) | ../.. | n/a | -| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 4.0 | -| [vpc\_endpoint\_security\_group](#module\_vpc\_endpoint\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | -| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 4.0 | +| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | +| [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 | ## Resources @@ -50,8 +49,8 @@ Note that this example may create resources which will incur monetary charges on | [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | | [aws_iam_role.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy_attachment.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | | [aws_iam_policy_document.ecs_task_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs diff --git a/examples/fargate/main.tf b/examples/fargate/main.tf index 46d950a..b714314 100644 --- a/examples/fargate/main.tf +++ b/examples/fargate/main.tf @@ -2,9 +2,14 @@ provider "aws" { region = local.region } +data "aws_availability_zones" "available" {} + locals { region = "us-east-1" - name = "batch-ex-${replace(basename(path.cwd), "_", "-")}" + name = "batch-ex-${basename(path.cwd)}" + + vpc_cidr = "10.0.0.0/16" + azs = slice(data.aws_availability_zones.available.names, 0, 3) tags = { Name = local.name @@ -13,8 +18,6 @@ locals { } } -data "aws_region" "current" {} - ################################################################################ # Batch Module ################################################################################ @@ -58,7 +61,7 @@ module "batch" { type = "FARGATE" max_vcpus = 4 - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] + security_group_ids = [module.vpc_endpoints.security_group_id] subnets = module.vpc.private_subnets # `tags = {}` here is not applicable for spot @@ -72,7 +75,7 @@ module "batch" { type = "FARGATE_SPOT" max_vcpus = 4 - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] + security_group_ids = [module.vpc_endpoints.security_group_id] subnets = module.vpc.private_subnets # `tags = {}` here is not applicable for spot @@ -173,78 +176,59 @@ module "batch" { module "vpc" { source = "terraform-aws-modules/vpc/aws" - version = "~> 4.0" + version = "~> 5.0" name = local.name - cidr = "10.99.0.0/18" + cidr = local.vpc_cidr - azs = ["${local.region}a", "${local.region}b", "${local.region}c"] - public_subnets = ["10.99.0.0/24", "10.99.1.0/24", "10.99.2.0/24"] - private_subnets = ["10.99.3.0/24", "10.99.4.0/24", "10.99.5.0/24"] + azs = local.azs + private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] + public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] enable_nat_gateway = true single_nat_gateway = true - public_route_table_tags = { Name = "${local.name}-public" } - public_subnet_tags = { Name = "${local.name}-public" } - private_route_table_tags = { Name = "${local.name}-private" } - private_subnet_tags = { Name = "${local.name}-private" } - - enable_dhcp_options = true - enable_dns_hostnames = true - dhcp_options_domain_name = data.aws_region.current.name == "us-east-1" ? "ec2.internal" : "${data.aws_region.current.name}.compute.internal" - tags = local.tags } module "vpc_endpoints" { source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" - version = "~> 4.0" - - vpc_id = module.vpc.vpc_id - security_group_ids = [module.vpc_endpoint_security_group.security_group_id] - - endpoints = { - ecr_api = { - service = "ecr.api" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - ecr_dkr = { - service = "ecr.dkr" - private_dns_enabled = true - subnet_ids = module.vpc.private_subnets - } - s3 = { - service = "s3" - service_type = "Gateway" - route_table_ids = module.vpc.private_route_table_ids + version = "~> 5.0" + + vpc_id = module.vpc.vpc_id + + # Security group + create_security_group = true + security_group_name_prefix = "${local.name}-vpc-endpoints-" + security_group_description = "VPC endpoint security group" + security_group_rules = { + ingress_https = { + description = "HTTPS from VPC" + cidr_blocks = [module.vpc.vpc_cidr_block] } } - - tags = local.tags -} - -module "vpc_endpoint_security_group" { - source = "terraform-aws-modules/security-group/aws" - version = "~> 4.0" - - name = "${local.name}-vpc-endpoint" - description = "Security group for VPC endpoints" - vpc_id = module.vpc.vpc_id - - ingress_with_self = [ + endpoints = merge( { - from_port = 443 - to_port = 443 - protocol = "tcp" - description = "Container to VPC endpoint service" - self = true + s3 = { + service = "s3" + service_type = "Gateway" + route_table_ids = module.vpc.private_route_table_ids + tags = { + Name = "${local.name}-s3" + } + } }, - ] - - egress_cidr_blocks = ["0.0.0.0/0"] - egress_rules = ["https-443-tcp"] + { + for service in toset(["ecr.api", "ecr.dkr", "ecs"]) : + replace(service, ".", "_") => + { + service = service + subnet_ids = module.vpc.private_subnets + private_dns_enabled = true + tags = { Name = "${local.name}-${service}" } + } + } + ) tags = local.tags } diff --git a/examples/fargate/versions.tf b/examples/fargate/versions.tf index d8dd1a4..aaf26b8 100644 --- a/examples/fargate/versions.tf +++ b/examples/fargate/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0" + version = ">= 6.0" } } } diff --git a/main.tf b/main.tf index d1ca1d6..27731f6 100644 --- a/main.tf +++ b/main.tf @@ -1,4 +1,11 @@ -data "aws_partition" "current" {} +data "aws_partition" "current" { + count = var.create ? 1 : 0 +} + +locals { + partition = try(data.aws_partition.current[0].partition, "") + dns_suffix = try(data.aws_partition.current[0].dns_suffix, "") +} ################################################################################ # Compute Environment(s) @@ -7,8 +14,8 @@ data "aws_partition" "current" {} resource "aws_batch_compute_environment" "this" { for_each = { for k, v in var.compute_environments : k => v if var.create } - compute_environment_name = lookup(each.value, "name", null) - compute_environment_name_prefix = try(each.value.name_prefix, null) != null ? "${each.value.name_prefix}-" : null + name = lookup(each.value, "name", null) + name_prefix = try(each.value.name_prefix, null) != null ? "${each.value.name_prefix}-" : null service_role = var.create_service_iam_role ? aws_iam_role.service[0].arn : each.value.service_role type = lookup(each.value, "type", "MANAGED") @@ -70,15 +77,23 @@ resource "aws_batch_compute_environment" "this" { create_before_destroy = true } - tags = merge(var.tags, lookup(each.value, "tags", {})) + tags = merge( + { terraform-aws-modules = "batch" }, + var.tags, + try(each.value.tags, {}) + ) } ################################################################################ # Compute Environment - Instance Role ################################################################################ +locals { + create_instance_iam_role = var.create && var.create_instance_iam_role +} + data "aws_iam_policy_document" "instance" { - count = var.create && var.create_instance_iam_role ? 1 : 0 + count = local.create_instance_iam_role ? 1 : 0 statement { sid = "ECSAssumeRole" @@ -86,13 +101,13 @@ data "aws_iam_policy_document" "instance" { principals { type = "Service" - identifiers = ["ec2.${data.aws_partition.current.dns_suffix}"] + identifiers = ["ec2.${local.dns_suffix}"] } } } resource "aws_iam_role" "instance" { - count = var.create && var.create_instance_iam_role ? 1 : 0 + count = local.create_instance_iam_role ? 1 : 0 name = var.instance_iam_role_use_name_prefix ? null : var.instance_iam_role_name name_prefix = var.instance_iam_role_use_name_prefix ? "${var.instance_iam_role_name}-" : null @@ -107,20 +122,25 @@ resource "aws_iam_role" "instance" { create_before_destroy = true } - tags = merge(var.tags, var.instance_iam_role_tags) + tags = merge( + var.tags, + var.instance_iam_role_tags, + ) } resource "aws_iam_role_policy_attachment" "instance" { - for_each = var.create && var.create_instance_iam_role ? toset(compact(distinct(concat([ - "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" - ], var.instance_iam_role_additional_policies)))) : toset([]) + for_each = { for k, v in merge( + { + AmazonEC2ContainerServiceforEC2Role = "arn:${local.partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" + }, + var.instance_iam_role_additional_policies) : k => v if local.create_instance_iam_role } policy_arn = each.value role = aws_iam_role.instance[0].name } resource "aws_iam_instance_profile" "instance" { - count = var.create && var.create_instance_iam_role ? 1 : 0 + count = local.create_instance_iam_role ? 1 : 0 name = var.instance_iam_role_use_name_prefix ? null : var.instance_iam_role_name name_prefix = var.instance_iam_role_use_name_prefix ? "${var.instance_iam_role_name}-" : null @@ -131,15 +151,22 @@ resource "aws_iam_instance_profile" "instance" { create_before_destroy = true } - tags = merge(var.tags, var.instance_iam_role_tags) + tags = merge( + var.tags, + var.instance_iam_role_tags, + ) } ################################################################################ # Compute Environment - Service Role ################################################################################ +locals { + create_service_iam_role = var.create && var.create_service_iam_role +} + data "aws_iam_policy_document" "service" { - count = var.create && var.create_service_iam_role ? 1 : 0 + count = local.create_service_iam_role ? 1 : 0 statement { sid = "ECSAssumeRole" @@ -147,13 +174,13 @@ data "aws_iam_policy_document" "service" { principals { type = "Service" - identifiers = ["batch.${data.aws_partition.current.dns_suffix}"] + identifiers = ["batch.${local.dns_suffix}"] } } } resource "aws_iam_role" "service" { - count = var.create && var.create_service_iam_role ? 1 : 0 + count = local.create_service_iam_role ? 1 : 0 name = var.service_iam_role_use_name_prefix ? null : var.service_iam_role_name name_prefix = var.service_iam_role_use_name_prefix ? "${var.service_iam_role_name}-" : null @@ -168,13 +195,18 @@ resource "aws_iam_role" "service" { create_before_destroy = true } - tags = merge(var.tags, var.service_iam_role_tags) + tags = merge( + var.tags, + var.service_iam_role_tags, + ) } resource "aws_iam_role_policy_attachment" "service" { - for_each = var.create && var.create_service_iam_role ? toset(compact(distinct(concat([ - "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSBatchServiceRole" - ], var.service_iam_role_additional_policies)))) : toset([]) + for_each = { for k, v in merge( + { + AWSBatchServiceRole = "arn:${local.partition}:iam::aws:policy/service-role/AWSBatchServiceRole" + }, + var.service_iam_role_additional_policies) : k => v if local.create_service_iam_role } policy_arn = each.value role = aws_iam_role.service[0].name @@ -184,8 +216,12 @@ resource "aws_iam_role_policy_attachment" "service" { # Compute Environment - Spot Fleet Role ################################################################################ +locals { + create_spot_fleet_iam_role = var.create && var.create_spot_fleet_iam_role +} + data "aws_iam_policy_document" "spot_fleet" { - count = var.create && var.create_spot_fleet_iam_role ? 1 : 0 + count = local.create_spot_fleet_iam_role ? 1 : 0 statement { sid = "ECSAssumeRole" @@ -193,13 +229,13 @@ data "aws_iam_policy_document" "spot_fleet" { principals { type = "Service" - identifiers = ["spotfleet.${data.aws_partition.current.dns_suffix}"] + identifiers = ["spotfleet.${local.dns_suffix}"] } } } resource "aws_iam_role" "spot_fleet" { - count = var.create && var.create_spot_fleet_iam_role ? 1 : 0 + count = local.create_spot_fleet_iam_role ? 1 : 0 name = var.spot_fleet_iam_role_use_name_prefix ? null : var.spot_fleet_iam_role_name name_prefix = var.spot_fleet_iam_role_use_name_prefix ? "${var.spot_fleet_iam_role_name}-" : null @@ -214,13 +250,18 @@ resource "aws_iam_role" "spot_fleet" { create_before_destroy = true } - tags = merge(var.tags, var.spot_fleet_iam_role_tags) + tags = merge( + var.tags, + var.spot_fleet_iam_role_tags, + ) } resource "aws_iam_role_policy_attachment" "spot_fleet" { - for_each = var.create && var.create_spot_fleet_iam_role ? toset(compact(distinct(concat([ - "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole" - ], var.spot_fleet_iam_role_additional_policies)))) : toset([]) + for_each = { for k, v in merge( + { + AmazonEC2SpotFleetTaggingRole = "arn:${local.partition}:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole" + }, + var.spot_fleet_iam_role_additional_policies) : k => v if local.create_spot_fleet_iam_role } policy_arn = each.value role = aws_iam_role.spot_fleet[0].name @@ -230,16 +271,39 @@ resource "aws_iam_role_policy_attachment" "spot_fleet" { # Job Queue ################################################################################ +locals { + create_job_queues = var.create && var.create_job_queues +} + resource "aws_batch_job_queue" "this" { - for_each = { for k, v in var.job_queues : k => v if var.create && var.create_job_queues } + for_each = { for k, v in var.job_queues : k => v if local.create_job_queues } name = each.value.name state = each.value.state priority = each.value.priority scheduling_policy_arn = try(each.value.create_scheduling_policy, true) ? aws_batch_scheduling_policy.this[each.key].arn : try(each.value.scheduling_policy_arn, null) - compute_environments = slice([for env in try(each.value.compute_environments, keys(var.compute_environments)) : aws_batch_compute_environment.this[env].arn], 0, min(length(try(each.value.compute_environments, keys(var.compute_environments))), 3)) - tags = merge(var.tags, lookup(each.value, "tags", {})) + dynamic "compute_environment_order" { + for_each = [ + for idx, env in slice( + try(each.value.compute_environments, keys(var.compute_environments)), + 0, + min(length(try(each.value.compute_environments, keys(var.compute_environments))), 3) + ) : { + order = idx + 1 + arn = aws_batch_compute_environment.this[env].arn + } + ] + + content { + order = compute_environment_order.value.order + compute_environment = compute_environment_order.value.arn + } + } + tags = merge( + var.tags, + try(each.value.tags, {}), + ) } ################################################################################ @@ -247,8 +311,8 @@ resource "aws_batch_job_queue" "this" { ################################################################################ resource "aws_batch_scheduling_policy" "this" { - for_each = { for k, v in var.job_queues : k => v if var.create && var.create_job_queues && try(v.create_scheduling_policy, true) } - + for_each = { for k, v in var.job_queues : k => v if local.create_job_queues && try(v.create_scheduling_policy, true) } + name = each.value.name fair_share_policy { @@ -259,12 +323,15 @@ resource "aws_batch_scheduling_policy" "this" { for_each = { for k, v in try(each.value.fair_share_policy.share_distribution, {}) : k => v if can(each.value.fair_share_policy.share_distribution) } content { share_identifier = share_distribution.value.share_identifier - weight_factor = lookup(share_distribution.value, "weight_factor", null) + weight_factor = try(share_distribution.value.weight_factor, null) } } } - tags = merge(var.tags, lookup(each.value, "tags", {})) + tags = merge( + var.tags, + try(each.value.tags, {}), + ) } ################################################################################ @@ -274,32 +341,35 @@ resource "aws_batch_scheduling_policy" "this" { resource "aws_batch_job_definition" "this" { for_each = { for k, v in var.job_definitions : k => v if var.create && var.create_job_definitions } - name = lookup(each.value, "name", each.key) - container_properties = lookup(each.value, "container_properties", null) - parameters = lookup(each.value, "parameters", {}) - platform_capabilities = lookup(each.value, "platform_capabilities", null) - type = lookup(each.value, "type", "container") + name = try(each.value.name, each.key) + container_properties = try(each.value.container_properties, null) + parameters = try(each.value.parameters, {}) + platform_capabilities = try(each.value.platform_capabilities, null) + type = try(each.value.type, "container") dynamic "retry_strategy" { - for_each = lookup(each.value, "retry_strategy", null) != null ? [each.value.retry_strategy] : [] + for_each = try([each.value.retry_strategy], []) content { - attempts = lookup(retry_strategy.value, "attempts", null) + attempts = try(retry_strategy.value.attempts, null) dynamic "evaluate_on_exit" { - for_each = try(retry_strategy.value.evaluate_on_exit, {}) + for_each = try(retry_strategy.value.evaluate_on_exit, []) content { action = evaluate_on_exit.value.action - on_exit_code = lookup(evaluate_on_exit.value, "on_exit_code", null) - on_reason = lookup(evaluate_on_exit.value, "on_reason", null) - on_status_reason = lookup(evaluate_on_exit.value, "on_status_reason", null) + on_exit_code = try(evaluate_on_exit.value.on_exit_code, null) + on_reason = try(evaluate_on_exit.value.on_reason, null) + on_status_reason = try(evaluate_on_exit.value.on_status_reason, null) } } } } timeout { - attempt_duration_seconds = lookup(each.value, "attempt_duration_seconds", null) + attempt_duration_seconds = try(each.value.attempt_duration_seconds, null) } - propagate_tags = lookup(each.value, "propagate_tags", null) - tags = merge(var.tags, lookup(each.value, "tags", {})) + propagate_tags = try(each.value.propagate_tags, null) + + tags = merge( + var.tags, try(each.value.tags, {}), + ) } diff --git a/variables.tf b/variables.tf index 04c30a2..867a359 100644 --- a/variables.tf +++ b/variables.tf @@ -62,8 +62,8 @@ variable "instance_iam_role_permissions_boundary" { variable "instance_iam_role_additional_policies" { description = "Additional policies to be added to the IAM role" - type = list(string) - default = [] + type = map(string) + default = {} } variable "instance_iam_role_tags" { @@ -114,8 +114,8 @@ variable "service_iam_role_permissions_boundary" { variable "service_iam_role_additional_policies" { description = "Additional policies to be added to the IAM role" - type = list(string) - default = [] + type = map(string) + default = {} } variable "service_iam_role_tags" { @@ -166,8 +166,8 @@ variable "spot_fleet_iam_role_permissions_boundary" { variable "spot_fleet_iam_role_additional_policies" { description = "Additional policies to be added to the IAM role" - type = list(string) - default = [] + type = map(string) + default = {} } variable "spot_fleet_iam_role_tags" { diff --git a/versions.tf b/versions.tf index d8dd1a4..88fefa8 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.3" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0" + version = ">= 6.0" } } }