Query through YAML and create custom local for for_each loop

Viewed 36

Let me introduce you to our setup. We have a /apps folder that includes some yml files:

/apps
 |___ testing-one.yml
 |___ testing-two.yml

apps/testing-one.yml

    name: testing one
    hostnames:
      - name: testing-a
        external: true
        internal: true
        internal_stages: ["dev","qs"]
      - name: testing-b
        external: true
        internal: true
        internal_stages: ["dev","qs"]

or apps/testing-two.yml

    name: testing-two
    hostnames:
      - name: testing-x
        external: true
        internal: true
        internal_stages: ["dev","qs"]

As you can see, some files have just one entry under hostnames other have two entry. For further customization of the List, we create a local variable, that holds the data of each file under apps/ folder.

applications = [for filename in fileset(path.module, "apps/*.yml") : yamldecode(file(filename))]

The output of local.applications looks as followed:

+ name = [
      + {
          + hostnames = [
              + {
                  + external        = true
                  + internal        = true
                  + internal_stages = [
                      + "dev",
                      + "qs",
                    ]
                  + name            = "testing-a"
                },
              + {
                  + external        = true
                  + internal        = true
                  + internal_stages = [
                      + "dev",
                      + "qs",
                    ]
                  + name            = "testing-b"
                },
            ]
          + name      = "testing one"
        },
      + {
          + hostnames = [
              + {
                  + external        = true
                  + internal        = true
                  + internal_stages = [
                      + "dev",
                      + "qs",
                    ]
                  + name            = "testing-x"
                },
            ]
          + name      = "testing-two"
        },
    ]

What do we need?

For later resource creation, we need a map with the following value.

  1. For every name entry under hostname, create a map where the key is testing-a (value of hostname.name) and the value is testing one (value of just name)

Something like this:

[
{testing-a: testing one},
{testing-b: testing one},
{testing-x: testing-two}
]

Why do we need that type of Map?

Later we have to create a resource with for_each inside that is using the key and the value of the list.

resource "local_file" "foo" {
  for_each = {for key, value in local.final_list : key => value}

  content  = each.key
  filename = each.value
}

What can I try to resolve this?

1 Answers

The following local variable outputs your expected result I believe:

final_list = flatten([for app in local.applications : [
    for host in app.hostnames : {
        (host.name) = app.name
    }
]])

The output I received after creating an output called "out_test" is as follows:

+ out_test = [
  + {
      + testing-a = "testing one"
    },
  + {
      + testing-b = "testing one"
    },
  + {
      + testing-x = "testing-two"
    },
]

As Marko mentioned, you will need to turn this in to a map for the for_each which you could do inline as follows or the more clean way would be to wrap the local variable with the merge function if you are able to:

resource "local_file" "foo" {
    for_each = { for key, value in merge(local.final_list...) : key => value }

    content  = each.key
    filename = each.value
}
Related