Search code examples
amazon-web-servicesterraformgithub-actions

Multi-line strings for terraform local-exec commands


I am studying Terraform. Currently, I am deploying my application to AWS. I use EC2, Cluster, Task Definition, ASG, and others.

My application deployment includes building a Docker image with my Java code, which is located in another GitHub repository. I am using GitHub Actions for deployment.

Now, part of my Terraform code looks like this:

resource "null_resource" "build_docker_image" {

provisioner "local-exec" {
working_dir = var.work_directory
command     = \<\<EOF
aws ecr get-login-password --region ${var.region} | docker login --username AWS --password-stdin ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com && cd ${var.work_directory} && chmod +x ./mvnw && ./mvnw clean package && docker build -t ${var.back_repository_name} . && docker tag ${var.back_repository_name}:latest ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest && docker push ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest
EOF
}

triggers = {
"run_at" = timestamp()
}

}

However, this command is very long because it is written in one line.

I tried to make this line shorter, but I could not succeed. If I write this command on multiple lines, when I run my Terraform (terraform apply), only the first line runs.

I tried using bash, but it did not work (<3>WSL (34) ERROR: CreateProcessParseCommon:711: Failed to translate):


  provisioner "local-exec" {
    working_dir = var.work_directory
    command     = <<EOF
bash deploy.sh ${var.region} ${data.aws_caller_identity.current_user.account_id} ${var.back_repository_name}
    EOF
  }


#!/bin/bash
aws ecr get-login-password --region $1 | docker login --username AWS --password-stdin $2.dkr.ecr.$1.amazonaws.com
docker build -t $3 .
docker tag $3:latest $2.dkr.ecr.$1.amazonaws.com/$3:latest
docker push $2.dkr.ecr.$1.amazonaws.com/$3:latest

Also, I try use ' / ' or ' \n ' but it is not work too.

Please help me solve the problem. May be there are patters for building docker image.


Solution

  • From the bash manual:

    The backslash character ‘\’ may be used to remove any special meaning for the next character read and for line continuation.

    So if you would like to break one command into multiple lines you need to use the \ character in the place where you would like to move the command to the next line:

    resource "null_resource" "build_docker_image" {
      
      provisioner "local-exec" {
        working_dir = var.work_directory
        
        command     = <<EOF
    aws ecr get-login-password --region ${var.region} | docker login \
    --username AWS \
    --password-stdin ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com && \
    cd ${var.work_directory} && \
    chmod +x ./mvnw && \
    ./mvnw clean package && \
    docker build -t ${var.back_repository_name} . && \
    docker tag ${var.back_repository_name}:latest ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest && \
    docker push ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest
    EOF
      }
    
      triggers = {
        "run_at" = timestamp()
      }
    }
    

    Or for better readability start heredoc with <<EOF- (mind the hyphen) so you can use indentation inside heredoc which will be ignored by Terraform (Indented Heredocs):

    resource "null_resource" "build_docker_image" {
    
      provisioner "local-exec" {
        working_dir = var.work_directory
        command     = <<-EOF
        aws ecr get-login-password --region ${var.region} | docker login \
        --username AWS \
        --password-stdin ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com && \
        cd ${var.work_directory} && \
        chmod +x ./mvnw && \
        ./mvnw clean package && \
        docker build -t ${var.back_repository_name} . && \
        docker tag ${var.back_repository_name}:latest ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest && \
        docker push ${data.aws_caller_identity.current_user.account_id}.dkr.ecr.${var.region}.amazonaws.com/${var.back_repository_name}:latest
        EOF
      }
    
      triggers = {
        "run_at" = timestamp()
      }
    }