Terraform - Create a map of objects - terraform

This is doing my head in a little bit. So I want to create a map of objects like so:
{
"nic_1" = {
"interface_id" = "blah"
"ip_configuration_name" = "blah"
},
"nic_2" = {
"interface_id" = "blah"
"ip_configuration_name" = "blah"
},
}
The source for this data comes from the below list:
ni-resource = [
{
"id" = "blah"
"ip_configuration" = [
{
"name" = "blah"
},
]
"name" = "nic_1"
},
{
"id" = "blah"
"ip_configuration" = [
{
"name" = "blah"
},
]
"name" = "nic_2"
},
]
So in other words the ni-resource->id needs to map to interface_id and ni-resource->ip_configuration->name needs to map to ip_configuration_name.
I am trying to create a local as below which is not working:
locals {
ni_list = { for ni in ni-resource :
ni["name"] => {
interface_id = ni["id"]
ip_configuration = ni["ip_configuration"][0]["name"]
}
}
}
The error I am getting is as follows:
Error: Invalid object key
The key expression produced an invalid result: string required.
Here is the full ni-resource output:
ni-resource = [
{
"applied_dns_servers" = []
"dns_servers" = []
"enable_accelerated_networking" = false
"enable_ip_forwarding" = false
"id" = "blah"
"internal_dns_name_label" = ""
"internal_domain_name_suffix" = "blah"
"ip_configuration" = [
{
"name" = "blah"
"primary" = true
"private_ip_address" = "dummy"
"private_ip_address_allocation" = "Dynamic"
"private_ip_address_version" = "IPv4"
"public_ip_address_id" = ""
"subnet_id" = "dummy"
},
]
"location" = "dummy"
"mac_address" = ""
"name" = "nic_1l"
"private_ip_address" = "dummy"
"private_ip_addresses" = [
"dummy",
]
"resource_group_name" = "dummy"
"virtual_machine_id" = ""
},
]

Related

Dynamically Rebuilding a Terraform Complex Type

I could be going about this the wrong way, but I'm trying to copy a complex type and inject an object at specific point in a list of complex types. I have a working solution but it is not dynamic and I am forced to repeat myself for each point that I'm modifying.
The below works, but is not dynamic. I am required to repeat a block in the conditional merge statement for each property I need to manipulate.
locals {
map_to_merge = {
foo = "bar"
}
original_list = [
{
property_1 = "value"
property_2 = {
"nested" = {
string_property = "string"
map_property_1 = {
a = "b"
list = []
}
map_property_2 = {
x = "y"
}
}
}
}
]
modified_list = [
for item in local.original_list : merge(item, {property_2 = {
for key, value in item.property_2 : key => merge(value,
contains(keys(value), "map_property_1") ? {
map_property_1 = merge(value.map_property_1, local.map_to_merge)
} : {},
contains(keys(value), "map_property_2") ? {
map_property_2 = merge(value.map_property_2, local.map_to_merge)
} : {}
)
}})
]
}
output "test_original" {
value = local.original_list
}
output "test_modified" {
value = local.modified_list
}
The output is,
+ test_modified = [
+ {
+ property_1 = "value"
+ property_2 = {
+ nested = {
+ map_property_1 = {
+ a = "b"
+ foo = "bar"
+ list = []
}
+ map_property_2 = {
+ foo = "bar"
+ x = "y"
}
+ string_property = "string"
}
}
},
]
+ test_original = [
+ {
+ property_1 = "value"
+ property_2 = {
+ nested = {
+ map_property_1 = {
+ a = "b"
+ list = []
}
+ map_property_2 = {
+ x = "y"
}
+ string_property = "string"
}
}
},
]
What I'd like to do is something like below as it allows me not to repeat the conditional merge statement for each property I want to merge with.
locals {
map_to_merge = {
foo = "bar"
}
original_list = [
{
property_1 = "value"
property_2 = {
"nested" = {
string_property = "string"
map_property_1 = {
a = "b"
list = []
}
map_property_2 = {
x = "y"
}
}
}
}
]
modified_list = [
for item in local.original_list : merge(item, {property_2 = {
for nested, definition in item.property_2 : nested => merge(definition, {
for key, value in definition : key => can(tomap(value))
? merge(
value,
key == "map_property_1" || key == "map_property_2"
? local.map_to_merge
: {}
)
: value
})
}})
]
}
output "test_original" {
value = local.original_list
}
output "test_modified" {
value = local.modified_list
}
But I am getting an error,
Error: Inconsistent conditional result types
on test.tf line 41, in locals:
40: for key, value in definition : key => can(tomap(value))
41: ? merge(
42: value,
43: key == "map_property_1" || key == "map_property_2"
44: ? { foo = "bar" }
45: : {}
46: )
47: : value
The true and false result expressions must have consistent types. The given
expressions are object and object, respectively.
Is there a dynamic/better way to do this or do I need to repeat the block for each property that needs to be manipulated?
Turns out that switching from the use of can to try enables this to run as I'd expect.
locals {
map_to_merge = {
foo = "bar"
}
original_list = [
{
property_1 = "value"
property_2 = {
"nested" = {
string_property = "string"
map_property_1 = {
a = "b"
list = []
}
map_property_2 = {
x = "y"
}
}
}
}
]
modified_list = [
for item in local.original_list : merge(item, {property_2 = {
for nested, definition in item.property_2 : nested => merge(definition, {
for key, value in definition : key => try(
merge(
value,
key == "map_property_1" || key == "map_property_2"
? local.map_to_merge
: {}
),
value
)
})
}})
]
}
output "test_original" {
value = local.original_list
}
output "test_modified" {
value = local.modified_list
}
Here is the output,
+ test_modified = [
+ {
+ property_1 = "value"
+ property_2 = {
+ nested = {
+ map_property_1 = {
+ a = "b"
+ foo = "bar"
+ list = []
}
+ map_property_2 = {
+ foo = "bar"
+ x = "y"
}
+ string_property = "string"
}
}
},
]
+ test_original = [
+ {
+ property_1 = "value"
+ property_2 = {
+ nested = {
+ map_property_1 = {
+ a = "b"
+ list = []
}
+ map_property_2 = {
+ x = "y"
}
+ string_property = "string"
}
}
},
]

Creating BigQuery Procedure or function in Terraform

I need to create Bigquery user defined function/procedure in Terraform
resource "google_bigquery_routine" "sproc" {
dataset_id = "cssp"
routine_id = "tf_test_routine_id"
routine_type = "TABLE_VALUED_FUNCTION"
language = "SQL"
definition_body = <<-EOS
SELECT 1 + value AS value
EOS
arguments {
name = "value"
argument_kind = "FIXED_TYPE"
data_type = jsonencode({ "typeKind" : "INT64" })
}
return_table_type = jsonencode({"columns" : [
{ "name" : "value", "type" : { "typeKind" : "INT64" } },
] })
}

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
}
]

How to Recreate Terraform map with duplicate keys?

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"
}
},
]

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