I am trying to "merge" a list of objects (each items of local.what_i_have
below) together by keeping some keys as scalar (identical values, here instance_id
and tag_name
) and merging others (here tag_value
) into a set/list.
locals {
what_i_have_v2 = {
"cluster=foo|instance=foo#1|tag=tag1" = [
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_a"
},
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_b"
},
],
"cluster=foo|instance=foo#2|tag=tag1" = [
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_a"
},
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_b"
},
],
"cluster=bar|instance=bar#1|tag=tag1" = [
{
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = "val1_a"
},
],
"cluster=bar|instance=bar#1|tag=tag2" = [
{
instance_id = "i-bbb11111"
tag_name = "tag2"
tag_value = "val2_a"
},
{
instance_id = "i-bbb11111"
tag_name = "tag2"
tag_value = "val2_b"
},
],
},
}
Any of the following output might work for me:
locals {
what_i_want_v1 = {
"cluster=foo|instance=foo#1" = {
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = ["val1_a", "val1_b"] # Values for identical `what_i_have` key are now "merged" in a set/list
},
"cluster=foo|instance=foo#2" = {
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = ["val1_a", "val1_b"]
},
"cluster=bar|instance=bar#1" = {
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = ["val1_a"]
},
},
what_i_want_v2 = [ # Not a map anymore but I don't mind
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = ["val1_a", "val1_b"]
},
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = ["val1_a", "val1_b"]
},
{
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = ["val1_a"]
},
],
what_i_want_v3 = [
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_a+val1_b" # Not an set/list but a string with a "+" separator
},
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_a+val1_b"
},
{
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = "val1_a"
},
],
}
Is this possible?
I naively tried to merge()
to see what it does (local.attempt_1
below):
locals {
attempt_1 = {for k, v in local.what_i_have: k => merge(v...)}
}
But it (obviously) swallows values:
# attempt_1 =
{
"cluster=bar|instance=bar#1" = {
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = "val1_a"
}
"cluster=foo|instance=foo#1" = {
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_b"
}
"cluster=foo|instance=foo#2" = {
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_b"
}
}
Context: I am building what_i_have
as a for_each
for a aws_ec2_tag
resource, to tag instances from a list of tags to have.
Update 1: what_i_have
can contain any tag name, updated the map in question (as what_i_have_v2
).
Here is the original flawed what_i_have
:
locals {
what_i_have = {
"cluster=foo|instance=foo#1" = [
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_a"
},
{
instance_id = "i-fff11111"
tag_name = "tag1"
tag_value = "val1_b"
},
],
"cluster=foo|instance=foo#2" = [
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_a"
},
{
instance_id = "i-fff22222"
tag_name = "tag1"
tag_value = "val1_b"
},
],
"cluster=bar|instance=bar#1" = [
{
instance_id = "i-bbb11111"
tag_name = "tag1"
tag_value = "val1_a"
},
],
},
}
You could flatten the values and then iterate over them:
flattened = flatten(values(local.what_i_have))
what_i_want_v2 = [
for instance in distinct([for item in local.flattened : item.instance_id]) : {
instance_id = instance
tag_name = "tag1"
tag_value = distinct([for item in local.flattened : item.tag_value if item.instance_id == instance])
}
]
> local.what_i_want_v2
[
{
"instance_id" = "i-bbb11111"
"tag_name" = "tag1"
"tag_value" = tolist([
"val1_a",
])
},
{
"instance_id" = "i-fff11111"
"tag_name" = "tag1"
"tag_value" = tolist([
"val1_a",
"val1_b",
])
},
{
"instance_id" = "i-fff22222"
"tag_name" = "tag1"
"tag_value" = tolist([
"val1_a",
"val1_b",
])
},
]