The other day I was wondering if it was possble to unpack a list of elements as args to a function in Terraform similar to *
in Python or splat in Ruby?
Because this code will give invalid function argument errors:
locals {
new_bits = [4,4,8,4]
subnets = cidrsubnets("10.1.0.0/16", local.new_bits) # <= can i unpack?
}
It turns out you can do this with the expansion symbol ...
(three periods). Not to be confused with the Unicode ellipsis character. In the Terraform docs it’s used for Expanding Function Arguments:
locals {
new_bits = [4,4,8,4]
subnets = cidrsubnets("10.1.0.0/16", local.new_bits...)
}
Resulting subnets list:
local.subnets = [
"10.1.0.0/20",
"10.1.16.0/20",
"10.1.32.0/24",
"10.1.48.0/20",
]
It’s pretty straight forward now that we know to use the expansion symbol ...
for the “unpacking” behavior. But wait, there’s more! While reading through the For Expressions section I came accross using an expansion symbol in a for
loop “if the result type is an object (using { and } delimiters) then the value result expression can be followed by the … symbol to group together results that have a common key”.
Apparently, if we attempt to group values with the same key using for
without ...
to generate a new map then you get a Duplicate object key
error:
$ terraform console
> { for s in ["here", "there", "this", "that"] : substr(s, 0, 1) => s }
Error: Duplicate object key
on <console-input> line 1:
(source code not available)
Two different items produced the key "t" in this 'for' expression. If
duplicates are expected, use the ellipsis (...) after the value expression to
enable grouping by key.
The error message says to use the ellipsis but it’s not clear on how to use it.
And it’s weird that the error refers to ...
as an ellipsis because
the docs call it an expansion symbol.
Now ...
enters the ring! And we’re able to group each word in the list
by the same key, the first letter in each word, in the new map!
$ terraform console
> { for s in ["here", "there", "this", "that"] : substr(s, 0, 1) => s... }
{
"h" = [
"here",
]
"t" = [
"there",
"this",
"that"
]
}
I haven’t needed a for
filter with group by behavior yet but this will definitely come in handy when I do!
RTFM is a WIP.
~jq1
Update:
Here’s another great unpacking example from Stack Overflow.