How to generate a map from two disjoint datastructures in Terraform?

Viewed 164

I have a list and a map like so:

locals {

  traffic_rules = [
    {
      name         = "eu-pool"
      geo_mappings = ["GEO-EU"]
      failover     = [local.endpoint_pools.a, local.endpoint_pools.b, local.endpoint_pools.c]
    },
    {
      name         = "world-pool"
      geo_mappings = ["WORLD"]
      failover     = [local.endpoint_pools.a]
    },
  ]

  endpoint_pools = {
    a = [
      {
        fqdn   = "endpoint_pool.a.com."
        weight = 1
    }]
    b = [
      {
        fqdn   = "endpoint_pool.b1.com."
        weight = 1
      },
      {
        fqdn   = "endpoint_pool.b2.com."
        weight = 1
    }]
    c = [
      {
        fqdn   = "endpoint_pool.c.com."
        weight = 1
    }]
  }

Basically, I want to iterate through traffic_rules and gather:

  1. the index of failover[item] in traffic_rules when I iterate through it
  2. the name of the traffic_rule, eg "eu-pool"
  3. the string "a/b/c" from local.endpoint_pools.a/b/c (these are also keys in endpoint_pools map)

In the end, I need to be able to generate a flattened map like below:

{
“eu-pool-a” =   {
    endpoint_pool_name = "a"
    priority = 1
    top_profile_name = “eu-pool”, 
    bottom_profile_name = “bottom-profile-a”
    }
“eu-pool-b” =   {
    endpoint_pool_name = "b"
    priority = 2
    top_profile_name = “eu-pool”, 
    bottom_profile_name = “bottom-profile-b”
    }
“eu-pool-c” =   {
    endpoint_pool_name = "c"
    priority = 3
    top_profile_name = “eu-pool”, 
    bottom_profile_name = “bottom-profile-c”
    }
“world-pool-a” =    {
    endpoint_pool_name = "a"
    priority = 1
    top_profile_name = “world-pool”, 
    bottom_profile_name = “bottom-profile-a”
    }
}

I started off trying to flatten traffic_rules, then realized that TF is substituting local.endpoint_pools.a/b/c into its actual contents, so I am completely losing the context/string of a/b/c.

1 Answers

Like @MartinAtkins recommend, you should really concentrate on simplify your input data, rather then to try to hack up some complex TF expression.

Also your output data structure does not agree with your input data, as per my understanding, as you have two endpoints for endpoint_pools[b] yet they are not accounted for in your output data. I assume that you want to use both of them, or the first one only?

Anyway, you can first create a helper structure in locals which maps endpoint to pool name:

locals {

  fqdn_to_pool_name = merge([
         for pool_name,v in local.endpoint_pools:
           {
             for v1 in v:  
               "${v1.fqdn}" => {pool_name = pool_name}
           }
     ]...)

}

Then you can generate your structure as follows (I assume you account for both endpoints):

output "test" {

  value = merge(flatten([for rule in local.traffic_rules:
            [for idx, failovers in rule.failover:             
              { for idx2, failover in failovers:
               "${rule.name}-${local.fqdn_to_pool_name[failover.fqdn].pool_name}" => {
                  endpoint_pool_name = local.fqdn_to_pool_name[failover.fqdn].pool_name
                  priority = idx + 1
                  top_profile_name = rule.name
                  bottom_profile_name = "bottom-profile-${local.fqdn_to_pool_name[failover.fqdn].pool_name}"
                }...
              }  
            ]
          ])...)

}

which gives:

test = {
  "eu-pool-a" = [
    {
      "bottom_profile_name" = "bottom-profile-a"
      "endpoint_pool_name" = "a"
      "priority" = 1
      "top_profile_name" = "eu-pool"
    },
  ]
  "eu-pool-b" = [
    {
      "bottom_profile_name" = "bottom-profile-b"
      "endpoint_pool_name" = "b"
      "priority" = 2
      "top_profile_name" = "eu-pool"
    },
    {
      "bottom_profile_name" = "bottom-profile-b"
      "endpoint_pool_name" = "b"
      "priority" = 2
      "top_profile_name" = "eu-pool"
    },
  ]
  "eu-pool-c" = [
    {
      "bottom_profile_name" = "bottom-profile-c"
      "endpoint_pool_name" = "c"
      "priority" = 3
      "top_profile_name" = "eu-pool"
    },
  ]
  "world-pool-a" = [
    {
      "bottom_profile_name" = "bottom-profile-a"
      "endpoint_pool_name" = "a"
      "priority" = 1
      "top_profile_name" = "world-pool"
    },
  ]
}

Related