Dynamic map creation in terraform - terraform

I have a map passed as variable
dummy = {
1 = {
instances = {
"ip1" = {
a = "earth"
b = "hi"
c = 1
}
"ip2" = {
a = "world"
b = "hello"
c = 2
}
"ip3" = {
a = "planet"
b = "hey"
c = 3
}
}
}
}
Now I want construct a map as follows
value = {
"ip1" = {
b = "hi"
c = 1
}
"ip2" = {
b = "hello"
c = 2
}
"ip3" = {
b = "hey"
c = 3
}
}
I tried using for loops but nothing seems to work out
The following is what I have tried since
_meta = {
for instance in var.dummy.1.instances:
(instance.key) = {
b = instance.value.b
c = instance.value.c
}
}
But it says I cant access the key with for iteration variable

_meta = {
for key, instance in var.dummy.1.instances:
key => {
b = instance.b
c = instance.c
}
}
A for expression is a bit different from a for_each. You don't get key or value variables in a for expression and you can explicitly pull whole entries from the map as I've shown above using key, value in map as the expression form.
You also need to use a fat arrow => operator between the key and value of the generated map entries.

Related

How to create a map by switching keys and values from another map in Terraform?

Given the map of objects that contains a list of repeating strings:
variable "input_var" = {
type = object(map(
name = string
tags = optional(list(string))
)),
default = {
"one" = {
name = "nameone"
tags = ["tag1", "tag2"]
}
"two" = {
name = "nametwo"
tags = ["tag1", "tag3"]
}
"three" = {
name = "namethree"
tags = ["tag2"]
}
"four" = {
name = "namefour"
}
}
}
I want to create a map with keys being the tags from all elements of var.input_var.
Taking the above defaults, a sample of output is:
{
"tag1": [
{
name = "nameone"
key = "one"
},
{
name = "nametwo"
key = "two"
},
],
"tag2": [
{
name = "namethree"
key = "three"
}
],
"tag3": [
{
name = "nametwo"
key = "two"
}
]
}
I was able to achieve this in a two step steps.
First is to create a unique set of tags:
locals{
tags_set = distinct(flatten([
for k, v in var.input_var: coalesce(v.tags, [])
]))
}
followed by creating the (local) map out of local.tags_set:
tags_map = { for key_tag in local.tags_set:
key_tag => flatten([for k, v in var.input_var: [
for tag in coalesce(v.tags, []) : {
key = k
name = v.name
} if tag == key_tag
]]) }
Is there a better implementation for this, in a single step and/or more efficient?

In terraform, how do you sort a list of objects and grab the last value?

Given the following list of objects where order is not guaranteed. How do I use terraform to sort a list and grab the latest value?
locals {
list_of_objects = [
{
name = "0.25388.50855"
sort_versions_by_semver = false
tags = {
"baseosimg" = "windows2022datacenter"
}
},
{
name = "0.25424.21095"
sort_versions_by_semver = false
tags = {
"baseosimg" = "windows2022datacenter"
}
},
{
name = "0.25399.6325"
sort_versions_by_semver = false
tags = {
"baseosimg" = "windows2022datacenter"
}
},
]
}
In terraform if you convert the list of objects to a map, it will automatically sort it. From there you can grab the last value (or first).
locals {
map_of_sorted_objects = { for a in local.list_of_objects : a.name => a }
}
output "test" {
value = lookup(
local.map_of_sorted_objects,
element(
sort(keys(local.map_of_sorted_objects)),
length(local.map_of_sorted_objects) - 1
)
)
}
Output
test = {
"name" = "0.25424.21095"
"sort_versions_by_semver" = false
"tags" = {
"baseosimg" = "windows2022datacenter"
}
}

Terraform converting list records into a list of maps

I am struggling to take the output from a Terraform function (a list block) and convert it into a list of maps, I am trying to convert
The following:
mylist = [
{
key = "mykey1"
property1 = "mykey1property1"
property2 = "mykey1property2"
},
{
key = "mykey2"
property1 = "mykey2property1"
property2 = "mykey2property2"
}
]
into:
mylistmap = {
mykey1 = {
property1 = "mykey1property1"
property2 = "mykey1property2"
}
mykey2 = {
property1 = "mykey2property1"
property2 = "mykey2property2"
}
}
I think zipmap is what I need but I cant find any decent examples to do this.
Not sure if this is the best way possible, but with some manipulation with keys and values I was able to achieve what you want:
locals {
mylist = [
{
key = "mykey1"
property1 = "mykey1property1"
property2 = "mykey1property2"
},
{
key = "mykey2"
property1 = "mykey2property1"
property2 = "mykey2property2"
}
]
mylistmap = { for i in local.mylist: i.key => {
for k,v in i: k => v if k != "key"
}
}
}
Using terraform console, this yields the following values:
> local.mylistmap
{
"mykey1" = {
"property1" = "mykey1property1"
"property2" = "mykey1property2"
}
"mykey2" = {
"property1" = "mykey2property1"
"property2" = "mykey2property2"
}
}

Retrieve value from map using keypath

Let's say I have an map and a keypath to a property nested deeply within:
locals {
data = {
a = {
b = {
c = "Hello World"
}
}
}
keypath = "a.b.c"
}
How can I get the value at the indicated keypath? The keypath can have any number of levels.
output "value" {
value = local.data[???] # Should return "Hello World"
}

How can combine the map values with terraform?

I've tried this:
variable "records" {
type = "map"
default = {
"mediapop.co." = ["www.mediapop.co"],
"mediapopinc.com." = ["mediapopinc.com", "www.mediapopinc.com"] ,
"mediapop.sg." = ["mediapop.sg", "www.mediapop.sg"],
}
}
output "records" {
value = "${flatten(values(var.records))}"
}
but values() only allows for flat maps. Is there a workaround?
Using transpose:
output "transpose" {
value = "${transpose(var.records))"
}
output "values" {
value = "${keys(transpose(var.records)))"
}
outputs
transpose = {
mediapop.sg = [mediapop.sg.]
mediapopinc.com = [mediapopinc.com.]
www.mediapop.co = [mediapop.co.]
www.mediapop.sg = [mediapop.sg.]
www.mediapopinc.com = [mediapopinc.com.]
}
values = [
mediapop.sg,
mediapopinc.com,
www.mediapop.co,
www.mediapop.sg,
www.mediapopinc.com
]

Resources