How to Iterate over nested objects and create sub-resource inside dynamic block

53 Views Asked by At

I am trying to create multiple frontend_ip_configuration for azurerm_lb. Below is my setup for this:

1. Tfvars file:

 loadbalancers2 = [
        { # First LB
        name                = "test"
        location            = "eastus"
        resource_group_name = "myrg"
        subnet              = "test"
        frontend_private_ips = [
          {
            fpip_config_name_suffix = "FIP01"
            private_ip_address = "10.202.1.12"
          },
          {
            fpip_config_name_suffix = "FIP02"
            private_ip_address = "10.202.1.13"
          }
        ]
        ..
        },
    ]

2. Locals & Resource:

locals {
       alb_frontend_config_list = flatten([
        for alb in var.loadbalancers2 : [
          for fend in alb.frontend_private_ips : {
            fpip_config_name_suffix = fend.fpip_config_name_suffix
            fpip_config_name = "${alb.name}-${fend.fpip_config_name_suffix}"
            private_ip_address = fend.private_ip_address
          }
        ]
       ])
    }

resource "azurerm_lb" "loadbalancers2" {
      for_each            = { for alb in var.loadbalancers2 : alb.name  => alb }
      name                = each.value.name
      location            = each.value.location
      .. 
    
      dynamic "frontend_ip_configuration" {
        for_each = local.alb_frontend_config_list # ?? 
        iterator = fend # ?? 
        content {
          name                = fend.fpip_config_name # Does not works
          subnet_id           = data.azurerm_subnet.subnets[each.value.subnet].id
          private_ip_address  = ( fend.value  != "" ? fend.value : null )
          private_ip_address_allocation = ( fend.value != "" ? "Static" : "Dynamic" )
        }
      }
    }

I want to do something like this. How do I achieve this:

frontend_ip_configuration {
    name = "${each.value.name}-${each.value.frontend_private_ips[0].fpip_config_name_suffix}"
    subnet_id = data.azurerm_subnet.subnets[each.value.subnet].id
    private_ip_address  = ( each.value.frontend_private_ips[0].private_ip_address  != "" ? each.value.frontend_private_ips[0].private_ip_address : null )
    private_ip_address_allocation = ( each.value.frontend_private_ips[0].private_ip_address != "" ? "Static" : "Dynamic" )
  }

  frontend_ip_configuration {
    name = "${each.value.name}-${each.value.frontend_private_ips[1].fpip_config_name_suffix}"
    subnet_id = data.azurerm_subnet.subnets[each.value.subnet].id
    private_ip_address  = ( each.value.frontend_private_ips[1].private_ip_address  != "" ? each.value.frontend_private_ips[1].private_ip_address : null )
    private_ip_address_allocation = ( each.value.frontend_private_ips[1].private_ip_address != "" ? "Static" : "Dynamic" )
  }
1

There are 1 best solutions below

0
Vinay B On BEST ANSWER

I tried to Iterate over nested objects and create sub-resource inside dynamic block and I was able to provision the requirement successfully

To meet your goal of creating multiple frontend_ip_configuration entries for an Azure Load Balancer (azurerm_lb) in Terraform, you'll need to fine-tune your method to ensure the dynamic block properly iterates over the frontend_private_ips for each load balancer. The current structure of your locals and resource block requires some adjustments to function as expected.

  • Your alb_frontend_config_list local flattens all frontend configurations into a single list without associating them back to their respective load balancers, which makes it challenging to apply them correctly in the dynamic block within the azurerm_lb resource.
  • The dynamic block within the azurerm_lb resource should iterate over frontend_private_ips for each load balancer, but the existing setup does not facilitate this due to the mentioned flattening.

I make necessary changes in the code and rewrite it as per the requirement for multiple load balancers.

My terraform configuration:

provider "azurerm" {
  features {}
}

variable "loadbalancers" {
  description = "A list of load balancer configurations."
  type = any
}

resource "azurerm_resource_group" "rg" {
  for_each = { for lb in var.loadbalancers : lb.name => lb }
  
  name = each.value.resource_group_name
  location = each.value.location
}

data "azurerm_subnet" "subnets" {
  for_each = {for lb in var.loadbalancers : lb.name => lb}

  name                 = each.value.subnet_name
  virtual_network_name = each.value.vnet_name
  resource_group_name  = each.value.vnet_resource_group_name
}

resource "azurerm_lb" "loadbalancer" {
  for_each = { for lb in var.loadbalancers : lb.name => lb }

  name                = each.value.name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
  sku                 = "Standard"
  depends_on          = [azurerm_resource_group.rg]

  dynamic "frontend_ip_configuration" {
    for_each = each.value.frontend_private_ips

    content {
      name                          = "${each.value.name}-${frontend_ip_configuration.value.fpip_config_name_suffix}"
      subnet_id                     = data.azurerm_subnet.subnets[each.key].id
      private_ip_address            = frontend_ip_configuration.value.private_ip_address != "" ? frontend_ip_configuration.value.private_ip_address : null
      private_ip_address_allocation = frontend_ip_configuration.value.private_ip_address != "" ? "Static" : "Dynamic"
    }
  }
}

tfvars:

loadbalancers = [
  {
    name                = "lb1"
    location            = "eastus"
    resource_group_name = "rgvk-lb1"
    subnet_name         = "testsnet1"
    vnet_name           = "testvnet1"
    vnet_resource_group_name = "rg-name"
    frontend_private_ips = [
      {
        fpip_config_name_suffix = "FIP01"
        private_ip_address      = "10.0.0.4"
      },
      {
        fpip_config_name_suffix = "FIP02"
        private_ip_address      = "10.0.0.10" # Already within the range
      }
    ]
  },
  {
    name                = "lb2"
    location            = "eastus"
    resource_group_name = "rgvk-lb2"
    subnet_name         = "testsnet2"
    vnet_name           = "testvnet2"
    vnet_resource_group_name = "rg-name"
    frontend_private_ips = [
      {
        fpip_config_name_suffix = "FIP03"
        private_ip_address      = "10.0.0.5"
      },
      {
        fpip_config_name_suffix = "FIP04"
        private_ip_address      = "10.0.0.20" # Already within the range
      }
    ]
  }
]

deployment succeeded:

enter image description here

enter image description here

enter image description here