Dynamic block used together with count

Hi!
I’m quite inexperienced with terraform, and I’m spinning my head around something I guess should be quite easy to overcome:

I have a small module to create azure vnet and x number of subnets. The call for the module with the input variables looks like this:

module "vnet" {
  source               = "../module_vnet"
  location             = var.location
  environment          = var.environment
  resource_group_name  = azurerm_resource_group.networktest.name
  vnet_name            = "terraform"
  address_space        = ["10.2.0.0/22"]
  subnet_count        = 2
  delegations         = ["Microsoft.ContainerInstance/containerGroups",]
}

the module itself looks like this (without all the network security groups and rules):

data "azurerm_resource_group" "main" {
  name = var.resource_group_name
}

resource "azurerm_virtual_network" "vnet" {
  name                = "vnet-${var.vnet_name}-${var.environment}"
  tags                = data.azurerm_resource_group.main.tags
  location            = var.location
  address_space       = var.address_space
  resource_group_name = var.resource_group_name
  dns_servers         = var.dns_servers
}

resource "azurerm_subnet" "subnet" {
  count                                          = var.subnet_count
  name                                           = "${var.vnet_name}-subnet-${count.index}"
  virtual_network_name                           = azurerm_virtual_network.vnet.name
  resource_group_name                            = var.resource_group_name
  address_prefix                                 = cidrsubnet(var.address_space[0], 2, count.index)
  enforce_private_link_endpoint_network_policies = var.private_link

  dynamic "delegation" {
    for_each = var.delegations
    content {
      name = delegation.value
      service_delegation {
        name = delegation.value
        actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
      }
    }
  }
}

This will off course create 2 subnets where both have enabled service delegations. However, what I want is somehow to define which subnet should have delegations enabled.
How should I proceed to do this? I really like the idea of just changing the subnet_count to add/subtract subnets without need to enter a lot of information, so I would really like to keep this logic.

In order to include a delegation block in only one of your subnets you’ll need to have some way to identify which subnet that is. The easiest answer, I suppose, would just be to hard-code that index zero is always the one that gets it, and any others do not:

resource "azurerm_subnet" "subnet" {
  count = var.subnet_count

  # ...

  dynamic "delegation" {
    for_each = count.index == 0 ? var.delegations : []
    content {
      # ...
    }
  }
}

If hard-coding index zero isn’t acceptable, you’ll need to introduce some other way for the caller to specify which one to use. That could be, for example, an additional input variable giving the index to use, which you could then use instead of the hard-coded 0 in the above example.

Thanks a lot! :slight_smile:
With this module and the below input I can now enable the delegations on the third of the 4 subnets and that helps me a lot!

 dynamic "delegation" {
     for_each = count.index == var.delegation_subnet ? var.delegations : []
     content {
       name = delegation.value
       service_delegation {
         name = delegation.value
         actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
      }
     }
  }

address_space = [“10.2.0.0/22”]
subnet_count = 4
delegations = [“Microsoft.ContainerInstance/containerGroups”,]
delegation_subnet = 2

But what I really would want is to be able to list the subnets that all wants to enable delegations, do you have any tip to accomplish this? Like this input should enable delegations on the thrid and fourth subnet created:

address_space = [“10.2.0.0/22”]
subnet_count = 4
delegations = [“Microsoft.ContainerInstance/containerGroups”,]
delegation_subnet = [“2”, “3”]

Hi @Frank_Thingelstad,

If we declare that delegation_subnet variable as a set of numbers then we can test for whether a particular value is in it using contains, to generalize the previous example to support any number of delegation subnets:

variable "delegation_subnets" {
  type = set(number)
}

resource "azurerm_subnet" "subnet" {
  count = var.subnet_count

  # ...

  dynamic "delegation" {
    for_each = contains(var.delegation_subnets, count.index) ? var.delegations : []
    content {
      # ...
    }
  }
}

(A list(number) value would work just fine here too, because contains also accepts lists, but declaring it as a set makes it explicit that we’re intending to use this as an unordered collection of unique numbers rather than as an ordered sequence of numbers.)