0
votes

I would like to get with Terraform the active address space of VNets for Azure in Terraform that have a certain tag. For this I thought I could use Resource data source for virtual networks:

data "azurerm_resources" "vnets"{
  type = "Microsoft.Network/virtualNetworks"
  required_tags = {
    tag_name = "tag"
  }
}

Then I realized that required attribute "address_space" belongs actually to the Virtual Networks Data Source (https://www.terraform.io/docs/providers/azurerm/r/virtual_network.html). Still I need to get the information about existing virtual networks from the Resources Data Source. So I tried nesting the data sources, but the following code does not work:

data "azurerm_virtual_network" "vnets"{
  for_each = [for r in data.azurerm_resources.vnets.resources: {r.name = split("/", split("/resourceGroups", r.id))}]
  name = each.key
  resource_group_name = each.value
}

If that were to work, the idea would then be to determine the lowest possible VNet address space I can give to a new VNet based on the currently allocated VNet addresses (active_vnet_addresses) and a predefined address space (eligible_vnet_addresses) constrained by the number of resource groups (980=3*255+215) per subscription in Azure:

locals {
active_vnet_addresses = azurerm_virtual_network.vnets.address_space
eligible_vnet_addresses = concat([for s in range(1,255,1): "10.${s}.0.0/16"], [for s in range(1,255,1): "11.${s}.0.0/16"], [for s in range(1,255,1): "12.${s}.0.0/16"], [for s in range(1,215,1): "13.${s}.0.0/16"])
available_vnet_addresses = setsubtract(local.eligible_vnet_addresses, local.active_vnet_addresses)
available_vnet_numbers_sorted = sort([for a in local.available_vnet_addresses: split(".", a)[1]])
lowest_available_address_num = (length(local.available_vnet_numbers_sorted) == 0 ? "no more resource groups available" : local.available_vnet_numbers_sorted[0])
}

I am quite new to Terraform and this is my best effort, so I greatly appreciate suggestion on code improvements and would highly appreciate if someone could point me to a solution on how to get already active address spaces from Azure in Terraform.

1
That's good, but I still wait before accepting your answer definitively in case someone else would post a better answer (as suggested by SO).mgross
A better answer? What's better do you expect?Charles Xu
Well, in principle one does not know. But there were already posts on SO where someone came up with a brilliant solution, but could not get the accepted answer anymore and therefore I usually wait some time before accepting an answer as definite. I think it is difficult to give a better answer, but in this case what would be nice if there would be a solution where you only need one data source. Depending on the solution, I would consider the answer simpler and as such better. Of course, putting tags on resource groups would be a solution, but I do not know if that is better practice.mgross

1 Answers

1
votes

To make the nesting data sources that you tried works, you need to change your code like this:

data "azurerm_virtual_network" "vnet" {
    for_each = zipmap(flatten([for id in data.azurerm_resources.vnets.resources[*].id: element(split("/", id), 4)]), data.azurerm_resources.vnets.resources[*].name)
    resource_group_name = each.key
    name = each.value
}

These data sources only get a map of the existing VNet details. And each element of the map display like this:

"group_name" = {
    "address_space" = [
      "172.18.44.0/24",
    ]
    "guid" = "7212a68b-94a0-4be9-b972-b1c61e6ec007"
    "id" = "xxxxxxxxxxxxx"
    "location" = "southcentralus"
    "name" = "romungi-ml-studio-vnet"
    "resource_group_name" = "group_name"
    "subnets" = [
      "default",
    ]
    "vnet_peerings" = {}
  }

So if you just want to get the address space of all the VNet, you need to continue to convert the data sources. To convert the details into a map and each member looks like this:

"VNet_name" = address_space

Here the code:

locals {
    vnet_address_spaces = zipmap(values(data.azurerm_virtual_network.vnet)[*].name, values(data.azurerm_virtual_network.vnet)[*].address_space)
}

The whole map shows here:

vnets = {
  "vnet1" = [
    "172.18.1.0/24",
  ]
  "vnet2" = [
    "172.17.2.0/24",
  ]
  "vnet3" = [
    "172.18.44.0/24",
  ]
  "vnet4" = [
    "10.0.0.0/16",
  ]
}