Home > Back-end >  How to pass terraform variables into appspec.yml file?
How to pass terraform variables into appspec.yml file?

Time:08-30

I am creating a couple of resources using terraform i.e. S3, CodeDeploy and ECS. I am creating my S3 bucket and uploading an appspec.yml file in it.

This is what my appspec.yml looks like :-

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "Hardcoded-ARN"
        LoadBalancerInfo:
          ContainerName: "new-nginx-app"
          ContainerPort: 80

And this is my ECS module :-

resource "aws_ecs_cluster" "foo" {
  name = "white-hart"
}

resource "aws_ecs_task_definition" "test" {
  family                   = "white-hart"
  container_definitions    = file("${path.module}/definition.json")
  requires_compatibilities = toset(["FARGATE"])
  memory                   = 1024
  cpu                      = 256
  network_mode             = "awsvpc"
  execution_role_arn       = aws_iam_role.white-hart-role.arn
  runtime_platform {
    operating_system_family = "LINUX"
  }
}

Basically what i am trying to do is to somehow pass the aws_ecs_task_definition.arn to my appspec.yml file so i do not have to hardcode it. Is there a way to achieve it without the use of build tools?

CodePudding user response:

There is a way, by using the built-in templatefile [1] function. In order to achieve that, you can do a couple of things, but if used with an existing S3 bucket, you should do the following:

resource "aws_s3_object" "appspec_object" {
  bucket = <your s3 bucket name>
  key    = "appspec.yaml"
  acl    = "private"
  content = templatefile("${path.module}/appspec.yaml.tpl", {
    task_definition_arn = aws_ecs_task_definition.test.arn
  })

  tags = {
    UseWithCodeDeploy = true
  }
}

Next, you should convert your current appspec.yml file to a template file (called appspec.yaml.tpl):

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "${task_definition_arn}"
        LoadBalancerInfo:
          ContainerName: "new-nginx-app"
          ContainerPort: 80

Even more, you could replace all the hardcoded values in the template with variables and reuse it, e.g.:

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "${task_definition_arn}"
        LoadBalancerInfo:
          ContainerName: "${container_name}"
          ContainerPort: "${container_port}"

In that case, the S3 object resource would be:

resource "aws_s3_object" "appspec_object" {
  bucket = <your s3 bucket name>
  key    = "appspec.yaml"
  acl    = "private"
  content = templatefile("${path.module}/appspec.yaml.tpl", {
    task_definition_arn  = aws_ecs_task_definition.test.arn
    container_name       = "new-nginx-app"
    container_port       = 80
  })

  tags = {
    UseWithCodeDeploy = true
  }
}

The placeholder values in the template file will be replaced with values provided when calling the templatefile function.


[1] https://www.terraform.io/language/functions/templatefile

  • Related