How to Iterate Through A List of Objects with Terraform's for_each function

1
2
3
4
5
6
7
8
# create file local.users.yml
user:
  - name: foobar1
    email: [email protected]
  - name: foobar2
    email: [email protected]
  - name: foobar3
    email: [email protected]
1
2
3
4
5
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:

1
2
3
4
5
6
resource "something" {
for_each local.users_config

name = each.key # or even each.value.name
email = each.value.email
}

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
user:
  - 'foobar1':
      name: foobar1
      email: [email protected]
  - 'foobar2':
       name: foobar2
       email: [email protected]
  - 'foobar3':
       name: foobar3
       email: [email protected]

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.

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.

1
2
3
4
5
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.


Webmentions

(No webmentions yet.)