I am trying to build multiple vnets in Azure using Terraform 0.12+ and its new for_each and running into some trouble. I was hoping that the new capabilities would allow me to create a generic network module that takes in a complex variable but I perhaps have reached its limit or am just not thinking it through correctly.. Essentially I my variable is built like
variable "networks" {
type = list(object({ name = string, newbits = number, netnum = number, subnets = list(object({ name = string, newbits = number, netnum = number}))}))
}
You can see that its an array of networks with a subarray of the subnets for that network. Doing it this way would make it easy to document the network without the extra lines of the terraform resource requirements so our network team can easily adjust/expand without needing to worry about knowing the HCL.
I can perform the necessary functions of building the multiple vnet resources using count and its index, but I would like to use the for_each as it allows for indexing off of the key rather than a count which could change over time (requiring redeployment which we cannot do).
network object
networks = [
{
# x.x.1.0/24
name = "DMZ",
newbits = "8",
netnum = "1",
subnets = [
{
# x.x.1.0/25
name = "DMZ"
newbits = "9",
netnum = "2"
}
]
},
{
# x.x.33.0/24
name = "Intermediary"
newbits = "8",
netnum = "33",
subnets = [
{
# x.x.33.0/25
name = "subnet1"
newbits = "9",
netnum = "66"
},
{
# x.x.33.128/25
name = "subnet2"
newbits = "9",
netnum = "67"
}
]
}
]
I have tried and successfully built the vnets with a for_each by changing the object into a map and then using the each.key and each.value (doing a cidrsubnet for the each.value) but the problem lies in making the subnets.
locals {
vnets = {
for vnet in var.networks:
vnet.name => cidrsubnet(var.root_cidr, vnet.newbits, vnet.netnum)
}
}
Since the map does not include those subnets it I am just banging my head against the wall. Does anyone have any suggestions? Or am I really making this overly complex when I dont need to be?
The resource creation that works, but no subnets
resource "azurerm_virtual_network" "vnets" {
for_each = local.vnets
name = each.key
address_space = [each.value]
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
}
I was hoping I could use a dynamic block and perhaps filtering it to match the each.key inside of the network resource. I also tried doing it with its own subnet resource after but just cant figure it out.
This is the whole resource I was hoping would work
resource "azurerm_virtual_network" "vnets" {
for_each = local.vnets
name = "99999-Nucleus-${each.key}"
address_space = [each.value]
location = azurerm_resource_group.network.location
resource_group_name = azurerm_resource_group.network.name
dynamic "subnet" {
for_each = [for vnet in var.networks:
[for s in vnet.subnets: {
name = s.name
prefix = cidrsubnet(var.root_cidr, s.newbits, s.netnum)
}] if var.networks.name == each.key]
content {
name = subnet.value.name
address_prefix = subnet.value.prefix
}
}
}