diff --git a/.gitignore b/.gitignore index 4eae1e71..b2450588 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ terraform.rc node_modules/ tfplan *.zip +*tf.plan .idea/ .vscode/ diff --git a/infrastructure/README.md b/infrastructure/README.md index 59a730ce..b5c81dfb 100644 --- a/infrastructure/README.md +++ b/infrastructure/README.md @@ -8,7 +8,7 @@ | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.62.0 | +| [aws](#provider\_aws) | 5.66.0 | ## Modules @@ -84,9 +84,11 @@ | [ndr-app-config](#module\_ndr-app-config) | ./modules/app_config | n/a | | [ndr-bulk-staging-store](#module\_ndr-bulk-staging-store) | ./modules/s3/ | n/a | | [ndr-docker-ecr-ui](#module\_ndr-docker-ecr-ui) | ./modules/ecr/ | n/a | +| [ndr-docker-ecr-weekly-ods-update](#module\_ndr-docker-ecr-weekly-ods-update) | ./modules/ecr/ | n/a | | [ndr-document-store](#module\_ndr-document-store) | ./modules/s3/ | n/a | | [ndr-ecs-container-port-ssm-parameter](#module\_ndr-ecs-container-port-ssm-parameter) | ./modules/ssm_parameter | n/a | -| [ndr-ecs-fargate](#module\_ndr-ecs-fargate) | ./modules/ecs | n/a | +| [ndr-ecs-fargate-app](#module\_ndr-ecs-fargate-app) | ./modules/ecs | n/a | +| [ndr-ecs-fargate-ods-update](#module\_ndr-ecs-fargate-ods-update) | ./modules/ecs | n/a | | [ndr-feedback-mailbox](#module\_ndr-feedback-mailbox) | ./modules/ses | n/a | | [ndr-lloyd-george-store](#module\_ndr-lloyd-george-store) | ./modules/s3/ | n/a | | [ndr-vpc-ui](#module\_ndr-vpc-ui) | ./modules/vpc/ | n/a | @@ -188,6 +190,8 @@ | [aws_iam_role.ecs_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.manifest_presign_url_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.mesh_forwarder](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.ods_weekly_update_ecs_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.ods_weekly_update_task_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.s3_backup_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.sns_failure_feedback_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role.splunk_sqs_forwarder](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | @@ -218,6 +222,7 @@ | [aws_s3_bucket_lifecycle_configuration.lg-lifecycle-rules](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource | | [aws_s3_bucket_lifecycle_configuration.staging-store-lifecycle-rules](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource | | [aws_s3_bucket_policy.logs_bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | +| [aws_scheduler_schedule.ods_weekly_update_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/scheduler_schedule) | resource | | [aws_security_group.ndr_mesh_sg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | | [aws_sns_topic.alarm_notifications_topic](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource | | [aws_sns_topic_subscription.alarm_notifications_sns_topic_subscription](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource | diff --git a/infrastructure/api.tf b/infrastructure/api.tf index 196de111..c16dfeed 100644 --- a/infrastructure/api.tf +++ b/infrastructure/api.tf @@ -13,7 +13,7 @@ resource "aws_api_gateway_rest_api" "ndr_doc_store_api" { resource "aws_api_gateway_domain_name" "custom_api_domain" { domain_name = local.api_gateway_full_domain_name - regional_certificate_arn = module.ndr-ecs-fargate.certificate_arn + regional_certificate_arn = module.ndr-ecs-fargate-app.certificate_arn endpoint_configuration { types = ["REGIONAL"] diff --git a/infrastructure/ecr.tf b/infrastructure/ecr.tf index b1711c56..a3974202 100644 --- a/infrastructure/ecr.tf +++ b/infrastructure/ecr.tf @@ -5,3 +5,11 @@ module "ndr-docker-ecr-ui" { environment = var.environment owner = var.owner } +module "ndr-docker-ecr-weekly-ods-update" { + count = local.is_sandbox ? 0 : 1 + source = "./modules/ecr/" + app_name = "${terraform.workspace}-weekly-ods-update" + + environment = var.environment + owner = var.owner +} diff --git a/infrastructure/ecs.tf b/infrastructure/ecs.tf index 50f94149..662e5111 100644 --- a/infrastructure/ecs.tf +++ b/infrastructure/ecs.tf @@ -1,6 +1,9 @@ -module "ndr-ecs-fargate" { +module "ndr-ecs-fargate-app" { source = "./modules/ecs" ecs_cluster_name = "app-cluster" + is_lb_needed = true + is_autoscaling_needed = true + is_service_needed = true vpc_id = module.ndr-vpc-ui.vpc_id public_subnets = module.ndr-vpc-ui.public_subnets private_subnets = module.ndr-vpc-ui.private_subnets @@ -22,9 +25,71 @@ module "ndr-ecs-container-port-ssm-parameter" { source = "./modules/ssm_parameter" name = "container_port" description = "Docker container port number for ${var.environment}" - resource_depends_on = module.ndr-ecs-fargate - value = module.ndr-ecs-fargate.container_port + resource_depends_on = module.ndr-ecs-fargate-app + value = module.ndr-ecs-fargate-app.container_port type = "SecureString" owner = var.owner environment = var.environment +} + +module "ndr-ecs-fargate-ods-update" { + count = local.is_sandbox ? 0 : 1 + source = "./modules/ecs" + ecs_cluster_name = "ods-weekly-update" + vpc_id = module.ndr-vpc-ui.vpc_id + public_subnets = module.ndr-vpc-ui.public_subnets + private_subnets = module.ndr-vpc-ui.private_subnets + sg_name = "${terraform.workspace}-ods-weekly-update-sg" + ecs_launch_type = "FARGATE" + ecs_cluster_service_name = "${terraform.workspace}-ods-weekly-update" + ecr_repository_url = module.ndr-docker-ecr-weekly-ods-update[0].ecr_repository_url + environment = var.environment + owner = var.owner + container_port = 80 + is_autoscaling_needed = false + is_lb_needed = false + is_service_needed = false + alarm_actions_arn_list = [] + logs_bucket = aws_s3_bucket.logs_bucket.bucket + task_role = aws_iam_role.ods_weekly_update_task_role[0].arn + environment_vars = [ + { + "name" : "table_name", + "value" : module.lloyd_george_reference_dynamodb_table.table_name + }, + { + "name" : "PDS_FHIR_IS_STUBBED", + "value" : tostring(local.is_sandbox) + } + ] + ecs_container_definition_memory = 512 + ecs_container_definition_cpu = 256 + ecs_task_definition_memory = 512 + ecs_task_definition_cpu = 256 +} + +resource "aws_iam_role" "ods_weekly_update_task_role" { + count = local.is_sandbox ? 0 : 1 + name = "${terraform.workspace}_ods_weekly_update_task_role" + managed_policy_arns = [ + module.lloyd_george_reference_dynamodb_table.dynamodb_policy, + aws_iam_policy.ssm_access_policy.arn, + ] + assume_role_policy = jsonencode( + { + "Version" : "2012-10-17", + "Statement" : [ + { + "Sid" : "", + "Effect" : "Allow", + "Principal" : { + "Service" : [ + "ecs-tasks.amazonaws.com" + ] + }, + "Action" : "sts:AssumeRole" + } + ] + } + ) } \ No newline at end of file diff --git a/infrastructure/firewall.tf b/infrastructure/firewall.tf index be769f0e..21110a5a 100644 --- a/infrastructure/firewall.tf +++ b/infrastructure/firewall.tf @@ -10,7 +10,7 @@ module "firewall_waf_v2" { } resource "aws_wafv2_web_acl_association" "web_acl_association" { - resource_arn = module.ndr-ecs-fargate.load_balancer_arn + resource_arn = module.ndr-ecs-fargate-app.load_balancer_arn web_acl_arn = module.firewall_waf_v2[0].arn count = (terraform.workspace == "ndra" || @@ -18,7 +18,7 @@ resource "aws_wafv2_web_acl_association" "web_acl_association" { terraform.workspace == "ndrc" || terraform.workspace == "ndrd") ? 0 : 1 depends_on = [ - module.ndr-ecs-fargate, + module.ndr-ecs-fargate-app, module.firewall_waf_v2[0] ] } \ No newline at end of file diff --git a/infrastructure/modules/ecs/README.md b/infrastructure/modules/ecs/README.md index 582b0185..d0ecfecf 100644 --- a/infrastructure/modules/ecs/README.md +++ b/infrastructure/modules/ecs/README.md @@ -47,20 +47,32 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [alarm\_actions\_arn\_list](#input\_alarm\_actions\_arn\_list) | n/a | `list(string)` | n/a | yes | +| [autoscaling\_max\_capacity](#input\_autoscaling\_max\_capacity) | n/a | `number` | `6` | no | +| [autoscaling\_min\_capacity](#input\_autoscaling\_min\_capacity) | n/a | `number` | `3` | no | | [aws\_region](#input\_aws\_region) | n/a | `string` | `"eu-west-2"` | no | -| [certificate\_domain](#input\_certificate\_domain) | n/a | `string` | n/a | yes | +| [certificate\_domain](#input\_certificate\_domain) | n/a | `string` | `""` | no | | [container\_port](#input\_container\_port) | n/a | `number` | `8080` | no | -| [domain](#input\_domain) | n/a | `string` | n/a | yes | +| [desired\_count](#input\_desired\_count) | n/a | `number` | `3` | no | +| [domain](#input\_domain) | n/a | `string` | `""` | no | | [ecr\_repository\_url](#input\_ecr\_repository\_url) | n/a | `any` | n/a | yes | | [ecs\_cluster\_name](#input\_ecs\_cluster\_name) | n/a | `string` | n/a | yes | | [ecs\_cluster\_service\_name](#input\_ecs\_cluster\_service\_name) | n/a | `string` | n/a | yes | +| [ecs\_container\_definition\_cpu](#input\_ecs\_container\_definition\_cpu) | n/a | `number` | `512` | no | +| [ecs\_container\_definition\_memory](#input\_ecs\_container\_definition\_memory) | n/a | `number` | `1024` | no | | [ecs\_launch\_type](#input\_ecs\_launch\_type) | n/a | `string` | `"FARGATE"` | no | +| [ecs\_task\_definition\_cpu](#input\_ecs\_task\_definition\_cpu) | n/a | `number` | `1024` | no | +| [ecs\_task\_definition\_memory](#input\_ecs\_task\_definition\_memory) | n/a | `number` | `2048` | no | | [environment](#input\_environment) | n/a | `string` | n/a | yes | +| [environment\_vars](#input\_environment\_vars) | n/a | `list` |
[
null
]
| no | +| [is\_autoscaling\_needed](#input\_is\_autoscaling\_needed) | n/a | `bool` | `true` | no | +| [is\_lb\_needed](#input\_is\_lb\_needed) | n/a | `bool` | `false` | no | +| [is\_service\_needed](#input\_is\_service\_needed) | n/a | `bool` | `true` | no | | [logs\_bucket](#input\_logs\_bucket) | n/a | `any` | n/a | yes | | [owner](#input\_owner) | n/a | `string` | n/a | yes | | [private\_subnets](#input\_private\_subnets) | n/a | `any` | n/a | yes | | [public\_subnets](#input\_public\_subnets) | n/a | `any` | n/a | yes | | [sg\_name](#input\_sg\_name) | n/a | `string` | n/a | yes | +| [task\_role](#input\_task\_role) | n/a | `any` | `null` | no | | [vpc\_id](#input\_vpc\_id) | n/a | `string` | n/a | yes | ## Outputs @@ -70,5 +82,7 @@ No modules. | [certificate\_arn](#output\_certificate\_arn) | The arn of certificate that load balancer is using | | [container\_port](#output\_container\_port) | The container port number of docker image, which was provided as input variable of this module | | [dns\_name](#output\_dns\_name) | n/a | +| [ecs\_cluster\_arn](#output\_ecs\_cluster\_arn) | n/a | | [load\_balancer\_arn](#output\_load\_balancer\_arn) | The arn of the load balancer | | [security\_group\_id](#output\_security\_group\_id) | n/a | +| [task\_definition\_arn](#output\_task\_definition\_arn) | n/a | diff --git a/infrastructure/modules/ecs/alarms.tf b/infrastructure/modules/ecs/alarms.tf index 879d0df8..0976adac 100644 --- a/infrastructure/modules/ecs/alarms.tf +++ b/infrastructure/modules/ecs/alarms.tf @@ -1,5 +1,6 @@ resource "aws_cloudwatch_metric_alarm" "alb_alarm_4XX" { - alarm_name = "4XX-status-${aws_lb.ecs_lb.name}" + count = !local.is_sandbox && var.is_lb_needed ? 1 : 0 + alarm_name = "4XX-status-${aws_lb.ecs_lb[0].name}" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = "1" namespace = "AWS/ApplicationELB" @@ -9,22 +10,21 @@ resource "aws_cloudwatch_metric_alarm" "alb_alarm_4XX" { threshold = 20 treat_missing_data = "notBreaching" dimensions = { - LoadBalancer = aws_lb.ecs_lb.arn_suffix + LoadBalancer = aws_lb.ecs_lb[0].arn_suffix } - alarm_description = "This alarm indicates that at least 20 4XX statuses have occurred on ${aws_lb.ecs_lb.name} in a minute." + alarm_description = "This alarm indicates that at least 20 4XX statuses have occurred on ${aws_lb.ecs_lb[0].name} in a minute." alarm_actions = var.alarm_actions_arn_list tags = { - Name = "4XX-status-${aws_lb.ecs_lb.name}" + Name = "4XX-status-${aws_lb.ecs_lb[0].name}" Owner = var.owner Environment = var.environment Workspace = terraform.workspace } - count = local.is_sandbox ? 0 : 1 } resource "aws_cloudwatch_metric_alarm" "alb_alarm_5XX" { - alarm_name = "5XX-status-${aws_lb.ecs_lb.name}" + alarm_name = "5XX-status-${aws_lb.ecs_lb[0].name}" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = "1" namespace = "AWS/ApplicationELB" @@ -34,18 +34,18 @@ resource "aws_cloudwatch_metric_alarm" "alb_alarm_5XX" { threshold = 5 treat_missing_data = "notBreaching" dimensions = { - LoadBalancer = aws_lb.ecs_lb.arn_suffix + LoadBalancer = aws_lb.ecs_lb[0].arn_suffix } - alarm_description = "This alarm indicates that at least 5 5XX statuses have occurred on ${aws_lb.ecs_lb.name} within 5 minutes." + alarm_description = "This alarm indicates that at least 5 5XX statuses have occurred on ${aws_lb.ecs_lb[0].name} within 5 minutes." alarm_actions = var.alarm_actions_arn_list tags = { - Name = "5XX-status-${aws_lb.ecs_lb.name}" + Name = "5XX-status-${aws_lb.ecs_lb[0].name}" Owner = var.owner Environment = var.environment Workspace = terraform.workspace } - count = local.is_sandbox ? 0 : 1 + count = !local.is_sandbox && var.is_lb_needed ? 1 : 0 } resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_high_alarm" { @@ -60,7 +60,7 @@ resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_high_alarm" { dimensions = { ClusterName = aws_ecs_cluster.ndr_ecs_cluster.name - ServiceName = aws_ecs_service.ndr_ecs_service.name + ServiceName = aws_ecs_service.ndr_ecs_service[0].name } alarm_description = "The CPU usage for ${var.ecs_cluster_service_name} is currently above 85%, the autoscaling will begin scaling up." @@ -72,7 +72,7 @@ resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_high_alarm" { Environment = var.environment Workspace = terraform.workspace } - count = local.is_sandbox ? 0 : 1 + count = local.is_sandbox || !var.is_service_needed ? 0 : 1 } resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_low_alarm" { @@ -87,7 +87,7 @@ resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_low_alarm" { dimensions = { ClusterName = aws_ecs_cluster.ndr_ecs_cluster.name - ServiceName = aws_ecs_service.ndr_ecs_service.name + ServiceName = aws_ecs_service.ndr_ecs_service[0].name } alarm_description = "The CPU usage for ${var.ecs_cluster_service_name} is currently belowe 15%, the autoscaling will begin scaling down." @@ -99,5 +99,5 @@ resource "aws_cloudwatch_metric_alarm" "ndr_ecs_service_cpu_low_alarm" { Environment = var.environment Workspace = terraform.workspace } - count = local.is_sandbox ? 0 : 1 + count = local.is_sandbox || !var.is_service_needed ? 0 : 1 } \ No newline at end of file diff --git a/infrastructure/modules/ecs/lb.tf b/infrastructure/modules/ecs/lb.tf index 66b6ba13..c9a8786c 100644 --- a/infrastructure/modules/ecs/lb.tf +++ b/infrastructure/modules/ecs/lb.tf @@ -1,4 +1,5 @@ resource "aws_lb" "ecs_lb" { + count = var.is_lb_needed ? 1 : 0 name = "${terraform.workspace}-lb" internal = false load_balancer_type = "application" @@ -21,6 +22,8 @@ resource "aws_lb" "ecs_lb" { } resource "aws_lb_target_group" "ecs_lb_tg" { + count = var.is_lb_needed ? 1 : 0 + name = "${terraform.workspace}-ecs" port = 80 protocol = "HTTP" @@ -46,32 +49,37 @@ resource "aws_lb_target_group" "ecs_lb_tg" { } resource "aws_lb_listener" "https" { - load_balancer_arn = aws_lb.ecs_lb.arn + count = var.is_lb_needed ? 1 : 0 + load_balancer_arn = aws_lb.ecs_lb[0].arn port = "443" protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06" - certificate_arn = data.aws_acm_certificate.amazon_issued.arn + certificate_arn = data.aws_acm_certificate.amazon_issued[0].arn default_action { type = "forward" - target_group_arn = aws_lb_target_group.ecs_lb_tg.arn + target_group_arn = aws_lb_target_group.ecs_lb_tg[0].arn } } data "aws_acm_certificate" "amazon_issued" { + count = var.is_lb_needed ? 1 : 0 + domain = var.certificate_domain types = ["AMAZON_ISSUED"] most_recent = true } resource "aws_lb_listener" "http" { - load_balancer_arn = aws_lb.ecs_lb.arn + count = var.is_lb_needed ? 1 : 0 + + load_balancer_arn = aws_lb.ecs_lb[0].arn port = "80" protocol = "HTTP" default_action { type = "redirect" - target_group_arn = aws_lb_target_group.ecs_lb_tg.arn + target_group_arn = aws_lb_target_group.ecs_lb_tg[0].arn redirect { port = "443" protocol = "HTTPS" diff --git a/infrastructure/modules/ecs/main.tf b/infrastructure/modules/ecs/main.tf index bfa6d61f..04f25042 100644 --- a/infrastructure/modules/ecs/main.tf +++ b/infrastructure/modules/ecs/main.tf @@ -1,17 +1,18 @@ resource "aws_ecs_task_definition" "ndr_ecs_task" { - family = "${terraform.workspace}-ndr-service-task" + family = "${terraform.workspace}-task-${var.ecs_cluster_name}" execution_role_arn = aws_iam_role.task_exec.arn + task_role_arn = var.task_role network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] - cpu = 1024 - memory = 2048 + cpu = var.ecs_task_definition_cpu + memory = var.ecs_task_definition_memory container_definitions = jsonencode([ { - name = "${terraform.workspace}-app-container" + name = "${terraform.workspace}-container-${var.ecs_cluster_name}" image = var.ecr_repository_url - cpu = 512 - memory = 1024 + cpu = var.ecs_container_definition_cpu + memory = var.ecs_container_definition_memory essential = true networkMode = "awsvpc" portMappings = [ @@ -28,10 +29,11 @@ resource "aws_ecs_task_definition" "ndr_ecs_task" { "awslogs-stream-prefix" : terraform.workspace } } + environment = var.environment_vars } ]) } resource "aws_cloudwatch_log_group" "awslogs-ndr-ecs" { - name = "${terraform.workspace}-ecs-task" + name = "${terraform.workspace}-ecs-task-${var.ecs_cluster_name}" } diff --git a/infrastructure/modules/ecs/output.tf b/infrastructure/modules/ecs/output.tf index f0f12922..af28b428 100644 --- a/infrastructure/modules/ecs/output.tf +++ b/infrastructure/modules/ecs/output.tf @@ -1,5 +1,5 @@ output "dns_name" { - value = aws_lb.ecs_lb.dns_name + value = var.is_lb_needed ? aws_lb.ecs_lb[0].dns_name : null } output "security_group_id" { @@ -8,15 +8,23 @@ output "security_group_id" { output "load_balancer_arn" { description = "The arn of the load balancer" - value = aws_lb.ecs_lb.arn + value = var.is_lb_needed ? aws_lb.ecs_lb[0].arn : null } output "certificate_arn" { description = "The arn of certificate that load balancer is using" - value = data.aws_acm_certificate.amazon_issued.arn + value = var.is_lb_needed ? data.aws_acm_certificate.amazon_issued[0].arn : null } output "container_port" { description = "The container port number of docker image, which was provided as input variable of this module" value = var.container_port +} + +output "ecs_cluster_arn" { + value = aws_ecs_cluster.ndr_ecs_cluster.arn +} + +output "task_definition_arn" { + value = aws_ecs_task_definition.ndr_ecs_task.arn } \ No newline at end of file diff --git a/infrastructure/modules/ecs/service.tf b/infrastructure/modules/ecs/service.tf index 3d067925..67e97c11 100644 --- a/infrastructure/modules/ecs/service.tf +++ b/infrastructure/modules/ecs/service.tf @@ -1,8 +1,9 @@ resource "aws_ecs_service" "ndr_ecs_service" { + count = var.is_service_needed ? 1 : 0 name = var.ecs_cluster_service_name cluster = aws_ecs_cluster.ndr_ecs_cluster.id task_definition = aws_ecs_task_definition.ndr_ecs_task.arn - desired_count = 3 + desired_count = var.desired_count launch_type = var.ecs_launch_type network_configuration { @@ -11,13 +12,16 @@ resource "aws_ecs_service" "ndr_ecs_service" { subnets = [for subnet in var.private_subnets : subnet] } - load_balancer { - target_group_arn = aws_lb_target_group.ecs_lb_tg.arn - container_name = "${terraform.workspace}-app-container" - container_port = var.container_port + dynamic "load_balancer" { + for_each = var.is_lb_needed ? toset([1]) : toset([]) + content { + target_group_arn = aws_lb_target_group.ecs_lb_tg[0].arn + container_name = "${terraform.workspace}-container-${var.ecs_cluster_name}" + container_port = var.container_port + } } - depends_on = [aws_lb_target_group.ecs_lb_tg] + depends_on = [aws_lb_target_group.ecs_lb_tg[0]] tags = { Name = "${terraform.workspace}-ecs" @@ -27,13 +31,13 @@ resource "aws_ecs_service" "ndr_ecs_service" { } resource "aws_appautoscaling_target" "ndr_ecs_service_autoscale_target" { - max_capacity = 6 - min_capacity = 3 - resource_id = "service/${aws_ecs_cluster.ndr_ecs_cluster.name}/${aws_ecs_service.ndr_ecs_service.name}" + max_capacity = var.autoscaling_max_capacity + min_capacity = var.autoscaling_min_capacity + resource_id = "service/${aws_ecs_cluster.ndr_ecs_cluster.name}/${aws_ecs_service.ndr_ecs_service[0].name}" scalable_dimension = "ecs:service:DesiredCount" service_namespace = "ecs" - depends_on = [aws_ecs_cluster.ndr_ecs_cluster, aws_ecs_service.ndr_ecs_service] + depends_on = [aws_ecs_cluster.ndr_ecs_cluster, aws_ecs_service.ndr_ecs_service[0]] tags = { Name = "${terraform.workspace}-ecs-service-autoscale-target" @@ -41,14 +45,16 @@ resource "aws_appautoscaling_target" "ndr_ecs_service_autoscale_target" { Environment = var.environment Workspace = terraform.workspace } + count = !var.is_autoscaling_needed ? 0 : 1 + } resource "aws_appautoscaling_policy" "ndr_ecs_service_autoscale_up" { name = "${terraform.workspace}-${var.ecs_cluster_name}-${var.ecs_cluster_service_name}-autoscale-up-policy" policy_type = "StepScaling" - resource_id = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.resource_id - scalable_dimension = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.scalable_dimension - service_namespace = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.service_namespace + resource_id = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].resource_id + scalable_dimension = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].scalable_dimension + service_namespace = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].service_namespace step_scaling_policy_configuration { adjustment_type = "ChangeInCapacity" @@ -60,15 +66,15 @@ resource "aws_appautoscaling_policy" "ndr_ecs_service_autoscale_up" { scaling_adjustment = 1 } } - count = local.is_sandbox ? 0 : 1 + count = local.is_sandbox || !var.is_autoscaling_needed ? 0 : 1 } resource "aws_appautoscaling_policy" "ndr_ecs_service_autoscale_down" { name = "${terraform.workspace}-${var.ecs_cluster_name}-${var.ecs_cluster_service_name}-autoscale-down-policy" policy_type = "StepScaling" - resource_id = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.resource_id - scalable_dimension = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.scalable_dimension - service_namespace = aws_appautoscaling_target.ndr_ecs_service_autoscale_target.service_namespace + resource_id = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].resource_id + scalable_dimension = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].scalable_dimension + service_namespace = aws_appautoscaling_target.ndr_ecs_service_autoscale_target[0].service_namespace step_scaling_policy_configuration { adjustment_type = "ChangeInCapacity" @@ -80,5 +86,5 @@ resource "aws_appautoscaling_policy" "ndr_ecs_service_autoscale_down" { scaling_adjustment = -1 } } - count = local.is_sandbox ? 0 : 1 + count = local.is_sandbox || !var.is_autoscaling_needed ? 0 : 1 } diff --git a/infrastructure/modules/ecs/task_iam.tf b/infrastructure/modules/ecs/task_iam.tf index 3bee08e3..6af2d25a 100644 --- a/infrastructure/modules/ecs/task_iam.tf +++ b/infrastructure/modules/ecs/task_iam.tf @@ -1,5 +1,5 @@ resource "aws_iam_role" "task_exec" { - name = "${terraform.workspace}-ecs-task" + name = "${terraform.workspace}-${var.ecs_cluster_name}-ecs-task" assume_role_policy = jsonencode( { "Version" : "2012-10-17", @@ -25,7 +25,7 @@ resource "aws_iam_role_policy_attachment" "ecs_task_exec" { } resource "aws_iam_role_policy" "s3_access" { - name = "${terraform.workspace}-s3_access_policy" + name = "${terraform.workspace}-${var.ecs_cluster_name}-s3-access-policy" role = aws_iam_role.task_exec.name policy = jsonencode({ diff --git a/infrastructure/modules/ecs/variable.tf b/infrastructure/modules/ecs/variable.tf index 8a0644e7..1698cc47 100644 --- a/infrastructure/modules/ecs/variable.tf +++ b/infrastructure/modules/ecs/variable.tf @@ -42,11 +42,13 @@ variable "ecr_repository_url" { } variable "domain" { - type = string + type = string + default = "" } variable "certificate_domain" { - type = string + type = string + default = "" } variable "container_port" { @@ -61,7 +63,66 @@ variable "alarm_actions_arn_list" { variable "logs_bucket" { } +variable "desired_count" { + type = number + default = 3 +} + +variable "autoscaling_min_capacity" { + type = number + default = 3 +} + +variable "autoscaling_max_capacity" { + type = number + default = 6 +} + +variable "is_lb_needed" { + type = bool + default = false +} + +variable "is_service_needed" { + type = bool + default = true +} + +variable "is_autoscaling_needed" { + type = bool + default = true +} + +variable "environment_vars" { + default = [null] +} + +variable "ecs_task_definition_memory" { + default = 2048 + type = number +} + +variable "ecs_task_definition_cpu" { + default = 1024 + type = number +} + +variable "ecs_container_definition_memory" { + default = 1024 + type = number +} + +variable "ecs_container_definition_cpu" { + default = 512 + type = number +} + +variable "task_role" { + default = null +} + locals { is_sandbox = contains(["ndra", "ndrb", "ndrc", "ndrd"], terraform.workspace) is_production = contains(["prod", "pre-prod", "production"], terraform.workspace) -} \ No newline at end of file +} + diff --git a/infrastructure/route53.tf b/infrastructure/route53.tf index 9fcc9ac9..a2de5404 100644 --- a/infrastructure/route53.tf +++ b/infrastructure/route53.tf @@ -5,7 +5,7 @@ module "route53_fargate_ui" { domain = var.domain certificate_domain = var.certificate_domain using_arf_hosted_zone = true - dns_name = module.ndr-ecs-fargate.dns_name + dns_name = module.ndr-ecs-fargate-app.dns_name api_gateway_subdomain_name = local.api_gateway_subdomain_name api_gateway_full_domain_name = aws_api_gateway_domain_name.custom_api_domain.regional_domain_name diff --git a/infrastructure/schedules.tf b/infrastructure/schedules.tf index 2c847c60..9a585c92 100644 --- a/infrastructure/schedules.tf +++ b/infrastructure/schedules.tf @@ -111,4 +111,49 @@ resource "aws_lambda_permission" "statistical_report_schedule_permission" { module.statistical-report-lambda, aws_cloudwatch_event_rule.statistical_report_schedule ] +} + +resource "aws_scheduler_schedule" "ods_weekly_update_ecs" { + count = local.is_sandbox ? 0 : 1 + name_prefix = "${terraform.workspace}_ods_weekly_update_ecs" + description = "A weekly trigger for the ods update run" + + flexible_time_window { + mode = "OFF" + } + + schedule_expression = "cron(0 4 ? * SAT *)" + + target { + arn = module.ndr-ecs-fargate-ods-update[0].ecs_cluster_arn + role_arn = aws_iam_role.ods_weekly_update_ecs_execution[0].arn + ecs_parameters { + task_definition_arn = module.ndr-ecs-fargate-ods-update[0].task_definition_arn + task_count = 1 + launch_type = "FARGATE" + network_configuration { + assign_public_ip = false + security_groups = [module.ndr-ecs-fargate-ods-update[0].security_group_id] + subnets = [for subnet in module.ndr-vpc-ui.private_subnets : subnet] + } + } + } +} + +resource "aws_iam_role" "ods_weekly_update_ecs_execution" { + count = local.is_sandbox ? 0 : 1 + name = "${terraform.workspace}_ods_weekly_update_scheduler_role" + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "scheduler.amazonaws.com" + } + }, + ] + }) + managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole"] } \ No newline at end of file diff --git a/infrastructure/tf.plan b/infrastructure/tf.plan deleted file mode 100644 index 39a39275..00000000 Binary files a/infrastructure/tf.plan and /dev/null differ diff --git a/infrastructure/vpc.tf b/infrastructure/vpc.tf index 7250d80d..fd3e6dec 100644 --- a/infrastructure/vpc.tf +++ b/infrastructure/vpc.tf @@ -14,7 +14,7 @@ module "ndr-vpc-ui" { num_private_subnets = var.num_private_subnets endpoint_interface_services = ["ecr.api", "logs", "secretsmanager", "ecr.dkr", "ssm"] endpoint_gateway_services = ["s3", "dynamodb"] - security_group_id = module.ndr-ecs-fargate.security_group_id + security_group_id = module.ndr-ecs-fargate-app.security_group_id # Tags environment = var.environment diff --git a/virusscanner/terraform/README.md b/virusscanner/terraform/README.md index e5f16bb1..2cf59bb6 100644 --- a/virusscanner/terraform/README.md +++ b/virusscanner/terraform/README.md @@ -8,7 +8,7 @@ | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.46.0 | +| [aws](#provider\_aws) | 5.43.0 | ## Modules