I have a cloud-init config file to be used to spin up VMs in AWS using Terraform that I also want to run locally using Multipass for testing and debugging.
The cloud-init file includes some shell scripts which Terraform requires to be rewritten such that they refer to variables as $$var
instead of just $var
. It also uses a template variable for the hostname.
To be able to use the same config file on both cloud and locally, I figured that I could use the following command to expand the templating and start the Multipass VM without manual string replacements:
terraform console <<< "templatefile(\"cloud-init.yaml\", {hostname: \"test\"})" | multipass launch -n test --cloud-init -
But it turns out that the templatefile
function wraps its output in heredoc:
<<EOT
... contents ...
EOT
Multipass of course doesn't understand this syntax and prints the (rather unhelpful) error message:
launch failed: operator[] call on a scalar (key: "users")
Ideally, the Terraform command should be able to render the file without heredoc wrapper. But alternatively, is there a shell trick that would make this work?
It's a little gross, but piping the contents through sed '1d;$d'
removes the first and last lines which contain the heredoc markers:
terraform console <<< 'templatefile("cloud-init.yaml", {hostname: "test"})' | sed '1d;$d' | multipass launch -n test --cloud-init -
This is of course fragile as e.g. whitespace changes could break the assumptions of where the markers are. This solution should therefore be considered a hack/workaround in lack of a better one.
Late to the party, but better late than never. My scenario was taking a k8s yaml file and using it as a template file for the kubernetes_manifest provider, and ran into the same problem of the heredoc formatting breaking the provider. Ended up using yamldecode()
and it cleared out the heredoc formatting.
manifest = yamldecode(templatefile("./hpa.yaml", var.hpavalues))
Not the cleanest depending on the format you get the file in. in your case you'd probably have to do something like:
terraform console <<< 'yamlencode(yamldecode(templatefile("cloud-init.yaml", {hostname: "test"})))' | multipass launch -n test --cloud-init -
But there are a couple options, yamldecode(), jsondecode(), and their respective encode partners.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With