-
-
Save chanux/e9ebabb46169b9d2c46c331f56da4800 to your computer and use it in GitHub Desktop.
Demystifying nested loops in Terraform
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
locals { | |
# You have configuration in a data structure, a list of maps that defines an | |
# instance of connections with the sources and the desitnations it is | |
# supposed to connect to. However, it does not make sense to establish | |
# a connection between 'the same endpoints' so we need to exclude those. | |
data = [ | |
{ | |
name = "foo" | |
sources = ["a", "b",] | |
dests = ["x", "y", "a",] | |
}, | |
{ | |
name = "bar" | |
sources = ["a", "b",] | |
dests = ["x", "b",] | |
}, | |
] | |
# We would need nested loops to come up with all the connection objects. | |
# However, this cannot be achieved with for_each in the connection resource | |
# type, because you cannot nest there. In such a scenario, it makes sense to | |
# build the final data structure which is a group of 'atomic' data needed for | |
# each connection. | |
res = merge(flatten([ | |
for o in local.data : | |
[ | |
for s in o.sources : | |
{ | |
for d in o.dests : | |
"${o.name}_${s}_${d}" => { | |
source : s | |
dest : d | |
} if s != d | |
} | |
] | |
])...) | |
# In the first two loops, we make a list of lists. This is just for the sake | |
# of iterating. At the bottom level, we build a map of objects. This is the | |
# meat of it. Here we build the final data set needed for a single | |
# connection. The map key is designed to be unique across elments. It's also | |
# best to make it descriptive, so when you see it in the state, it makes | |
# sense to you! | |
# | |
# We exclude the case where source and destination are the same with | |
# `if s != d` | |
# | |
# At the top level, we flatten the list of lists we built just for the sake | |
# of iterating and then we use ellipsis(...) on the resulting list. This is | |
# to dynamically split the list of maps into a bunch of map elements so that | |
# we can merge it all into one big map. | |
} | |
output "res" { | |
value = local.res | |
} | |
resource "local_file" "main" { | |
for_each = local.res | |
content = jsonencode(each.value) | |
filename = "${path.module}/data/${each.key}" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment