Terraform: Can't use Bash parameter expansion

Created on 26 Aug 2017  ยท  3Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.9.8

Terraform Configuration Files

#...
# User data
data "template_file" "setup_server" {
  template = "${file("../scripts/setup-server.sh")}"

  vars {
    project_name       = "${var.project_name}"
    aws_ecr_access_key = "${var.aws_ecr_access_key}"
    aws_ecr_secret_key = "${var.aws_ecr_secret_key}"
  }
}
#...
# ../scripts/setup-server.sh
username=${USERNAME:-deploy}      # Line 9, where it encounters the error

main() {
  create_user
  configure_docker
  make_app_dir
  configure_ssh
  install_awscli
  configure_awscli
}
...
main

Crash Output

data.template_file.setup_server: Refreshing state...
Error refreshing state: 1 error(s) occurred:
* data.template_file.setup_server: 1 error(s) occurred:
* data.template_file.setup_server: data.template_file.setup_server: failed to render : parse error at 9:20: expected "}" but found ":"

Expected Behavior

I expect that the variable username is set to depoly, using mywiki.wooledge.org/BashGuide/Parameters#Parameter_Expansion

Actual Behavior

Terraform thinks that every ${*} should be "substituted"

Steps to Reproduce

Render a template file that includes a variable with parameter expansion like the above

References

Didn't found

question

Most helpful comment

Hi @MrOutis,

Sequences that look like interpolation sequences can be escaped by doubling the quotes:

username=$${USERNAME:-deploy}

To reduce the impact of such conflicts, I usually recommend splitting the logic and the variables into two separate files. The template would then just be a wrapper around the main script, which is uploaded verbatim without any template processing.

If having the result split into two separate files is not acceptable, an alternative is to have the main body of the script in a separate file _within the Terraform config_ and then insert it as a template variable:

data "template_file" "setup_server" {
  template = "${file("../scripts/setup-server.sh.template")}"

  vars {
    project_name       = "${var.project_name}"
    aws_ecr_access_key = "${var.aws_ecr_access_key}"
    aws_ecr_secret_key = "${var.aws_ecr_secret_key}"

    logic = "${file("../scripts/setup-server-logic.sh")}"
  }
}

The file setup-server.sh.template might then look something like this:

#!/usr/bin/env bash

PROJECT_NAME="${project_name}"
AWS_ACCESS_KEY_ID="${aws_ecr_access_key}"
AWS_SECRET_ACCESS_KEY="${aws_ecr_secret_key}"

${logic}

Since the file function doesn't do any sort of interpretation of the file being read (apart from assuming it's a UTF-8 encoded), any ${...} sequences in setup-server-logic.sh will then be left untouched.

All 3 comments

Hi @MrOutis,

Sequences that look like interpolation sequences can be escaped by doubling the quotes:

username=$${USERNAME:-deploy}

To reduce the impact of such conflicts, I usually recommend splitting the logic and the variables into two separate files. The template would then just be a wrapper around the main script, which is uploaded verbatim without any template processing.

If having the result split into two separate files is not acceptable, an alternative is to have the main body of the script in a separate file _within the Terraform config_ and then insert it as a template variable:

data "template_file" "setup_server" {
  template = "${file("../scripts/setup-server.sh.template")}"

  vars {
    project_name       = "${var.project_name}"
    aws_ecr_access_key = "${var.aws_ecr_access_key}"
    aws_ecr_secret_key = "${var.aws_ecr_secret_key}"

    logic = "${file("../scripts/setup-server-logic.sh")}"
  }
}

The file setup-server.sh.template might then look something like this:

#!/usr/bin/env bash

PROJECT_NAME="${project_name}"
AWS_ACCESS_KEY_ID="${aws_ecr_access_key}"
AWS_SECRET_ACCESS_KEY="${aws_ecr_secret_key}"

${logic}

Since the file function doesn't do any sort of interpretation of the file being read (apart from assuming it's a UTF-8 encoded), any ${...} sequences in setup-server-logic.sh will then be left untouched.

awesome, @apparentlymart!
I'll close the issue as I used the workaround that you proposed.

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings