The following code
variable "object" {
type = set(map(string))
default = [
{
path = "path2"
ip = "1.2.3.4"
},
{
path = "path3"
ip = "8.8.8.8"
}
]
}
module "out" {
source = "../modules/out"
my_var = {
# {
# name = "value1"
# path = "path1"
# }
# {
for i in var.object: i.ip => {
name = format("name-%s", index(tolist(var.object), i) +1)
path = i.path
}
}
# }
}
output "my_out" {
value = module.out.my_output
}
locals {
var1 = {
for i in var.object:
i.ip => {
name = format("name-%s", index(tolist(var.object), i) +1)
path = i.path
}
}
}
output "my_var1" {
value = local.var1
}
calling the ‘out’ module
variable "my_var" {
type = map(map(string))
}
output "my_output" {
value = {
for i in var.my_var:
i.name => i.path
}
}
generates this output
my_out = {
"name-1" = "path2"
"name-2" = "path3"
}
my_var1 = {
"1.2.3.4" = {
"name" = "name-1"
"path" = "path2"
}
"8.8.8.8" = {
"name" = "name-2"
"path" = "path3"
}
}
However, when uncommenting the commented section, it fails with this error:
Error: Missing attribute value
Expected an attribute value, introduced by an equals sign ("=").
This is strange to me since the module variable defines a map of maps of strings, which is accepted in the module when the section is commented out. So adding an extra map inline when uncommenting should also be accepted. What am I doing wrong?
Your outer map doesn’t have any keys specified. You need to specify a key for each of the elements of that map:
my_var = {
"EXAMPLE KEY 1" = {
name = "value1"
path = "path1"
}
"EXAMPLE KEY 2" = {
for i in var.object: i.ip => {
name = format("name-%s", index(tolist(var.object), i) +1)
path = i.path
}
}
}
With that said, I think just doing the above would fix the syntax error but introduce a type-checking error, because “EXAMPLE KEY 2” in my example above has a map of maps as value, rather than a map of strings as the type constraint requires. I’m not sure exactly what data structure you want my_var
to have, so I’m not sure what to suggest from here; if you can show an example of a literal map value that shows what you intend to generate with that expression then that will hopefully help me to see what your goal is and thus suggest a way to meet it here.
Thank you for your reply. Indeed, your prediction of type error verified. Your answer made me question my usage of a map of maps instead of a list of maps, which suits better my need. Just for reference, and because I don’t want to be DenverCoder9, I’ll paste my solution, but it doesn’t rely on a map of maps anymore.
What I really needed was to supply to a module a list of maps, some being hardcoded, and others being iterated on a variable.
Now this code:
variable "fw_private_ip" {
default = "1.2.3.4"
}
variable "databricks_udr" {
type = list(string)
description = "Default values are for West Europe"
default = [
"23.100.0.135/32",
"40.74.30.81/32"
]
}
module "route_table" {
source = "../modules/out"
route_list = concat(
[
{
name = "to-firewall"
address_prefix = "0.0.0.0/0"
next_hop_type = "VirtualAppliance"
next_hop_in_ip_address = var.fw_private_ip
}
],
[
for ip in var.databricks_udr:
{
name = format("to-control-plane-%s", index(var.databricks_udr, ip) +1)
address_prefix = ip
next_hop_type = "Internet"
}
])
}
output "my_out" {
value = module.route_table.my_output
}
And this module:
variable "route_list" {
type = list(map(string))
}
output "my_output" {
value = local.routes
}
locals {
routes = [
for route in var.route_list : {
name = route.name
address_prefix = route.address_prefix
next_hop_type = route.next_hop_type
next_hop_in_ip_address = lookup(route, "next_hop_in_ip_address", null)
}
]
}
Generate this expected output:
my_out = [
{
"address_prefix" = "0.0.0.0/0"
"name" = "to-firewall"
"next_hop_in_ip_address" = "1.2.3.4"
"next_hop_type" = "VirtualAppliance"
},
{
"address_prefix" = "23.100.0.135/32"
"name" = "to-control-plane-1"
"next_hop_in_ip_address" = tostring(null)
"next_hop_type" = "Internet"
},
{
"address_prefix" = "40.74.30.81/32"
"name" = "to-control-plane-2"
"next_hop_in_ip_address" = tostring(null)
"next_hop_type" = "Internet"
},
]