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?
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}"
])
})
}
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"
}
}