Terraform state

This is a follow-up on my work with logic for adding subnets in a preconfigured vNET. By using cidrsubnet the Terraform script successfully adds four subnets into the vNET. After the first run with apply command we have four subnets in the state file with the names db01, paas01, web01 and app01. When creating the next plan we give the parameters to create four new subnets with the names db02, paas02, web02 and app02. The problem arise when running apply for the second time. According to the state file the 01-subnets exists but after execution the existing subnets are removed and creating the new 02-subnets. That was not my intension. What am I doing wrong, is not this a typical Use Case?

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 = local.subnets 
  name     = "snet-${each.key}-${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,

If you want the 01 and 02 objects to exist at once then you’d need to change your variable "appid" to be a set of strings instead of a string and then change the rest of the configuration to declare that the other set of objects must exist again for each element of that set.

variable "app_ids" {
  type    = set(string)
  default = ["01", "02"]
}

Some other things would need to change in your configuration to make this work. I’m not sure of all of the things to change but one thing would be the definition of local.subnets to generate subnets for each app id:

locals {
  app_subnet_elems = flatten([
    for app_id in var.app_ids : [
      for k, n in var.subnet_list : {
        key   = "${k}${app_id}"
        value = n
    ]
  ])
  subnets = tomap({
    for elem in local.app_subnet_pairs : elem.key => elem.value
  })
}

You might also need to change other parts of your configuration if you need to generate different CIDR ranges for each application, etc.

This should give you a data structure with subnets for multiple apps at once, with keys like web01, web02, app01, app02, etc. You can then add new “app ids” later by adding new entries into var.app_ids, and delete ones you no longer need by removing their entry from var.app_id.