-
-
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 objects where the | |
# object 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. For | |
# readability, let's build (sculpt, if you may) the final data structure | |
# which is a group of 'atomic' data needed for each connection in locals. | |
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 two lists of lists (Please note that 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 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 | |
# a single map (The lists are just means to an end. Remember? they were just | |
# for the sake of iterating). | |
} | |
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
Example output, for reference: