Nested Heredoc within local-exec command not working

provisioner "local-exec" {
    command = <<EOT
            echo 'Change to ${var.env} account...'
            mkdir -p ~/.aws

            cat > ~/.aws/config <<CONFIG 
            [default]
            region = us-east-1
            output = json
            [profile ${var.env}_account]
            role_arn = ${local.db_migrate_role_arn}
            credential_source = EcsContainer
            CONFIG


            ARN_VAL=$(aws ecs run-task --enable-execute-command\
              --overrides '{"containerOverrides": [{\
                "name": "${var.app_name}-api",\
                "command":[ "chamber", "exec", "${var.env}-${var.app_name}", "--", "/bin/sh", "-c", ${local.db_migration_command} ]\
              }]}'\
              --task-definition "${local.db_migrate_task_def}"\
              --cluster "${local.app_cluster_name}"\
              --network-configuration '{"awsvpcConfiguration": {"subnets":${local.db_migrate_subnet_groups},"securityGroups":["${local.db_migrate_security_groups}"],"assignPublicIp":"ENABLED"}}'\
              --started-by "JG-DB-Migrate")
            echo "Task has been initiated... the Task Arn is $ARN_VAL"  
            echo "Wait until the task's container reaches the STOPPED state..."
            aws ecs wait tasks-stopped --cluster "${local.app_cluster_name}" --tasks $ARN_VAL
            EXIT_VAL=$(aws ecs describe-tasks --cluster "${local.app_cluster_name}" --tasks $ARN_VAL --query 'tasks[0].containers[0].exitCode' --output text)
            if [ "$EXIT_VAL" = "0" ]
            then 
              echo "Database Migration was successful!"
            else 
              echo "Errors encountered while executing database migration... please check New Relic for the error messages"
              exit 1
            fi
            EOT
  }
}

Command above creates ~/.aws/config with the following:

            [default]
            region = us-east-1
            output = json
            [profile dev_account]
            role_arn = <redacted>
            credential_source = EcsContainer
            CONFIG


            ARN_VAL=
            echo "Task has been initiated... the Task Arn is "  
            echo "Wait until the task's container reaches the STOPPED state..."
            aws ecs wait tasks-stopped --cluster "dev-apps" --tasks 
            EXIT_VAL=
            if [ "" = "0" ]
            then 
              echo "Database Migration was successful!"
            else 
              echo "Errors encountered while executing database migration... please check New Relic for the error messages"
              exit 1
            fi

It should have stopped at the CONFIG and not included it or anything after it in the file. Does Terraform change the interpretation of the cat heredoc? I also tried adding interpreter=[“bash”] with the same results.

Any suggestions would be appreciated. Thanks!

You have whitespace before the CONFIG end marker. It must be hard against the left margin to be interpreted.

Indeed… to be more explicit, the problem here is that the inner heredocs are being handled by your shell rather than by Terraform and so the shell’s parsing rules are what decide the meaning, rather than Terraform’s.

Terraform does allow indented heredocs, but shells typically don’t. Instead, they expect the closing line to exactly match the closing marker, with no extra spaces before or after it.

Terraform’s heredoc feature has a special mode where it will trim off the same amount of leading spaces from each line so that the result does not need to be indented by the same number of spaces as the template is, and I think that will be the easiest option for your case. Add a dash - between the << and the opening marker to activate that mode:

command = <<-EOT

If you add that then Terraform will analyze all of the lines in the template to see which one has the smallest number of leading spaces (ignoring totally empty lines) and then will trim that smallest number of spaces from the start of every line while rendering the template. You should therefore get a shell script without all of the extra indentation on every line.

1 Like

Solved. Thanks much for your assistance