String interpolation with a map

Hi,

I’m wondering if this syntax of string interpolation is OK in HCL2 packer template:

"xxx-${var.foo["mykey"]}-yyy"

where the variable foo is a map with a key mykey.

According to the packer validate . command, this syntax is OK. But I found nothing in documentation concerning this kind of interpolation. It’s an unusual form where you can see a double quote which closes the previous double quote. Typically, it would be an incorrect syntax in a shell language.

But is it OK in HCL2?

Thanks for your help.

Edit: I have forgotten to mention that I’m using Packer v1.10.1.

Hi @flaf,

Looks valid to me, it’s accessing an element from map foo at key mykey, I don’t see any reason why it shouldn’t work. I’m not sure I understand what you mean by “unusual form where you can see a double quote which closes the previous double quote” though, since the context during interpolation is not that of the encompassing string, this would be perfectly valid.

In POSIX shell an equivalent would be something like the following:

$ var="2134"
$ echo "var value is $(echo "$var"), as expected"
var value is 2134, as expected

In this case the substitution context being different from the argument’s context means that the "$var" expansion occurs as expected, and the full argument gets passed to echo as its $1 regardless of splitting.

In HCL this works similarly, I wrote a quick test template to make sure this worked as expected, and it does seem to do the trick

variable "test" {
  type = map(string)
  default = {
    "test": "2134"
  }
}

source "null" "test" {
  communicator = "none"
}

build {
  sources = ["null.test"]

  provisioner "shell-local" {
    inline = ["echo variable input is ${var.test["test"]}"]
  }
}

Running packer on this template yields this:

$ packer build template_test.pkr.hcl 
null.test: output will be in this color.

==> null.test: Running local shell script: /tmp/packer-shell1447012293
    null.test: variable input is 2134
Build 'null.test' finished after 9 milliseconds 755 microseconds.

==> Wait completed after 9 milliseconds 775 microseconds

==> Builds finished. The artifacts of successful builds are:
--> null.test: Did not export anything. This is the null builder

I believe you can safely use this construction in your templates, provided the key is present in the map you’re referencing, this should interpolate without problem!

Thanks a lot bajolet-hashicorp for your complete answer.

You said:

In fact, in the syntax "xxx-${var.foo["mykey"]}-yyy", I imagined something like that:

  • the first double quote opens a string,
  • but the second double quote closes the string,
  • the third double quote opens a new string,
  • and the fourth double quote closes the new string.

Then I thought that the content between the second and the third double quote could be badly interpreted. But you have convinced me with your relevant shell example. Things weren’t working the way I’d imagined. In fact, the syntax ${...} seems to work like a pre-processor interpreted firstly by Packer which creates a kind of new template code and then this “final” code is interpreted by Packer.

I’m thinking it might be worth giving an explicit example of interpolation with map in Packer’s doc, but maybe my mind is finally a little twisted. :slight_smile:

Thanks again for your help bajolet-hashicorp.