How to loop nested map of objects using for_each loop in terraform

286 Views Asked by At

I am trying to get the networks nic element values using the for_each loop, below is the sample terraform code I am trying with,

locals {
  image = {
    nodes ={
      vm1 ={
          name = "vm1"
        networks ={
          nic1 = {
           name = "vm1-nic1"
          }
          nic2 ={
            name ="vm1-nic2"
          }
        }
      },
      vm2 ={
        name = "vm2"
        networks ={
          nic1 = {
            name = "vm2-nic1"
          }
          nic2 ={
            name = "vm2-nic2"
          }
        }
      }
    }
  }
}

output "iterate" {
  value = [
    for_each = local.image.nodes[].networks
  ]
}

Output error while terraform plan.

terraform plan
╷
│ Error: Missing item separator
│
│   on provider.tf line 111, in output "iterate":
│  110:   value = [
│  111:     for_each = local.image.nodes.nodes
│
│ Expected a comma to mark the beginning of the next item.

can someone throw some light on the fix ? Thank You in advance.

1

There are 1 best solutions below

1
On BEST ANSWER

I tried to loop nested map of objects using for_each loop using terraform and I was able to provision the requirement successfully.

The error suggests that a syntax issue on the line for_each = local.image.nodes.nodes. This is not the correct way to iterate over elements in Terraform.

The main issue in the configuration you shared is incorrect use of for_each in the output block**: In Terraform, for_each is used with resources and modules, not within an output block directly. To iterate over a map or a list in an output, you use a list comprehension or for loop.

I rewrite the configuration which will use a for loop inside the output block to iterate over each node and its network interfaces.

My terraform configuation:

provider "azurerm" {
    features {}
}

resource "azurerm_resource_group" "example" {
  name     = "demorg-vk"
  location = "West Europe"
}


resource "azurerm_virtual_network" "example" {
  name                = "demovk-vnet"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
}

resource "azurerm_subnet" "example" {
  name                 = "demovk-subnet"
  resource_group_name  = azurerm_resource_group.example.name
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_network_interface" "example" {
  for_each            = { for vm in flatten([for vm_name, vm in local.image.nodes : [for nic_name, nic in vm.networks : { vm_name = vm_name, nic_name = nic_name, nic_value = nic.name }]]) : "${vm.vm_name}-${vm.nic_name}" => vm }
  name                = each.value.nic_value
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  ip_configuration {
    name                          = "vktestconfiguration1"
    subnet_id                     = azurerm_subnet.example.id
    private_ip_address_allocation = "Dynamic"
    
  }
}

locals {
  image = {
    nodes = {
      vm1 = {
        name     = "vm1"
        networks = {
          nic1 = {
            name = "vm1-nic1"
          }
          nic2 = {
            name = "vm1-nic2"
          }
        }
      },
      vm2 = {
        name     = "vm2"
        networks = {
          nic1 = {
            name = "vm2-nic1"
          }
          nic2 = {
            name = "vm2-nic2"
          }
        }
      }
    }
  }
}

output "iterate" {
  value = [
    for vm_name, vm in local.image.nodes : [
      for nic_name, nic in vm.networks : {
        vm_name   = vm_name
        nic_name  = nic_name
        nic_value = nic.name
      }
    ]
  ]
}

Output:

enter image description here

enter image description here

enter image description here