How to Iterate Through A List of Objects with Terraform's for_each function
What I want to do🔗
# create file local.users.yml
user:
- name: foobar1
email: foobar1@foobar.com
- name: foobar2
email: foobar2@foobar.com
- name: foobar3
email: foobar3@foobar.com
locals {
users_file = "local.users.yml"
users_file_content = fileexists(local.users_file) ? file(local.users_file) : "NoSettingsFileFound: true"
users_config = yamldecode(local.users_file_content)
}
What I want to work:
resource "something" {
for_each local.users_config
name = each.key # or even each.value.name
email = each.value.email
}
What I've had to do🔗
Now to iterate through this collection, I've had challenges, as the only way I've gotten this to work would be to ensure there was a designated key in the yaml
structure.
This provides a map object with a key/value format, instead of a collection of normal objects.
This would result in a yaml format like:
user:
- 'foobar1':
name: foobar1
email: foobar1@foobar.com
- 'foobar2':
name: foobar2
email: foobar2@foobar.com
- 'foobar3':
name: foobar3
email: foobar3@foobar.com
This provides the "key" for each entry, allowing Terraform's engine to correctly identify the unique entry. This is important, as without a unique key to determine the resource a plan couldn't run in a deterministic manner by comparing correctly the previously created resource against the prospective plan.
Another Way Using Expressions🔗
Iterating through a map has been the main way I've handled this, I finally ironed out how to use expressions with Terraform to allow an object list to be the source of a for_each
operation.
This makes feeding Terraform plans from yaml
or other input much easier to work with.
Most of the examples I've seen confused the issue by focusing on very complex flattening or other steps. From this stack overflow answer, I experimented and finally got my expression to work with only a single line.
resource "foobar" "this" {
for_each = {for user in local.users_config.users: user.name => user}
name = each.key
email = each.value.email
}
This results in a simple yaml object list being correctly turned into something Terraform can work with, as it defines the unique key in the expression.