Skip to content

Commit

Permalink
Add ECS Services to ignore desired_count (#116)
Browse files Browse the repository at this point in the history
* Add ECS services to ignore desired_count

Co-authored-by: David Rill <[email protected]>
Co-authored-by: cloudpossebot <[email protected]>
  • Loading branch information
3 people authored Jun 2, 2021
1 parent 381cf0b commit 91284c5
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 6 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

<!-- markdownlint-disable -->
# terraform-aws-ecs-alb-service-task [![Latest Release](https://img.shields.io/github/release/cloudposse/terraform-aws-ecs-alb-service-task.svg)](https://github.com/cloudposse/terraform-aws-ecs-alb-service-task/releases/latest) [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com)
<!-- markdownlint-restore -->
Expand Down Expand Up @@ -29,7 +30,6 @@

Terraform module to create an ECS Service for a web app (task), and an ALB target group to route requests.


---

This project is part of our comprehensive ["SweetOps"](https://cpco.io/sweetops) approach towards DevOps.
Expand Down Expand Up @@ -60,7 +60,6 @@ We literally have [*hundreds of terraform modules*][terraform_modules] that are




## Security & Compliance [<img src="https://cloudposse.com/wp-content/uploads/2020/11/bridgecrew.svg" width="250" align="right" />](https://bridgecrew.io/)

Security scanning is graciously provided by Bridgecrew. Bridgecrew is the leading fully hosted, cloud-native solution providing continuous Terraform security and compliance.
Expand Down Expand Up @@ -276,7 +275,9 @@ Available targets:
| Name | Type |
|------|------|
| [aws_ecs_service.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_desired_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_task_definition](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_task_definition_and_desired_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_task_definition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
| [aws_iam_role.ecs_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.ecs_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
Expand Down Expand Up @@ -326,6 +327,7 @@ Available targets:
| <a name="input_force_new_deployment"></a> [force\_new\_deployment](#input\_force\_new\_deployment) | Enable to force a new task deployment of the service. | `bool` | `false` | no |
| <a name="input_health_check_grace_period_seconds"></a> [health\_check\_grace\_period\_seconds](#input\_health\_check\_grace\_period\_seconds) | Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown, up to 7200. Only valid for services configured to use load balancers | `number` | `0` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for default, which is `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_ignore_changes_desired_count"></a> [ignore\_changes\_desired\_count](#input\_ignore\_changes\_desired\_count) | Whether to ignore changes for desired count in the ECS service | `bool` | `false` | no |
| <a name="input_ignore_changes_task_definition"></a> [ignore\_changes\_task\_definition](#input\_ignore\_changes\_task\_definition) | Whether to ignore changes in container definition and task definition in the ECS service | `bool` | `true` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The naming order of the id output and Name tag.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no |
Expand Down
3 changes: 3 additions & 0 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
| Name | Type |
|------|------|
| [aws_ecs_service.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_desired_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_task_definition](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_service.ignore_changes_task_definition_and_desired_count](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_task_definition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
| [aws_iam_role.ecs_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.ecs_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
Expand Down Expand Up @@ -78,6 +80,7 @@
| <a name="input_force_new_deployment"></a> [force\_new\_deployment](#input\_force\_new\_deployment) | Enable to force a new task deployment of the service. | `bool` | `false` | no |
| <a name="input_health_check_grace_period_seconds"></a> [health\_check\_grace\_period\_seconds](#input\_health\_check\_grace\_period\_seconds) | Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown, up to 7200. Only valid for services configured to use load balancers | `number` | `0` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for default, which is `0`.<br>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_ignore_changes_desired_count"></a> [ignore\_changes\_desired\_count](#input\_ignore\_changes\_desired\_count) | Whether to ignore changes for desired count in the ECS service | `bool` | `false` | no |
| <a name="input_ignore_changes_task_definition"></a> [ignore\_changes\_task\_definition](#input\_ignore\_changes\_task\_definition) | Whether to ignore changes in container definition and task definition in the ECS service | `bool` | `true` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The naming order of the id output and Name tag.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no |
Expand Down
174 changes: 172 additions & 2 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ resource "aws_security_group_rule" "nlb" {
}

resource "aws_ecs_service" "ignore_changes_task_definition" {
count = local.enabled && var.ignore_changes_task_definition ? 1 : 0
count = local.enabled && var.ignore_changes_task_definition && ! var.ignore_changes_desired_count ? 1 : 0
name = module.this.id
task_definition = coalesce(var.task_definition, "${join("", aws_ecs_task_definition.default.*.family)}:${join("", aws_ecs_task_definition.default.*.revision)}")
desired_count = var.desired_count
Expand Down Expand Up @@ -396,8 +396,178 @@ resource "aws_ecs_service" "ignore_changes_task_definition" {
}
}

resource "aws_ecs_service" "ignore_changes_task_definition_and_desired_count" {
count = local.enabled && var.ignore_changes_task_definition && var.ignore_changes_desired_count ? 1 : 0
name = module.this.id
task_definition = coalesce(var.task_definition, "${join("", aws_ecs_task_definition.default.*.family)}:${join("", aws_ecs_task_definition.default.*.revision)}")
desired_count = var.desired_count
deployment_maximum_percent = var.deployment_maximum_percent
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
health_check_grace_period_seconds = var.health_check_grace_period_seconds
launch_type = length(var.capacity_provider_strategies) > 0 ? null : var.launch_type
platform_version = var.launch_type == "FARGATE" ? var.platform_version : null
scheduling_strategy = var.launch_type == "FARGATE" ? "REPLICA" : var.scheduling_strategy
enable_ecs_managed_tags = var.enable_ecs_managed_tags
iam_role = local.enable_ecs_service_role ? coalesce(var.service_role_arn, join("", aws_iam_role.ecs_service.*.arn)) : null
wait_for_steady_state = var.wait_for_steady_state
force_new_deployment = var.force_new_deployment
enable_execute_command = var.exec_enabled

dynamic "capacity_provider_strategy" {
for_each = var.capacity_provider_strategies
content {
capacity_provider = capacity_provider_strategy.value.capacity_provider
weight = capacity_provider_strategy.value.weight
base = lookup(capacity_provider_strategy.value, "base", null)
}
}

dynamic "service_registries" {
for_each = var.service_registries
content {
registry_arn = service_registries.value.registry_arn
port = lookup(service_registries.value, "port", null)
container_name = lookup(service_registries.value, "container_name", null)
container_port = lookup(service_registries.value, "container_port", null)
}
}

dynamic "ordered_placement_strategy" {
for_each = var.ordered_placement_strategy
content {
type = ordered_placement_strategy.value.type
field = lookup(ordered_placement_strategy.value, "field", null)
}
}

dynamic "placement_constraints" {
for_each = var.service_placement_constraints
content {
type = placement_constraints.value.type
expression = lookup(placement_constraints.value, "expression", null)
}
}

dynamic "load_balancer" {
for_each = var.ecs_load_balancers
content {
container_name = load_balancer.value.container_name
container_port = load_balancer.value.container_port
elb_name = lookup(load_balancer.value, "elb_name", null)
target_group_arn = lookup(load_balancer.value, "target_group_arn", null)
}
}

cluster = var.ecs_cluster_arn
propagate_tags = var.propagate_tags
tags = var.use_old_arn ? null : module.this.tags

deployment_controller {
type = var.deployment_controller_type
}

# https://www.terraform.io/docs/providers/aws/r/ecs_service.html#network_configuration
dynamic "network_configuration" {
for_each = var.network_mode == "awsvpc" ? ["true"] : []
content {
security_groups = compact(concat(var.security_group_ids, aws_security_group.ecs_service.*.id))
subnets = var.subnet_ids
assign_public_ip = var.assign_public_ip
}
}

lifecycle {
ignore_changes = [task_definition, desired_count]
}
}

resource "aws_ecs_service" "ignore_changes_desired_count" {
count = local.enabled && ! var.ignore_changes_task_definition && var.ignore_changes_desired_count ? 1 : 0
name = module.this.id
task_definition = coalesce(var.task_definition, "${join("", aws_ecs_task_definition.default.*.family)}:${join("", aws_ecs_task_definition.default.*.revision)}")
desired_count = var.desired_count
deployment_maximum_percent = var.deployment_maximum_percent
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
health_check_grace_period_seconds = var.health_check_grace_period_seconds
launch_type = length(var.capacity_provider_strategies) > 0 ? null : var.launch_type
platform_version = var.launch_type == "FARGATE" ? var.platform_version : null
scheduling_strategy = var.launch_type == "FARGATE" ? "REPLICA" : var.scheduling_strategy
enable_ecs_managed_tags = var.enable_ecs_managed_tags
iam_role = local.enable_ecs_service_role ? coalesce(var.service_role_arn, join("", aws_iam_role.ecs_service.*.arn)) : null
wait_for_steady_state = var.wait_for_steady_state
force_new_deployment = var.force_new_deployment
enable_execute_command = var.exec_enabled

dynamic "capacity_provider_strategy" {
for_each = var.capacity_provider_strategies
content {
capacity_provider = capacity_provider_strategy.value.capacity_provider
weight = capacity_provider_strategy.value.weight
base = lookup(capacity_provider_strategy.value, "base", null)
}
}

dynamic "service_registries" {
for_each = var.service_registries
content {
registry_arn = service_registries.value.registry_arn
port = lookup(service_registries.value, "port", null)
container_name = lookup(service_registries.value, "container_name", null)
container_port = lookup(service_registries.value, "container_port", null)
}
}

dynamic "ordered_placement_strategy" {
for_each = var.ordered_placement_strategy
content {
type = ordered_placement_strategy.value.type
field = lookup(ordered_placement_strategy.value, "field", null)
}
}

dynamic "placement_constraints" {
for_each = var.service_placement_constraints
content {
type = placement_constraints.value.type
expression = lookup(placement_constraints.value, "expression", null)
}
}

dynamic "load_balancer" {
for_each = var.ecs_load_balancers
content {
container_name = load_balancer.value.container_name
container_port = load_balancer.value.container_port
elb_name = lookup(load_balancer.value, "elb_name", null)
target_group_arn = lookup(load_balancer.value, "target_group_arn", null)
}
}

cluster = var.ecs_cluster_arn
propagate_tags = var.propagate_tags
tags = var.use_old_arn ? null : module.this.tags

deployment_controller {
type = var.deployment_controller_type
}

# https://www.terraform.io/docs/providers/aws/r/ecs_service.html#network_configuration
dynamic "network_configuration" {
for_each = var.network_mode == "awsvpc" ? ["true"] : []
content {
security_groups = compact(concat(var.security_group_ids, aws_security_group.ecs_service.*.id))
subnets = var.subnet_ids
assign_public_ip = var.assign_public_ip
}
}

lifecycle {
ignore_changes = [desired_count]
}
}

resource "aws_ecs_service" "default" {
count = local.enabled && var.ignore_changes_task_definition == false ? 1 : 0
count = local.enabled && ! var.ignore_changes_task_definition && ! var.ignore_changes_desired_count ? 1 : 0
name = module.this.id
task_definition = coalesce(var.task_definition, "${join("", aws_ecs_task_definition.default.*.family)}:${join("", aws_ecs_task_definition.default.*.revision)}")
desired_count = var.desired_count
Expand Down
4 changes: 2 additions & 2 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ output "ecs_exec_role_policy_name" {

output "service_name" {
description = "ECS Service name"
value = join("", aws_ecs_service.default.*.name) != "" ? join("", aws_ecs_service.default.*.name) : join("", aws_ecs_service.ignore_changes_task_definition.*.name)
value = try(aws_ecs_service.default[0].name, aws_ecs_service.ignore_changes_task_definition[0].name, aws_ecs_service.ignore_changes_desired_count[0].name, aws_ecs_service.ignore_changes_task_definition_and_desired_count[0].name)
}

output "service_arn" {
description = "ECS Service ARN"
value = join("", aws_ecs_service.default.*.id) != "" ? join("", aws_ecs_service.default.*.id) : join("", aws_ecs_service.ignore_changes_task_definition.*.id)
value = try(aws_ecs_service.default[0].id, aws_ecs_service.ignore_changes_task_definition[0].id, aws_ecs_service.ignore_changes_desired_count[0].id, aws_ecs_service.ignore_changes_task_definition_and_desired_count[0].id)
}

output "service_role_arn" {
Expand Down
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ variable "ignore_changes_task_definition" {
default = true
}

variable "ignore_changes_desired_count" {
type = bool
description = "Whether to ignore changes for desired count in the ECS service"
default = false
}

variable "assign_public_ip" {
type = bool
description = "Assign a public IP address to the ENI (Fargate launch type only). Valid values are `true` or `false`. Default `false`"
Expand Down

0 comments on commit 91284c5

Please sign in to comment.