Home > Software design >  Terraform - nested loop for resource creation
Terraform - nested loop for resource creation

Time:02-06

I'm trying to create all defined virtual_networks in all defined resource_groups.

So the variables looks like this:

inputs = {
  virtual_networks = {
    "test-net1": {
      address_space = ["10.0.0.0/24"]
    }

    "test-net2": {
      address_space = ["10.0.1.0/24"]
    }
  }
  resource_groups = {
    "group1": {
      location  = "West Europe"
    }
    "group2": {
      location  = "East Europe"
    }
  }
}

The resource block looks something like this:

resource "azurerm_virtual_network" "virtual_network" {
  for_each = var.resource_groups

  name                = <FIRST KEY OF var.virtual_networks>
  resource_group_name = each.key
  location            = each.value["location"]
  address_space       = <ADDRESS_SPACE VALUE OF FIRST NETWORK FROM var.virtual_networks>

}

I tried many different ways transforming/restructuring/merging the maps from the variables so i can iterate over them in a better way for this use-case. However i just could not find the right structure and how to build it.

I built the following local variable to help solving this. However i was not able to structure the map in a way so i can loop over it in a single resource block.

locals = {
  resource_groups = {
    for key, resource_groups in var.resource_groups : "${key}" => 
    merge(
      var.virtual_networks,
      resource_groups
    )
  }
}

Outputs:

           group1 = {
               location             = "West Europe"
               test-net1            = {
                   address_space = [
                       "10.0.0.0/24",
                    ]
                }
               test-net2 = {
                   address_space = [
                       "10.0.1.0/24",
                    ]
                }
            }
           group2  = {
               location             = "West Europe"
               test-net1            = {
                   address_space = [
                       "10.0.0.0/24",
                    ]
                }
               test-net2 = {
                   address_space = [
                       "10.0.1.0/24",
                    ]
                }
            }       

CodePudding user response:

As far as i understand, you want to created a neseted loop over two dictionaries. You cloud structure your local like this :

locals {
  resource_groups = distinct(flatten([
    for k1, rg in var.resource_groups : [
      for k2, vn in var.virtual_networks : {
        group = merge({name = "${k1}"}, rg )
        network = merge({name = "${k2}"}, vn )
      }
    ]
  ]))
}

The output would result in:

Changes to Outputs:
    test = [
        {
            group   = {
                location = "West Europe"
                name     = "group1"
            }
            network = {
                address_space = [
                    "10.0.0.0/24",
                ]
                name          = "test-net1"
            }
        },
        {
            group   = {
                location = "West Europe"
                name     = "group1"
            }
            network = {
                address_space = [
                    "10.0.1.0/24",
                ]
                name          = "test-net2"
            }
        },
        {
            group   = {
                location = "East Europe"
                name     = "group2"
            }
            network = {
                address_space = [
                    "10.0.0.0/24",
                ]
                name          = "test-net1"
            }
        },
        {
            group   = {
                location = "East Europe"
                name     = "group2"
            }
            network = {
                address_space = [
                    "10.0.1.0/24",
                ]
                name          = "test-net2"
            }
        },
    ]

And your resource would look like this:

resource "azurerm_virtual_network" "virtual_network" {
  for_each = {for obj in local.resource_groups : "${obj.group.name}_${obj.network.name}" => obj}

  name                = each.value.network.name
  resource_group_name = each.value.group.name
  location            = each.value.group.location
  address_space       = each.value.network.address_space

}
  • Related