Files

1578 lines
875 KiB
JSON

{
"sessionId": "6bd0db73-863c-4f0b-80e1-7ba56b1a7eea",
"projectHash": "d2d5f4c51b3ac9afd9ddd000bb98ba9cea9b1fdbcb0f7c87c7cddc0043a2d24f",
"startTime": "2026-01-23T17:12:46.031Z",
"lastUpdated": "2026-01-23T17:44:38.771Z",
"messages": [
{
"id": "a314e56e-d3ce-45a5-9f72-87475c6ddadb",
"timestamp": "2026-01-23T17:12:46.031Z",
"type": "user",
"content": "make containerInsights a configurable setting for ecs clusters."
},
{
"id": "0087c451-00ca-4eec-9685-ffad3228a333",
"timestamp": "2026-01-23T17:13:00.668Z",
"type": "gemini",
"content": "I will start by searching for the `aws_ecs_cluster` resource definition to locate where the ECS cluster is configured and checking for any existing `containerInsights` settings.",
"thoughts": [
{
"subject": "Examining the Codebase",
"description": "I've begun the process of identifying the relevant locations within the codebase where ECS clusters are defined. My initial approach involves listing files to pinpoint where the `containerInsights` configuration can be found, or ideally, where it can be incorporated. I plan to delve deeper into the configuration files to understand the current implementation.",
"timestamp": "2026-01-23T17:12:58.626Z"
},
{
"subject": "Locating Cluster Definitions",
"description": "I'm now zeroing in on the file `ecs-cluster-infrastructure.tf`, as it seems most promising for containing the ECS cluster definitions. I'll execute a search for instances of `aws_ecs_cluster` to pinpoint the specific configuration blocks. I'll also be sure to check `variables.tf` for any existing ECS cluster-related variables.",
"timestamp": "2026-01-23T17:13:00.357Z"
}
],
"tokens": {
"input": 15230,
"output": 50,
"cached": 0,
"thoughts": 170,
"tool": 0,
"total": 15450
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "search_file_content-1769188380662-4c8dec9575014",
"name": "search_file_content",
"args": {
"pattern": "aws_ecs_cluster"
},
"result": [
{
"functionResponse": {
"id": "search_file_content-1769188380662-4c8dec9575014",
"name": "search_file_content",
"response": {
"output": "Found 16 matches for pattern \"aws_ecs_cluster\" in path \".\":\n---\nFile: utilities-infrastructure-ecs-cluster.tf\nL1: resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n---\nFile: ecs-cluster-infrastructure-service-codedeploy-blue-green.tf\nL109: cluster_name = aws_ecs_cluster.infrastructure[0].name\n---\nFile: ecs-cluster-infrastructure-alert-ecs-asg-diff.tf\nL12: alarm_description = \"Container Instance / ASG Instance Difference for ${aws_ecs_cluster.infrastructure[0].name} Cluster\"\nL23: ClusterName = aws_ecs_cluster.infrastructure[0].name\n---\nFile: ecs-cluster-infrastructure-service-scheduled-task.tf\nL191: arn = aws_ecs_cluster.infrastructure[0].arn\n---\nFile: ecs-cluster-infrastructure-service-build-pipeline.tf\nL209: ClusterName = aws_ecs_cluster.infrastructure[0].name\n---\nFile: README.md\nL114: | [aws_ecs_cluster.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |\nL115: | [aws_ecs_cluster.infrastrucutre_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |\n---\nFile: ecs-cluster-infrastructure.tf\nL1: resource \"aws_ecs_cluster\" \"infrastructure\" {\n---\nFile: ecs-cluster-infrastructure-service.tf\nL280: cluster = aws_ecs_cluster.infrastructure[0].name\n---\nFile: ecs-cluster-infrastructure-logspout-service.tf\nL45: cluster = aws_ecs_cluster.infrastructure[0].name\n---\nFile: rds-infrastructure-s3-backups-scheduled-task.tf\nL64: arn = aws_ecs_cluster.infrastrucutre_utilities[0].arn\n---\nFile: ecs-cluster-infrastructure-datadog-agent-service.tf\nL320: cluster = aws_ecs_cluster.infrastructure[0].name\n---\nFile: ecs-cluster-infrastructure-alert-asg-cpu.tf\nL12: alarm_description = \"CPU Utilization for ${aws_ecs_cluster.infrastructure[0].name}'s Auto Scaling Group\"\n---\nFile: ecs-cluster-infrastructure-alert-pending-tasks.tf\nL12: alarm_description = \"Pending Tasks for ${aws_ecs_cluster.infrastructure[0].name} Cluster\"\nL23: ClusterName = aws_ecs_cluster.infrastructure[0].name\n---"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:13:00.949Z",
"resultDisplay": "Found 16 matches",
"displayName": "SearchText",
"description": "FAST, optimized search powered by `ripgrep`. PREFERRED over standard `run_shell_command(\"grep ...\")` due to better performance and automatic output limiting (max 20k matches).",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "182af92b-941e-44ae-af59-ca0117a8c0b0",
"timestamp": "2026-01-23T17:13:19.087Z",
"type": "gemini",
"content": "I will read `ecs-cluster-infrastructure.tf`, `utilities-infrastructure-ecs-cluster.tf`, and `variables.tf` to understand the current ECS cluster configurations and variable definitions.",
"thoughts": [
{
"subject": "Investigating ECS Clusters",
"description": "I'm currently focused on the ECS cluster definitions. It seems there are two distinct clusters defined in the Terraform configuration: one in `ecs-cluster-infrastructure.tf` and another in `utilities-infrastructure-ecs-cluster.tf`. I need to understand the purpose and relationship of these clusters.",
"timestamp": "2026-01-23T17:13:11.402Z"
},
{
"subject": "Assessing Cluster Configurations",
"description": "I'm now diving into the `ecs-cluster-infrastructure.tf` file. My goal is to determine the configuration details for the primary infrastructure cluster, specifically noting the `containerInsights` setting. Afterwards, I will shift my focus to `utilities-infrastructure-ecs-cluster.tf`. I need to understand if there is a conflict. Also, I intend to scrutinize `variables.tf` to see how best to integrate a new variable.",
"timestamp": "2026-01-23T17:13:18.365Z"
}
],
"tokens": {
"input": 13796,
"output": 89,
"cached": 0,
"thoughts": 134,
"tool": 0,
"total": 14019
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769188398701-227ca9095f4c8",
"name": "read_file",
"args": {
"file_path": "ecs-cluster-infrastructure.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188398701-227ca9095f4c8",
"name": "read_file",
"response": {
"output": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:13:19.138Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
},
{
"id": "read_file-1769188398893-b04d538a531e8",
"name": "read_file",
"args": {
"file_path": "utilities-infrastructure-ecs-cluster.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188398893-b04d538a531e8",
"name": "read_file",
"response": {
"output": "resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n count = local.enable_infrastructure_utilities ? 1 : 0\n\n name = local.infrastructure_utilities_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:13:19.138Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
},
{
"id": "read_file-1769188399081-09ea9d37b65d",
"name": "read_file",
"args": {
"file_path": "variables.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188399081-09ea9d37b65d",
"name": "read_file",
"response": {
"output": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:13:19.138Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "487530da-a7b6-430c-9740-e21f6895bc84",
"timestamp": "2026-01-23T17:14:11.395Z",
"type": "gemini",
"content": "I will read `locals.tf` and search for \"utilities\" in `variables.tf` to determine the appropriate variable structure for enabling container insights on both the infrastructure and utilities ECS clusters.",
"thoughts": [
{
"subject": "Observing Container Insights",
"description": "I'm currently focused on the ECS cluster's configuration within the Terraform file. Specifically, I've noted that container insights are explicitly enabled. I'm considering the implications of this hardcoded setting and how it might impact the cluster's overall monitoring and observability strategy.",
"timestamp": "2026-01-23T17:13:40.895Z"
},
{
"subject": "Assessing Configuration Variables",
"description": "I'm now diving deeper into the existing variables file. My initial plan was to introduce two new variables to control container insights. However, after further review, I want to avoid redundant variables if possible. I'm carefully examining the existing infrastructure configuration and local variables, and I'm reconsidering the best approach for managing these settings. My goal is to ensure flexibility without unnecessary complexity. I want to search for \"utilities\" now in the variables.tf file.",
"timestamp": "2026-01-23T17:14:10.895Z"
}
],
"tokens": {
"input": 29587,
"output": 75,
"cached": 28557,
"thoughts": 407,
"tool": 0,
"total": 30069
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769188451198-d5b56d7871f7a",
"name": "read_file",
"args": {
"file_path": "locals.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188451198-d5b56d7871f7a",
"name": "read_file",
"response": {
"output": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:14:11.456Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
},
{
"id": "search_file_content-1769188451387-d1d52b1c84c7f8",
"name": "search_file_content",
"args": {
"pattern": "utilities",
"search_file_content_file_path": "variables.tf"
},
"result": [
{
"functionResponse": {
"id": "search_file_content-1769188451387-d1d52b1c84c7f8",
"name": "search_file_content",
"response": {
"output": "Found 231 matches for pattern \"utilities\" in path \".\":\n---\nFile: utilities-infrastructure-ecs-cluster.tf\nL1: resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\nL2: count = local.enable_infrastructure_utilities ? 1 : 0\nL4: name = local.infrastructure_utilities_ecs_cluster_name\n---\nFile: utilities-infrastructure-task-iam.tf\nL1: resource \"aws_iam_role\" \"infrastructure_utilities_task_execution\" {\nL2: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL4: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-execution-${each.key}\"), 0, 6)}\"\nL5: description = \"${local.resource_prefix}-utilities-task-execution-${each.key}\"\nL12: resource \"aws_iam_policy\" \"infrastructure_utilities_task_execution_ecr_pull\" {\nL13: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL15: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-execution-${each.key}-ecr-pull\"), 0, 6)}\"\nL16: description = \"${local.resource_prefix}-utilities-task-execution-${each.key}-ecr-pull\"\nL19: { ecr_repository_arn = aws_ecr_repository.infrastructure_utilities[0].arn }\nL23: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_execution_ecr_pull\" {\nL24: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL26: role = aws_iam_role.infrastructure_utilities_task_execution[each.key].name\nL27: policy_arn = aws_iam_policy.infrastructure_utilities_task_execution_ecr_pull[each.key].arn\nL30: resource \"aws_iam_policy\" \"infrastructure_utilities_task_execution_cloudwatch_logs\" {\nL31: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL33: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-execution-${each.key}-cloudwatch-logs\"), 0, 6)}\"\nL34: description = \"${local.resource_prefix}-utilities-task-execution-${each.key}-cloudwatch-logs\"\nL38: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_execution_cloudwatch_logs\" {\nL39: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL41: role = aws_iam_role.infrastructure_utilities_task_execution[each.key].name\nL42: policy_arn = aws_iam_policy.infrastructure_utilities_task_execution_cloudwatch_logs[each.key].arn\nL45: resource \"aws_iam_policy\" \"infrastructure_utilities_task_execution_get_secret_value\" {\nL46: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL48: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-execution-${each.key}-get-secret-value\"), 0, 6)}\"\nL49: description = \"${local.resource_prefix}-utilities-task-execution-${each.key}-get-secret-value\"\nL57: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_execution_get_secret_value\" {\nL58: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL60: role = aws_iam_role.infrastructure_utilities_task_execution[each.key].name\nL61: policy_arn = aws_iam_policy.infrastructure_utilities_task_execution_get_secret_value[each.key].arn\nL64: resource \"aws_iam_policy\" \"infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt\" {\nL65: for_each = local.enable_infrastructure_utilities ? {\nL69: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}-get-secret-value-kms-decrypt\"), 0, 6)}\"\nL70: description = \"${local.resource_prefix}-utilities-task-${each.key}-get-secret-value-kms-decrypt\"\nL76: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt\" {\nL77: for_each = local.enable_infrastructure_utilities ? {\nL81: role = aws_iam_role.infrastructure_utilities_task_execution[each.key].name\nL82: policy_arn = aws_iam_policy.infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt[each.key].arn\nL85: resource \"aws_iam_role\" \"infrastructure_utilities_task\" {\nL86: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL88: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}\"), 0, 6)}\"\nL89: description = \"${local.resource_prefix}-utilities-task-${each.key}\"\nL110: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL127: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL131: resource \"aws_iam_policy\" \"infrastructure_utilities_task_ssm_create_channels\" {\nL132: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL134: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}-ssm-create-channels\"), 0, 6)}\"\nL135: description = \"${local.resource_prefix}-utilities-task-${each.key}-ssm-create-channels\"\nL139: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_ssm_create_channels\" {\nL140: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL142: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL143: policy_arn = aws_iam_policy.infrastructure_utilities_task_ssm_create_channels[each.key].arn\nL146: resource \"aws_iam_policy\" \"infrastructure_utilities_task_ecs_exec_log_s3_write\" {\nL147: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL149: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}-ecs-exec-log-s3-write\"), 0, 6)}\"\nL150: description = \"${local.resource_prefix}-utilities-task-${each.key}-ecs-exec-log-s3-write\"\nL157: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_ecs_exec_log_s3_write\" {\nL158: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL160: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL161: policy_arn = aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_s3_write[each.key].arn\nL164: resource \"aws_iam_policy\" \"infrastructure_utilities_task_ecs_exec_log_kms_decrypt\" {\nL165: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL167: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}-ecs-exec-log-kms-decrypt\"), 0, 6)}\"\nL168: description = \"${local.resource_prefix}-utilities-task-${each.key}-ecs-exec-log-kms-decrypt\"\nL174: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_ecs_exec_log_kms_decrypt\" {\nL175: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL177: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL178: policy_arn = aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_kms_decrypt[each.key].arn\nL181: resource \"aws_iam_policy\" \"infrastructure_utilities_task_kms_encrypt\" {\nL182: for_each = local.enable_infrastructure_utilities && local.infrastructure_kms_encryption ? local.infrastructure_rds : {}\nL184: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-task-${each.key}-kms-encrypt\"), 0, 6)}\"\nL185: description = \"${local.resource_prefix}-utilities-task-${each.key}-kms-encrypt\"\nL192: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_task_kms_encrypt\" {\nL193: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL195: role = aws_iam_role.infrastructure_utilities_task[each.key].name\nL196: policy_arn = aws_iam_policy.infrastructure_utilities_task_kms_encrypt[each.key].arn\n---\nFile: utilities-infrastructure-cloudwatch-logs.tf\nL1: resource \"aws_cloudwatch_log_group\" \"infrastructure_utilities\" {\nL2: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL4: name = \"${local.resource_prefix}-infrastructure-utilities-${each.key}\"\n---\nFile: README.md\nL73: | [aws_cloudwatch_event_rule.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\nL82: | [aws_cloudwatch_event_target.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\nL90: | [aws_cloudwatch_log_group.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\nL99: | [aws_codebuild_project.infrastructure_utilities_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |\nL109: | [aws_ecr_lifecycle_policy.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource |\nL113: | [aws_ecr_repository.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |\nL115: | [aws_ecs_cluster.infrastrucutre_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |\nL123: | [aws_ecs_task_definition.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\nL200: | [aws_iam_policy.infrastructure_utilities_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL201: | [aws_iam_policy.infrastructure_utilities_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL202: | [aws_iam_policy.infrastructure_utilities_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL203: | [aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL204: | [aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL205: | [aws_iam_policy.infrastructure_utilities_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL206: | [aws_iam_policy.infrastructure_utilities_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL207: | [aws_iam_policy.infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL208: | [aws_iam_policy.infrastructure_utilities_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL209: | [aws_iam_policy.infrastructure_utilities_task_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL210: | [aws_iam_policy.infrastructure_utilities_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\nL230: | [aws_iam_role.infrastructure_utilities_image_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\nL231: | [aws_iam_role.infrastructure_utilities_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\nL232: | [aws_iam_role.infrastructure_utilities_task_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\nL293: | [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL294: | [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL295: | [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL296: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL297: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL298: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL299: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL300: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL301: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL302: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL303: | [aws_iam_role_policy_attachment.infrastructure_utilities_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\nL439: | [aws_security_group.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\nL465: | [aws_security_group_rule.infrastructure_utilities_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL466: | [aws_security_group_rule.infrastructure_utilities_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL467: | [aws_security_group_rule.infrastructure_utilities_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL468: | [aws_security_group_rule.infrastructure_utilities_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL469: | [aws_security_group_rule.infrastructure_utilities_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL470: | [aws_security_group_rule.infrastructure_utilities_task_ingress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\nL489: | [terraform_data.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n---\nFile: rds-infrastructure-security-group.tf\nL22: resource \"aws_security_group_rule\" \"infrastructure_utilities_task_ingress_tcp\" {\nL23: for_each = (local.infrastructure_vpc_network_enable_public || local.infrastructure_vpc_network_enable_private) && local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL25: description = \"Allow RDS port tcp ingress from Utilities\"\nL30: source_security_group_id = aws_security_group.infrastructure_utilities[each.key].id\n---\nFile: rds-infrastructure-s3-backups-scheduled-task.tf\nL36: aws_iam_role.infrastructure_utilities_task_execution[each.key].arn,\nL37: aws_iam_role.infrastructure_utilities_task[each.key].arn,\nL64: arn = aws_ecs_cluster.infrastrucutre_utilities[0].arn\nL69: name = \"utilities-${each.key}\",\nL83: task_definition_arn = aws_ecs_task_definition.infrastructure_utilities[each.key].arn\nL92: aws_security_group.infrastructure_utilities[each.key].id,\n---\nFile: buildspecs/dalmatian-utilities.yml\nL15: - echo Building dalmatian-utilities docker image ...\nL16: - docker build -t dalmatian-utilities:latest .\nL20: - docker tag dalmatian-utilities:latest \"$REPOSITORY_URI:latest\"\n---\nFile: kms-infrastructure.tf\nL64: )}${length(local.infrastructure_rds) > 0 && local.infrastructure_kms_encryption && local.enable_infrastructure_utilities ? \",\" : \"\"}\nL68: for k, v in local.infrastructure_rds : aws_iam_role.infrastructure_utilities_task[k].arn if local.enable_infrastructure_utilities\nL71: )}${length(local.infrastructure_rds) > 0 && local.infrastructure_kms_encryption && local.enable_infrastructure_utilities ? \",\" : \"\"}\nL74: log_group_arn = length(local.infrastructure_rds) > 0 && local.infrastructure_kms_encryption && local.enable_infrastructure_utilities ? \"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:log-group:${local.resource_prefix}-infrastructure-utilities-*\" : \"\"\n---\nFile: utilities-infrastructure-image-codebuild.tf\nL1: resource \"aws_iam_role\" \"infrastructure_utilities_image_codebuild\" {\nL2: count = local.enable_infrastructure_utilities ? 1 : 0\nL4: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-image-codebuild\"), 0, 6)}\"\nL5: description = \"${local.resource_prefix}-utilities-image-codebuild\"\nL12: resource \"aws_iam_policy\" \"infrastructure_utilities_image_codebuild_cloudwatch_rw\" {\nL13: count = local.enable_infrastructure_utilities ? 1 : 0\nL15: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-image-codebuild-cloudwatch-rw\"), 0, 6)}\"\nL16: description = \"${local.resource_prefix}-utilities-image-codebuild-cloudwatch-rw\"\nL20: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_image_codebuild_cloudwatch_rw\" {\nL21: count = local.enable_infrastructure_utilities ? 1 : 0\nL23: role = aws_iam_role.infrastructure_utilities_image_codebuild[0].name\nL24: policy_arn = aws_iam_policy.infrastructure_utilities_image_codebuild_cloudwatch_rw[0].arn\nL27: resource \"aws_iam_policy\" \"infrastructure_utilities_image_codebuild_allow_builds\" {\nL28: count = local.enable_infrastructure_utilities ? 1 : 0\nL30: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-image-codebuild-allow-builds\"), 0, 6)}\"\nL31: description = \"${local.resource_prefix}-utilities-image-codebuild-allow-builds\"\nL35: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_image_codebuild_allow_builds\" {\nL36: count = local.enable_infrastructure_utilities ? 1 : 0\nL38: role = aws_iam_role.infrastructure_utilities_image_codebuild[0].name\nL39: policy_arn = aws_iam_policy.infrastructure_utilities_image_codebuild_allow_builds[0].arn\nL42: resource \"aws_iam_policy\" \"infrastructure_utilities_image_codebuild_ecr_push\" {\nL43: count = local.enable_infrastructure_utilities ? 1 : 0\nL45: name = \"${local.resource_prefix}-${substr(sha512(\"utilities-image-codebuild-ecr-push\"), 0, 6)}\"\nL49: { ecr_repository_arn = aws_ecr_repository.infrastructure_utilities[0].arn }\nL53: resource \"aws_iam_role_policy_attachment\" \"infrastructure_utilities_image_codebuild_ecr_push\" {\nL54: count = local.enable_infrastructure_utilities ? 1 : 0\nL56: role = aws_iam_role.infrastructure_utilities_image_codebuild[0].name\nL57: policy_arn = aws_iam_policy.infrastructure_utilities_image_codebuild_ecr_push[0].arn\nL60: resource \"aws_codebuild_project\" \"infrastructure_utilities_image_build\" {\nL61: count = local.enable_infrastructure_utilities ? 1 : 0\nL63: name = \"${local.resource_prefix}-utilities-image-build\"\nL64: description = \"${local.resource_prefix} Utilities Image Build\"\nL66: service_role = aws_iam_role.infrastructure_utilities_image_codebuild[0].arn\nL85: value = aws_ecr_repository.infrastructure_utilities[0].repository_url\nL103: buildspec = templatefile(\"${path.root}/buildspecs/dalmatian-utilities.yml\", {})\nL107: aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_cloudwatch_rw,\nL108: aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_allow_builds,\nL109: aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_ecr_push,\nL113: resource \"terraform_data\" \"infrastructure_utilities_image_build_trigger_codebuild\" {\nL114: count = local.enable_infrastructure_utilities ? 1 : 0\nL117: md5(templatefile(\"${path.root}/buildspecs/dalmatian-utilities.yml\", {})),\nL124: -n \"${aws_codebuild_project.infrastructure_utilities_image_build[0].name}\"\nL129: resource \"aws_cloudwatch_event_rule\" \"infrastructure_utilities_image_build_trigger_codebuild\" {\nL130: count = local.enable_infrastructure_utilities ? 1 : 0\nL132: name = \"${local.resource_prefix_hash}-utilities-image-build-trigger-codebuild\"\nL133: description = \"${local.resource_prefix} Utilities Image Build Trigger CodeBuild\"\nL137: resource \"aws_cloudwatch_event_target\" \"infrastructure_utilities_image_build_trigger_codebuild\" {\nL138: count = local.enable_infrastructure_utilities ? 1 : 0\nL140: target_id = \"${local.resource_prefix_hash}-utilities-image-build-trigger-codebuild\"\nL141: rule = aws_cloudwatch_event_rule.infrastructure_utilities_image_build_trigger_codebuild[0].name\nL142: arn = aws_codebuild_project.infrastructure_utilities_image_build[0].id\nL143: role_arn = aws_iam_role.infrastructure_utilities_image_codebuild[0].arn\n---\nFile: utilities-infrastructure-security-group.tf\nL1: resource \"aws_security_group\" \"infrastructure_utilities\" {\nL2: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL4: name = \"${local.resource_prefix}-infrastructure-utilities-${each.key}\"\nL5: description = \"Infrastructure Utilities\"\nL9: resource \"aws_security_group_rule\" \"infrastructure_utilities_egress_https_tcp\" {\nL10: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL19: security_group_id = aws_security_group.infrastructure_utilities[each.key].id\nL22: resource \"aws_security_group_rule\" \"infrastructure_utilities_egress_https_udp\" {\nL23: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL32: security_group_id = aws_security_group.infrastructure_utilities[each.key].id\nL35: resource \"aws_security_group_rule\" \"infrastructure_utilities_egress_dns_tcp\" {\nL36: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL48: security_group_id = aws_security_group.infrastructure_utilities[each.key].id\nL51: resource \"aws_security_group_rule\" \"infrastructure_utilities_egress_dns_udp\" {\nL52: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL64: security_group_id = aws_security_group.infrastructure_utilities[each.key].id\nL67: resource \"aws_security_group_rule\" \"infrastructure_utilities_egress_rds\" {\nL68: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL76: security_group_id = aws_security_group.infrastructure_utilities[each.key].id\n---\nFile: utilities-infrastructure-task-definition.tf\nL1: resource \"aws_ecs_task_definition\" \"infrastructure_utilities\" {\nL2: for_each = local.enable_infrastructure_utilities ? local.infrastructure_rds : {}\nL4: family = \"${local.resource_prefix}-infrastructure-utilities-${each.key}\"\nL8: container_name = \"utilities-${each.key}\"\nL9: image = aws_ecr_repository.infrastructure_utilities[0].repository_url\nL50: cloudwatch_log_group = aws_cloudwatch_log_group.infrastructure_utilities[each.key].name\nL51: awslogs_stream_prefix = \"utilities\"\nL55: execution_role_arn = aws_iam_role.infrastructure_utilities_task_execution[each.key].arn\nL56: task_role_arn = aws_iam_role.infrastructure_utilities_task[each.key].arn\nL63: aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_ecr_pull,\nL64: aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_cloudwatch_logs,\nL66: aws_iam_role_policy_attachment.infrastructure_utilities_task_kms_encrypt,\nL67: terraform_data.infrastructure_utilities_image_build_trigger_codebuild,\n---\nFile: utilities-infrastructure-ecr.tf\nL1: resource \"aws_ecr_repository\" \"infrastructure_utilities\" {\nL2: count = local.enable_infrastructure_utilities ? 1 : 0\nL4: name = \"${local.resource_prefix}-utilities\"\nL19: resource \"aws_ecr_lifecycle_policy\" \"infrastructure_utilities\" {\nL20: count = local.enable_infrastructure_utilities ? 1 : 0\nL22: repository = aws_ecr_repository.infrastructure_utilities[0].name\n---\nFile: locals.tf\nL256: enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\nL257: infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n---"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:14:11.456Z",
"resultDisplay": "Found 231 matches",
"displayName": "SearchText",
"description": "FAST, optimized search powered by `ripgrep`. PREFERRED over standard `run_shell_command(\"grep ...\")` due to better performance and automatic output limiting (max 20k matches).",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "8ac6109c-6736-4e2b-ac62-46eb0d50d4e9",
"timestamp": "2026-01-23T17:15:54.706Z",
"type": "gemini",
"content": "I will check if `terraform` is available in the environment to validate my changes. Then, I will read `variables.tf` to identify the best location for the new variables. Afterward, I will update `variables.tf` to include `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`, and finally, I will update `ecs-cluster-infrastructure.tf` and `utilities-infrastructure-ecs-cluster.tf` to utilize these new variables.",
"thoughts": [
{
"subject": "Confirming Utility Logic",
"description": "I've confirmed that the `enable_infrastructure_utilities` flag is determined by the presence of RDS instances. It's triggered when `var.infrastructure_rds` has a length greater than zero. Now, I'm focusing on defining two variables within `variables.tf`. The first will be `infrastructure_ecs_cluster_container_insights`.",
"timestamp": "2026-01-23T17:14:24.516Z"
},
{
"subject": "Defining New Variables",
"description": "I've successfully identified the triggering condition for `enable_infrastructure_utilities`. My next steps involve incorporating two new variables for container insights: `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`. I plan to default them to \"enabled\". I'm now outlining the steps for adding these variables via `replace` and updating relevant TF files. Before proceeding with those steps, I need to check for the availability of `terraform` to ensure I can validate my changes.",
"timestamp": "2026-01-23T17:15:54.691Z"
}
],
"tokens": {
"input": 44096,
"output": 119,
"cached": 29533,
"thoughts": 300,
"tool": 0,
"total": 44515
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769188554691-0b1a37847c366",
"name": "run_shell_command",
"args": {
"command": "terraform version"
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769188554691-0b1a37847c366",
"name": "run_shell_command",
"response": {
"output": "Command: terraform version\nDirectory: (root)\nOutput: Terraform v1.14.3\non darwin_arm64\n+ provider registry.terraform.io/datadog/datadog v3.63.0\n+ provider registry.terraform.io/hashicorp/archive v2.7.0\n+ provider registry.terraform.io/hashicorp/aws v5.97.0\n+ provider registry.terraform.io/hashicorp/external v2.3.5\n+ provider registry.terraform.io/hashicorp/null v3.2.4\n+ provider registry.terraform.io/hashicorp/random v3.7.2\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 83324"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:17:48.002Z",
"resultDisplay": "Terraform v1.14.3\non darwin_arm64\n+ provider registry.terraform.io/datadog/datadog v3.63.0\n+ provider registry.terraform.io/hashicorp/archive v2.7.0\n+ provider registry.terraform.io/hashicorp/aws v5.97.0\n+ provider registry.terraform.io/hashicorp/external v2.3.5\n+ provider registry.terraform.io/hashicorp/null v3.2.4\n+ provider registry.terraform.io/hashicorp/random v3.7.2",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "3f377746-aeae-4521-86d2-2d8ce33ccb50",
"timestamp": "2026-01-23T17:17:52.482Z",
"type": "gemini",
"content": "I will read `variables.tf` to locate the `infrastructure_ecs_cluster_ami_version` variable, ensuring I can place the new variables in a logical position within the file.",
"thoughts": [
{
"subject": "Pinpointing Configuration Details",
"description": "I've confirmed that Terraform is ready. My next step is to examine the `variables.tf` file. I'm focusing on identifying a strategic location, and am currently searching for `infrastructure_ecs_cluster_ ami_version`, as it's near other relevant ECS cluster settings.",
"timestamp": "2026-01-23T17:17:52.194Z"
}
],
"tokens": {
"input": 44405,
"output": 52,
"cached": 40366,
"thoughts": 49,
"tool": 0,
"total": 44506
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769188672478-cb77b3e3a54be",
"name": "read_file",
"args": {
"file_path": "variables.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188672478-cb77b3e3a54be",
"name": "read_file",
"response": {
"output": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:17:52.504Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "0f017e83-cacb-4601-a13a-4de013da16f2",
"timestamp": "2026-01-23T17:18:02.941Z",
"type": "gemini",
"content": "I will start by adding the `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables to `variables.tf`. Next, I will update `ecs-cluster-infrastructure.tf` to reference `var.infrastructure_ecs_cluster_container_insights` and `utilities-infrastructure-ecs-cluster.tf` to reference `var.infrastructure_utilities_ecs_cluster_container_insights`. Finally, I will verify the changes with `terraform validate` and `terraform fmt`.",
"thoughts": [
{
"subject": "Analyzing Variable Placement",
"description": "I've decided to incorporate the `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables directly after the existing `infrastructure_ecs_cluster_ami_version` variable in the configuration. I believe this keeps them logically grouped with related infrastructure settings, improving readability.",
"timestamp": "2026-01-23T17:17:58.957Z"
},
{
"subject": "Refining Variable Definitions",
"description": "I'm verifying the variable types for container insights. Confirmed: they should be strings, given the \"enabled\" or \"disabled\" values required by the ECS cluster resource's `setting.value` attribute. Next, I'll update `variables.tf` and then integrate the variables into the respective cluster definition files.",
"timestamp": "2026-01-23T17:18:00.527Z"
}
],
"tokens": {
"input": 56626,
"output": 344,
"cached": 44990,
"thoughts": 254,
"tool": 0,
"total": 57224
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769188682936-9ef587b3f5e18",
"name": "replace",
"args": {
"old_string": "variable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}",
"new_string": "variable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n}",
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"expected_replacements": 1,
"instruction": "Add `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables after `infrastructure_ecs_cluster_ami_version`."
},
"result": [
{
"functionResponse": {
"id": "replace-1769188682936-9ef587b3f5e18",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:18:28.266Z",
"resultDisplay": {
"fileDiff": "Index: variables.tf\n===================================================================\n--- variables.tf\tCurrent\n+++ variables.tf\tProposed\n@@ -274,6 +274,16 @@\n type = string\n }\n \n+variable \"infrastructure_ecs_cluster_container_insights\" {\n+ description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n+ type = string\n+}\n+\n+variable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n+ description = \"Enable Container Insights for the Utilities ECS Cluster\"\n+ type = string\n+}\n+\n variable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n",
"fileName": "variables.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"originalContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"newContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"diffStat": {
"model_added_lines": 10,
"model_removed_lines": 0,
"model_added_chars": 323,
"model_removed_chars": 0,
"user_added_lines": 0,
"user_removed_lines": 1026,
"user_added_chars": 0,
"user_removed_chars": 46980
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "483288f3-49ee-431d-81a5-8241bf8248b2",
"timestamp": "2026-01-23T17:19:06.055Z",
"type": "gemini",
"content": "I will update `ecs-cluster-infrastructure.tf` to replace the hardcoded \"enabled\" value for `containerInsights` with the `var.infrastructure_ecs_cluster_container_insights` variable.",
"thoughts": [
{
"subject": "Revising ECS Configuration",
"description": "I'm now diving into `ecs-cluster-infrastructure.tf`. My focus is on refining the configuration to align perfectly with the latest deployment strategies. This involves a close examination of resource definitions to ensure optimal performance and scalability.",
"timestamp": "2026-01-23T17:19:05.715Z"
}
],
"tokens": {
"input": 57020,
"output": 143,
"cached": 56002,
"thoughts": 13,
"tool": 0,
"total": 57176
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769188746048-a3bc9f7202b4b",
"name": "replace",
"args": {
"new_string": " setting {\n name = \"containerInsights\"\n value = var.infrastructure_ecs_cluster_container_insights\n }",
"instruction": "Use `var.infrastructure_ecs_cluster_container_insights` for the containerInsights setting value.",
"old_string": " setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }",
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf",
"expected_replacements": 1
},
"result": [
{
"functionResponse": {
"id": "replace-1769188746048-a3bc9f7202b4b",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:19:34.835Z",
"resultDisplay": {
"fileDiff": "Index: ecs-cluster-infrastructure.tf\n===================================================================\n--- ecs-cluster-infrastructure.tf\tCurrent\n+++ ecs-cluster-infrastructure.tf\tProposed\n@@ -5,7 +5,7 @@\n \n setting {\n name = \"containerInsights\"\n- value = \"enabled\"\n+ value = var.infrastructure_ecs_cluster_container_insights\n }\n \n dynamic \"configuration\" {\n",
"fileName": "ecs-cluster-infrastructure.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf",
"originalContent": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n",
"newContent": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = var.infrastructure_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 1,
"model_added_chars": 61,
"model_removed_chars": 21,
"user_added_lines": 0,
"user_removed_lines": 313,
"user_added_chars": 0,
"user_removed_chars": 10748
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "db1fa2cc-db02-439c-ba10-ba3162e60989",
"timestamp": "2026-01-23T17:20:15.480Z",
"type": "gemini",
"content": "I will now update the `utilities-infrastructure-ecs-cluster.tf` file to replace the hardcoded \"enabled\" value for the `containerInsights` setting with the variable `var.infrastructure_utilities_ecs_cluster_container_insights`.",
"thoughts": [
{
"subject": "Revising ECS Cluster",
"description": "I'm now diving into the `utilities-infrastructure-ecs-cluster.tf` file. I'm focusing on ensuring it aligns with the latest best practices for ECS cluster configuration. This includes optimizing resource allocation and fine-tuning security settings. The goal is to maximize performance while minimizing potential vulnerabilities.",
"timestamp": "2026-01-23T17:20:15.474Z"
}
],
"tokens": {
"input": 57218,
"output": 178,
"cached": 55969,
"thoughts": 15,
"tool": 0,
"total": 57411
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769188815474-294777aa687fa",
"name": "replace",
"args": {
"old_string": " setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }",
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf",
"new_string": " setting {\n name = \"containerInsights\"\n value = var.infrastructure_utilities_ecs_cluster_container_insights\n }",
"instruction": "Use `var.infrastructure_utilities_ecs_cluster_container_insights` for the containerInsights setting value.",
"expected_replacements": 1
},
"result": [
{
"functionResponse": {
"id": "replace-1769188815474-294777aa687fa",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:20:21.561Z",
"resultDisplay": {
"fileDiff": "Index: utilities-infrastructure-ecs-cluster.tf\n===================================================================\n--- utilities-infrastructure-ecs-cluster.tf\tCurrent\n+++ utilities-infrastructure-ecs-cluster.tf\tProposed\n@@ -5,7 +5,7 @@\n \n setting {\n name = \"containerInsights\"\n- value = \"enabled\"\n+ value = var.infrastructure_utilities_ecs_cluster_container_insights\n }\n \n dynamic \"configuration\" {\n",
"fileName": "utilities-infrastructure-ecs-cluster.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf",
"originalContent": "resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n count = local.enable_infrastructure_utilities ? 1 : 0\n\n name = local.infrastructure_utilities_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = \"enabled\"\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n",
"newContent": "resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n count = local.enable_infrastructure_utilities ? 1 : 0\n\n name = local.infrastructure_utilities_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = var.infrastructure_utilities_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 1,
"model_added_chars": 71,
"model_removed_chars": 21,
"user_added_lines": 0,
"user_removed_lines": 22,
"user_added_chars": 0,
"user_removed_chars": 690
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "d146fc54-280e-41cb-a11a-ae7d3a4dbf4b",
"timestamp": "2026-01-23T17:20:27.569Z",
"type": "gemini",
"content": "I will attempt to validate the Terraform configuration using `terraform validate`. If that fails due to initialization issues, I will proceed with `terraform init -backend=false` followed by `terraform validate`.",
"thoughts": [
{
"subject": "Assessing Configuration Verification",
"description": "I'm now running `terraform validate` to check the updated code. The presence of a `.terraform` directory suggests initialization has already occurred, so I'm proceeding directly with validation. If there are any errors, I'll address them immediately.",
"timestamp": "2026-01-23T17:20:26.260Z"
},
{
"subject": "Testing Deployment Readiness",
"description": "I've just finished the code changes and am now focused on validation. I'm taking a pragmatic approach: I'll try `terraform validate` directly. Seeing the `.terraform` directory suggests initialization is already done. If it fails, I'll initialize. Then, I'll go back and validate again.",
"timestamp": "2026-01-23T17:20:27.294Z"
}
],
"tokens": {
"input": 57432,
"output": 51,
"cached": 55935,
"thoughts": 111,
"tool": 0,
"total": 57594
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769188827564-136cae586ea398",
"name": "run_shell_command",
"args": {
"command": "terraform validate"
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769188827564-136cae586ea398",
"name": "run_shell_command",
"response": {
"output": "Command: terraform validate\nDirectory: (root)\nOutput: Success! The configuration is valid.\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 83745"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:20:34.665Z",
"resultDisplay": "Success! The configuration is valid.",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "25dc84c4-9efb-4067-b90a-0704148dcdf1",
"timestamp": "2026-01-23T17:20:41.953Z",
"type": "gemini",
"content": "I'll review `ecs-cluster-infrastructure.tf` to check for direct variable usage. If I find that `local.` is consistently preferred over `var.`, I'll update `locals.tf` to include the new variables and modify the resources to use those locals instead.",
"thoughts": [
{
"subject": "Examining the Configuration",
"description": "The configuration is confirmed to be valid. I'm now considering how variables are handled, noting the absence of explicit mapping using locals, which deviates from some established patterns in the repo. This prompted me to review `locals.tf`, and I've noted a large number of mappings there.",
"timestamp": "2026-01-23T17:20:39.188Z"
},
{
"subject": "Reviewing Variable Usage",
"description": "I'm now zeroing in on the use of variables. It seems the preferred style is to map variables to locals within `locals.tf`, and then reference the local. I identified one potential direct variable usage in `ecs-cluster-infrastructure.tf`, so I am rereading that file to confirm how variables are used directly there.",
"timestamp": "2026-01-23T17:20:41.651Z"
}
],
"tokens": {
"input": 57543,
"output": 76,
"cached": 55820,
"thoughts": 334,
"tool": 0,
"total": 57953
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769188841949-96972e3192498",
"name": "read_file",
"args": {
"file_path": "ecs-cluster-infrastructure.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188841949-96972e3192498",
"name": "read_file",
"response": {
"output": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = var.infrastructure_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:20:41.967Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "a7157710-f1b6-4528-b40f-0ce098516735",
"timestamp": "2026-01-23T17:23:19.313Z",
"type": "gemini",
"content": "I'll add `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` to `locals.tf`, ensuring I place them near related ECS cluster variables. Then, I'll update `ecs-cluster-infrastructure.tf` and `utilities-infrastructure-ecs-cluster.tf` to use these new locals instead of the variables directly.",
"thoughts": [
{
"subject": "Assessing Consistency Goals",
"description": "I'm zeroing in on the best approach. My focus is on making the code more maintainable and consistent. I've pinpointed a path forward: integrating the new variable within `locals.tf` to align with the existing style. Next, I need to find the best place in `locals.tf` to insert the new variable.",
"timestamp": "2026-01-23T17:23:19.296Z"
}
],
"tokens": {
"input": 60930,
"output": 96,
"cached": 59521,
"thoughts": 191,
"tool": 0,
"total": 61217
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769188999296-7fb65ec730a618",
"name": "read_file",
"args": {
"file_path": "locals.tf"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769188999296-7fb65ec730a618",
"name": "read_file",
"response": {
"output": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:23:19.336Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "13f6898f-4764-4cc4-b745-06268289fe21",
"timestamp": "2026-01-23T17:24:22.884Z",
"type": "gemini",
"content": "I will begin by updating `locals.tf` to include `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`, placing them near their respective cluster name definitions. Afterward, I'll update `ecs-cluster-infrastructure.tf` and `utilities-infrastructure-ecs-cluster.tf` to reference these new local variables.",
"thoughts": [
{
"subject": "Analyzing variable placement",
"description": "I'm currently focused on determining the best location for the new container insights variables within `locals.tf`. I've identified lines 208 and 257 as potential spots, corresponding to the ECS cluster and utilities cluster configurations, respectively. The next step is updating the Terraform files to leverage these new local variables.",
"timestamp": "2026-01-23T17:24:22.493Z"
}
],
"tokens": {
"input": 67624,
"output": 317,
"cached": 67373,
"thoughts": 172,
"tool": 0,
"total": 68113
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769189062866-477d7a695f35c8",
"name": "replace",
"args": {
"expected_replacements": 1,
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf",
"old_string": " enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version",
"new_string": " enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_container_insights = var.infrastructure_ecs_cluster_container_insights\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version",
"instruction": "Add `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` to locals."
},
"result": [
{
"functionResponse": {
"id": "replace-1769189062866-477d7a695f35c8",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:34:07.577Z",
"resultDisplay": {
"fileDiff": "Index: locals.tf\n===================================================================\n--- locals.tf\tCurrent\n+++ locals.tf\tProposed\n@@ -129,6 +129,7 @@\n \n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n+ infrastructure_ecs_cluster_container_insights = var.infrastructure_ecs_cluster_container_insights\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n",
"fileName": "locals.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf",
"originalContent": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n",
"newContent": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_container_insights = var.infrastructure_ecs_cluster_container_insights\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 0,
"model_added_chars": 118,
"model_removed_chars": 0,
"user_added_lines": 0,
"user_removed_lines": 290,
"user_added_chars": 0,
"user_removed_chars": 22476
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "cf14bb88-075d-41e3-b2e1-7f12d23bbfda",
"timestamp": "2026-01-23T17:34:14.941Z",
"type": "gemini",
"content": "I will add the `infrastructure_utilities_ecs_cluster_container_insights` variable to `locals.tf`, ensuring it's correctly assigned from the corresponding input variable.",
"thoughts": [
{
"subject": "Reflecting on Implementation",
"description": "I'm currently working to add `infrastructure_utilities_ecs_cluster_container_insights` to the `locals.tf` file. This is crucial for gaining better visibility into the cluster's performance. The goal is to ensure that the necessary insights are readily available for monitoring and troubleshooting within the infrastructure.",
"timestamp": "2026-01-23T17:34:13.442Z"
}
],
"tokens": {
"input": 67971,
"output": 244,
"cached": 0,
"thoughts": 24,
"tool": 0,
"total": 68239
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769189654935-2e41995116789",
"name": "replace",
"args": {
"old_string": " enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults",
"instruction": "Add `infrastructure_utilities_ecs_cluster_container_insights` to locals.",
"expected_replacements": 1,
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf",
"new_string": " enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n infrastructure_utilities_ecs_cluster_container_insights = var.infrastructure_utilities_ecs_cluster_container_insights\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults"
},
"result": [
{
"functionResponse": {
"id": "replace-1769189654935-2e41995116789",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:34:24.147Z",
"resultDisplay": {
"fileDiff": "Index: locals.tf\n===================================================================\n--- locals.tf\tCurrent\n+++ locals.tf\tProposed\n@@ -256,6 +256,7 @@\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n+ infrastructure_utilities_ecs_cluster_container_insights = var.infrastructure_utilities_ecs_cluster_container_insights\n \n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n",
"fileName": "locals.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/locals.tf",
"originalContent": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_container_insights = var.infrastructure_ecs_cluster_container_insights\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n",
"newContent": "locals {\n project_name = var.project_name\n infrastructure_name = var.infrastructure_name\n environment = var.environment\n aws_region = var.aws_region\n aws_account_id = data.aws_caller_identity.current.account_id\n resource_prefix = \"${var.project_name}-${var.infrastructure_name}-${var.environment}\"\n resource_prefix_hash = format(\"%.8s\", sha512(local.resource_prefix))\n\n infrastructure_kms_encryption = var.infrastructure_kms_encryption\n infrastructure_kms_key_policy_statements = var.infrastructure_kms_key_policy_statements\n\n infrastructure_logging_bucket_retention = var.infrastructure_logging_bucket_retention\n\n infrastructure_slack_sns_topic_name = \"${local.project_name}-cloudwatch-slack-alerts\"\n infrastructure_opsgenie_sns_topic_name = \"${local.project_name}-cloudwatch-opsgenie-alerts\"\n infrastructure_slack_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_slack ||\n local.infrastructure_ecs_cluster_pending_task_alert_slack ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n )\n infrastructure_opsgenie_sns_topic_in_use = (\n local.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie ||\n local.infrastructure_ecs_cluster_pending_task_alert_opsgenie ||\n local.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n )\n\n enable_infrastructure_logs_bucket = (\n local.infrastructure_vpc_flow_logs_s3_with_athena ||\n length(local.infrastructure_ecs_cluster_services) != 0 ||\n length(local.custom_s3_buckets) != 0 ||\n local.enable_cloudformatian_s3_template_store ||\n local.enable_infrastructure_vpc_transfer_s3_bucket ||\n local.infrastructure_ecs_cluster_enable_execute_command_logging ||\n local.enable_infrastructure_rds_backup_to_s3 ||\n length(local.custom_lambda_functions) != 0\n )\n logs_bucket_s3_source_arns = concat(\n length(local.infrastructure_ecs_cluster_services) != 0 ? [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store[0].arn] : [],\n local.enable_infrastructure_vpc_transfer_s3_bucket ? [aws_s3_bucket.infrastructure_vpc_transfer[0].arn] : [],\n [for k, v in local.custom_s3_buckets : aws_s3_bucket.custom[k].arn],\n local.enable_infrastructure_rds_backup_to_s3 ? [aws_s3_bucket.infrastructure_rds_s3_backups[0].arn] : [],\n local.enable_lambda_functions_s3_store ? [aws_s3_bucket.lambda_custom_functions_store[0].arn] : []\n )\n logs_bucket_logs_source_arns = concat(\n local.infrastructure_vpc_flow_logs_s3_with_athena ? [\"arn:aws:logs:${local.aws_region}:${local.aws_account_id}:*\"] : []\n )\n logs_bucket_athena_result_output_dir = \"athena-result-output\"\n\n route53_root_hosted_zone_domain_name = var.route53_root_hosted_zone_domain_name\n aws_profile_name_route53_root = var.aws_profile_name_route53_root\n enable_infrastructure_route53_hosted_zone = var.enable_infrastructure_route53_hosted_zone\n create_infrastructure_route53_delegations = local.route53_root_hosted_zone_domain_name != \"\" && local.aws_profile_name_route53_root != \"\" && local.enable_infrastructure_route53_hosted_zone\n infrastructure_route53_domain = \"${local.environment}.${var.infrastructure_name}.${local.route53_root_hosted_zone_domain_name}\"\n\n enable_infrastructure_wildcard_certificate = local.enable_infrastructure_route53_hosted_zone && (length(local.infrastructure_ecs_cluster_services) > 0 || length(local.custom_s3_buckets) > 0)\n\n infrastructure_datadog_api_key = var.infrastructure_datadog_api_key\n infrastructure_datadog_app_key = var.infrastructure_datadog_app_key\n infrastructure_datadog_region = var.infrastructure_datadog_region\n infrastructure_datadog_api_url = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"https://api.datadoghq.com/\",\n \"US3\" = \"https://api.us3.datadoghq.com/\",\n \"US5\" = \"https://api.us5.datadoghq.com/\",\n \"EU1\" = \"https://api.datadoghq.eu/\",\n \"US1-FED\" = \"https://api.ddog-gov.com/\",\n \"AP1\" = \"https://api.ap1.datadoghq.com/\"\n }[local.infrastructure_datadog_region] : \"https://api.datadoghq.com/\"\n infrastructure_datadog_site = local.infrastructure_datadog_region != \"\" ? {\n \"US1\" = \"datadoghq.com\",\n \"US3\" = \"us3.datadoghq.com\",\n \"US5\" = \"us5.datadoghq.com\",\n \"EU1\" = \"datadoghq.eu\",\n \"US1-FED\" = \"ddog-gov.com\",\n \"AP1\" = \"ap1.datadoghq.com\"\n }[local.infrastructure_datadog_region] : \"datadoghq.com\"\n enable_infrastructure_ecs_cluster_datadog_agent = local.enable_infrastructure_ecs_cluster && var.enable_infrastructure_ecs_cluster_datadog_agent\n\n infrastructure_vpc = var.infrastructure_vpc\n infrastructure_vpc_cidr_block = var.infrastructure_vpc_cidr_block\n infrastructure_vpc_enable_dns_support = var.infrastructure_vpc_enable_dns_support\n infrastructure_vpc_enable_dns_hostnames = var.infrastructure_vpc_enable_dns_hostnames\n infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy\n infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics\n infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block\n infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public\n infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private\n infrastructure_vpc_network_availability_zones = toset(sort(var.infrastructure_vpc_network_availability_zones))\n infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)\n infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)\n infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix\n infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)\n infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)\n infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix\n infrastructure_vpc_network_acl_egress_lockdown_private = var.infrastructure_vpc_network_acl_egress_lockdown_private\n infrastructure_vpc_network_acl_egress_custom_rules_private = var.infrastructure_vpc_network_acl_egress_custom_rules_private\n infrastructure_vpc_network_acl_ingress_lockdown_private = var.infrastructure_vpc_network_acl_ingress_lockdown_private\n infrastructure_vpc_network_acl_ingress_custom_rules_private = var.infrastructure_vpc_network_acl_ingress_custom_rules_private\n infrastructure_vpc_network_acl_egress_lockdown_public = var.infrastructure_vpc_network_acl_egress_lockdown_public\n infrastructure_vpc_network_acl_egress_custom_rules_public = var.infrastructure_vpc_network_acl_egress_custom_rules_public\n infrastructure_vpc_network_acl_ingress_lockdown_public = var.infrastructure_vpc_network_acl_ingress_lockdown_public\n infrastructure_vpc_network_acl_ingress_custom_rules_public = var.infrastructure_vpc_network_acl_ingress_custom_rules_public\n infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc\n infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, \"/\")\n infrastructure_vpc_flow_logs_retention = var.infrastructure_vpc_flow_logs_retention\n infrastructure_vpc_flow_logs_traffic_type = var.infrastructure_vpc_flow_logs_traffic_type\n infrastructure_vpc_flow_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/vpc-flow-logs.json.tpl\", {}))\n infrastructure_vpc_flow_logs_glue_table_partition_keys = [\n { name = \"year\", type = \"int\" },\n { name = \"month\", type = \"int\" },\n { name = \"day\", type = \"int\" },\n { name = \"hour\", type = \"int\" },\n ]\n enable_infrastructure_vpc_transfer_s3_bucket = var.enable_infrastructure_vpc_transfer_s3_bucket\n infrastructure_vpc_transfer_s3_bucket_access_vpc_ids = concat(\n local.infrastructure_vpc ? [aws_vpc.infrastructure[0].id] : [],\n var.infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\n )\n infrastructure_vpc_transfer_ssm_download_command = \"aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\\\\\"{{ TargetUID }}\\\\\\\" ] && [ -n \\\\\\\"{{ TargetGID }}\\\\\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi\"\n infrastructure_vpc_transfer_ssm_upload_command = \"aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}\"\n\n enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host\n infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules\n\n infrastructure_dockerhub_email = var.infrastructure_dockerhub_email\n infrastructure_dockerhub_username = var.infrastructure_dockerhub_username\n infrastructure_dockerhub_token = var.infrastructure_dockerhub_token\n\n enable_infrastructure_ecs_cluster = var.enable_infrastructure_ecs_cluster && local.infrastructure_vpc\n infrastructure_ecs_cluster_name = \"${local.resource_prefix}-infrastructure\"\n infrastructure_ecs_cluster_container_insights = var.infrastructure_ecs_cluster_container_insights\n infrastructure_ecs_cluster_ami_version = var.infrastructure_ecs_cluster_ami_version\n infrastructure_ecs_cluster_ami_name_filter = \"al2023-ami-ecs-hvm-${local.infrastructure_ecs_cluster_ami_version}\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name = \"/dev/xvdcz\"\n infrastructure_ecs_cluster_ebs_docker_storage_volume_size = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n infrastructure_ecs_cluster_ebs_docker_storage_volume_type = var.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n infrastructure_ecs_cluster_publicly_avaialble = var.infrastructure_ecs_cluster_publicly_avaialble && local.infrastructure_vpc_network_enable_public\n infrastructure_ecs_cluster_custom_security_group_rules = var.infrastructure_ecs_cluster_custom_security_group_rules\n infrastructure_ecs_cluster_instance_type = var.infrastructure_ecs_cluster_instance_type\n infrastructure_ecs_cluster_termination_timeout = var.infrastructure_ecs_cluster_termination_timeout\n infrastructure_ecs_cluster_draining_lambda_enabled = var.infrastructure_ecs_cluster_draining_lambda_enabled && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_draining_lambda_log_retention = var.infrastructure_ecs_cluster_draining_lambda_log_retention\n infrastructure_ecs_cluster_termination_sns_topic_name = \"${local.resource_prefix}-infrastructure-ecs-cluster-termination\"\n infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size\n infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size\n infrastructure_ecs_cluster_allow_kms_encryption = local.infrastructure_kms_encryption && anytrue([\n local.enable_infrastructure_vpc_transfer_s3_bucket,\n ])\n infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime\n infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression = var.infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\n infrastructure_ecs_cluster_instance_refresh_lambda_log_retention = var.infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\n infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max)\n infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min)\n infrastructure_ecs_cluster_autoscaling_time_based_custom = {\n for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : \"${custom[\"min\"]}-${custom[\"max\"]} ${custom[\"cron\"]}\" => custom\n }\n enable_infrastructure_ecs_cluster_asg_cpu_alert = var.enable_infrastructure_ecs_cluster_asg_cpu_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods = var.infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\n infrastructure_ecs_cluster_asg_cpu_alert_period = var.infrastructure_ecs_cluster_asg_cpu_alert_period\n infrastructure_ecs_cluster_asg_cpu_alert_threshold = var.infrastructure_ecs_cluster_asg_cpu_alert_threshold\n infrastructure_ecs_cluster_asg_cpu_alert_slack = var.infrastructure_ecs_cluster_asg_cpu_alert_slack && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n infrastructure_ecs_cluster_asg_cpu_alert_opsgenie = var.infrastructure_ecs_cluster_asg_cpu_alert_opsgenie && local.enable_infrastructure_ecs_cluster_asg_cpu_alert\n enable_infrastructure_ecs_cluster_pending_task_alert = var.enable_infrastructure_ecs_cluster_pending_task_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention = var.infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\n infrastructure_ecs_cluster_pending_task_alert_evaluation_periods = var.infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\n infrastructure_ecs_cluster_pending_task_alert_period = var.infrastructure_ecs_cluster_pending_task_alert_period\n infrastructure_ecs_cluster_pending_task_alert_threshold = var.infrastructure_ecs_cluster_pending_task_alert_threshold\n infrastructure_ecs_cluster_pending_task_alert_slack = var.infrastructure_ecs_cluster_pending_task_alert_slack\n infrastructure_ecs_cluster_pending_task_alert_opsgenie = var.infrastructure_ecs_cluster_pending_task_alert_opsgenie\n enable_infrastructure_ecs_cluster_ecs_asg_diff_alert = var.enable_infrastructure_ecs_cluster_ecs_asg_diff_alert && local.enable_infrastructure_ecs_cluster\n infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention = var.infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\n infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\n infrastructure_ecs_cluster_ecs_asg_diff_alert_period = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_period\n infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\n infrastructure_ecs_cluster_ecs_asg_diff_alert_slack = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\n infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie = var.infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\n infrastructure_ecs_cluster_enable_debug_mode = var.infrastructure_ecs_cluster_enable_debug_mode\n infrastructure_ecs_cluster_enable_execute_command_logging = var.infrastructure_ecs_cluster_enable_execute_command_logging\n infrastructure_ecs_cluster_wafs = var.infrastructure_ecs_cluster_wafs\n infrastructure_ecs_cluster_syslog_endpoint = var.infrastructure_ecs_cluster_syslog_endpoint\n infrastructure_ecs_cluster_syslog_docker_address = length(split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)) > 1 ? \"tcp${split(\"syslog\", local.infrastructure_ecs_cluster_syslog_endpoint)[1]}\" : \"\"\n infrastructure_ecs_cluster_syslog_port = local.infrastructure_ecs_cluster_syslog_endpoint != \"\" ? split(\":\", local.infrastructure_ecs_cluster_syslog_endpoint)[2] : null\n infrastructure_ecs_cluster_syslog_permitted_peer = var.infrastructure_ecs_cluster_syslog_permitted_peer\n infrastructure_ecs_cluster_logspout_command = var.infrastructure_ecs_cluster_logspout_command\n infrastructure_ecs_cluster_logspout_enabled = local.enable_infrastructure_ecs_cluster && length(local.infrastructure_ecs_cluster_logspout_command) > 1\n infrastructure_ecs_cluster_user_data = base64encode(\n templatefile(\"ec2-userdata/ecs-instance.tpl\", {\n docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,\n ecs_cluster_name = local.infrastructure_ecs_cluster_name,\n dockerhub_token = local.infrastructure_dockerhub_token,\n dockerhub_email = local.infrastructure_dockerhub_email,\n docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n efs_id = local.enable_infrastructure_ecs_cluster_efs && (\n local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public\n ) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : \"\",\n region = local.aws_region,\n efs_dirs = join(\" \", local.ecs_cluster_efs_directories),\n syslog_endpoint = local.infrastructure_ecs_cluster_syslog_endpoint\n syslog_permitted_peer = local.infrastructure_ecs_cluster_syslog_permitted_peer\n log_debug_mode = local.infrastructure_ecs_cluster_enable_debug_mode\n })\n )\n\n\n enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc\n ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode\n ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode\n ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition\n ecs_cluster_efs_directories = var.ecs_cluster_efs_directories\n\n infrastructure_ecs_cluster_service_defaults = var.infrastructure_ecs_cluster_service_defaults\n infrastructure_ecs_cluster_services_keys = length(var.infrastructure_ecs_cluster_services) > 0 ? keys(values(var.infrastructure_ecs_cluster_services)[0]) : []\n infrastructure_ecs_cluster_services = {\n for k, v in var.infrastructure_ecs_cluster_services : k => merge({\n for service_key in local.infrastructure_ecs_cluster_services_keys : service_key => try(coalesce(v[service_key], local.infrastructure_ecs_cluster_service_defaults[service_key]), null)\n })\n }\n infrastructure_ecs_cluster_services_alb_enable_global_accelerator = var.infrastructure_ecs_cluster_services_alb_enable_global_accelerator && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_ip_allow_list = var.infrastructure_ecs_cluster_services_alb_ip_allow_list\n enable_infrastructure_ecs_cluster_services_alb_logs = var.enable_infrastructure_ecs_cluster_services_alb_logs && length(local.infrastructure_ecs_cluster_services) > 0\n infrastructure_ecs_cluster_services_alb_logs_retention = var.infrastructure_ecs_cluster_services_alb_logs_retention\n infrastructure_ecs_cluster_service_cloudfront_logs_glue_table_columns = jsondecode(templatefile(\"${path.root}/glue-table-schemas/cloudfront-logs.json.tpl\", {}))\n\n infrastructure_rds_defaults = var.infrastructure_rds_defaults\n infrastructure_rds_keys = length(var.infrastructure_rds) > 0 ? keys(values(var.infrastructure_rds)[0]) : []\n infrastructure_rds = {\n for k, v in var.infrastructure_rds : k => merge({\n for rds_key in local.infrastructure_rds_keys : rds_key => try(coalesce(v[rds_key], local.infrastructure_rds_defaults[rds_key]), null)\n })\n }\n rds_engines = {\n \"instance\" = {\n \"mysql\" = \"mysql\",\n \"postgres\" = \"postgres\"\n },\n \"cluster\" = {\n \"mysql\" = \"aurora-mysql\",\n \"postgres\" = \"aurora-postgresql\"\n }\n }\n rds_licenses = {\n \"mysql\" = \"general-public-license\"\n \"postgres\" = \"postgresql-license\"\n }\n rds_ports = {\n \"mysql\" = 3306\n \"postgres\" = 5432\n }\n rds_s3_backups_container_entrypoint_file = {\n \"mysql\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-mysql.txt.tpl\"\n \"postgres\" = \"${path.root}/ecs-entrypoints/rds-s3-backups-postgres.txt.tpl\"\n }\n enable_infrastructure_rds_backup_to_s3 = var.enable_infrastructure_rds_backup_to_s3\n infrastructure_rds_backup_to_s3_cron_expression = var.infrastructure_rds_backup_to_s3_cron_expression\n infrastructure_rds_backup_to_s3_retention = var.infrastructure_rds_backup_to_s3_retention\n enable_infrastructure_utilities = length(var.infrastructure_rds) > 0\n infrastructure_utilities_ecs_cluster_name = \"${local.resource_prefix}-infrastructure-utilities\"\n infrastructure_utilities_ecs_cluster_container_insights = var.infrastructure_utilities_ecs_cluster_container_insights\n\n infrastructure_elasticache_defaults = var.infrastructure_elasticache_defaults\n infrastructure_elasticache_keys = length(var.infrastructure_elasticache) > 0 ? keys(values(var.infrastructure_elasticache)[0]) : []\n infrastructure_elasticache = {\n for k, v in var.infrastructure_elasticache : k => merge({\n for elasticache_key in local.infrastructure_elasticache_keys : elasticache_key => try(coalesce(v[elasticache_key], local.infrastructure_elasticache_defaults[elasticache_key]), null)\n })\n }\n elasticache_ports = {\n \"redis\" = 6379\n }\n\n custom_route53_hosted_zones = var.custom_route53_hosted_zones\n\n custom_s3_buckets = var.custom_s3_buckets\n\n enable_cloudformatian_s3_template_store = var.enable_cloudformatian_s3_template_store != null ? var.enable_cloudformatian_s3_template_store : false\n custom_cloudformation_stacks = var.custom_cloudformation_stacks\n\n custom_lambda_functions = var.custom_lambda_functions != null ? var.custom_lambda_functions : {}\n enable_lambda_functions_s3_store = length(local.custom_lambda_functions) > 0\n\n s3_object_presign = local.enable_cloudformatian_s3_template_store ? toset([\n for k, v in local.custom_cloudformation_stacks : \"${aws_s3_bucket.cloudformation_custom_stack_template_store[0].id}/${v[\"s3_template_store_key\"]}\" if v[\"s3_template_store_key\"] != null\n ]) : []\n\n default_tags = {\n Project = local.project_name,\n Infrastructure = local.infrastructure_name,\n Environment = local.environment,\n Prefix = local.resource_prefix,\n }\n\n custom_resource_tags = zipmap([for idx in range(length(var.custom_resource_tags)) : idx], var.custom_resource_tags)\n custom_resource_tags_delay = var.custom_resource_tags_delay\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 0,
"model_added_chars": 119,
"model_removed_chars": 0,
"user_added_lines": 0,
"user_removed_lines": 290,
"user_added_chars": 0,
"user_removed_chars": 22681
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "8f2a52aa-6244-4a88-8d7a-86f22a7cb9b9",
"timestamp": "2026-01-23T17:34:29.917Z",
"type": "gemini",
"content": "I will now update `ecs-cluster-infrastructure.tf` to replace the direct variable reference `var.infrastructure_ecs_cluster_container_insights` with the local variable `local.infrastructure_ecs_cluster_container_insights`.",
"thoughts": [
{
"subject": "Revising Infrastructure Code",
"description": "I'm now integrating the local variable into `ecs-cluster-infrastructure.tf`. It's a straightforward implementation, aiming for cleaner code. I expect this will improve readability and maintainability going forward.",
"timestamp": "2026-01-23T17:34:28.650Z"
}
],
"tokens": {
"input": 68245,
"output": 186,
"cached": 67170,
"thoughts": 19,
"tool": 0,
"total": 68450
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769189669911-56075ca989b2c",
"name": "replace",
"args": {
"old_string": " setting {\n name = \"containerInsights\"\n value = var.infrastructure_ecs_cluster_container_insights\n }",
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf",
"expected_replacements": 1,
"new_string": " setting {\n name = \"containerInsights\"\n value = local.infrastructure_ecs_cluster_container_insights\n }",
"instruction": "Use `local.infrastructure_ecs_cluster_container_insights` instead of `var.infrastructure_ecs_cluster_container_insights`."
},
"result": [
{
"functionResponse": {
"id": "replace-1769189669911-56075ca989b2c",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:34:39.167Z",
"resultDisplay": {
"fileDiff": "Index: ecs-cluster-infrastructure.tf\n===================================================================\n--- ecs-cluster-infrastructure.tf\tCurrent\n+++ ecs-cluster-infrastructure.tf\tProposed\n@@ -5,7 +5,7 @@\n \n setting {\n name = \"containerInsights\"\n- value = var.infrastructure_ecs_cluster_container_insights\n+ value = local.infrastructure_ecs_cluster_container_insights\n }\n \n dynamic \"configuration\" {\n",
"fileName": "ecs-cluster-infrastructure.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/ecs-cluster-infrastructure.tf",
"originalContent": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = var.infrastructure_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n",
"newContent": "resource \"aws_ecs_cluster\" \"infrastructure\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = local.infrastructure_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"infrastructure-ecs-cluster\"), 0, 6)}\"\n description = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"ecs.amazonaws.com\", \"ec2.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ec2-ecs\"\n policy = templatefile(\"${path.root}/policies/ec2-ecs.json.tpl\", {})\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_ec2_ecs\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n name = \"${local.resource_prefix}-s3-transfer-bucket-rw\"\n policy = templatefile(\n \"${path.root}/policies/s3-object-rw.json.tpl\",\n {\n bucket_arn = aws_s3_bucket.infrastructure_vpc_transfer[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_s3_transfer_bucket_rw\" {\n count = local.enable_infrastructure_vpc_transfer_s3_bucket ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n {\n kms_key_arn = aws_kms_key.infrastructure[0].arn\n }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_kms_encrypt\" {\n count = local.infrastructure_ecs_cluster_allow_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt[0].arn\n}\n\nresource \"aws_iam_instance_profile\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n role = aws_iam_role.infrastructure_ecs_cluster[0].name\n}\n\nresource \"aws_launch_template\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n description = \"Infrastructure ECS Cluster (${local.resource_prefix})\"\n\n block_device_mappings {\n # Root EBS volume\n device_name = \"/dev/xvda\"\n\n ebs {\n volume_size = 40\n encrypted = true\n delete_on_termination = true\n }\n }\n\n block_device_mappings {\n # Docker Storage EBS volume\n device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name\n\n ebs {\n volume_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size\n volume_type = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_type\n encrypted = true\n delete_on_termination = true\n }\n }\n\n capacity_reservation_specification {\n capacity_reservation_preference = \"open\"\n }\n\n network_interfaces {\n associate_public_ip_address = local.infrastructure_ecs_cluster_publicly_avaialble\n security_groups = [aws_security_group.infrastructure_ecs_cluster_container_instances[0].id]\n }\n\n iam_instance_profile {\n name = aws_iam_instance_profile.infrastructure_ecs_cluster[0].name\n }\n\n metadata_options {\n http_endpoint = \"enabled\"\n http_tokens = \"required\"\n }\n\n monitoring {\n enabled = true\n }\n\n disable_api_termination = false\n disable_api_stop = false\n ebs_optimized = true\n image_id = data.aws_ami.ecs_cluster_ami[0].id\n instance_initiated_shutdown_behavior = \"stop\"\n instance_type = local.infrastructure_ecs_cluster_instance_type\n\n user_data = local.infrastructure_ecs_cluster_user_data\n\n depends_on = [\n aws_efs_mount_target.infrastructure_ecs_cluster,\n ]\n}\n\nresource \"aws_placement_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n strategy = \"spread\"\n spread_level = \"rack\"\n}\n\nresource \"aws_autoscaling_group\" \"infrastructure_ecs_cluster\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n\n launch_template {\n id = aws_launch_template.infrastructure_ecs_cluster[0].id\n version = \"$Latest\"\n }\n\n vpc_zone_identifier = local.infrastructure_ecs_cluster_publicly_avaialble ? [\n for subnet in aws_subnet.infrastructure_public : subnet.id\n ] : [\n for subnet in aws_subnet.infrastructure_private : subnet.id\n ]\n placement_group = aws_placement_group.infrastructure_ecs_cluster[0].id\n\n min_size = local.infrastructure_ecs_cluster_min_size\n max_size = local.infrastructure_ecs_cluster_max_size\n desired_capacity = local.infrastructure_ecs_cluster_min_size\n max_instance_lifetime = local.infrastructure_ecs_cluster_max_instance_lifetime\n\n termination_policies = [\"OldestLaunchConfiguration\", \"ClosestToNextInstanceHour\", \"Default\"]\n\n tag {\n key = \"Name\"\n value = \"${local.resource_prefix}-infrastructure-ecs-cluster\"\n propagate_at_launch = true\n }\n\n dynamic \"tag\" {\n for_each = local.default_tags\n\n content {\n key = tag.key\n value = tag.value\n propagate_at_launch = true\n }\n }\n\n instance_refresh {\n strategy = \"Rolling\"\n preferences {\n min_healthy_percentage = 100\n }\n triggers = [\"tag\"]\n }\n\n timeouts {\n delete = \"15m\"\n }\n\n enabled_metrics = [\n \"GroupAndWarmPoolDesiredCapacity\",\n \"GroupAndWarmPoolTotalCapacity\",\n \"GroupDesiredCapacity\",\n \"GroupInServiceCapacity\",\n \"GroupInServiceInstances\",\n \"GroupMaxSize\",\n \"GroupMinSize\",\n \"GroupPendingCapacity\",\n \"GroupPendingInstances\",\n \"GroupStandbyCapacity\",\n \"GroupStandbyInstances\",\n \"GroupTerminatingCapacity\",\n \"GroupTerminatingInstances\",\n \"GroupTotalCapacity\",\n \"GroupTotalInstances\",\n \"WarmPoolDesiredCapacity\",\n \"WarmPoolMinSize\",\n \"WarmPoolPendingCapacity\",\n \"WarmPoolTerminatingCapacity\",\n \"WarmPoolTotalCapacity\",\n \"WarmPoolWarmedCapacity\",\n ]\n\n depends_on = [\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw,\n aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt,\n ]\n}\n\nresource \"aws_sns_topic\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook\"\n kms_master_key_id = local.infrastructure_kms_encryption ? aws_kms_alias.infrastructure[0].name : null\n}\n\nresource \"aws_iam_role\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-${substr(sha512(\"ecs-termination-hook\"), 0, 6)}\"\n description = \"${local.resource_prefix}-ecs-termination-hook\"\n assume_role_policy = templatefile(\n \"${path.root}/policies/assume-roles/service-principle-standard.json.tpl\",\n { services = jsonencode([\"autoscaling.amazonaws.com\"]) }\n )\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-sns-publish\"\n policy = templatefile(\n \"${path.root}/policies/sns-publish.json.tpl\",\n { sns_topic_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish[0].arn\n}\n\nresource \"aws_iam_policy\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n name = \"${local.resource_prefix}-ecs-termination-hook-kms-encrypt\"\n policy = templatefile(\n \"${path.root}/policies/kms-encrypt.json.tpl\",\n { kms_key_arn = aws_kms_key.infrastructure[0].arn }\n )\n}\n\nresource \"aws_iam_role_policy_attachment\" \"infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt\" {\n count = local.enable_infrastructure_ecs_cluster && local.infrastructure_kms_encryption ? 1 : 0\n\n role = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].id\n policy_arn = aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt[0].arn\n}\n\nresource \"aws_autoscaling_lifecycle_hook\" \"infrastructure_ecs_cluster_termination\" {\n count = local.enable_infrastructure_ecs_cluster ? 1 : 0\n\n name = local.infrastructure_ecs_cluster_termination_sns_topic_name\n autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name\n default_result = local.infrastructure_ecs_cluster_draining_lambda_enabled ? \"ABANDON\" : \"CONTINUE\"\n heartbeat_timeout = local.infrastructure_ecs_cluster_termination_timeout\n lifecycle_transition = \"autoscaling:EC2_INSTANCE_TERMINATING\"\n role_arn = aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n notification_target_arn = aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination[0].arn\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 1,
"model_added_chars": 63,
"model_removed_chars": 61,
"user_added_lines": 0,
"user_removed_lines": 313,
"user_added_chars": 0,
"user_removed_chars": 10748
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "b6dedac7-c3f3-4070-b56f-7b51c71b5b5f",
"timestamp": "2026-01-23T17:34:44.246Z",
"type": "gemini",
"content": "I will update the `utilities-infrastructure-ecs-cluster.tf` file to use the `local.infrastructure_utilities_ecs_cluster_container_insights` variable for the `containerInsights` setting, replacing the direct variable reference.",
"thoughts": [
{
"subject": "Revising the Configuration",
"description": "I'm now integrating the local variable into `utilities-infrastructure-ecs-cluster.tf`. This should enhance modularity, as I finalize this configuration. The immediate goal is to ensure all references are correctly updated for optimal function.",
"timestamp": "2026-01-23T17:34:43.137Z"
}
],
"tokens": {
"input": 68465,
"output": 196,
"cached": 67133,
"thoughts": 21,
"tool": 0,
"total": 68682
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769189684240-ed69f2c2e9c258",
"name": "replace",
"args": {
"old_string": " setting {\n name = \"containerInsights\"\n value = var.infrastructure_utilities_ecs_cluster_container_insights\n }",
"expected_replacements": 1,
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf",
"instruction": "Use `local.infrastructure_utilities_ecs_cluster_container_insights` instead of `var.infrastructure_utilities_ecs_cluster_container_insights`.",
"new_string": " setting {\n name = \"containerInsights\"\n value = local.infrastructure_utilities_ecs_cluster_container_insights\n }"
},
"result": [
{
"functionResponse": {
"id": "replace-1769189684240-ed69f2c2e9c258",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:34:47.510Z",
"resultDisplay": {
"fileDiff": "Index: utilities-infrastructure-ecs-cluster.tf\n===================================================================\n--- utilities-infrastructure-ecs-cluster.tf\tCurrent\n+++ utilities-infrastructure-ecs-cluster.tf\tProposed\n@@ -5,7 +5,7 @@\n \n setting {\n name = \"containerInsights\"\n- value = var.infrastructure_utilities_ecs_cluster_container_insights\n+ value = local.infrastructure_utilities_ecs_cluster_container_insights\n }\n \n dynamic \"configuration\" {\n",
"fileName": "utilities-infrastructure-ecs-cluster.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/utilities-infrastructure-ecs-cluster.tf",
"originalContent": "resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n count = local.enable_infrastructure_utilities ? 1 : 0\n\n name = local.infrastructure_utilities_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = var.infrastructure_utilities_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n",
"newContent": "resource \"aws_ecs_cluster\" \"infrastrucutre_utilities\" {\n count = local.enable_infrastructure_utilities ? 1 : 0\n\n name = local.infrastructure_utilities_ecs_cluster_name\n\n setting {\n name = \"containerInsights\"\n value = local.infrastructure_utilities_ecs_cluster_container_insights\n }\n\n dynamic \"configuration\" {\n for_each = local.infrastructure_ecs_cluster_enable_execute_command_logging ? [1] : []\n content {\n execute_command_configuration {\n kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null\n logging = \"OVERRIDE\"\n\n log_configuration {\n s3_bucket_encryption_enabled = true\n s3_bucket_name = aws_s3_bucket.infrastructure_logs[0].id\n s3_key_prefix = \"ecs-exec\"\n }\n }\n }\n }\n}\n",
"diffStat": {
"model_added_lines": 1,
"model_removed_lines": 1,
"model_added_chars": 73,
"model_removed_chars": 71,
"user_added_lines": 0,
"user_removed_lines": 22,
"user_added_chars": 0,
"user_removed_chars": 690
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "abb6a173-b0a6-490a-aa1e-ceec3fb795bb",
"timestamp": "2026-01-23T17:35:00.451Z",
"type": "gemini",
"content": "I'll verify the Terraform configuration by running `terraform validate` to ensure everything is correctly set up.",
"thoughts": [
{
"subject": "Re-Validating Configuration",
"description": "I've just run `terraform validate` once more to ensure everything is still shipshape. No issues popped up, thankfully! The configuration seems sound, so I can confidently proceed to the next step.",
"timestamp": "2026-01-23T17:35:00.132Z"
}
],
"tokens": {
"input": 68697,
"output": 33,
"cached": 67096,
"thoughts": 12,
"tool": 0,
"total": 68742
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769189700443-9f75adae43ef18",
"name": "run_shell_command",
"args": {
"command": "terraform validate"
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769189700443-9f75adae43ef18",
"name": "run_shell_command",
"response": {
"output": "Command: terraform validate\nDirectory: (root)\nOutput: Success! The configuration is valid.\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 89241"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:35:10.224Z",
"resultDisplay": "Success! The configuration is valid.",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "11cb879e-12f2-42fd-8a2e-9f0170b91597",
"timestamp": "2026-01-23T17:35:20.723Z",
"type": "gemini",
"content": "I will read the `README.md` file to assess the necessary updates for documenting the new variables `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`.",
"thoughts": [
{
"subject": "Evaluating Configuration Progress",
"description": "I've confirmed the configuration's validity. I've successfully incorporated the `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables within `variables.tf`. Corresponding locals were also integrated into `locals.tf`, and the `ecs-cluster-infrastructure` module has been updated.",
"timestamp": "2026-01-23T17:35:19.785Z"
},
{
"subject": "Documenting New Variables",
"description": "I've checked the existing `README.md` file. Now, I need to augment it to include thorough documentation for the newly added variables, ensuring clarity for any future users of the configuration.",
"timestamp": "2026-01-23T17:35:20.400Z"
}
],
"tokens": {
"input": 68790,
"output": 58,
"cached": 67067,
"thoughts": 140,
"tool": 0,
"total": 68988
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769189720720-53d26a1f9b35a8",
"name": "read_file",
"args": {
"file_path": "README.md"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769189720720-53d26a1f9b35a8",
"name": "read_file",
"response": {
"output": "\nIMPORTANT: The file content has been truncated.\nStatus: Showing lines 1-631 of 631 total lines.\nAction: To read more of the file, you can use the 'offset' and 'limit' parameters in a subsequent 'read_file' call. For example, to read the next section of the file, use offset: 631.\n\n--- FILE CONTENT (truncated) ---\n# Terraform dxw Dalmatian infrastructure\n\n[![Terraform CI](https://github.com/dxw/terraform-dxw-dalmatian-infrastructure/actions/workflows/continuous-integration-terraform.yml/badge.svg?branch=main)](https://github.com/dxw/terraform-dxw-dalmatian-infrastructure/actions/workflows/continuous-integration-terraform.yml?branch=main)\n[![GitHub release](https://img.shields.io/github/release/dxw/terraform-dxw-dalmatian-infrastructure.svg)](https://github.com/dxw/terraform-dxw-dalmatian-infrastructure/releases)\n\nThis project creates and manages resources within an AWS account for infrastructures on dxw's Dalmatian hosting platform.\n\n<!-- BEGIN_TF_DOCS -->\n## Requirements\n\n| Name | Version |\n|------|---------|\n| <a name=\"requirement_terraform\"></a> [terraform](#requirement\\_terraform) | >= 1.6.5 |\n| <a name=\"requirement_archive\"></a> [archive](#requirement\\_archive) | >= 2.4.1 |\n| <a name=\"requirement_aws\"></a> [aws](#requirement\\_aws) | >= 5.30.0 |\n| <a name=\"requirement_datadog\"></a> [datadog](#requirement\\_datadog) | >= 3.46.0 |\n| <a name=\"requirement_external\"></a> [external](#requirement\\_external) | >= 2.3.2 |\n| <a name=\"requirement_null\"></a> [null](#requirement\\_null) | >= 3.2.2 |\n| <a name=\"requirement_random\"></a> [random](#requirement\\_random) | >= 3.6.0 |\n\n## Providers\n\n| Name | Version |\n|------|---------|\n| <a name=\"provider_archive\"></a> [archive](#provider\\_archive) | 2.7.0 |\n| <a name=\"provider_aws\"></a> [aws](#provider\\_aws) | 5.97.0 |\n| <a name=\"provider_aws.awsroute53root\"></a> [aws.awsroute53root](#provider\\_aws.awsroute53root) | 5.97.0 |\n| <a name=\"provider_aws.useast1\"></a> [aws.useast1](#provider\\_aws.useast1) | 5.97.0 |\n| <a name=\"provider_datadog\"></a> [datadog](#provider\\_datadog) | 3.63.0 |\n| <a name=\"provider_external\"></a> [external](#provider\\_external) | 2.3.5 |\n| <a name=\"provider_random\"></a> [random](#provider\\_random) | 3.7.2 |\n| <a name=\"provider_terraform\"></a> [terraform](#provider\\_terraform) | n/a |\n\n## Resources\n\n| Name | Type |\n|------|------|\n| [aws_acm_certificate.infrastructure_wildcard](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource |\n| [aws_acm_certificate.infrastructure_wildcard_us_east_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource |\n| [aws_acm_certificate_validation.infrastructure_wildcard](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |\n| [aws_acm_certificate_validation.infrastructure_wildcard_us_east_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource |\n| [aws_alb.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb) | resource |\n| [aws_alb_listener.infrastructure_ecs_cluster_service_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |\n| [aws_alb_listener.infrastructure_ecs_cluster_service_http_https_redirect](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |\n| [aws_alb_listener.infrastructure_ecs_cluster_service_https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |\n| [aws_alb_listener_rule.infrastructure_ecs_cluster_service_host_header](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener_rule) | resource |\n| [aws_alb_listener_rule.infrastructure_ecs_cluster_service_host_header_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener_rule) | resource |\n| [aws_alb_listener_rule.service_alb_host_rule_bypass_exclusions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener_rule) | resource |\n| [aws_alb_target_group.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_target_group) | resource |\n| [aws_alb_target_group.infrastructure_ecs_cluster_service_blue](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_target_group) | resource |\n| [aws_alb_target_group.infrastructure_ecs_cluster_service_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_target_group) | resource |\n| [aws_athena_workgroup.infrastructure_ecs_cluster_service_cloudfront_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/athena_workgroup) | resource |\n| [aws_athena_workgroup.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/athena_workgroup) | resource |\n| [aws_autoscaling_group.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group) | resource |\n| [aws_autoscaling_lifecycle_hook.infrastructure_ecs_cluster_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_lifecycle_hook) | resource |\n| [aws_autoscaling_schedule.ecs_infrastructure_time_based_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource |\n| [aws_autoscaling_schedule.ecs_infrastructure_time_based_max](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource |\n| [aws_autoscaling_schedule.ecs_infrastructure_time_based_min](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource |\n| [aws_cloudformation_stack.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack) | resource |\n| [aws_cloudfront_cache_policy.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_cache_policy) | resource |\n| [aws_cloudfront_distribution.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource |\n| [aws_cloudfront_distribution.infrastructure_ecs_cluster_service_cloudfront](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource |\n| [aws_cloudfront_function.custom_s3_buckets_viewer_request](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_function) | resource |\n| [aws_cloudfront_origin_access_control.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_control) | resource |\n| [aws_cloudwatch_event_rule.ecs_cluster_infrastructure_ecs_asg_diff_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.ecs_cluster_infrastructure_instance_refresh](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.ecs_cluster_infrastructure_pending_task_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_datadog_agent_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_service_ecr_scan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_rds_s3_backups_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_rule.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |\n| [aws_cloudwatch_event_target.ecr_scan_event_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.ecs_cluster_infrastructure_ecs_asg_diff_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.ecs_cluster_infrastructure_instance_refresh](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.ecs_cluster_infrastructure_pending_task_metric_1_min_cron](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.infrastructure_ecs_cluster_datadog_agent_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.infrastructure_rds_s3_backups_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_event_target.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |\n| [aws_cloudwatch_log_group.ecs_cluster_infrastructure_draining_lambda_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.ecs_cluster_infrastructure_instance_refresh_lambda_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.ecs_cluster_infrastructure_pending_task_metric_lambda_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.infrastructure_ecs_cluster_datadog_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.infrastructure_rds_exports](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_log_group.lambda_custom_functions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_asg_cpu](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |\n| [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_ecs_asg_diff](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |\n| [aws_cloudwatch_metric_alarm.infrastructure_ecs_cluster_pending_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource |\n| [aws_codebuild_project.infrastructure_ecs_cluster_datadog_agent_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |\n| [aws_codebuild_project.infrastructure_ecs_cluster_logspout_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |\n| [aws_codebuild_project.infrastructure_ecs_cluster_service_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |\n| [aws_codebuild_project.infrastructure_utilities_image_build](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |\n| [aws_codedeploy_app.infrastructure_ecs_cluster_service_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codedeploy_app) | resource |\n| [aws_codedeploy_deployment_config.infrastructure_ecs_cluster_service_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codedeploy_deployment_config) | resource |\n| [aws_codedeploy_deployment_group.infrastructure_ecs_cluster_service_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codedeploy_deployment_group) | resource |\n| [aws_codepipeline.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codepipeline) | resource |\n| [aws_db_instance.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance) | resource |\n| [aws_db_option_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_option_group) | resource |\n| [aws_db_parameter_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_parameter_group) | resource |\n| [aws_db_subnet_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_subnet_group) | resource |\n| [aws_default_network_acl.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_network_acl) | resource |\n| [aws_ecr_lifecycle_policy.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_lifecycle_policy) | resource |\n| [aws_ecr_repository.infrastructure_ecs_cluster_datadog_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |\n| [aws_ecr_repository.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |\n| [aws_ecr_repository.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |\n| [aws_ecr_repository.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |\n| [aws_ecs_cluster.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |\n| [aws_ecs_cluster.infrastrucutre_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |\n| [aws_ecs_service.infrastructure_ecs_cluster_datadog_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |\n| [aws_ecs_service.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |\n| [aws_ecs_service.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |\n| [aws_ecs_task_definition.infrastructure_ecs_cluster_datadog_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\n| [aws_ecs_task_definition.infrastructure_ecs_cluster_logspout](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\n| [aws_ecs_task_definition.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\n| [aws_ecs_task_definition.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\n| [aws_ecs_task_definition.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |\n| [aws_efs_file_system.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system) | resource |\n| [aws_efs_mount_target.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_mount_target) | resource |\n| [aws_eip.infrastructure_nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |\n| [aws_elasticache_parameter_group.infrastructure_elasticache_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_parameter_group) | resource |\n| [aws_elasticache_replication_group.infrastructure_elasticache_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group) | resource |\n| [aws_elasticache_serverless_cache.infrastructure_elasticache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_serverless_cache) | resource |\n| [aws_elasticache_subnet_group.infrastructure_elasticache_cluster_subnet_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_subnet_group) | resource |\n| [aws_flow_log.infrastructure_vpc_flow_logs_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |\n| [aws_flow_log.infrastructure_vpc_flow_logs_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |\n| [aws_globalaccelerator_accelerator.infrastructure_ecs_cluster_service_alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/globalaccelerator_accelerator) | resource |\n| [aws_globalaccelerator_endpoint_group.service_loadbalancer_alb_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/globalaccelerator_endpoint_group) | resource |\n| [aws_globalaccelerator_endpoint_group.service_loadbalancer_alb_https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/globalaccelerator_endpoint_group) | resource |\n| [aws_globalaccelerator_listener.infrastructure_ecs_cluster_service_alb_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/globalaccelerator_listener) | resource |\n| [aws_globalaccelerator_listener.infrastructure_ecs_cluster_service_alb_https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/globalaccelerator_listener) | resource |\n| [aws_glue_catalog_database.infrastructure_ecs_cluster_service_cloudfront_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_database) | resource |\n| [aws_glue_catalog_database.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_database) | resource |\n| [aws_glue_catalog_table.infrastructure_ecs_cluster_service_cloudfront_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_table) | resource |\n| [aws_glue_catalog_table.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_table) | resource |\n| [aws_iam_instance_profile.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_draining_ecs_container_instance_state_update_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_draining_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_draining_sns_publish_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_ecs_asg_diff_metric_asg_describe_asg_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_ecs_asg_diff_metric_cloudwatch_put_metric_data_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_ecs_asg_diff_metric_ecs_describe_cluster_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_ecs_asg_diff_metric_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_instance_refresh_allow_instance_refresh](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_instance_refresh_allow_modify_launch_template](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_instance_refresh_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_instance_refresh_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_pending_task_metric_cloudwatch_put_metric_data_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_pending_task_metric_ecs_describe_cluster_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_pending_task_metric_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_datadog_agent_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_s3_transfer_bucket_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_blue_green_codedeploy_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codebuild_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codebuild_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codepipeline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codepipeline_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codepipeline_codestar_connection](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codepipeline_ecs_deploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_codepipeline_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_scheduled_task_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_scheduled_task_pass_role_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_execution_s3_read_envfiles](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_ecs_cluster_service_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_rds_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_rds_s3_backups_cloudwatch_schedule_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_rds_s3_backups_cloudwatch_schedule_pass_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_rds_s3_backups_task_s3_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_rds_s3_backups_task_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.infrastructure_utilities_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.lambda_custom_functions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_policy.lambda_custom_functions_custom_policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |\n| [aws_iam_role.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.ecs_cluster_infrastructure_instance_refresh_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_datadog_agent_image_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_datadog_agent_task_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_logspout_image_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_codepipeline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_ecs_cluster_service_task_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_rds_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_rds_s3_backups_cloudwatch_schedule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_utilities_image_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_utilities_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_utilities_task_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role.lambda_custom_functions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role_policy.infrastructure_vpc_flow_logs_allow_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_draining_ecs_container_instance_state_update_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_draining_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_draining_sns_publish_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_ecs_asg_diff_cloudwatch_metric_put_metric_data_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_ecs_asg_diff_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_ecs_asg_diff_metric_asg_describe_asg_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_ecs_asg_diff_metric_ecs_describe_cluster_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_instance_refresh_allow_instance_refresh](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_instance_refresh_allow_modify_launch_template](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_instance_refresh_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_instance_refresh_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_pending_task_cloudwatch_metric_put_metric_data_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_pending_task_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_pending_task_metric_ecs_describe_cluster_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_datadog_agent_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_logspout_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_s3_transfer_bucket_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_blue_green_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_blue_green_codedeploy_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codebuild](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codebuild_blue_green](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codebuild_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codepipeline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codepipeline_codedeploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codepipeline_codestar_connection](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codepipeline_ecs_deploy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_codepipeline_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_scheduled_task_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_scheduled_task_pass_role_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_execution_s3_read_envfiles](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_service_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_rds_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_cloudwatch_schedule_ecs_run_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_cloudwatch_schedule_pass_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_task_s3_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_task_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_allow_builds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_image_codebuild_ecr_push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_ecs_exec_log_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_ecs_exec_log_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_ecr_pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_ecs_get_secret_value_kms_decrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_execution_get_secret_value](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.infrastructure_utilities_task_ssm_create_channels](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.lambda_custom_functions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.lambda_custom_functions_custom_policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_instance.infrastructure_bastion](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |\n| [aws_internet_gateway.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |\n| [aws_kms_alias.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |\n| [aws_kms_alias.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |\n| [aws_kms_alias.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |\n| [aws_kms_key.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |\n| [aws_kms_key.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |\n| [aws_kms_key.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |\n| [aws_lambda_function.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_function.ecs_cluster_infrastructure_draining](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_function.ecs_cluster_infrastructure_ecs_asg_diff_metric](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_function.ecs_cluster_infrastructure_instance_refresh](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_function.ecs_cluster_infrastructure_pending_task_metric](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_permission.ecs_cluster_infrastructure_draining_allow_sns_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.ecs_cluster_infrastructure_ecs_asg_diff_metric_allow_cloudwatch_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.ecs_cluster_infrastructure_instance_refresh_allow_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.ecs_cluster_infrastructure_pending_task_metric_allow_cloudwatch_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_launch_template.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template) | resource |\n| [aws_lb_listener_certificate.service_shared_alb_certificate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_certificate) | resource |\n| [aws_nat_gateway.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource |\n| [aws_network_acl.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl) | resource |\n| [aws_network_acl.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl) | resource |\n| [aws_network_acl_association.infrastructure_private_subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_association) | resource |\n| [aws_network_acl_association.infrastructure_public_subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_association) | resource |\n| [aws_network_acl_rule.egress_allow_all_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.egress_allow_all_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.egress_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.egress_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.ingress_allow_all_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.ingress_allow_all_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.ingress_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_network_acl_rule.ingress_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_acl_rule) | resource |\n| [aws_placement_group.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/placement_group) | resource |\n| [aws_rds_cluster.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster) | resource |\n| [aws_rds_cluster_instance.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance) | resource |\n| [aws_route.infrustructure_public_internet_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |\n| [aws_route.private_nat_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |\n| [aws_route53_record.custom_a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_alias](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_cname](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_mx](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_ns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_s3_cloudfront_record](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.custom_txt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.infrastructure_ns](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.infrastructure_wildcard_ssl_verification](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.service_loadbalancer_record_alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.service_loadbalancer_record_alb_global_accelerator_a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.service_record](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_record.service_record_ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource |\n| [aws_route53_zone.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource |\n| [aws_route53_zone.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone) | resource |\n| [aws_route_table.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |\n| [aws_route_table.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |\n| [aws_route_table_association.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |\n| [aws_route_table_association.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |\n| [aws_s3_bucket.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |\n| [aws_s3_bucket_acl.infrastructure_logs_log_delivery_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl) | resource |\n| [aws_s3_bucket_lifecycle_configuration.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_lifecycle_configuration.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_lifecycle_configuration.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_lifecycle_configuration.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_lifecycle_configuration.logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |\n| [aws_s3_bucket_logging.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_logging.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource |\n| [aws_s3_bucket_ownership_controls.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource |\n| [aws_s3_bucket_ownership_controls.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource |\n| [aws_s3_bucket_policy.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_policy.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |\n| [aws_s3_bucket_public_access_block.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_public_access_block.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_server_side_encryption_configuration.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |\n| [aws_s3_bucket_versioning.cloudformation_custom_stack_template_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_ecs_cluster_service_alb_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_ecs_cluster_service_build_pipeline_artifact_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_ecs_cluster_service_environment_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_rds_s3_backups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.infrastructure_vpc_transfer](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_bucket_versioning.lambda_custom_functions_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |\n| [aws_s3_object.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |\n| [aws_s3_object.lambda_custom_functions_default_zip](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |\n| [aws_secretsmanager_secret.infrastructure_ecs_cluster_datadog_agent_api_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |\n| [aws_secretsmanager_secret_version.infrastructure_ecs_cluster_datadog_agent_api_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |\n| [aws_security_group.custom_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_ec2_bastion_host](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_ecs_cluster_container_instances](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_ecs_cluster_efs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_ecs_cluster_service_alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_elasticache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group.infrastructure_utilities](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_logspout_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_nfs_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_ingress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_ingress_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_efs_ingress_nfs_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_service_alb_container_instance_egress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_service_alb_container_instance_egress_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_service_alb_http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_ecs_cluster_service_alb_https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_elasticache_ingress_tcp_custom_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_elasticache_ingress_tcp_ecs_instances](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_rds_ingress_tcp_custom_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_rds_ingress_tcp_ecs_instances](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_security_group_rule.infrastructure_utilities_task_ingress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |\n| [aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource |\n| [aws_sns_topic_subscription.ecs_cluster_infrastructure_draining_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource |\n| [aws_ssm_document.infrastructure_vpc_transfer_s3_download](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_document) | resource |\n| [aws_ssm_document.infrastructure_vpc_transfer_s3_upload](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_document) | resource |\n| [aws_subnet.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |\n| [aws_subnet.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |\n| [aws_vpc.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource |\n| [aws_wafv2_ip_set.infrastructure_ecs_cluster_ipv4_allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set) | resource |\n| [aws_wafv2_ip_set.infrastructure_ecs_cluster_ipv4_deny_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set) | resource |\n| [aws_wafv2_ip_set.infrastructure_ecs_cluster_ipv6_allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set) | resource |\n| [aws_wafv2_ip_set.infrastructure_ecs_cluster_ipv6_deny_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_ip_set) | resource |\n| [aws_wafv2_web_acl.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource |\n| [datadog_service_definition_yaml.infrastructure_ecs_cluster_service](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/service_definition_yaml) | resource |\n| [random_password.infrastructure_ecs_cluster_service_cloudfront_bypass_protection_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |\n| [terraform_data.infrastructure_ecs_cluster_datadog_agent_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [terraform_data.infrastructure_ecs_cluster_logspout_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [terraform_data.infrastructure_ecs_cluster_service_blue_green_create_codedeploy_deployment](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [terraform_data.infrastructure_ecs_cluster_service_env_file](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [terraform_data.infrastructure_utilities_image_build_trigger_codebuild](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [terraform_data.tag_resources](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |\n| [archive_file.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [archive_file.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [archive_file.ecs_cluster_infrastructure_instance_refresh_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [archive_file.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [archive_file.lambda_custom_functions_default_zip](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [aws_ami.bastion_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |\n| [aws_ami.ecs_cluster_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |\n| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |\n| [aws_cloudfront_cache_policy.managed_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |\n| [aws_cloudfront_origin_request_policy.managed_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_origin_request_policy) | data source |\n| [aws_cloudfront_response_headers_policy.managed_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_response_headers_policy) | data source |\n| [aws_elb_service_account.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/elb_service_account) | data source |\n| [aws_route53_zone.root](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |\n| [aws_s3_object.ecs_cluster_service_buildspec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source |\n| [aws_sns_topic.infrastructure_opsgenie_sns_topic](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source |\n| [aws_sns_topic.infrastructure_slack_sns_topic](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/sns_topic) | data source |\n| [external_external.s3_presigned_url](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source |\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| <a name=\"input_aws_profile_name_route53_root\"></a> [aws\\_profile\\_name\\_route53\\_root](#input\\_aws\\_profile\\_name\\_route53\\_root) | AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists. | `string` | n/a | yes |\n| <a name=\"input_aws_region\"></a> [aws\\_region](#input\\_aws\\_region) | AWS region in which to launch resources | `string` | n/a | yes |\n| <a name=\"input_custom_cloudformation_stacks\"></a> [custom\\_cloudformation\\_stacks](#input\\_custom\\_cloudformation\\_stacks) | Map of CloudFormation stacks to deploy<br/> {<br/> stack-name = {<br/> s3\\_template\\_store\\_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`<br/> template\\_body: (Optional - use of s3\\_template\\_store\\_key is preferred) The CloudFormation template body<br/> parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })<br/> on\\_failure: What to do on failure, either 'DO\\_NOTHING', 'ROLLBACK' or 'DELETE'<br/> capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`<br/> }<br/> } | <pre>map(object({<br/> s3_template_store_key = optional(string, null)<br/> template_body = optional(string, null)<br/> parameters = optional(map(string), null)<br/> on_failure = optional(string, null)<br/> capabilities = optional(list(string), null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_custom_lambda_functions\"></a> [custom\\_lambda\\_functions](#input\\_custom\\_lambda\\_functions) | Map of Lambda functions to deploy<br/> {<br/> function-name = {<br/> function\\_zip\\_s3\\_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).<br/> handler: The function entrypoint in the code<br/> runtime: The function runtime<br/> memory: Amount of memory in MB your Lambda Function can use at runtime.<br/> timeout: Amount of time your Lambda Function has to run in seconds<br/> environment\\_variables: Map of environment variables that are accessible from the function code during execution.<br/> custom\\_policies: Map of custom policies to attach to the Lambda role<br/> log\\_retention: Days to retain logs<br/> launch\\_in\\_infrastructure\\_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.<br/> }<br/> } | <pre>map(object({<br/> function_zip_s3_key = optional(string, null)<br/> handler = optional(string, null)<br/> runtime = optional(string, null)<br/> memory = optional(number, null)<br/> timeout = optional(number, null)<br/> environment_variables = optional(map(string), null)<br/> custom_policies = optional(map(object({<br/> description = string<br/> policy = object({<br/> Version = string<br/> Statement = list(object({<br/> Action = list(string)<br/> Effect = string<br/> Resource = list(string)<br/> }))<br/> })<br/> })), {})<br/> log_retention = optional(number, null)<br/> launch_in_infrastructur... [truncated]\n| <a name=\"input_custom_resource_tags\"></a> [custom\\_resource\\_tags](#input\\_custom\\_resource\\_tags) | A hacky way to add custom tags to resources<br/> Uses a script to add tags to resources using their ARNs<br/> Because Terraform will remove the tags, we may need to add a delay to running the script,<br/> which can be specified using var.custom\\_resource\\_tags\\_delay<br/> [<br/> {<br/> arns: Comma deliminated list of ARNs to apply the tags to<br/> tags: Map of key/values for the tags<br/> }<br/> ] | <pre>list(object({<br/> arns = string,<br/> tags = map(string)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_custom_resource_tags_delay\"></a> [custom\\_resource\\_tags\\_delay](#input\\_custom\\_resource\\_tags\\_delay) | The delay in seconds to wait before running the tag script | `number` | n/a | yes |\n| <a name=\"input_custom_route53_hosted_zones\"></a> [custom\\_route53\\_hosted\\_zones](#input\\_custom\\_route53\\_hosted\\_zones) | Map of Route53 Hosted Zone configurations to create<br/> {<br/> example.com = {<br/> ns\\_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })<br/> a\\_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })<br/> alias\\_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone\\_id = \"Z2FDTNDATAQYW2\" })<br/> cname\\_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })<br/> mx\\_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })<br/> txt\\_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })<br/> }<br/> } | <pre>map(object({<br/> ns_records = optional(map(object({<br/> values = list(string)<br/> ttl = optional(number, 300)<br/> })), null)<br/> a_records = optional(map(object({<br/> values = list(string)<br/> ttl = optional(number, 300)<br/> })), null)<br/> alias_records = optional(map(object({<br/> value = string<br/> zone_id = string<br/> })), null)<br/> cname_records = optional(map(object({<br/> values = list(string)<br/> ttl = optional(number, 300)<br/> })), null)<br/> mx_records = optional(map(object({<br/> values = list(string)<br/> ttl = optional(number, 300)<br/> })), null)<br/> txt_records = optional(map(object({<br/> values = list(string)<br/> ttl = optional(number, 300)<br/> })), null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_custom_s3_buckets\"></a> [custom\\_s3\\_buckets](#input\\_custom\\_s3\\_buckets) | Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"<br/> {<br/> bucket-name = {<br/> create\\_dedicated\\_kms\\_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.<br/> custom\\_kms\\_key\\_policy\\_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')<br/> use\\_aes256\\_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`<br/> transition\\_to\\_ia\\_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days<br/> transition\\_to\\_glacier\\_days: Conditionally transition objects to 'Glacier' storage in N days<br/> cloudfront\\_dedicated\\_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.<br/> cloudfront\\_decicated\\_distribution\\_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain<br/> cloudfront\\_decicated\\_distribution\\_tls\\_certificate\\_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate<br/> cloudfront\\_s3\\_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.<br/> cloudfront\\_basic\\_auth\\_user\\_list: Map o... [truncated]\n| <a name=\"input_ecs_cluster_efs_directories\"></a> [ecs\\_cluster\\_efs\\_directories](#input\\_ecs\\_cluster\\_efs\\_directories) | ECS cluster EFS directories to create | `list(string)` | n/a | yes |\n| <a name=\"input_ecs_cluster_efs_infrequent_access_transition\"></a> [ecs\\_cluster\\_efs\\_infrequent\\_access\\_transition](#input\\_ecs\\_cluster\\_efs\\_infrequent\\_access\\_transition) | ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition. | `number` | n/a | yes |\n| <a name=\"input_ecs_cluster_efs_performance_mode\"></a> [ecs\\_cluster\\_efs\\_performance\\_mode](#input\\_ecs\\_cluster\\_efs\\_performance\\_mode) | ECS cluser EFS performance mode | `string` | n/a | yes |\n| <a name=\"input_ecs_cluster_efs_throughput_mode\"></a> [ecs\\_cluster\\_efs\\_throughput\\_mode](#input\\_ecs\\_cluster\\_efs\\_throughput\\_mode) | ECS cluser EFS throughput mode | `string` | n/a | yes |\n| <a name=\"input_enable_cloudformatian_s3_template_store\"></a> [enable\\_cloudformatian\\_s3\\_template\\_store](#input\\_enable\\_cloudformatian\\_s3\\_template\\_store) | Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created. | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_bastion_host\"></a> [enable\\_infrastructure\\_bastion\\_host](#input\\_enable\\_infrastructure\\_bastion\\_host) | Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster\"></a> [enable\\_infrastructure\\_ecs\\_cluster](#input\\_enable\\_infrastructure\\_ecs\\_cluster) | Enable creation of infrastructure ECS cluster, to place ECS services | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_asg_cpu_alert\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert) | Enable a CPU alert for the ECS cluster's Autoscaling Group | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_datadog_agent\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_datadog\\_agent](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_datadog\\_agent) | Conditionally launch Datadog agent containers on the ECS cluster | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert) | Enable the ECS Cluster Container Instance / ASG instance diff alert | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_efs\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_efs](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_efs) | Conditionally create and mount EFS to the ECS cluster instances | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_pending_task_alert\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert) | Enable the ECS Cluster pending task alert | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_ecs_cluster_services_alb_logs\"></a> [enable\\_infrastructure\\_ecs\\_cluster\\_services\\_alb\\_logs](#input\\_enable\\_infrastructure\\_ecs\\_cluster\\_services\\_alb\\_logs) | Enable Infrastructure ECS cluster services ALB logs | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_rds_backup_to_s3\"></a> [enable\\_infrastructure\\_rds\\_backup\\_to\\_s3](#input\\_enable\\_infrastructure\\_rds\\_backup\\_to\\_s3) | Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3 | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_route53_hosted_zone\"></a> [enable\\_infrastructure\\_route53\\_hosted\\_zone](#input\\_enable\\_infrastructure\\_route53\\_hosted\\_zone) | Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module. | `bool` | n/a | yes |\n| <a name=\"input_enable_infrastructure_vpc_transfer_s3_bucket\"></a> [enable\\_infrastructure\\_vpc\\_transfer\\_s3\\_bucket](#input\\_enable\\_infrastructure\\_vpc\\_transfer\\_s3\\_bucket) | Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_environment\"></a> [environment](#input\\_environment) | The environment name to be used as part of the resource prefix | `string` | n/a | yes |\n| <a name=\"input_infrastructure_bastion_host_custom_security_group_rules\"></a> [infrastructure\\_bastion\\_host\\_custom\\_security\\_group\\_rules](#input\\_infrastructure\\_bastion\\_host\\_custom\\_security\\_group\\_rules) | Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \"egress\", ... } }) | <pre>map(object({<br/> description = string<br/> type = string<br/> from_port = number<br/> to_port = number<br/> protocol = string<br/> source_security_group_id = optional(string, \"\")<br/> cidr_blocks = optional(list(string), [])<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_datadog_api_key\"></a> [infrastructure\\_datadog\\_api\\_key](#input\\_infrastructure\\_datadog\\_api\\_key) | Datadog API key | `string` | n/a | yes |\n| <a name=\"input_infrastructure_datadog_app_key\"></a> [infrastructure\\_datadog\\_app\\_key](#input\\_infrastructure\\_datadog\\_app\\_key) | Datadog App key | `string` | n/a | yes |\n| <a name=\"input_infrastructure_datadog_region\"></a> [infrastructure\\_datadog\\_region](#input\\_infrastructure\\_datadog\\_region) | Datadog region | `string` | n/a | yes |\n| <a name=\"input_infrastructure_dockerhub_email\"></a> [infrastructure\\_dockerhub\\_email](#input\\_infrastructure\\_dockerhub\\_email) | Dockerhub email | `string` | n/a | yes |\n| <a name=\"input_infrastructure_dockerhub_token\"></a> [infrastructure\\_dockerhub\\_token](#input\\_infrastructure\\_dockerhub\\_token) | Dockerhub token which has permissions to pull images | `string` | n/a | yes |\n| <a name=\"input_infrastructure_dockerhub_username\"></a> [infrastructure\\_dockerhub\\_username](#input\\_infrastructure\\_dockerhub\\_username) | Dockerhub username | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ami_version\"></a> [infrastructure\\_ecs\\_cluster\\_ami\\_version](#input\\_infrastructure\\_ecs\\_cluster\\_ami\\_version) | AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>) | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\"></a> [infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_evaluation\\_periods](#input\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_evaluation\\_periods) | Evaluation periods for the ECS cluster's Autoscaling Group CPU alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\"></a> [infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_opsgenie](#input\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_opsgenie) | Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_asg_cpu_alert_period\"></a> [infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_period](#input\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_period) | Period (in secods) for the ECS cluster's Autoscaling Group CPU alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_asg_cpu_alert_slack\"></a> [infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_slack](#input\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_slack) | Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_asg_cpu_alert_threshold\"></a> [infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_threshold](#input\\_infrastructure\\_ecs\\_cluster\\_asg\\_cpu\\_alert\\_threshold) | Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_autoscaling_time_based_custom\"></a> [infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_custom](#input\\_infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_custom) | List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired. | <pre>list(<br/> object({<br/> cron = string<br/> min = number<br/> max = number<br/> })<br/> )</pre> | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_autoscaling_time_based_max\"></a> [infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_max](#input\\_infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_max) | List of cron expressions to scale the ECS cluster to the configured max size | `list(string)` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_autoscaling_time_based_min\"></a> [infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_min](#input\\_infrastructure\\_ecs\\_cluster\\_autoscaling\\_time\\_based\\_min) | List of cron expressions to scale the ECS cluster to the configured min size | `list(string)` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_custom_security_group_rules\"></a> [infrastructure\\_ecs\\_cluster\\_custom\\_security\\_group\\_rules](#input\\_infrastructure\\_ecs\\_cluster\\_custom\\_security\\_group\\_rules) | Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \"egress\", ... } }) | <pre>map(object({<br/> description = string<br/> type = string<br/> from_port = number<br/> to_port = number<br/> protocol = string<br/> source_security_group_id = optional(string, \"\")<br/> cidr_blocks = optional(list(string), [])<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_draining_lambda_enabled\"></a> [infrastructure\\_ecs\\_cluster\\_draining\\_lambda\\_enabled](#input\\_infrastructure\\_ecs\\_cluster\\_draining\\_lambda\\_enabled) | Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_draining_lambda_log_retention\"></a> [infrastructure\\_ecs\\_cluster\\_draining\\_lambda\\_log\\_retention](#input\\_infrastructure\\_ecs\\_cluster\\_draining\\_lambda\\_log\\_retention) | Log retention for the ECS cluster draining Lambda | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ebs_docker_storage_volume_size\"></a> [infrastructure\\_ecs\\_cluster\\_ebs\\_docker\\_storage\\_volume\\_size](#input\\_infrastructure\\_ecs\\_cluster\\_ebs\\_docker\\_storage\\_volume\\_size) | Size of EBS volume for Docker storage on the infrastructure ECS instances | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ebs_docker_storage_volume_type\"></a> [infrastructure\\_ecs\\_cluster\\_ebs\\_docker\\_storage\\_volume\\_type](#input\\_infrastructure\\_ecs\\_cluster\\_ebs\\_docker\\_storage\\_volume\\_type) | Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3) | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_evaluation\\_periods](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_evaluation\\_periods) | Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_opsgenie](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_opsgenie) | Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_alert_period\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_period](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_period) | Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_slack](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_slack) | Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_threshold](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_alert\\_threshold) | Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\"></a> [infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_metric\\_lambda\\_log\\_retention](#input\\_infrastructure\\_ecs\\_cluster\\_ecs\\_asg\\_diff\\_metric\\_lambda\\_log\\_retention) | Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_enable_debug_mode\"></a> [infrastructure\\_ecs\\_cluster\\_enable\\_debug\\_mode](#input\\_infrastructure\\_ecs\\_cluster\\_enable\\_debug\\_mode) | Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs) | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_enable_execute_command_logging\"></a> [infrastructure\\_ecs\\_cluster\\_enable\\_execute\\_command\\_logging](#input\\_infrastructure\\_ecs\\_cluster\\_enable\\_execute\\_command\\_logging) | Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\"></a> [infrastructure\\_ecs\\_cluster\\_instance\\_refresh\\_lambda\\_log\\_retention](#input\\_infrastructure\\_ecs\\_cluster\\_instance\\_refresh\\_lambda\\_log\\_retention) | Log retention for the ECS cluster instance refresh lambda | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\"></a> [infrastructure\\_ecs\\_cluster\\_instance\\_refresh\\_lambda\\_schedule\\_expression](#input\\_infrastructure\\_ecs\\_cluster\\_instance\\_refresh\\_lambda\\_schedule\\_expression) | Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_instance_type\"></a> [infrastructure\\_ecs\\_cluster\\_instance\\_type](#input\\_infrastructure\\_ecs\\_cluster\\_instance\\_type) | The instance type for EC2 instances launched in the ECS cluster | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_logspout_command\"></a> [infrastructure\\_ecs\\_cluster\\_logspout\\_command](#input\\_infrastructure\\_ecs\\_cluster\\_logspout\\_command) | If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint` | `list(string)` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_max_instance_lifetime\"></a> [infrastructure\\_ecs\\_cluster\\_max\\_instance\\_lifetime](#input\\_infrastructure\\_ecs\\_cluster\\_max\\_instance\\_lifetime) | Maximum lifetime in seconds of an instance within the ECS cluster | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_max_size\"></a> [infrastructure\\_ecs\\_cluster\\_max\\_size](#input\\_infrastructure\\_ecs\\_cluster\\_max\\_size) | Maximum number of instances for the ECS cluster | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_min_size\"></a> [infrastructure\\_ecs\\_cluster\\_min\\_size](#input\\_infrastructure\\_ecs\\_cluster\\_min\\_size) | Minimum number of instances for the ECS cluster | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_evaluation\\_periods](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_evaluation\\_periods) | Evaluation periods for the ECS cluster's Pending Task alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_alert_opsgenie\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_opsgenie](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_opsgenie) | Enable Opsgenie alerts for the ECS cluster's Pending Task alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_alert_period\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_period](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_period) | Period (in secods) for the ECS cluster's Pending Task alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_alert_slack\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_slack](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_slack) | Enable Slack alerts for the ECS cluster's Pending Task alert | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_alert_threshold\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_threshold](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_alert\\_threshold) | Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\"></a> [infrastructure\\_ecs\\_cluster\\_pending\\_task\\_metric\\_lambda\\_log\\_retention](#input\\_infrastructure\\_ecs\\_cluster\\_pending\\_task\\_metric\\_lambda\\_log\\_retention) | Log retention for the ECS cluster pending task metric Lambda | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_publicly_avaialble\"></a> [infrastructure\\_ecs\\_cluster\\_publicly\\_avaialble](#input\\_infrastructure\\_ecs\\_cluster\\_publicly\\_avaialble) | Conditionally launch the ECS cluster EC2 instances into the Public subnet | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_service_defaults\"></a> [infrastructure\\_ecs\\_cluster\\_service\\_defaults](#input\\_infrastructure\\_ecs\\_cluster\\_service\\_defaults) | Default values for ECS Cluster Services | <pre>object({<br/> github_v1_source = optional(bool, null)<br/> github_v1_oauth_token = optional(string, null)<br/> codestar_connection_arn = optional(string, null)<br/> github_owner = optional(string, null)<br/> github_repo = optional(string, null)<br/> github_track_revision = optional(string, null)<br/> buildspec = optional(string, null)<br/> buildspec_from_github_repo = optional(bool, null)<br/> codebuild_environment_variables = optional(list(object({<br/> name = string<br/> value = string<br/> })), [])<br/> ecr_scan_target_sns_topic_arn = optional(string, null)<br/> deployment_type = optional(string, null)<br/> enable_cloudwatch_logs = optional(bool, null)<br/> cloudwatch_logs_retention = optional(number, null)<br/> enable_execute_command = optional(bool, null)<br/> deregistration_delay = optional(number, null)<br/> custom_policies = optional(map(object({<br/> description = string<br/> policy = object({<br/> Version = string<br/> Statement = list(object({<br/> Action = list(string)<br/> Effect = string<br/> Resource = list(string)<br/> }))<br/> })<br/> })), {})<br/> container_entrypoint = optional(list(string), null)<br/> container_port = optional(number, null)<br/> container_volumes = optional(list(map(string)), null)<br/> container_extra_hosts = optional(list(map(string)), null)<br/> container_count = optional(number, null)<br/> container_heath_check_path = optional(string, null)<br/> container_heath_grace_period = optional(number, nu... [truncated]\n| <a name=\"input_infrastructure_ecs_cluster_services\"></a> [infrastructure\\_ecs\\_cluster\\_services](#input\\_infrastructure\\_ecs\\_cluster\\_services) | Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"<br/> {<br/> service-name = {<br/> github\\_v1\\_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)<br/> github\\_v1\\_oauth\\_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here<br/> codestar\\_connection\\_arn: The CodeStar Connection ARN to use in the CodePipeline source<br/> github\\_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source<br/> github\\_repo: The GitHub repo name to be pulled by the CodePipeline source<br/> github\\_track\\_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source<br/> buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket<br/> buildspec\\_from\\_github\\_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec<br/> codebuild\\_environment\\_variables: List of codebuild environment variable objects (eg. [{ name = \"MY\\_VAR\", value = \"foo\" },{ name = \"MY\\_OTHER\\_VAR\", value = \"bar\"}])<br/> ecr\\_scan\\_target\\_sns\\_topic\\_arn: An SNS topic ARN to publish ECR scan results to<br/> deployment\\_type: The service deployment type - Can be one of 'rolling' or 'blue-green'<br/> enable\\_cloudwatch\\_logs: Conditionally enable cloudwatch logs for the service<br/> cloudwatch\\_logs\\_retention: CloudWatch log retention in days<br/> enable\\_execute\\_command: Enable Amazon ECS Exec to directly interact with containers<br/> deregistration\\_delay: Amount time for Elastic Load Balancing to wait before... [truncated]\n| <a name=\"input_infrastructure_ecs_cluster_services_alb_enable_global_accelerator\"></a> [infrastructure\\_ecs\\_cluster\\_services\\_alb\\_enable\\_global\\_accelerator](#input\\_infrastructure\\_ecs\\_cluster\\_services\\_alb\\_enable\\_global\\_accelerator) | Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_services_alb_ip_allow_list\"></a> [infrastructure\\_ecs\\_cluster\\_services\\_alb\\_ip\\_allow\\_list](#input\\_infrastructure\\_ecs\\_cluster\\_services\\_alb\\_ip\\_allow\\_list) | IP allow list for ingress traffic to the infrastructure ECS cluster services ALB | `list(string)` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_services_alb_logs_retention\"></a> [infrastructure\\_ecs\\_cluster\\_services\\_alb\\_logs\\_retention](#input\\_infrastructure\\_ecs\\_cluster\\_services\\_alb\\_logs\\_retention) | Retention in days for the infrasrtucture ecs cluster ALB logs | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_syslog_endpoint\"></a> [infrastructure\\_ecs\\_cluster\\_syslog\\_endpoint](#input\\_infrastructure\\_ecs\\_cluster\\_syslog\\_endpoint) | ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234' | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_syslog_permitted_peer\"></a> [infrastructure\\_ecs\\_cluster\\_syslog\\_permitted\\_peer](#input\\_infrastructure\\_ecs\\_cluster\\_syslog\\_permitted\\_peer) | Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com') | `string` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_termination_timeout\"></a> [infrastructure\\_ecs\\_cluster\\_termination\\_timeout](#input\\_infrastructure\\_ecs\\_cluster\\_termination\\_timeout) | The timeout for the terminiation lifecycle hook | `number` | n/a | yes |\n| <a name=\"input_infrastructure_ecs_cluster_wafs\"></a> [infrastructure\\_ecs\\_cluster\\_wafs](#input\\_infrastructure\\_ecs\\_cluster\\_wafs) | Map of WAF ACLs to create, which can be used with service CloudFront distributions | <pre>map(object({<br/> ipv4_deny_list = optional(list(string), null)<br/> ipv4_allow_list = optional(list(string), null)<br/> ipv6_deny_list = optional(list(string), null)<br/> ipv6_allow_list = optional(list(string), null)<br/> aws_managed_rules = optional(list(object({<br/> name = string<br/> action = string<br/> exclude_rules = optional(list(string), null)<br/> excluded_path_patterns = optional(list(string), null)<br/> })), null)<br/> rate_limiting = optional(object({<br/> enabled = bool<br/> limit = optional(number, 1000)<br/> evaluation_window_sec = optional(number, 300)<br/> }), null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_elasticache\"></a> [infrastructure\\_elasticache](#input\\_infrastructure\\_elasticache) | Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"<br/> {<br/> elasticache-name = {<br/> type: Choose either `cluster` or `serverless`<br/> engine: ElastiCache engine (Only `redis` is currently supported)<br/> engine\\_version: ElastiCache Engine version (For serverless, Specify the major version only)<br/> parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })<br/> cluster\\_node\\_type: ElastiCache Cluster node type<br/> cluster\\_node\\_count: ElastiCache Cluster node count<br/> serverless\\_max\\_storage: Serverless maximum storage<br/> serverless\\_max\\_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)<br/> snapshot\\_retention\\_limit: Snapshot retention limit<br/> }<br/> } | <pre>map(object({<br/> type = optional(string, null)<br/> engine = optional(string, null)<br/> engine_version = optional(string, null)<br/> parameters = optional(map(string), null)<br/> cluster_node_type = optional(string, null)<br/> cluster_node_count = optional(number, null)<br/> serverless_max_storage = optional(string, null)<br/> serverless_max_ecpu = optional(number, null)<br/> snapshot_retention_limit = optional(number, null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_elasticache_defaults\"></a> [infrastructure\\_elasticache\\_defaults](#input\\_infrastructure\\_elasticache\\_defaults) | Default values for ElastiCaches | <pre>object({<br/> type = optional(string, null)<br/> engine = optional(string, null)<br/> engine_version = optional(string, null)<br/> parameters = optional(map(string), null)<br/> cluster_node_type = optional(string, null)<br/> cluster_node_count = optional(number, null)<br/> serverless_max_storage = optional(number, null)<br/> serverless_max_ecpu = optional(number, null)<br/> snapshot_retention_limit = optional(number, null)<br/> })</pre> | n/a | yes |\n| <a name=\"input_infrastructure_kms_encryption\"></a> [infrastructure\\_kms\\_encryption](#input\\_infrastructure\\_kms\\_encryption) | Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_kms_key_policy_statements\"></a> [infrastructure\\_kms\\_key\\_policy\\_statements](#input\\_infrastructure\\_kms\\_key\\_policy\\_statements) | Additional KMS key policy statements for the Infrastructure KMS key | `string` | n/a | yes |\n| <a name=\"input_infrastructure_logging_bucket_retention\"></a> [infrastructure\\_logging\\_bucket\\_retention](#input\\_infrastructure\\_logging\\_bucket\\_retention) | Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered | `number` | n/a | yes |\n| <a name=\"input_infrastructure_name\"></a> [infrastructure\\_name](#input\\_infrastructure\\_name) | The infrastructure name to be used as part of the resource prefix | `string` | n/a | yes |\n| <a name=\"input_infrastructure_rds\"></a> [infrastructure\\_rds](#input\\_infrastructure\\_rds) | Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"<br/> {<br/> rds-name = {<br/> type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora<br/> engine: RDS engine (Either `mysql` or `postgres`)<br/> engine\\_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)<br/> parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })<br/> instance\\_class: RDS instance class<br/> allocated\\_storage: RDS allocated storage<br/> storage\\_type: RDS storage type<br/> dedicated\\_kms\\_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key<br/> dedicated\\_kms\\_key\\_policy\\_statements: Additional KMS key policies to add to the dedicated KMS key policy<br/> iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)<br/> storage_throughput: RDS storage throughput (Only required when `storage\\_type` is `gp3`. Only applicable for `type` of `instance`)<br/> multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)<br/> monitoring\\_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.<br/> cloudwatch\\_logs\\_export\\_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid v... [truncated]\n| <a name=\"input_infrastructure_rds_backup_to_s3_cron_expression\"></a> [infrastructure\\_rds\\_backup\\_to\\_s3\\_cron\\_expression](#input\\_infrastructure\\_rds\\_backup\\_to\\_s3\\_cron\\_expression) | Cron expression for when to trigger the SQL backups to S3 | `string` | n/a | yes |\n| <a name=\"input_infrastructure_rds_backup_to_s3_retention\"></a> [infrastructure\\_rds\\_backup\\_to\\_s3\\_retention](#input\\_infrastructure\\_rds\\_backup\\_to\\_s3\\_retention) | Retention in days to keep the S3 SQL backups | `number` | n/a | yes |\n| <a name=\"input_infrastructure_rds_defaults\"></a> [infrastructure\\_rds\\_defaults](#input\\_infrastructure\\_rds\\_defaults) | Default values for RDSs | <pre>object({<br/> type = optional(string, null)<br/> engine = optional(string, null)<br/> engine_version = optional(string, null)<br/> parameters = optional(map(string), null)<br/> instance_class = optional(string, null)<br/> allocated_storage = optional(number, null)<br/> storage_type = optional(string, null)<br/> dedicated_kms_key = optional(bool, null)<br/> dedicated_kms_key_policy_statements = optional(string, null)<br/> iops = optional(number, null)<br/> storage_throughput = optional(number, null)<br/> multi_az = optional(bool, null)<br/> monitoring_interval = optional(number, null)<br/> cloudwatch_logs_export_types = optional(list(string), null)<br/> cluster_instance_count = optional(number, null)<br/> cluster_serverlessv2_min_capacity = optional(number, null)<br/> cluster_serverlessv2_max_capacity = optional(number, null)<br/> })</pre> | n/a | yes |\n| <a name=\"input_infrastructure_vpc\"></a> [infrastructure\\_vpc](#input\\_infrastructure\\_vpc) | Enable infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_assign_generated_ipv6_cidr_block\"></a> [infrastructure\\_vpc\\_assign\\_generated\\_ipv6\\_cidr\\_block](#input\\_infrastructure\\_vpc\\_assign\\_generated\\_ipv6\\_cidr\\_block) | Assign generated IPv6 CIDR block on infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_cidr_block\"></a> [infrastructure\\_vpc\\_cidr\\_block](#input\\_infrastructure\\_vpc\\_cidr\\_block) | Infrastructure VPC CIDR block | `string` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_enable_dns_hostnames\"></a> [infrastructure\\_vpc\\_enable\\_dns\\_hostnames](#input\\_infrastructure\\_vpc\\_enable\\_dns\\_hostnames) | Enable DNS hostnames on infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_enable_dns_support\"></a> [infrastructure\\_vpc\\_enable\\_dns\\_support](#input\\_infrastructure\\_vpc\\_enable\\_dns\\_support) | Enable DNS support on infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_enable_network_address_usage_metrics\"></a> [infrastructure\\_vpc\\_enable\\_network\\_address\\_usage\\_metrics](#input\\_infrastructure\\_vpc\\_enable\\_network\\_address\\_usage\\_metrics) | Enable network address usage metrics on infrastructure VPC | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_flow_logs_cloudwatch_logs\"></a> [infrastructure\\_vpc\\_flow\\_logs\\_cloudwatch\\_logs](#input\\_infrastructure\\_vpc\\_flow\\_logs\\_cloudwatch\\_logs) | Enable VPC logs on infrastructure VPC to CloudWatch Logs | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_flow_logs_retention\"></a> [infrastructure\\_vpc\\_flow\\_logs\\_retention](#input\\_infrastructure\\_vpc\\_flow\\_logs\\_retention) | VPC flow logs retention in days | `number` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_flow_logs_s3_key_prefix\"></a> [infrastructure\\_vpc\\_flow\\_logs\\_s3\\_key\\_prefix](#input\\_infrastructure\\_vpc\\_flow\\_logs\\_s3\\_key\\_prefix) | Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs | `string` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_flow_logs_s3_with_athena\"></a> [infrastructure\\_vpc\\_flow\\_logs\\_s3\\_with\\_athena](#input\\_infrastructure\\_vpc\\_flow\\_logs\\_s3\\_with\\_athena) | Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_flow_logs_traffic_type\"></a> [infrastructure\\_vpc\\_flow\\_logs\\_traffic\\_type](#input\\_infrastructure\\_vpc\\_flow\\_logs\\_traffic\\_type) | Infrastructure VPC flow logs traffic type | `string` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_instance_tenancy\"></a> [infrastructure\\_vpc\\_instance\\_tenancy](#input\\_infrastructure\\_vpc\\_instance\\_tenancy) | Infrastructure VPC instance tenancy | `string` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_egress_custom_rules_private\"></a> [infrastructure\\_vpc\\_network\\_acl\\_egress\\_custom\\_rules\\_private](#input\\_infrastructure\\_vpc\\_network\\_acl\\_egress\\_custom\\_rules\\_private) | Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules. | <pre>list(object({<br/> protocol = string<br/> from_port = number<br/> to_port = number<br/> action = string<br/> cidr_block = string<br/> ipv6_cidr_block = optional(string, null)<br/> icmp_type = optional(number, null)<br/> icmp_code = optional(number, null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_egress_custom_rules_public\"></a> [infrastructure\\_vpc\\_network\\_acl\\_egress\\_custom\\_rules\\_public](#input\\_infrastructure\\_vpc\\_network\\_acl\\_egress\\_custom\\_rules\\_public) | Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules. | <pre>list(object({<br/> protocol = string<br/> from_port = number<br/> to_port = number<br/> action = string<br/> cidr_block = string<br/> ipv6_cidr_block = optional(string, null)<br/> icmp_type = optional(number, null)<br/> icmp_code = optional(number, null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_egress_lockdown_private\"></a> [infrastructure\\_vpc\\_network\\_acl\\_egress\\_lockdown\\_private](#input\\_infrastructure\\_vpc\\_network\\_acl\\_egress\\_lockdown\\_private) | Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_egress_lockdown_public\"></a> [infrastructure\\_vpc\\_network\\_acl\\_egress\\_lockdown\\_public](#input\\_infrastructure\\_vpc\\_network\\_acl\\_egress\\_lockdown\\_public) | Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_ingress_custom_rules_private\"></a> [infrastructure\\_vpc\\_network\\_acl\\_ingress\\_custom\\_rules\\_private](#input\\_infrastructure\\_vpc\\_network\\_acl\\_ingress\\_custom\\_rules\\_private) | Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules. | <pre>list(object({<br/> protocol = string<br/> from_port = number<br/> to_port = number<br/> action = string<br/> cidr_block = string<br/> ipv6_cidr_block = optional(string, null)<br/> icmp_type = optional(number, null)<br/> icmp_code = optional(number, null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_ingress_custom_rules_public\"></a> [infrastructure\\_vpc\\_network\\_acl\\_ingress\\_custom\\_rules\\_public](#input\\_infrastructure\\_vpc\\_network\\_acl\\_ingress\\_custom\\_rules\\_public) | Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules. | <pre>list(object({<br/> protocol = string<br/> from_port = number<br/> to_port = number<br/> action = string<br/> cidr_block = string<br/> ipv6_cidr_block = optional(string, null)<br/> icmp_type = optional(number, null)<br/> icmp_code = optional(number, null)<br/> }))</pre> | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_ingress_lockdown_private\"></a> [infrastructure\\_vpc\\_network\\_acl\\_ingress\\_lockdown\\_private](#input\\_infrastructure\\_vpc\\_network\\_acl\\_ingress\\_lockdown\\_private) | Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_acl_ingress_lockdown_public\"></a> [infrastructure\\_vpc\\_network\\_acl\\_ingress\\_lockdown\\_public](#input\\_infrastructure\\_vpc\\_network\\_acl\\_ingress\\_lockdown\\_public) | Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules. | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_availability_zones\"></a> [infrastructure\\_vpc\\_network\\_availability\\_zones](#input\\_infrastructure\\_vpc\\_network\\_availability\\_zones) | A list of availability zone characters (eg. [\"a\", \"b\", \"c\"]) | `list(string)` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_enable_private\"></a> [infrastructure\\_vpc\\_network\\_enable\\_private](#input\\_infrastructure\\_vpc\\_network\\_enable\\_private) | Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled) | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_network_enable_public\"></a> [infrastructure\\_vpc\\_network\\_enable\\_public](#input\\_infrastructure\\_vpc\\_network\\_enable\\_public) | Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway | `bool` | n/a | yes |\n| <a name=\"input_infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\"></a> [infrastructure\\_vpc\\_transfer\\_s3\\_bucket\\_access\\_vpc\\_ids](#input\\_infrastructure\\_vpc\\_transfer\\_s3\\_bucket\\_access\\_vpc\\_ids) | Additional VPC ids which are allowed to access the transfer S3 bucket | `list(string)` | n/a | yes |\n| <a name=\"input_project_name\"></a> [project\\_name](#input\\_project\\_name) | Project name to be used as a prefix for all resources | `string` | n/a | yes |\n| <a name=\"input_route53_root_hosted_zone_domain_name\"></a> [route53\\_root\\_hosted\\_zone\\_domain\\_name](#input\\_route53\\_root\\_hosted\\_zone\\_domain\\_name) | Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones. | `string` | n/a | yes |\n\n## Outputs\n\nNo outputs.\n<!-- END_TF_DOCS -->\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:35:20.754Z",
"resultDisplay": "Read all 631 lines from README.md (some lines were shortened)",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "c554cabd-3f1c-4ad1-aa14-b7c91ff3c770",
"timestamp": "2026-01-23T17:35:30.623Z",
"type": "gemini",
"content": "I will check if `terraform-docs` is installed and available. If it is, I will run it to update the documentation within the `README.md` file.",
"thoughts": [
{
"subject": "Verifying Documentation Source",
"description": "I'm currently investigating the origin of the documentation within the `README.md` file. The presence of those specific HTML comment tags strongly suggests `terraform-docs` is responsible. My immediate next step is to ascertain the availability of this tool to proceed with the generation process.",
"timestamp": "2026-01-23T17:35:27.037Z"
},
{
"subject": "Evaluating Terraform Docs Availability",
"description": "I've confirmed the likely use of `terraform-docs` based on the HTML comment tags in `README.md`. My next action involves checking for the tool's presence, as well as confirming its version. This should indicate whether I can proceed with an automated update or require a manual intervention.",
"timestamp": "2026-01-23T17:35:30.284Z"
}
],
"tokens": {
"input": 108572,
"output": 50,
"cached": 69261,
"thoughts": 134,
"tool": 0,
"total": 108756
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769189730621-5ba053664e1be8",
"name": "run_shell_command",
"args": {
"command": "terraform-docs --version"
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769189730621-5ba053664e1be8",
"name": "run_shell_command",
"response": {
"output": "Command: terraform-docs --version\nDirectory: (root)\nOutput: terraform-docs version v0.21.0 darwin/arm64\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 89701"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:37:31.994Z",
"resultDisplay": "terraform-docs version v0.21.0 darwin/arm64",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "29f0201f-fc67-49f8-b392-15a3e3cba173",
"timestamp": "2026-01-23T17:40:01.511Z",
"type": "gemini",
"content": "I will execute `terraform-docs` in the current directory to update the `README.md` file using the existing `.terraform-docs.yml` configuration.",
"thoughts": [],
"tokens": {
"input": 108695,
"output": 47,
"cached": 107594,
"thoughts": 49,
"tool": 0,
"total": 108791
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769190001499-7e745c0aeadc",
"name": "run_shell_command",
"args": {
"command": "terraform-docs ."
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769190001499-7e745c0aeadc",
"name": "run_shell_command",
"response": {
"output": "Command: terraform-docs .\nDirectory: (root)\nOutput: README.md updated successfully\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 90983"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:40:08.225Z",
"resultDisplay": "README.md updated successfully",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "fc6f5fbc-d409-4621-a787-e8896d745a4d",
"timestamp": "2026-01-23T17:40:16.091Z",
"type": "gemini",
"content": "I'll review `tfvars.example` to see where to add the new variables `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`, ensuring users are aware of these configuration options.",
"thoughts": [
{
"subject": "Considering Recent Updates",
"description": "I've just finished the `README.md` updates. Specifically, I've created fresh variables in `variables.tf`. Following that, I've tweaked `locals.tf` to incorporate these new variables. Finally, I've revised `ecs-cluster-infrastructure.tf` and `utilities-infrastructure` to utilize the new local variables and the new ECS cluster infrastructure.",
"timestamp": "2026-01-23T17:40:14.876Z"
},
{
"subject": "Adding Variable Examples",
"description": "I've reviewed the changes and updated the `README.md`. I then ran `terraform docs`, so the documentation should be solid. Next, I identified the `tfvars.example` file and realized it needs updating to reflect the new variables. I'm now reviewing `tfvars.example` to incorporate these changes and ensure it accurately reflects the latest configurations.",
"timestamp": "2026-01-23T17:40:15.766Z"
}
],
"tokens": {
"input": 108802,
"output": 66,
"cached": 107527,
"thoughts": 181,
"tool": 0,
"total": 109049
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "read_file-1769190016089-a489a48e1e745",
"name": "read_file",
"args": {
"file_path": "tfvars.example"
},
"result": [
{
"functionResponse": {
"id": "read_file-1769190016089-a489a48e1e745",
"name": "read_file",
"response": {
"output": "environment = \"dev\"\n"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:40:16.101Z",
"resultDisplay": "",
"displayName": "ReadFile",
"description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'offset' and 'limit' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "66cd77c4-e46a-4047-b849-135e07256fe6",
"timestamp": "2026-01-23T17:40:28.296Z",
"type": "gemini",
"content": "I will update `variables.tf` to add `default = \"enabled\"` to both `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` to ensure backward compatibility and avoid breaking changes.",
"thoughts": [
{
"subject": "Analyzing variable usage",
"description": "I've been examining the `tfvars.example` file, and noticed it's quite sparse, only containing the `environment = \" dev\"` variable. My initial thought was to search for more comprehensive examples. I've switched gears and am now cross-referencing this against the `README.md` to ensure I'm getting the complete picture.",
"timestamp": "2026-01-23T17:40:24.727Z"
},
{
"subject": "Evaluating Variable Defaults",
"description": "I've realized the `variables.tf` file lacks default values for my new variables, making them required. This contradicts the goal of maintaining existing behavior by default. I need to add `default = \"enabled\"` to each variable definition to avoid a breaking change and ensure the original functionality persists unless explicitly overridden. I'm double-checking the file to make sure I don't miss anything.",
"timestamp": "2026-01-23T17:40:27.685Z"
}
],
"tokens": {
"input": 108874,
"output": 291,
"cached": 0,
"thoughts": 291,
"tool": 0,
"total": 109456
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "replace-1769190028291-f86531c6a0064",
"name": "replace",
"args": {
"expected_replacements": 1,
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"new_string": "variable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n}",
"instruction": "Add `default = \"enabled\"` to `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`.",
"old_string": "variable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n}"
},
"result": [
{
"functionResponse": {
"id": "replace-1769190028291-f86531c6a0064",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:40:50.965Z",
"resultDisplay": {
"fileDiff": "Index: variables.tf\n===================================================================\n--- variables.tf\tCurrent\n+++ variables.tf\tProposed\n@@ -277,11 +277,13 @@\n variable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n+ default = \"enabled\"\n }\n \n variable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n+ default = \"enabled\"\n }\n \n variable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n",
"fileName": "variables.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"originalContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"newContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"diffStat": {
"model_added_lines": 2,
"model_removed_lines": 0,
"model_added_chars": 50,
"model_removed_chars": 0,
"user_added_lines": 0,
"user_removed_lines": 1031,
"user_added_chars": 0,
"user_removed_chars": 47139
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "018b1b2a-4334-4a22-893a-3abdaae6f723",
"timestamp": "2026-01-23T17:40:58.416Z",
"type": "gemini",
"content": "I will run `terraform-docs .` to update the documentation with the new default values.",
"thoughts": [
{
"subject": "Revising Documentation with Defaults",
"description": "I've just finished implementing the default values within the configuration. Now, I must regenerate the documentation to ensure it accurately reflects these new, predefined settings. I'll execute `terraform-docs .` to achieve this.",
"timestamp": "2026-01-23T17:40:58.107Z"
}
],
"tokens": {
"input": 109195,
"output": 33,
"cached": 107050,
"thoughts": 30,
"tool": 0,
"total": 109258
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769190058412-eaed5a688eed48",
"name": "run_shell_command",
"args": {
"command": "terraform-docs ."
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769190058412-eaed5a688eed48",
"name": "run_shell_command",
"response": {
"output": "Command: terraform-docs .\nDirectory: (root)\nOutput: README.md updated successfully\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 91156"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:41:09.051Z",
"resultDisplay": "README.md updated successfully",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "45cbe90c-7058-4641-89b1-3fbbb9aa9fcf",
"timestamp": "2026-01-23T17:41:18.434Z",
"type": "gemini",
"content": "I'll run `terraform validate` one last time to ensure everything is correct.",
"thoughts": [
{
"subject": "Reflecting on Completion",
"description": "I've successfully finished the task, it seems. I identified the requirement to parameterize container insights. I then added the necessary variables, `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`, to the `variables.tf` file, both defaulting to \"enabled\".",
"timestamp": "2026-01-23T17:41:16.578Z"
},
{
"subject": "Finalizing the Implementation",
"description": "\\n\\n\n\nI've just run `terraform validate` once more, confirming all configurations are sound. This validates the completion. I then updated the documentation to reflect the changes, ensuring clarity for future users. The process is now finalized, with everything in place.",
"timestamp": "2026-01-23T17:41:18.166Z"
}
],
"tokens": {
"input": 109288,
"output": 29,
"cached": 107001,
"thoughts": 148,
"tool": 0,
"total": 109465
},
"model": "gemini-3-pro-preview",
"toolCalls": [
{
"id": "run_shell_command-1769190078430-6b742fd548004",
"name": "run_shell_command",
"args": {
"command": "terraform validate"
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769190078430-6b742fd548004",
"name": "run_shell_command",
"response": {
"output": "Command: terraform validate\nDirectory: (root)\nOutput: Success! The configuration is valid.\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 91197"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:41:20.992Z",
"resultDisplay": "Success! The configuration is valid.",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "6ab29432-0686-4238-a92e-a758cbebc27c",
"timestamp": "2026-01-23T17:41:28.146Z",
"type": "gemini",
"content": "I have successfully made `containerInsights` a configurable setting for both the infrastructure and utilities ECS clusters.\n\nHere's a summary of the changes:\n1. **Modified `variables.tf`**: Added two new variables, `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`, both defaulting to `\"enabled\"`.\n2. **Modified `locals.tf`**: Mapped the new variables to local values `local.infrastructure_ecs_cluster_container_insights` and `local.infrastructure_utilities_ecs_cluster_container_insights`.\n3. **Modified `ecs-cluster-infrastructure.tf`**: Updated the `aws_ecs_cluster.infrastructure` resource to use `local.infrastructure_ecs_cluster_container_insights` for the `containerInsights` setting.\n4. **Modified `utilities-infrastructure-ecs-cluster.tf`**: Updated the `aws_ecs_cluster.infrastrucutre_utilities` resource to use `local.infrastructure_utilities_ecs_cluster_container_insights` for the `containerInsights` setting.\n5. **Documentation**: Updated `README.md` using `terraform-docs`.\n6. **Validation**: Verified the configuration using `terraform validate`.",
"thoughts": [
{
"subject": "Concluding the Process",
"description": "I've reached the end. The analysis is complete; there's nothing more to add to my existing understanding. I've successfully achieved the final state.",
"timestamp": "2026-01-23T17:41:27.910Z"
}
],
"tokens": {
"input": 109377,
"output": 274,
"cached": 106844,
"thoughts": 4,
"tool": 0,
"total": 109655
},
"model": "gemini-3-pro-preview"
},
{
"id": "9a09f919-d32f-4240-ab1a-18aa0162059f",
"timestamp": "2026-01-23T17:43:19.332Z",
"type": "user",
"content": "add validation that the variabel is one of the 3 allowed. disabled, enabled and enhanced"
},
{
"id": "1c72e375-f520-4eef-afed-ce6c8d1ed108",
"timestamp": "2026-01-23T17:43:57.740Z",
"type": "gemini",
"content": "I will add validation blocks to the `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables in `variables.tf` to restrict their values to \"disabled\", \"enabled\", or \"enhanced\".",
"thoughts": [
{
"subject": "Validating Input Variables",
"description": "I'm focused on implementing input validation for the new variables in `variables.tf`. My plan is to restrict their values to \"disabled\", \"enabled\", or \"enhanced.\" I'm currently figuring out the best way to integrate these constraints into the Terraform configuration, likely using a `validation` block to ensure data integrity.",
"timestamp": "2026-01-23T17:43:52.403Z"
},
{
"subject": "Defining Variable Constraints",
"description": "I've reviewed the existing variable definitions in `variables.tf` and will add the `validation` blocks to the new variables. I'm building the validation conditions to accept only \"disabled\", \"enabled\", and \"enhanced\" values for `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights`. This aims to prevent invalid inputs.",
"timestamp": "2026-01-23T17:43:53.499Z"
},
{
"subject": "Implementing Input Validation",
"description": "I'm now writing the `validation` blocks for the two variables, using `contains` to limit input to \"disabled\", \"enabled\", and \"enhanced\". I'm structuring these similarly to other validation blocks in the `variables.tf` file, which should ensure consistency. I'll soon validate the changes with `terraform validate` and run `terraform-docs .` afterwards.",
"timestamp": "2026-01-23T17:43:57.426Z"
}
],
"tokens": {
"input": 131443,
"output": 449,
"cached": 3952,
"thoughts": 601,
"tool": 0,
"total": 132493
},
"model": "gemini-3-flash-preview",
"toolCalls": [
{
"id": "replace-1769190237736-8f1fdd814ba52",
"name": "replace",
"args": {
"expected_replacements": 1,
"new_string": "variable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n validation {\n condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_ecs_cluster_container_insights)\n error_message = \"Valid values for infrastructure_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n validation {\n condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_utilities_ecs_cluster_container_insights)\n error_message = \"Valid values for infrastructure_utilities_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n}",
"file_path": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"instruction": "Add validation to `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` to allow only 'disabled', 'enabled', or 'enhanced'.",
"old_string": "variable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n}"
},
"result": [
{
"functionResponse": {
"id": "replace-1769190237736-8f1fdd814ba52",
"name": "replace",
"response": {
"output": "Successfully modified file: /Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf (1 replacements)."
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:44:30.187Z",
"resultDisplay": {
"fileDiff": "Index: variables.tf\n===================================================================\n--- variables.tf\tCurrent\n+++ variables.tf\tProposed\n@@ -278,13 +278,21 @@\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n+ validation {\n+ condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_ecs_cluster_container_insights)\n+ error_message = \"Valid values for infrastructure_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n+}\n \n variable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n+ validation {\n+ condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_utilities_ecs_cluster_container_insights)\n+ error_message = \"Valid values for infrastructure_utilities_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n+}\n \n variable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n",
"fileName": "variables.tf",
"filePath": "/Users/bob/git/dxw/terraform-dxw-dalmatian-infrastructure/variables.tf",
"originalContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"newContent": "variable \"project_name\" {\n description = \"Project name to be used as a prefix for all resources\"\n type = string\n}\n\nvariable \"infrastructure_name\" {\n description = \"The infrastructure name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"environment\" {\n description = \"The environment name to be used as part of the resource prefix\"\n type = string\n}\n\nvariable \"aws_region\" {\n description = \"AWS region in which to launch resources\"\n type = string\n}\n\nvariable \"infrastructure_datadog_api_key\" {\n description = \"Datadog API key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_app_key\" {\n description = \"Datadog App key\"\n type = string\n sensitive = true\n}\n\nvariable \"infrastructure_datadog_region\" {\n description = \"Datadog region\"\n type = string\n}\n\nvariable \"enable_infrastructure_ecs_cluster_datadog_agent\" {\n description = \"Conditionally launch Datadog agent containers on the ECS cluster\"\n type = bool\n}\n\nvariable \"infrastructure_dockerhub_email\" {\n description = \"Dockerhub email\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_username\" {\n description = \"Dockerhub username\"\n type = string\n}\n\nvariable \"infrastructure_dockerhub_token\" {\n description = \"Dockerhub token which has permissions to pull images\"\n type = string\n}\n\nvariable \"infrastructure_kms_encryption\" {\n description = \"Enable infrastructure KMS encryption. This will create a single KMS key to be used across all resources that support KMS encryption.\"\n type = bool\n}\n\nvariable \"infrastructure_kms_key_policy_statements\" {\n description = \"Additional KMS key policy statements for the Infrastructure KMS key\"\n type = string\n}\n\nvariable \"infrastructure_logging_bucket_retention\" {\n description = \"Retention in days for the infrasrtucture S3 logs. This is for the default S3 logs bucket, where all AWS service logs will be delivered\"\n type = number\n}\n\nvariable \"infrastructure_vpc\" {\n description = \"Enable infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_cidr_block\" {\n description = \"Infrastructure VPC CIDR block\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_dns_support\" {\n description = \"Enable DNS support on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_enable_dns_hostnames\" {\n description = \"Enable DNS hostnames on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_instance_tenancy\" {\n description = \"Infrastructure VPC instance tenancy\"\n type = string\n}\n\nvariable \"infrastructure_vpc_enable_network_address_usage_metrics\" {\n description = \"Enable network address usage metrics on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_assign_generated_ipv6_cidr_block\" {\n description = \"Assign generated IPv6 CIDR block on infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_cloudwatch_logs\" {\n description = \"Enable VPC logs on infrastructure VPC to CloudWatch Logs\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_with_athena\" {\n description = \"Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_flow_logs_retention\" {\n description = \"VPC flow logs retention in days\"\n type = number\n}\n\nvariable \"infrastructure_vpc_flow_logs_traffic_type\" {\n description = \"Infrastructure VPC flow logs traffic type\"\n type = string\n}\n\nvariable \"infrastructure_vpc_flow_logs_s3_key_prefix\" {\n description = \"Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs\"\n type = string\n}\n\nvariable \"infrastructure_vpc_network_enable_public\" {\n description = \"Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_enable_private\" {\n description = \"Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_availability_zones\" {\n description = \"A list of availability zone characters (eg. [\\\"a\\\", \\\"b\\\", \\\"c\\\"])\"\n type = list(string)\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_private\" {\n description = \"Infrastructure vpc egress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all egress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_egress_custom_rules_public\" {\n description = \"Infrastructure vpc egress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_private\" {\n description = \"Creates a network ACL for the private subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_private\" {\n description = \"Infrastructure vpc ingress custom rules for the private subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_lockdown_public\" {\n description = \"Creates a network ACL for the public subnets which blocks all ingress traffic, permitting only the ports required for resources deployed by this module and custom rules.\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_network_acl_ingress_custom_rules_public\" {\n description = \"Infrastructure vpc ingress custom rules for the public subnets. These will be evaluated before any automatically added rules.\"\n type = list(object({\n protocol = string\n from_port = number\n to_port = number\n action = string\n cidr_block = string\n ipv6_cidr_block = optional(string, null)\n icmp_type = optional(number, null)\n icmp_code = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_vpc_transfer_s3_bucket\" {\n description = \"Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC\"\n type = bool\n}\n\nvariable \"infrastructure_vpc_transfer_s3_bucket_access_vpc_ids\" {\n description = \"Additional VPC ids which are allowed to access the transfer S3 bucket\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_bastion_host\" {\n description = \"Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager\"\n type = bool\n}\n\nvariable \"infrastructure_bastion_host_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"route53_root_hosted_zone_domain_name\" {\n description = \"Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones.\"\n type = string\n}\n\nvariable \"aws_profile_name_route53_root\" {\n description = \"AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists.\"\n type = string\n}\n\nvariable \"enable_infrastructure_route53_hosted_zone\" {\n description = \"Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module.\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster\" {\n description = \"Enable creation of infrastructure ECS cluster, to place ECS services\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ami_version\" {\n description = \"AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-<version>)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Infrastructure ECS Cluster\"\n type = string\n default = \"enabled\"\n validation {\n condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_ecs_cluster_container_insights)\n error_message = \"Valid values for infrastructure_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n}\n\nvariable \"infrastructure_utilities_ecs_cluster_container_insights\" {\n description = \"Enable Container Insights for the Utilities ECS Cluster\"\n type = string\n default = \"enabled\"\n validation {\n condition = contains([\"disabled\", \"enabled\", \"enhanced\"], var.infrastructure_utilities_ecs_cluster_container_insights)\n error_message = \"Valid values for infrastructure_utilities_ecs_cluster_container_insights are 'disabled', 'enabled', and 'enhanced'.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_size\" {\n description = \"Size of EBS volume for Docker storage on the infrastructure ECS instances\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ebs_docker_storage_volume_type\" {\n description = \"Type of EBS volume for Docker storage on the infrastructure ECS instances (eg. gp3)\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_publicly_avaialble\" {\n description = \"Conditionally launch the ECS cluster EC2 instances into the Public subnet\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_custom_security_group_rules\" {\n description = \"Map of custom security group rules to add to the ECS Cluster security group (eg. { rule-name = {type = \\\"egress\\\", ... } })\"\n type = map(object({\n description = string\n type = string\n from_port = number\n to_port = number\n protocol = string\n source_security_group_id = optional(string, \"\")\n cidr_blocks = optional(list(string), [])\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_instance_type\" {\n description = \"The instance type for EC2 instances launched in the ECS cluster\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_termination_timeout\" {\n description = \"The timeout for the terminiation lifecycle hook\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_enabled\" {\n description = \"Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_draining_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster draining Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_min_size\" {\n description = \"Minimum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_size\" {\n description = \"Maximum number of instances for the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_max_instance_lifetime\" {\n description = \"Maximum lifetime in seconds of an instance within the ECS cluster\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_schedule_expression\" {\n description = \"Conditionally launch a lambda to trigger an instance refresh on the ECS ASG, provided a schedule expression\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_instance_refresh_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster instance refresh lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_max\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured max size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_min\" {\n description = \"List of cron expressions to scale the ECS cluster to the configured min size\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_autoscaling_time_based_custom\" {\n description = \"List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired.\"\n type = list(\n object({\n cron = string\n min = number\n max = number\n })\n )\n}\n\nvariable \"enable_infrastructure_ecs_cluster_asg_cpu_alert\" {\n description = \"Enable a CPU alert for the ECS cluster's Autoscaling Group\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_threshold\" {\n description = \"Threshold (CPU%) for the ECS cluster's Autoscaling Group CPU alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_asg_cpu_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Autoscaling Group CPU alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_pending_task_alert\" {\n description = \"Enable the ECS Cluster pending task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster pending task metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Pending Task alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_pending_task_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Pending Task alert\"\n type = bool\n}\n\nvariable \"enable_infrastructure_ecs_cluster_ecs_asg_diff_alert\" {\n description = \"Enable the ECS Cluster Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_metric_lambda_log_retention\" {\n description = \"Log retention for the ECS cluster Container Instance / ASG instance diff metric Lambda\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_evaluation_periods\" {\n description = \"Evaluation periods for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_period\" {\n description = \"Period (in secods) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_threshold\" {\n description = \"Threshold (Number of pending tasks) for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = number\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_slack\" {\n description = \"Enable Slack alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_ecs_asg_diff_alert_opsgenie\" {\n description = \"Enable Opsgenie alerts for the ECS cluster's Container Instance / ASG instance diff alert\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_debug_mode\" {\n description = \"Enable debug mode for ECS and Docker on the Infrastructure ECS. This should only be enabled when debugging (Can cause a lot of logs)\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_enable_execute_command_logging\" {\n description = \"Enable ECS Exec logging for services within the cluster. This will log to the infrastructure logs S3 bucket\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_endpoint\" {\n description = \"ECS Infrastructure Syslog endpoint. If specified, rsyslog will be installed on the ECS container instances and configured to send logs to this endpoint. Logspout containers will also be launched to gather and send Docker logs (Application logs from the running ECS services). The port must be included in the URI, eg. 'syslog+tls://example.com:1234'\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_syslog_permitted_peer\" {\n description = \"Specify the certificate common name (CN) of the remote to ensure syslog communication is restricted to permitted endpoints (eg. '*.example.com')\"\n type = string\n}\n\nvariable \"infrastructure_ecs_cluster_logspout_command\" {\n description = \"If provided, a logspout container will be launched on each container instance with the given command. If specified, container logs will no longer automatically be sent to CloudWatch, or to the given `infrastructure_ecs_cluster_syslog_endpoint`\"\n type = list(string)\n}\n\nvariable \"infrastructure_ecs_cluster_wafs\" {\n description = \"Map of WAF ACLs to create, which can be used with service CloudFront distributions\"\n type = map(object({\n ipv4_deny_list = optional(list(string), null)\n ipv4_allow_list = optional(list(string), null)\n ipv6_deny_list = optional(list(string), null)\n ipv6_allow_list = optional(list(string), null)\n aws_managed_rules = optional(list(object({\n name = string\n action = string\n exclude_rules = optional(list(string), null)\n excluded_path_patterns = optional(list(string), null)\n })), null)\n rate_limiting = optional(object({\n enabled = bool\n limit = optional(number, 1000)\n evaluation_window_sec = optional(number, 300)\n }), null)\n }))\n validation {\n condition = alltrue([\n for waf in var.infrastructure_ecs_cluster_wafs :\n waf.rate_limiting != null && waf.rate_limiting.enabled && waf.rate_limiting.evaluation_window_sec != null ?\n contains([60, 120, 300, 600], waf.rate_limiting.evaluation_window_sec) :\n true\n ])\n error_message = \"Valid values for evaluation_window_sec are 60, 120, 300, and 600.\"\n }\n}\n\nvariable \"infrastructure_ecs_cluster_service_defaults\" {\n description = \"Default values for ECS Cluster Services\"\n type = object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = optional(list(string), null)\n schedule_expression = string\n })), {})\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n })\n}\n\nvariable \"infrastructure_ecs_cluster_services\" {\n description = <<EOT\n Map of ECS Cluster Services (The key will be the service name). Values in here will override `infrastructure_ecs_cluster_service_defaults` values if set.\"\n {\n service-name = {\n github_v1_source: Conditionally use GitHubV1 for the CodePipeline source (CodeStar will be used by default)\n github_v1_oauth_token: If `github_v1_source` is set to true, provide the GitHub OAuthToken here\n codestar_connection_arn: The CodeStar Connection ARN to use in the CodePipeline source\n github_owner: The GitHub Owner of the repository to be pulled by the CodePipeline source\n github_repo: The GitHub repo name to be pulled by the CodePipeline source\n github_track_revision: The branch/revision of the GitHub repository to be pulled by the CodePipeline source\n buildspec: The filename of the buildspec to use for the CodePipeline build phase, stored within the 'codepipeline buildspec store' S3 bucket\n buildspec_from_github_repo: Conditionally use the 'buildspec' filename stored within the GitHub repo as the buildspec\n codebuild_environment_variables: List of codebuild environment variable objects (eg. [{ name = \"MY_VAR\", value = \"foo\" },{ name = \"MY_OTHER_VAR\", value = \"bar\"}])\n ecr_scan_target_sns_topic_arn: An SNS topic ARN to publish ECR scan results to\n deployment_type: The service deployment type - Can be one of 'rolling' or 'blue-green'\n enable_cloudwatch_logs: Conditionally enable cloudwatch logs for the service\n cloudwatch_logs_retention: CloudWatch log retention in days\n enable_execute_command: Enable Amazon ECS Exec to directly interact with containers\n deregistration_delay: Amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused\n custom_policies: Map of custom policies to attach to the service task role (eg. { policy-name = { description = \\\"my custom policy\\\", policy = { Version = \\\"2012-10-17\\\", Statement = [] } } })\n container_entrypoint: The container entrypoint\n container_port: The service container port\n container_volumes: List of maps containing volume mappings eg. [ { \"name\" = \"my-volume\", \"host_path\" = \"/mnt/efs/my-dir\", \"container_path\" = \"/mnt/my-dir\" } ]\n container_extra_hosts: List of maps containing extra hosts eg. [ { \"hostname\" = \"my.host\", \"ip_address\" = \"10.1.2.3\" } ]\n container_count: Number of containers to launch for the service\n container_heath_check_path: Destination for the health check request\n container_heath_grace_period: Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown\n scheduled_tasks: A map of scheduled tasks that use the same image as the service defined eg. { \"name\" => { \"entrypoint\" = [\"bundle\", \"exec\", \"run_jobs\"], \"schedule_expression\" = \"cron(* * * * ? *)\" } }\n domain_names: Domain names to assign to CloudFront aliases, and the Application Load Balancer's `host_header` condition\n enable_cloudfront: Enable cloadfront for the service\n cloudfront_tls_certificate_arn: Certificate ARN to attach to CloudFront - must contain the names provided in `domain_names`\n cloudfront_access_logging_enabled: Enable access logging for the distribution to the infrastructure S3 logs bucket\n cloudfront_bypass_protection_enabled: This adds a secret header at the CloudFront level, which is then checked by the ALB listener rules. Requests are only forwarded if the header matches, preventing requests going directly to the ALB.\n cloudfront_bypass_protection_excluded_domains: A list of domains to exclude from the bypass protection\n cloudfront_origin_shield_enabled: Enable CloudFront Origin Shield\n cloudfront_managed_cache_policy: Conditionally specify a CloudFront Managed Cache Policy for the distribution\n cloudfront_managed_origin_request_policy: Conditionally specify a CloudFront Managed Origin Request Policy for the distribution\n cloudfront_managed_response_headers_policy: Conditionally specify a CloudFront Managed Response Headers Policy for the distribution\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n alb_tls_certificate_arn: Certificate ARN to attach to the Application Load Balancer - must contain the names provided in `domain_names`\n }\n }\n EOT\n type = map(object({\n github_v1_source = optional(bool, null)\n github_v1_oauth_token = optional(string, null)\n codestar_connection_arn = optional(string, null)\n github_owner = optional(string, null)\n github_repo = optional(string, null)\n github_track_revision = optional(string, null)\n buildspec = optional(string, null)\n buildspec_from_github_repo = optional(bool, null)\n codebuild_environment_variables = optional(list(object({\n name = string\n value = string\n })), [])\n ecr_scan_target_sns_topic_arn = optional(string, null)\n deployment_type = optional(string, null)\n enable_cloudwatch_logs = optional(bool, null)\n cloudwatch_logs_retention = optional(number, null)\n enable_execute_command = optional(bool, null)\n deregistration_delay = optional(number, null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n container_entrypoint = optional(list(string), null)\n container_port = optional(number, null)\n container_volumes = optional(list(map(string)), null)\n container_extra_hosts = optional(list(map(string)), null)\n container_count = optional(number, null)\n container_heath_check_path = optional(string, null)\n container_heath_grace_period = optional(number, null)\n scheduled_tasks = optional(map(object({\n entrypoint = list(string)\n schedule_expression = string\n })), null)\n domain_names = optional(list(string), null)\n enable_cloudfront = optional(bool, null)\n cloudfront_tls_certificate_arn = optional(string, null)\n cloudfront_access_logging_enabled = optional(bool, null)\n cloudfront_bypass_protection_enabled = optional(bool, null)\n cloudfront_bypass_protection_excluded_domains = optional(list(string), null)\n cloudfront_origin_shield_enabled = optional(bool, null)\n cloudfront_managed_cache_policy = optional(string, null)\n cloudfront_managed_origin_request_policy = optional(string, null)\n cloudfront_managed_response_headers_policy = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n alb_tls_certificate_arn = optional(string, null)\n }))\n}\n\nvariable \"infrastructure_rds_defaults\" {\n description = \"Default values for RDSs\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n })\n}\n\nvariable \"infrastructure_rds\" {\n description = <<EOT\n Map of RDSs (The key will be the rds name). Values in here will override `infrastructure_rds_defaults` values if set.\"\n {\n rds-name = {\n type: Choose either `instance` for RDS instance, or `cluster` for RDS Aurora\n engine: RDS engine (Either `mysql` or `postgres`)\n engine_version: RDS Engine version (Specify the major version only, to prevent terraform attempting to downgrade minor versions)\n parameters: Map of Parameters for the DB parameter group ({ parameter-name = parameter-value, ... })\n instance_class: RDS instance class\n allocated_storage: RDS allocated storage\n storage_type: RDS storage type\n dedicated_kms_key: If enabled, will create and use a dedicated KMS key, rather than the infrastructure KMS key\n dedicated_kms_key_policy_statements: Additional KMS key policies to add to the dedicated KMS key policy\n iops: RDS iops (When `type` is `instance`, this is only required for storage type of `io1` or `gp3` - When `cluster`, this must be a multiple between .5 and 50 of the storage amount for the DB cluster.`)\n storage_throughput: RDS storage throughput (Only required when `storage_type` is `gp3`. Only applicable for `type` of `instance`)\n multi_az: Enable Multi-AZ RDS (Not applicable for `type` of `cluster`. For `cluster - set `storage_type`, `allocated_storage`, `iops` and `instance_class`)\n monitoring_interval: The interval, in seconds, between points when Enhanced Monitoring metrics are collected for the DB instance. Valid Values: 0, 1, 5, 10, 15, 30, 60.\n cloudwatch_logs_export_types: List of log types to enable for exporting to CloudWatch Logs. See `EnableCloudwatchLogsExports.member.N` (https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html) for valid values.\n cluster_instance_count: Number of instances to launch within the Aurora DB cluster\n cluster_serverlessv2_min_capacity: Minimum capacity for an Aurora DB cluster\n cluster_serverlessv2_max_capacity: Maximum capacity for an Aurora DB cluster\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n instance_class = optional(string, null)\n allocated_storage = optional(number, null)\n storage_type = optional(string, null)\n dedicated_kms_key = optional(bool, null)\n dedicated_kms_key_policy_statements = optional(string, null)\n iops = optional(number, null)\n storage_throughput = optional(number, null)\n multi_az = optional(bool, null)\n monitoring_interval = optional(number, null)\n cloudwatch_logs_export_types = optional(list(string), null)\n cluster_instance_count = optional(number, null)\n cluster_serverlessv2_min_capacity = optional(number, null)\n cluster_serverlessv2_max_capacity = optional(number, null)\n }))\n}\n\nvariable \"enable_infrastructure_rds_backup_to_s3\" {\n description = \"Enable Infrastructure RDS backups to S3. This will create a scheduled Fargate task to take SQL dumps and upload them to S3\"\n type = bool\n}\n\nvariable \"infrastructure_rds_backup_to_s3_cron_expression\" {\n description = \"Cron expression for when to trigger the SQL backups to S3\"\n type = string\n}\n\nvariable \"infrastructure_rds_backup_to_s3_retention\" {\n description = \"Retention in days to keep the S3 SQL backups\"\n type = number\n}\n\nvariable \"infrastructure_elasticache_defaults\" {\n description = \"Default values for ElastiCaches\"\n type = object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(number, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n })\n}\n\nvariable \"infrastructure_elasticache\" {\n description = <<EOT\n Map of Elasticaches (The key will be the elasticache name). Values in here will override `infrastructure_elasticache_defaults` values if set.\"\n {\n elasticache-name = {\n type: Choose either `cluster` or `serverless`\n engine: ElastiCache engine (Only `redis` is currently supported)\n engine_version: ElastiCache Engine version (For serverless, Specify the major version only)\n parameters: Map of Parameters for the ElastiCache parameter group ({ parameter-name = parameter-value, ... })\n cluster_node_type: ElastiCache Cluster node type\n cluster_node_count: ElastiCache Cluster node count\n serverless_max_storage: Serverless maximum storage\n serverless_max_ecpu: Serverless maximum number of ECPUs the cache can consume per second (1000 - 15000000)\n snapshot_retention_limit: Snapshot retention limit\n }\n }\n EOT\n type = map(object({\n type = optional(string, null)\n engine = optional(string, null)\n engine_version = optional(string, null)\n parameters = optional(map(string), null)\n cluster_node_type = optional(string, null)\n cluster_node_count = optional(number, null)\n serverless_max_storage = optional(string, null)\n serverless_max_ecpu = optional(number, null)\n snapshot_retention_limit = optional(number, null)\n }))\n}\n\nvariable \"custom_route53_hosted_zones\" {\n description = <<EOT\n Map of Route53 Hosted Zone configurations to create\n {\n example.com = {\n ns_records: Map of NS records to create ({ \"domain.example.com\" = { values = [\"ns1.example.com\", \"ns2.example.com\"], ttl = 300 })\n a_records: Map of A records to create ({ \"domain.example.com\" = { values = [\"1.2.3.4\", \"5.6.7.8\"], ttl = 300 })\n alias_records: Map of ALIAS records to create ({ \"domain.example.com\" = { value = \"example.cloudfront.com\", zone_id = \"Z2FDTNDATAQYW2\" })\n cname_records: Map of CNAME records to create ({ \"domain.example.com\" = { values = [\"external1.example.com\", \"external2.example.com\"], ttl = 60 })\n mx_records: Map of MX records to create ({ \"example.com\" = { values = [\"1 mail.example.com\", \"5 mail2.example.com\"], ttl = 60 })\n txt_records: Map of TXT records to create ({ \"example.com\" = { values = [\"v=spf1 include:spf.example.com -all\"], ttl = 60 })\n }\n }\n EOT\n type = map(object({\n ns_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n a_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n alias_records = optional(map(object({\n value = string\n zone_id = string\n })), null)\n cname_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n mx_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n txt_records = optional(map(object({\n values = list(string)\n ttl = optional(number, 300)\n })), null)\n }))\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_enable_global_accelerator\" {\n description = \"Enable Global Accelerator (GA) for the infrastructure ECS cluster services ALB. If `cloudfront_bypass_protection_enabled` is set for a service, any domain pointing towards the GA must be added to the `cloudfront_bypass_protection_excluded_domains` list. It is recommended that the GA only be used for apex domains that redirect to the domain associated with CloudFront. Ideally, apex domains would use an ALIAS record pointing towards the CloudFront distribution.\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_ip_allow_list\" {\n description = \"IP allow list for ingress traffic to the infrastructure ECS cluster services ALB\"\n type = list(string)\n}\n\nvariable \"enable_infrastructure_ecs_cluster_services_alb_logs\" {\n description = \"Enable Infrastructure ECS cluster services ALB logs\"\n type = bool\n}\n\nvariable \"infrastructure_ecs_cluster_services_alb_logs_retention\" {\n description = \"Retention in days for the infrasrtucture ecs cluster ALB logs\"\n type = number\n}\n\nvariable \"enable_infrastructure_ecs_cluster_efs\" {\n description = \"Conditionally create and mount EFS to the ECS cluster instances\"\n type = bool\n}\n\nvariable \"ecs_cluster_efs_performance_mode\" {\n description = \"ECS cluser EFS performance mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_throughput_mode\" {\n description = \"ECS cluser EFS throughput mode\"\n type = string\n}\n\nvariable \"ecs_cluster_efs_infrequent_access_transition\" {\n description = \"ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition.\"\n type = number\n}\n\nvariable \"ecs_cluster_efs_directories\" {\n description = \"ECS cluster EFS directories to create\"\n type = list(string)\n}\n\nvariable \"custom_s3_buckets\" {\n description = <<EOT\n Map of S3 buckets to create, and conditionally serve via CloudFront. The S3 configuration will follow AWS best practices (eg. Private, ACLS disabled, SSE, Versioning, Logging). The bucket must be emptied before attempting deletion/destruction.\"\n {\n bucket-name = {\n create_dedicated_kms_key: Conditionally create a KMS key specifically for this bucket's server side encryption (rather than using the Infrastructure's KMS key). It's recommended to use this if the S3 bucket will be accessed from external AWS accounts.\n custom_kms_key_policy_statements: Conditionally add a string of comma delimited user-defined bucket policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}')\n use_aes256_encryption: Conditionally enforce using AES256 encryption, rather than the infrastructure KMS key. Also overrides `create_dedicated_kms_key`\n transition_to_ia_days: Conditionally transition objects to 'Standard Infrequent Access' storage in N days\n transition_to_glacier_days: Conditionally transition objects to 'Glacier' storage in N days\n cloudfront_dedicated_distribution: Conditionally create a CloudFront distribution to serve objects from the S3 bucket.\n cloudfront_decicated_distribution_aliases: Specify custom aliases, rather than using a generated infrastriucture subdomain\n cloudfront_decicated_distribution_tls_certificate_arn: Specify a CloudFront TLS certificate to use rather than the infrastructure wildcard certificate\n cloudfront_s3_root: Sets the S3 document root when being served from CloudFront. By default this will be '/'. If `cloudfront_infrastructure_ecs_cluster_service_path` has been set, this helps by modifying the request from `/sub-directory-path` to `/` by use of a CloudFront function.\n cloudfront_basic_auth_user_list: Map of username and password's to use as basic auth ({ alex: somepassword, joe: otherpassword })\n cloudfront_infrastructure_ecs_cluster_service: Conditionally create an Origin on a CloudFront distribution that is serving the given Infrastructure ECS Cluster Service name\n cloudfront_infrastructure_ecs_cluster_service_path: If `cloudfront_infrastructure_ecs_cluster_service`, set this to the path that objects will be served from.\n cloudfront_waf_association: Conditionally associate WAF created via `infrastructure_ecs_cluster_wafs` using the key of the waf configuration\n custom_bucket_policy_statements: Conditionally add a string of comma delimited user-defined key policy statements (eg. '{\"Effect\": ...},{\"Effect\": ...}'\n }\n }\n EOT\n type = map(object({\n create_dedicated_kms_key = optional(bool, null)\n custom_kms_key_policy_statements = optional(string, null)\n use_aes256_encryption = optional(bool, null)\n transition_to_ia_days = optional(number, null)\n transition_to_glacier_days = optional(number, null)\n cloudfront_dedicated_distribution = optional(bool, null)\n cloudfront_decicated_distribution_aliases = optional(list(string), null)\n cloudfront_decicated_distribution_tls_certificate_arn = optional(string, null)\n cloudfront_s3_root = optional(string, null)\n cloudfront_s3_root_file = optional(string, null)\n cloudfront_basic_auth_user_list = optional(map(string), null)\n cloudfront_infrastructure_ecs_cluster_service = optional(string, null)\n cloudfront_infrastructure_ecs_cluster_service_path = optional(string, null)\n cloudfront_waf_association = optional(string, null)\n custom_bucket_policy_statements = optional(string, null)\n }))\n}\n\nvariable \"enable_cloudformatian_s3_template_store\" {\n description = \"Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created.\"\n type = bool\n}\n\nvariable \"custom_cloudformation_stacks\" {\n description = <<EOT\n Map of CloudFormation stacks to deploy\n {\n stack-name = {\n s3_template_store_key: The filename of a CloudFormation template that is stored within the S3 bucket, created by the `enable_cloudformatian_s3_template_store`\n template_body: (Optional - use of s3_template_store_key is preferred) The CloudFormation template body\n parameters: The CloudFormation template parameters ({ parameter-name = parameter-value, ... })\n on_failure: What to do on failure, either 'DO_NOTHING', 'ROLLBACK' or 'DELETE'\n capabilities: A list of capabilities. Valid values: `CAPABILITY_NAMED_IAM`, `CAPABILITY_IAM`, `CAPABILITY_AUTO_EXPAND`\n }\n }\n EOT\n type = map(object({\n s3_template_store_key = optional(string, null)\n template_body = optional(string, null)\n parameters = optional(map(string), null)\n on_failure = optional(string, null)\n capabilities = optional(list(string), null)\n }))\n}\n\nvariable \"custom_resource_tags\" {\n description = <<EOT\n A hacky way to add custom tags to resources\n Uses a script to add tags to resources using their ARNs\n Because Terraform will remove the tags, we may need to add a delay to running the script,\n which can be specified using var.custom_resource_tags_delay\n [\n {\n arns: Comma deliminated list of ARNs to apply the tags to\n tags: Map of key/values for the tags\n }\n ]\n EOT\n type = list(object({\n arns = string,\n tags = map(string)\n }))\n}\n\nvariable \"custom_resource_tags_delay\" {\n description = \"The delay in seconds to wait before running the tag script\"\n type = number\n}\n\nvariable \"custom_lambda_functions\" {\n description = <<EOT\n Map of Lambda functions to deploy\n {\n function-name = {\n function_zip_s3_key: The key of a Zipped Lambda function that is stored within the S3 bucket, created by the `enable_lambda_functions_s3_store`. If a file with the same name, with the `.json` extension is found, this will be used as a policy for the function (eg. `my-function.zip` will use the `my-function.json` as a policy).\n handler: The function entrypoint in the code\n runtime: The function runtime\n memory: Amount of memory in MB your Lambda Function can use at runtime.\n timeout: Amount of time your Lambda Function has to run in seconds\n environment_variables: Map of environment variables that are accessible from the function code during execution.\n custom_policies: Map of custom policies to attach to the Lambda role\n log_retention: Days to retain logs\n launch_in_infrastructure_vpc: Conditionally launch within the infrastructure VPC. This will give access to resources launched within the VPC.\n }\n }\n EOT\n type = map(object({\n function_zip_s3_key = optional(string, null)\n handler = optional(string, null)\n runtime = optional(string, null)\n memory = optional(number, null)\n timeout = optional(number, null)\n environment_variables = optional(map(string), null)\n custom_policies = optional(map(object({\n description = string\n policy = object({\n Version = string\n Statement = list(object({\n Action = list(string)\n Effect = string\n Resource = list(string)\n }))\n })\n })), {})\n log_retention = optional(number, null)\n launch_in_infrastructure_vpc = optional(bool, null)\n }))\n}\n",
"diffStat": {
"model_added_lines": 8,
"model_removed_lines": 0,
"model_added_chars": 536,
"model_removed_chars": 0,
"user_added_lines": 0,
"user_removed_lines": 1031,
"user_added_chars": 0,
"user_removed_chars": 47139
},
"isNewFile": false
},
"displayName": "Edit",
"description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read_file tool to examine the file's current content before attempting a text replacement.\n \n The user has the ability to modify the `new_string` content. If modified, this will be stated in the response.\n \n Expectation for required parameters:\n 1. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n 2. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic and that `old_string` and `new_string` are different.\n 3. `instruction` is the detailed instruction of what needs to be changed. It is important to Make it specific and detailed so developers or large language models can understand what needs to be changed and perform the changes on their own if necessary. \n 4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n **Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n 5. Prefer to break down complex and long changes into multiple smaller atomic calls to this tool. Always check the content of the file after changes or not finding a string to match.\n **Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
"renderOutputAsMarkdown": true
}
]
},
{
"id": "8f47cd62-5846-47ea-884a-9937d9030cb5",
"timestamp": "2026-01-23T17:44:33.795Z",
"type": "gemini",
"content": "I'll run `terraform validate` to confirm the validation blocks are correct, then update the documentation with `terraform-docs .`.",
"thoughts": [],
"tokens": {
"input": 110148,
"output": 45,
"cached": 0,
"thoughts": 0,
"tool": 0,
"total": 110193
},
"model": "gemini-3-flash-preview",
"toolCalls": [
{
"id": "run_shell_command-1769190273791-113a3947020fc8",
"name": "run_shell_command",
"args": {
"command": "terraform validate && terraform-docs ."
},
"result": [
{
"functionResponse": {
"id": "run_shell_command-1769190273791-113a3947020fc8",
"name": "run_shell_command",
"response": {
"output": "Command: terraform validate && terraform-docs .\nDirectory: (root)\nOutput: Success! The configuration is valid.\n\nREADME.md updated successfully\nError: (none)\nExit Code: 0\nSignal: 0\nBackground PIDs: (none)\nProcess Group PGID: 91777"
}
}
}
],
"status": "success",
"timestamp": "2026-01-23T17:44:36.468Z",
"resultDisplay": "Success! The configuration is valid.\n\nREADME.md updated successfully",
"displayName": "Shell",
"description": "This tool executes a given shell command as `bash -c <command>`. Command can start background processes using `&`. Command is executed as a subprocess that leads its own process group. Command process group can be terminated as `kill -- -PGID` or signaled as `kill -s SIGNAL -- -PGID`.\n\n The following information is returned:\n\n Command: Executed command.\n Directory: Directory where command was executed, or `(root)`.\n Stdout: Output on stdout stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Stderr: Output on stderr stream. Can be `(empty)` or partial on error and for any unwaited background processes.\n Error: Error or `(none)` if no error was reported for the subprocess.\n Exit Code: Exit code or `(none)` if terminated by signal.\n Signal: Signal number or `(none)` if no signal was received.\n Background PIDs: List of background processes started or `(none)`.\n Process Group PGID: Process group started or `(none)`",
"renderOutputAsMarkdown": false
}
]
},
{
"id": "764c53a2-6d1f-48ef-aa26-411449593edd",
"timestamp": "2026-01-23T17:44:38.768Z",
"type": "gemini",
"content": "I have added validation to both `infrastructure_ecs_cluster_container_insights` and `infrastructure_utilities_ecs_cluster_container_insights` variables in `variables.tf`. They now only accept `\"disabled\"`, `\"enabled\"`, or `\"enhanced\"`. The `README.md` has also been updated to reflect these changes.",
"thoughts": [],
"tokens": {
"input": 110265,
"output": 71,
"cached": 109315,
"thoughts": 0,
"tool": 0,
"total": 110336
},
"model": "gemini-3-flash-preview"
}
]
}