Skip to content

Instantly share code, notes, and snippets.

@chanux

chanux/main.tf Secret

Last active August 10, 2023 06:45
Show Gist options
  • Save chanux/e9ebabb46169b9d2c46c331f56da4800 to your computer and use it in GitHub Desktop.
Save chanux/e9ebabb46169b9d2c46c331f56da4800 to your computer and use it in GitHub Desktop.
Demystifying nested loops in Terraform
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