terraform

Conditionally add element to existing map


I have a map variable

variable "tiers" {
  default = {
    DEMO_APP = {
      env = "demo"
      sg  = "tier-f5b5d2b4"
    }
    DEMO_DB = {
      env = "demo"
      sg  = "tier-5425ce73"
    }
    DEV_APP = {
      env = "dev"
      sg  = "tier-8e96a095"
    }
    DEV_DB = {
      env = "dev"
      sg  = "tier-3ac50a95"
    }
    QA_APP = {
      env = "qa"
      sg  = "tier-a176357f"
    }
    QA_DB = {
      env = "qa"
      sg  = "tier-0d05fa93"
    }
  }
  description = "Map of security group IDs"
  type = map(object({
    env = string
    sg  = string
  }))
}

I need to add a field to it that maps to a list created by a data object

data "loadbalancer" "lbs" {
  subproject = subproject.id
}

The end result should have each map element having an additional "lb" attribute:

    DEMO_APP = {
      env = "demo"
      sg  = "tier-f5b5d2b4"
      lb  = "lb-8956l096"
    }

The new element is mapped based on the env value, so each env = "demo" would have the same lb value.

I've gone through a few attempts at achieving this, but from digging around what I've come up with is to flatten out the structure with something like this:

locals {
  App_LBs = flatten([
    for keys, values in var.tiers : {
      name = keys
      env  = values.env
      sg   = values.sg
      lb = join("",
        [
          for each in data.loadbalancer.lbs.results : each.id if each.name == "${var.lb_prefix}-${values.env}"
      ])
    }
  ])
}

My hope was that this solution would create something like:

{
  name = "DEMO_APP"
  env  = "demo"
  sg   = "tier-f5b5d2b4"
  lb   = "lb-8956l096"
}
{
  name = DEMO_DB
  env = "demo"
  sg  = "tier-5425ce73"
  lb   = "lb-8956l096"
}

Unfortunately, this is failing when running with for_each due to being a tuple value. Is there a better way to simply add this element to the array, or potentially turn this into something for_each will accept?

Update

From the selected answer, I was able to put this together to get this working:

tiers_with_load_balancers = { 
  for tier, attributes in var.tiers :
  tier => merge(attributes,
    {
      lb = join("",
      [ 
        for each in data.loadbalancer.lbs.results : each.id if each.name == "${var.lb_prefix}-${attributes.env}"
      ])
    })
  }

Solution

  • You can use the merge function to add properties to existing elements.

    Example:

    variable "tiers" {
      default = {
        DEMO_APP = {
          env = "demo"
          sg  = "tier-f5b5d2b4"
        }
        DEMO_DB = {
          env = "demo"
          sg  = "tier-5425ce73"
        }
        DEV_APP = {
          env = "dev"
          sg  = "tier-8e96a095"
        }
        DEV_DB = {
          env = "dev"
          sg  = "tier-3ac50a95"
        }
        QA_APP = {
          env = "qa"
          sg  = "tier-a176357f"
        }
        QA_DB = {
          env = "qa"
          sg  = "tier-0d05fa93"
        }
      }
      description = "Map of security group IDs"
      type = map(object({
        env = string
        sg  = string
      }))
    }
    
    locals {
      # Hard-coded value used for demonstration purposes only,
      # replace it with proper value
      load_balancer = "lb-8956l096"
    
      tiers_with_load_balancers = {
        for tier, attributes in var.tiers :
        tier => merge(attributes, {
          lb = local.load_balancer  # <-------------------- New property
        })
      }
    }
    
    output "tiers_with_load_balancers" {
      value = local.tiers_with_load_balancers
    }
    

    Running terraform plan:

    Changes to Outputs:
      + tiers_with_load_balancers = {
          + DEMO_APP = {
              + env = "demo"
              + lb  = "lb-8956l096"
              + sg  = "tier-f5b5d2b4"
            }
          + DEMO_DB  = {
              + env = "demo"
              + lb  = "lb-8956l096"
              + sg  = "tier-5425ce73"
            }
          + DEV_APP  = {
              + env = "dev"
              + lb  = "lb-8956l096"
              + sg  = "tier-8e96a095"
            }
          + DEV_DB   = {
              + env = "dev"
              + lb  = "lb-8956l096"
              + sg  = "tier-3ac50a95"
            }
          + QA_APP   = {
              + env = "qa"
              + lb  = "lb-8956l096"
              + sg  = "tier-a176357f"
            }
          + QA_DB    = {
              + env = "qa"
              + lb  = "lb-8956l096"
              + sg  = "tier-0d05fa93"
            }
        }