terraformterraform-provider-vsphere

Iterate through nested data with foreach in Terraform


I know - there was a topic with an explanation of how to solve this with flatten function. Help me understand how it works, please.

So, I'm setting up terraform with the vSphere provider. I want to achieve a goal when the network data source is configured dynamically from virtual machine's settings.

I have the variable "virtual_machines" in vars.tf with VM setting:

variable "virtual_machines" {
  type = map(object({
        template        = string
        host_name       = string
        domain_name     = string
        num_cpus        = number
        memory          = number
        dns_server_list = list(string)
        gateway         = string
        interfaces      = list(object({
          network = string
          ipv4_address = string
          ipv4_netmask = string
        }))
  }))
}

And there are its values in vm.auto.rfvars:

virtual_machines = {
  "gw" = {
    template = "cent7_template"
    host_name = "gw"
        domain_name = "contoso.com"
    dns_server_list = ["8.8.8.8", "8.8.4.4"]

    num_cpus = 2
    memory = 2048
    interfaces = [
          {
            ipv4_address = "192.168.5.240"
        ipv4_netmask = "24"
            network = "VM Network"
      },
      {
        ipv4_address = "192.168.4.241"
            ipv4_netmask = "24"
            network = "VM Network2"
      }
    ]

    gateway = "192.168.5.251"

  }
}

In my main file there are sphere interfaces:

data "vsphere_network" "interfaces" {
  for_each      = networks.local
  name          = each.value.network
  datacenter_id = data.vsphere_datacenter.dc.id
}

I have big trouble understanding how to make this local var to get "network" value from "interfaces" object list.

There is my try:

locals {
  networks = flatten([
    for vm_key, objects in var.virtual_machines : [
      for interface in objects.interfaces : {
          network           = interface.network
          ipv4_address = interface.ipv4_address
          ipv4_netmask  = interface.ipv4_netmask
      }

  ])
}

After running this code I got the error:

     │ local.networks is tuple with 2 elements
│
│ The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of
│ strings, and you have provided a value of type tuple.

Help please understand how to iterate to this value please. Big thanx!


Solution

  • Your local.networks is a list of maps. You can't use such a data structure with for_each. But you can use a map of maps. The easiest way to convert it to a map of maps is:

    data "vsphere_network" "interfaces" {
      for_each      = {for idx, val in local.networks: idx => val}
      name          = each.value.network
      datacenter_id = data.vsphere_datacenter.dc.id
    }