Skip to content

Commit

Permalink
feat: Allow disabling service creation to support creating just a tas…
Browse files Browse the repository at this point in the history
…k definition (#176)

* feat: added create_service variable support

Addressing the issue #162
#162

The new create_service_resource variable controls whether a `service` resource should be created (which is `true` by default), but still allows skipping creation of the service when it's not required.

* chore: Update example, add output for task definition family and revision

---------

Co-authored-by: Bryant Biggs <[email protected]>
  • Loading branch information
lancedikson and bryantbiggs authored Mar 12, 2024
1 parent cd7e85c commit 94c992a
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.88.0
rev: v1.88.1
hooks:
- id: terraform_fmt
- id: terraform_wrapper_module_for_each
Expand Down
6 changes: 6 additions & 0 deletions examples/fargate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Note that this example may create resources which will incur monetary charges on
| <a name="module_alb"></a> [alb](#module\_alb) | terraform-aws-modules/alb/aws | ~> 9.0 |
| <a name="module_ecs_cluster"></a> [ecs\_cluster](#module\_ecs\_cluster) | ../../modules/cluster | n/a |
| <a name="module_ecs_service"></a> [ecs\_service](#module\_ecs\_service) | ../../modules/service | n/a |
| <a name="module_ecs_task_definition"></a> [ecs\_task\_definition](#module\_ecs\_task\_definition) | ../../modules/service | n/a |
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |

## Resources
Expand Down Expand Up @@ -73,7 +74,11 @@ No inputs.
| <a name="output_service_iam_role_unique_id"></a> [service\_iam\_role\_unique\_id](#output\_service\_iam\_role\_unique\_id) | Stable and unique string identifying the service IAM role |
| <a name="output_service_id"></a> [service\_id](#output\_service\_id) | ARN that identifies the service |
| <a name="output_service_name"></a> [service\_name](#output\_service\_name) | Name of the service |
| <a name="output_service_security_group_arn"></a> [service\_security\_group\_arn](#output\_service\_security\_group\_arn) | Amazon Resource Name (ARN) of the security group |
| <a name="output_service_security_group_id"></a> [service\_security\_group\_id](#output\_service\_security\_group\_id) | ID of the security group |
| <a name="output_service_task_definition_arn"></a> [service\_task\_definition\_arn](#output\_service\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) |
| <a name="output_service_task_definition_family"></a> [service\_task\_definition\_family](#output\_service\_task\_definition\_family) | The unique name of the task definition |
| <a name="output_service_task_definition_family_revision"></a> [service\_task\_definition\_family\_revision](#output\_service\_task\_definition\_family\_revision) | The family and revision (family:revision) of the task definition |
| <a name="output_service_task_definition_revision"></a> [service\_task\_definition\_revision](#output\_service\_task\_definition\_revision) | Revision of the task in a particular family |
| <a name="output_service_task_exec_iam_role_arn"></a> [service\_task\_exec\_iam\_role\_arn](#output\_service\_task\_exec\_iam\_role\_arn) | Task execution IAM role ARN |
| <a name="output_service_task_exec_iam_role_name"></a> [service\_task\_exec\_iam\_role\_name](#output\_service\_task\_exec\_iam\_role\_name) | Task execution IAM role name |
Expand All @@ -85,6 +90,7 @@ No inputs.
| <a name="output_service_tasks_iam_role_arn"></a> [service\_tasks\_iam\_role\_arn](#output\_service\_tasks\_iam\_role\_arn) | Tasks IAM role ARN |
| <a name="output_service_tasks_iam_role_name"></a> [service\_tasks\_iam\_role\_name](#output\_service\_tasks\_iam\_role\_name) | Tasks IAM role name |
| <a name="output_service_tasks_iam_role_unique_id"></a> [service\_tasks\_iam\_role\_unique\_id](#output\_service\_tasks\_iam\_role\_unique\_id) | Stable and unique string identifying the tasks IAM role |
| <a name="output_task_definition_run_task_command"></a> [task\_definition\_run\_task\_command](#output\_task\_definition\_run\_task\_command) | awscli command to run the standalone task |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

## License
Expand Down
49 changes: 49 additions & 0 deletions examples/fargate/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ module "ecs_service" {

linux_parameters = {
capabilities = {
add = []
drop = [
"NET_RAW"
]
Expand Down Expand Up @@ -170,6 +171,54 @@ module "ecs_service" {
tags = local.tags
}

################################################################################
# Standalone Task Definition (w/o Service)
################################################################################

module "ecs_task_definition" {
source = "../../modules/service"

# Service
name = "${local.name}-standalone"
cluster_arn = module.ecs_cluster.arn
create_service = false

# Task Definition
volume = {
ex-vol = {}
}

# Container definition(s)
container_definitions = {
al2023 = {
image = "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"

mount_points = [
{
sourceVolume = "ex-vol",
containerPath = "/var/www/ex-vol"
}
]

command = ["/usr/bin/cat", "/etc/os-release"]
}
}

subnet_ids = module.vpc.private_subnets

security_group_rules = {
egress_all = {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

tags = local.tags
}

################################################################################
# Supporting Resources
################################################################################
Expand Down
34 changes: 34 additions & 0 deletions examples/fargate/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ output "service_task_definition_revision" {
value = module.ecs_service.task_definition_revision
}

output "service_task_definition_family" {
description = "The unique name of the task definition"
value = module.ecs_service.task_definition_family
}

output "service_task_definition_family_revision" {
description = "The family and revision (family:revision) of the task definition"
value = module.ecs_service.task_definition_family_revision
}

output "service_task_exec_iam_role_name" {
description = "Task execution IAM role name"
value = module.ecs_service.task_exec_iam_role_name
Expand Down Expand Up @@ -130,3 +140,27 @@ output "service_autoscaling_scheduled_actions" {
description = "Map of autoscaling scheduled actions and their attributes"
value = module.ecs_service.autoscaling_scheduled_actions
}

output "service_security_group_arn" {
description = "Amazon Resource Name (ARN) of the security group"
value = module.ecs_service.security_group_arn
}

output "service_security_group_id" {
description = "ID of the security group"
value = module.ecs_service.security_group_id
}

################################################################################
# Standalone Task Definition (w/o Service)
################################################################################

output "task_definition_run_task_command" {
description = "awscli command to run the standalone task"
value = <<EOT
aws ecs run-task --cluster ${module.ecs_cluster.name} \
--task-definition ${module.ecs_task_definition.task_definition_family_revision} \
--network-configuration "awsvpcConfiguration={subnets=[${join(",", module.vpc.private_subnets)}],securityGroups=[${module.ecs_task_definition.security_group_id}]}" \
--region ${local.region}
EOT
}
3 changes: 2 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ module "service" {

for_each = { for k, v in var.services : k => v if var.create }

create = try(each.value.create, true)
create = try(each.value.create, true)
create_service = try(each.value.create_service, true)

# Service
ignore_task_definition_changes = try(each.value.ignore_task_definition_changes, false)
Expand Down
2 changes: 1 addition & 1 deletion modules/container-definition/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ locals {
secrets = length(var.secrets) > 0 ? var.secrets : null
startTimeout = var.start_timeout
stopTimeout = var.stop_timeout
systemControls = length(var.system_controls) > 0 ? var.system_controls : null
systemControls = length(var.system_controls) > 0 ? var.system_controls : []
ulimits = local.is_not_windows && length(var.ulimits) > 0 ? var.ulimits : null
user = local.is_not_windows ? var.user : null
volumesFrom = var.volumes_from
Expand Down
2 changes: 2 additions & 0 deletions modules/service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ module "ecs_service" {
| <a name="input_create"></a> [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no |
| <a name="input_create_iam_role"></a> [create\_iam\_role](#input\_create\_iam\_role) | Determines whether the ECS service IAM role should be created | `bool` | `true` | no |
| <a name="input_create_security_group"></a> [create\_security\_group](#input\_create\_security\_group) | Determines if a security group is created | `bool` | `true` | no |
| <a name="input_create_service"></a> [create\_service](#input\_create\_service) | Determines whether service resource will be created (set to `false` in case you want to create task definition only) | `bool` | `true` | no |
| <a name="input_create_task_definition"></a> [create\_task\_definition](#input\_create\_task\_definition) | Determines whether to create a task definition or use existing/provided | `bool` | `true` | no |
| <a name="input_create_task_exec_iam_role"></a> [create\_task\_exec\_iam\_role](#input\_create\_task\_exec\_iam\_role) | Determines whether the ECS task definition IAM role should be created | `bool` | `true` | no |
| <a name="input_create_task_exec_policy"></a> [create\_task\_exec\_policy](#input\_create\_task\_exec\_policy) | Determines whether the ECS task definition IAM policy should be created. This includes permissions included in AmazonECSTaskExecutionRolePolicy as well as access to secrets and SSM parameters | `bool` | `true` | no |
Expand Down Expand Up @@ -337,6 +338,7 @@ module "ecs_service" {
| <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | ID of the security group |
| <a name="output_task_definition_arn"></a> [task\_definition\_arn](#output\_task\_definition\_arn) | Full ARN of the Task Definition (including both `family` and `revision`) |
| <a name="output_task_definition_family"></a> [task\_definition\_family](#output\_task\_definition\_family) | The unique name of the task definition |
| <a name="output_task_definition_family_revision"></a> [task\_definition\_family\_revision](#output\_task\_definition\_family\_revision) | The family and revision (family:revision) of the task definition |
| <a name="output_task_definition_revision"></a> [task\_definition\_revision](#output\_task\_definition\_revision) | Revision of the task in a particular family |
| <a name="output_task_exec_iam_role_arn"></a> [task\_exec\_iam\_role\_arn](#output\_task\_exec\_iam\_role\_arn) | Task execution IAM role ARN |
| <a name="output_task_exec_iam_role_name"></a> [task\_exec\_iam\_role\_name](#output\_task\_exec\_iam\_role\_name) | Task execution IAM role name |
Expand Down
8 changes: 5 additions & 3 deletions modules/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ locals {
security_groups = flatten(concat([try(aws_security_group.this[0].id, [])], var.security_group_ids))
subnets = var.subnet_ids
}

create_service = var.create && var.create_service
}

resource "aws_ecs_service" "this" {
count = var.create && !var.ignore_task_definition_changes ? 1 : 0
count = local.create_service && !var.ignore_task_definition_changes ? 1 : 0

dynamic "alarms" {
for_each = length(var.alarms) > 0 ? [var.alarms] : []
Expand Down Expand Up @@ -213,7 +215,7 @@ resource "aws_ecs_service" "this" {
################################################################################

resource "aws_ecs_service" "ignore_task_definition" {
count = var.create && var.ignore_task_definition_changes ? 1 : 0
count = local.create_service && var.ignore_task_definition_changes ? 1 : 0

dynamic "alarms" {
for_each = length(var.alarms) > 0 ? [var.alarms] : []
Expand Down Expand Up @@ -1188,7 +1190,7 @@ resource "aws_ecs_task_set" "ignore_task_definition" {
################################################################################

locals {
enable_autoscaling = var.create && var.enable_autoscaling && !local.is_daemon
enable_autoscaling = local.create_service && var.enable_autoscaling && !local.is_daemon

cluster_name = element(split("/", var.cluster_arn), 1)
}
Expand Down
5 changes: 5 additions & 0 deletions modules/service/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ output "task_definition_family" {
value = try(aws_ecs_task_definition.this[0].family, null)
}

output "task_definition_family_revision" {
description = "The family and revision (family:revision) of the task definition"
value = "${try(aws_ecs_task_definition.this[0].family, "")}:${local.max_task_def_revision}"
}

################################################################################
# Task Execution - IAM Role
# https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html
Expand Down
6 changes: 6 additions & 0 deletions modules/service/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ variable "create" {
default = true
}

variable "create_service" {
description = "Determines whether service resource will be created (set to `false` in case you want to create task definition only)"
type = bool
default = true
}

variable "tags" {
description = "A map of tags to add to all resources"
type = map(string)
Expand Down
1 change: 1 addition & 0 deletions wrappers/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module "wrapper" {
create = try(each.value.create, var.defaults.create, true)
create_iam_role = try(each.value.create_iam_role, var.defaults.create_iam_role, true)
create_security_group = try(each.value.create_security_group, var.defaults.create_security_group, true)
create_service = try(each.value.create_service, var.defaults.create_service, true)
create_task_definition = try(each.value.create_task_definition, var.defaults.create_task_definition, true)
create_task_exec_iam_role = try(each.value.create_task_exec_iam_role, var.defaults.create_task_exec_iam_role, true)
create_task_exec_policy = try(each.value.create_task_exec_policy, var.defaults.create_task_exec_policy, true)
Expand Down

0 comments on commit 94c992a

Please sign in to comment.