Traverse through a map of map

Hi,
I have a specific deployment format that I would like to terraform,

Here’s how deployments look,

variable "deployments" {
  description = "A map of deployment"
  type = map(map(object({
    host = list(string)
    envs = list(string)
  })))
}

And an input will look like this,

  deployments    = {
    eu-west2-c = {
      grp1 = {
        host = ["example.co.uk"]
        envs = [
          "stg-a1",
          "stg-b1"
        ]
      }
      grp2 = {
        host = ["example.co.uk"]
        envs = [
          "stg-e1",
          "stg-f1"
        ]
      }
    }
    us-east1-a = {
      grp1 = {
        host = ["example.com"]
        envs = [
          "stg-a2",
          "stg-b2"
        ]
      }
    }
  }

I created some local vars like this,

locals {
  list_zones = tolist(keys(var.deployments))

  list_groups = distinct(flatten([
    for zone_key, zone in var.deployments:
      zone
  ]))

  list_envs = flatten([
    for zone_key, zone in var.deployments: [
      for group_key, group in zone:
        group.envs
    ]
  ])
}

terraform plan for the local vars look like this,

  + server_module_outputs = {
      + list_env_groups = [
          + {
              + "grp1" = {
                  + envs = [
                      + "stg-a1",
                      + "stg-b1",
                    ]
                  + host = [
                      + "example.co.uk",
                    ]
                }
              + "grp2" = {
                  + envs = [
                      + "stg-e1",
                      + "stg-f1",
                    ]
                  + host = [
                      + "example.co.uk",
                    ]
                }
            },
          + {
              + "grp1" = {
                  + envs = [
                      + "stg-a2",
                      + "stg-b2",
                    ]
                  + host = [
                      + "example.com",
                    ]
                }
            },
        ]
      + list_envs       = [
          + "stg-a1",
          + "stg-b1",
          + "stg-e1",
          + "stg-f1",
          + "stg-a2",
          + "stg-b2",
        ]
      + list_zones      = [
          + "eu-west2-c",
          + "us-east1-a",
        ]
    }

Now I would like to create few resources based on the above map,

  1. I would like to create distinct groups (grp1 and grp2) with the respective host entry, something like this,
resource "google_apigee_envgroup" "apigee" {
  for_each   =  distinct(local.list_groups.keys) // should create a resource for grp1 and grp2
  name       = "each.key"
  hostnames  = "each.value.host" // grp1's host value should be a list having both example.com and example.co.uk as the group name is the same
}
  1. And I would like to create environments (stg-a1…) like this and link to respective group (grp1…) based on the deployment map using a local-exec, something like this,
resource "google_apigee_environment" "apigee" {
  for_each = list_envs
  name         = each.value

  provisioner "local-exec" {
    when    = create
    command = <<EOF
curl -i -H "Authorization: Bearer ${data.google_client_config.current.access_token}"\
  "https://apigee.googleapis.com/v1/envgroups/**${respective_group}**/attachments" \
  -X POST -H "content-type:application/json" \
  -d '{"environment":"**current_environment**"}'
EOF
  }
  
}

I just require help with the “for_each” and “for” syntaxes, I know the resource creation and the local-exec works, so that’s fine.
Any help is greatly appreciated.

Have you tried using toset(list_envs) ?

Hi @tbugfinder
list_envs only has the environments, not the related groups.
It’s only the list list_env_groups that has the relationship between environments and groups.
That relationship is required by the local-exec curl here, look for the hidden, respective_group and current_environment

provisioner "local-exec" {
    when    = create
    command = <<EOF
curl -i -H "Authorization: Bearer ${data.google_client_config.current.access_token}"\
  "https://apigee.googleapis.com/v1/envgroups/**${respective_group}**/attachments" \
  -X POST -H "content-type:application/json" \
  -d '{"environment":"**current_environment**"}'
EOF
  }

So what should I put in the for_each and name here?

resource "google_apigee_environment" "apigee" {
  for_each = list_envs
  name         = each.value