Flatten nested foreach loops with Terraform

12 Sep 2024 in TIL

Given a list of identifiers and an associated list of values, here's how to flatten them all down to a single list of unique values.

hcl
# Define your input data. We'll convert this in to a list of ${name}-${version} values
variable "ai_providers" {
type = list(object({
name = string
versions = list(string)
}))
default = [
{
name = "OpenAI"
versions = ["gpt-3.5-turbo", "gpt-4o"]
},
{
name = "Anthropic"
versions = ["Opus", "Sonnet", "Haiku"]
},
{
name = "Mistral"
versions = ["7B", "8x7B", "8x22B"]
},
{
name = "llama3"
versions = ["8B", "70B"]
},
]
}
## Flatmap using nested loops and flatten()
locals {
ai_providers_flattened = flatten([
for provider in var.ai_providers : [
for version in provider.versions : {
version = version
provider = provider
key = "${provider.name}-${version}"
}
]
])
}
# Iterate over the flattened list to create resources
resource "demo_foo" "my_resource" {
for_each = { for api in local.ai_providers_flattened : api.key => api }
name = each.value.provider
version = each.value.version
}

The for_each = { for api in local.ai_providers_flattened : api.key => api } line confused me for a while. This line is used to identify the resource later as my_resource is now a map of objects rather than a single object. Let's walk through it step by step

  • demo_foo.my_resource is a map of objects
  • demo_foo.my_resource[api.key] points to a single resource
  • api.key is defined as "${provider.name}-${version}"
  • Details for the demo_foo resource for OpenAI gpt-4o is available at demo_foo.my_resource["OpenAI-gpt-4o"]