How to Recreate Terraform map with duplicate keys? - terraform

I'm getting terraform Local variable output as below. I want to reconstruct it to use in deferent argument. I have tried it many way , Still no luck, Appreciate community support on this.
snap_id_list = [
{
"3" = {
"/x01" = "snap-01397a07b574e781f"
}
},
{
"2" = {
"/x04" = "snap-035d6c4165d34041a"
}
},
{
"1" = {
"/x04" = "snap-07bc61be86cb0b3a2"
}
},
{
"3" = {
"/x04" = "snap-0aa3a4d1cbd87531b"
}
},
{
"1" = {
"/x01" = "snap-0e501f7d2798eeb70"
}
},
{
"2" = {
"/x01" = "snap-0fe2fe503e433fdbd"
}
},
]
I want to recreate it as below using common keys.
snap_id_list = [
{
"3" = {
"/x01" = "snap-01397a07b574e781f"
"/x04" = "snap-0aa3a4d1cbd87531b"
},
{
"2" = {
"/x04" = "snap-035d6c4165d34041a"
"/x01" = "snap-0fe2fe503e433fdbd"
},
{
"1" = {
"/x04" = "snap-07bc61be86cb0b3a2"
"/x01" = "snap-0e501f7d2798eeb70"
}
},
]

Related

Invert nested maps and list in Terraform

I have this structure in Terraform:
{
"us1" : {
"0": "192.168.1.1"
},
"europe2" : {
"0": "192.168.10.1",
"1": "10.0.0.1"
}
}
I want to transform it into this structure:
{
"0": {
"europe2": "192.168.1.1",
"us1": "192.168.10.1"
},
"1": {
"europe2": "10.0.0.1"
}
}
I used maps with 0 and 1 as indexing for clarity, but lists can be used instead in both starting and ending structure. Anyone has an idea how to do this ?
I saw operators like ellipsis, or functions like setproduct() but I didn't managed to sort this out.
This construction is what you are looking for:
variable "test" {
default = {
"us1" : {
"0": "192.168.1.1"
},
"europe2" : {
"0": "192.168.10.1",
"1": "10.0.0.1"
}
}
}
locals {
# in three steps
flatten_map = merge([
for key, val in var.test :
{ for idx, sub_val in val : "${key}-${idx}" => sub_val }
]...)
pre_final_map = {
for k, v in local.flatten_map :
"${split("-", k)[1]}" => { "${split("-", k)[0]}" = v }...
}
final_map = {
for k, v in local.pre_final_map:
k => merge(v...)
}
# all in one
all_in_one_map = {
for k0, v0 in {
for k, v in merge([
for key, val in var.test :
{ for idx, sub_val in val : "${key}-${idx}" => sub_val }
]...) : "${split("-", k)[1]}" => { "${split("-", k)[0]}" = v }...
} : "${k0}" => merge(v0...)
}
# convert to list
as_list = [
for k0, v0 in {
for k, v in merge([
for key, val in var.test :
{ for idx, sub_val in val : "${key}-${idx}" => sub_val }
]...) : "${split("-", k)[1]}" => { "${split("-", k)[0]}" = v }...
} : merge(v0...)
]
}
output in_three_steps {
value = local.final_map
}
output in_one_step {
value = local.all_in_one_map
}
output list_representation {
value = local.as_list
}
output:
in_one_step = {
"0" = {
"europe2" = "192.168.10.1"
"us1" = "192.168.1.1"
}
"1" = {
"europe2" = "10.0.0.1"
}
}
in_three_steps = {
"0" = {
"europe2" = "192.168.10.1"
"us1" = "192.168.1.1"
}
"1" = {
"europe2" = "10.0.0.1"
}
}
list_representation = [
{
"europe2" = "192.168.10.1"
"us1" = "192.168.1.1"
},
{
"europe2" = "10.0.0.1"
},
]
i have a much faster example:
locals {
original_map = {
"us1" : {
"0" : "192.168.1.1"
},
"europe2" : {
"0" : "192.168.10.1",
"1" : "10.0.0.1"
}
}
}
locals {
original_maps_values = [for key, value in local.original_map : [for idx, sub_value in value : [key, sub_value, idx]]]
transformed_map = { for v in chunklist(flatten(local.original_maps_values), 3) : v[2] => { "${v[0]}" = v[1] }... }
}
output "transformed_map" {
value = { for k, v in local.transformed_map : k => merge(v...) }
}
references:
expanding-function-arguments

Terraform: Nested for expression with no duplicity

I am newbie to Terraform, apologies in advance in case inappropriate logic is used.
There is nested map, want to create new map using existing one.
terraform.tfvars
vpcs_info= {
"devops" = {
main = {
cidr = "10.14.0.0/16"
region = "ap-south-1"
peering = {
creator = {
devops = "poc",
uat = "main"
}
}
},
poc = {
cidr = "10.9.0.0/16"
region = "ap-south-1"
peering = {
creator = {
dev = "main"
}
}
}
}
}
locas.tf
locals {
vpcs_info = {
for vpc, properties in var.vpcs_info.devops:
vpc => {for dst_env, dst_vpc in properties.peering.creator : vpc => {"name": "${dst_env}-${dst_vpc}-vpc", "id": "${timestamp()}" }...}
}
}
Actual output:
{
"main" = {
"main" = [
{
"id" = "2023-02-05T21:23:24Z"
"name" = "devops-poc-vpc"
},
{
"id" = "2023-02-05T21:23:24Z"
"name" = "uat-main-vpc"
},
]
}
"poc" = {
"poc" = [
{
"id" = "2023-02-05T21:23:24Z"
"name" = "dev-main-vpc"
},
]
}
}
If we observe, in the output there is duplicity in KEYS. Need to get below desired output using for expression:
Desired output:
{
"main" = {
{
"id" = "2023-02-05T21:23:24Z"
"name" = "devops-poc-vpc"
},
{
"id" = "2023-02-05T21:23:24Z"
"name" = "uat-main-vpc"
}
}
"poc" = {
{
"id" = "2023-02-05T21:23:24Z"
"name" = "dev-main-vpc"
}
}
}
Note: "id" is sensitive information in actual requirement, to avoid security challenges, "${timestamp()}" is being used here.
You can do that with merge:
vpcs_info = merge([
for vpc, properties in var.vpcs_info.devops: {
for dst_env, dst_vpc in properties.peering.creator:
vpc => {
"name" = "${dst_env}-${dst_vpc}-vpc"
"id" = "${timestamp()}"
}...
}
]...)

Extract Maps from List in Terraform

I have a list of complex maps, like so (I've simplified the maps, but really they're made up more maps):
[
{
"hooha" = {
"foo" = { "something" = "this" }
}
},
{
"woot" = {
"bar" = { "other_things" = "that" }
}
},
]
I need to feed this into jsonencode(), but first have it look like this:
{
"hooha" = {
"foo" = { "something" = "this" }
},
"woot" = {
"bar" = { "other_things" = "that" }
}
}
So from a list of maps, to a map of the maps.
This seemed trivial, but for the life of me, I can't figure it out!
You can use the function merge with a combination of with ... operator.
locals {
my_list = [
{
"hooha" = {
"foo" = { "something" = "this" }
},
"www" = {
"aa" = {"x" = "y"}
}
},
{
"woot" = {
"bar" = { "other_things" = "that" }
}
},
]
}
output "prepare" {
value = merge(local.my_list...)
}
The output will be something like this:
prepare = {
"hooha" = {
"foo" = {
"something" = "this"
}
}
"woot" = {
"bar" = {
"other_things" = "that"
}
}
"www" = {
"aa" = {
"x" = "y"
}
}
}

is there a way to concat tuple in terraform?

variable "query_param" {
type = list(string)
default = [
"hello",
"one",
"two"
]
}
locals {
common_tags = flatten([
for i in var.query_param: {
"method.request.querystring.${i}" = false
}
])
}
output name {
value = local.common_tags
description = "description"
}
I have this code to iterate the variable(list) to locals (map). I got the below output which is not desired.
name = [
{
"method.request.querystring.hello" = false
},
{
"method.request.querystring.one" = false
},
{
"method.request.querystring.two" = false
},
]
The desired output is getting all the values in a single array. As shown below.
name = [
{
"method.request.querystring.hello" = false,
"method.request.querystring.one" = false,
"method.request.querystring.two" = false
}
]
Is there any way to achieve this?
I think you would want something like this:
locals {
common_tags = {
for i in var.query_param :
"method.request.querystring.${i}" => false
}
}
The output of the code above will be as follows:
name = {
"method.request.querystring.hello" = false
"method.request.querystring.one" = false
"method.request.querystring.two" = false
}
Please note, the name itself is not an array in this case. If you want it to be, you can do the following:
locals {
common_tags = [{
for i in var.query_param :
"method.request.querystring.${i}" => false
}]
}
The output will be:
name = [
{
"method.request.querystring.hello" = false
"method.request.querystring.one" = false
"method.request.querystring.two" = false
}
]

Converting a list(map(list(map(string)))) into a map(list(map(string))) with terraform

Hi there is there any neat way to convert a list(map(list(map(string)))) into a map(list(map(string))) with terraform .
Here's what my input structure looks like
`variable "data" {
type = list(map(list(map(string))))
default = [
{
secrets = [
{
secret-name = "secret1"
secret-label = "label1"
},
{
secret-name = "secret2"
secret-label = "label2"
}
],
config-maps = [
{
config-map-name = "conf1"
java-options = "-Xmx256m"
config-label = "develop"
}
]
},
{
secrets = [
{
secret-name = "secret3"
secret-label = "label3"
}
],
config-maps = [
{
config-map-name = "conf2"
java-options = "-Xmx256m"
config-label = "develop"
}
]
}
]
}`
and here's what i want it to look like
`data = {
secrets = [
{
secret-name = "secret1"
secret-label = "label1"
},
{
secret-name = "secret2"
secret-label = "label2"
},
{
secret-name = "secret3"
secret-label = "label3"
},
],
config-maps = [
{
config-map-name = "conf1"
java-options = "-Xmx256m"
config-label = "develop"
},
{
config-map-name = "conf2"
java-options = "-Xmx256m"
config-label = "develop"
}
]
}
Can you guys help me achieve this please ?
Ps : preferably in the locals part
Then, how about this?
locals {
values = flatten([
for d in var.data : [
for _, v in d : v
]
])
keys = flatten([
for d in var.data : [
for k, v in d : [
for _ in v : k
]
]
])
}
output data {
value = {
for k in distinct(local.keys) :
k => matchkeys(local.values, local.keys, [k])
}
}
I hope this will help.

Resources