Dynamic maps used in for each

Given this map in Terraform:

variable "subnet_list"  {
  type = map
  default = {
  "web"   = 0
  "app"   = 1
  "db"    = 2
  "paas"  = 3
  }
}

Is there anyway to dynamically build a new map to be used when for example add subnets to a virtual network as:

map modified in runtime:

 "updated_subnet_list"  {
  type = map
   {
  "web01"   = 0
  "app01"   = 1
  "db01"    = 2
  "paas01"  = 3
  }
}

Lets say I have a map to be used for creating a bunch of subnets. But before using that variable I want to modify this map by using some input variable that was given to the Terraform plan command. I have seen some examples by using “dynamic” but can’t really understand how that can help here.

Given the input variable “appid” I did try this but no luck:

variable "subnet_list"  {
  type = map
  default = {
  "web${var.appid}"   = 0
  "app${var.appid}"   = 1
  "db${var.appid}"    = 2
  "paas${var.appid}"  = 3
  }
}

I will here share the complete script by using the tips from Apparentlymart. It still not compile because it seems that I cannot use the local variable "subnets" correctly.

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}
provider "azurerm" {
  features {}
}

variable subnet_size {
  description = "input variable indicating the subnet size: (xsmall, small, medium, large)"
  type = string
  default = "small"
}

variable subnet_count {
  description = "input variable indicating the existing number of subnets of size: (xsmall, small, medium, large)"
  type = number
  default = 0
}

variable appid {
  description = "Number indicating the application identity: (01, 02 etc)"
  type = string
  default = "01"
}

variable subnet_allocation_map {
  description = "Map of CIDR blocks to carve into subnets based on size"
  type = map
  default = {
    xsmall = "100.121.0.0/20"
    small  = "100.121.144.0/20"
    medium = "100.121.160.0/20"
    large  = "100.121.176.0/20"
   }
}

variable "newbit_size" {
  description = "Map the friendly name to our subnet bit mask"
  type        = map
  default = {
    xsmall = "9"
    small  = "8"
    medium = "6"
    large  = "5"
  }
}

variable "subnet_list"  {
  type = map
  default = {
  "web"   = 0
  "app"   = 1
  "db"    = 2
  "paas"  = 3
  }
}

locals {
  subnets = tomap({
    for k, n in var.subnet_list : "${k}${var.appid}" => n
  })
}

resource "azurerm_resource_group" "rg" {
  name = "rg-infra-external-prod"
  location = "westeurope"
}

resource "azurerm_virtual_network" "vnet" {
    name                = "vnet-external-prod-01"
    address_space       = [lookup(var.subnet_allocation_map, var.subnet_size)]
    location            = "westeurope"
    resource_group_name = azurerm_resource_group.rg.name

    tags = {
        "IaC" = "Terraform"
    }
}

resource "azurerm_subnet" "subnets" {

  for_each = var.subnets 
  name     = "snet-${each.key}${var.appid}-${var.subnet_size}-external-prod"
  
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name

  address_prefixes  = [cidrsubnet(lookup(var.subnet_allocation_map, var.subnet_size), lookup(var.newbit_size,var.subnet_size), each.value + var.subnet_count)] 
}

Hi @jan-isacsson,

I’m not sure I’m understanding your underlying problem and so I might be going in the wrong direction here, but trying to mimic your final example as closely as possible I think you could get there with a local value containing a for expression:

locals {
  subnets = tomap({
    for k, n in var.subnet_list : "${k}${var.appid}" => n
  })
}

This will declare a symbol local.subnets which should have the same shape as your final example, where each key has been appended with the value of var.appid.

Thanks,
I have experimented with something similar but couldn’t but it seems that it didn’t accepted variable references inside the for-in clause. But this looks different so I will test and let you know the results :slight_smile:

It now also compiles :slight_smile:
Changed from var.subnets to local.subnets