Stark & Wayne

Formatting Terraform Lists as Strings

I'm deep in the weeds again.

I'm inside of a YAML document inlined inside of a heredoc inside of a bash script that exists as a string inside of a heredoc inside of a Terraform configuration file written in HCL. It's not my finest work, but it's up there.

To complete this masterpiece, I simply need to convert a Terraform list of DNS server IPs into a YAML list of DNS server IPs. Easy enough. I've done string interpolation in Terraform all over this file. Anything here that isn't already wrapped in ${} probably could be.

So I have my DNS server list variable defined in my terraform.tfvars file as:

dns_servers = [ "1.1.1.1", "1.0.0.1" ]

And that sure looks like a JSON/YAML array to me. As somebody who has been coddled and babied on the conveniences of modern weakling languages like Python, Ruby, and Go, I've come to think that, naturally, I could do something like this:

"dns_servers: ${var.dns_servers}"

It follows then that, naturally, Terraform would balk at this assumption.

Error: Invalid template interpolation value: Cannot include the given value in a string template: string required.

Transparent formatting of lists into strings? Not in this house. We praise types in this house. Fine. I've been in other houses that praise types. Those houses have join functions to turn lists into strings. Terraform has one too!

"dns_servers: [\"${join("\", \"", var.dns_servers)}\"]"

So now, I'm putting ", " in between each element of the input list and then wrapping it in [" and "]. And it's a JSON-looking-list. Great! Terraform is even thrilled to see it.

But what if the input list is empty? Then the resulting string here would be:

dns_servers: [""]

That isn't an empty list. That's a list with one element which is the empty string. It's doing wrong things and justice must be served. Seems like I need a branch to a special case if the input list is empty. Luckily, Terraform has the concept of directives. Now we can perform feats of heroism previously reserved for C #ifdef macros, but now we can make it look even uglier. We can embed a Terraform if statement in these directives to get our branching functionality, and if we determine the input list is empty (using the length function), we can just output [].

"dns_servers: %{ if length(var.dns_servers) > 0 }[\"${join("\", \"", var.dns_servers)}\"]%{ else }[]%{endif}"

👌 Magnifique.