I have a map of objects in Terraform for a list of networks as follows:
networks = {
"network1" = {
subnet_names = ["subnet-1", "subnet-2", "subnet-3"]
}
"network2" = {
subnet_names = ["subnet-4", "subnet-5", "subnet-6"]
}
I want to create 6 network security groups (1 per subnet) as follows:
resource "azurerm_network_security_group" "example" {
for_each = toset(var.networks[*].subnet_names)
[...]
}
However when I plan with this code I get an error that var_networks doesn't have an element called subnet_names. I have tried a couple of for loops as well but I think I may need to do something with a nested for loop somewhere. what I want to achieve is a list like this: nsgs_to_create=["subnet-1", "subnet-2", "subnet-3", "subnet-4", "subnet-5", "subnet-6"]] Which I can then use to create the NSGs per subnet. Any suggestions? Thanks. Andrew.
CodePudding user response:
This should not be too complicated to achieve. You should use the built-in flatten
function which will flatten all the lists and return only one list:
locals {
networks = {
"network1" = {
subnet_names = ["subnet-1", "subnet-2", "subnet-3"]
}
"network2" = {
subnet_names = ["subnet-4", "subnet-5", "subnet-6"]
}
}
flattened_networks = flatten([for k, v in local.networks: values(v) ])
}
This returns (using terraform console
):
> local.flattened_networks
[
"subnet-1",
"subnet-2",
"subnet-3",
"subnet-4",
"subnet-5",
"subnet-6",
]
You can then use toset
to make it work with for_each
.
[1] https://www.terraform.io/language/functions/flatten
CodePudding user response:
If you want to solve it with a splat expression:
resource "azurerm_network_security_group" "example" {
for_each = toset(flatten(values(local.networks)[*].subnet_names))
[...]
}
Explanation:
- You need the
values
function to create an array, which look like this:
subnets = [
{
"subnet_names" = [
"subnet-1",
"subnet-2",
"subnet-3",
]
},
{
"subnet_names" = [
"subnet-4",
"subnet-5",
"subnet-6",
]
},
]
- You can use the splat expression to get only the subnet names, but this will result in an array of arrays. You have to use
flatten
for to build a simple array.
Additionally, this solution works if you will have other attributes for a subnet, for example:
locals {
networks = {
"network1" = {
subnet_names = ["subnet-1", "subnet-2", "subnet-3"]
cidr = "10.0.0.0/24"
# ...
}
"network2" = {
subnet_names = ["subnet-4", "subnet-5", "subnet-6"]
cidr = "10.0.1.0/24"
# ...
}
}
}
Output:
output "subnets" {
value = toset(flatten(values(local.networks)[*].subnet_names))
}
subnets = toset([
"subnet-1",
"subnet-2",
"subnet-3",
"subnet-4",
"subnet-5",
"subnet-6",
])