Dynamic blocks involving data sources

specifically using the vsphere provider as documented here:
was wondering how to implement multiple network stanzas when involving a datasource:

ref: https://www.terraform.io/docs/providers/vsphere/r/virtual_machine.html

specifically:

...
data "vsphere_network" "network" {
  name          = "var.networks.label"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}
...
resource "vsphere_virtual_machine" "vm" {
...
  network_interface {
     network_id = "${data.vsphere_network.network.id}"
  }
}
...

I’d like to do replace network_interface with something like

  dynamic "network_interface" {
    for_each = [for s in var.networks: {
        networkid = networks.label
    }]
    content {
       networkid = network_interface.networkid
    }
}

But I need to somehow get the data source to work across the array of hashes -

variable "networks" { default = [
   {label = "foo"},
   {label = "bar"}
   ]
}

I hope this is a good explanation of what I am trying to do with my psuedo code attempt.

Hi @rismoney!

What you’ve shared so far seems to be on the right track, as far as I can tell. Did you get some specific error when you tried that? If you could share it, we can hopefully suggest how to address that error.

I think I am probably missing a detail here because it’s not clear to me how the second example relates to the data source in the first example. I think seeing how Terraform behaved when you tried this would help to understand what I’m missing.

It’s not a question of an error (yet). My question is with regard to the data source.
How can I have the datasource iterate through the list map.

In typing this up, I need to have the value for
network_id = "${data.vsphere_network.network.id}"
not the networks.label value.

If I’m understanding correctly what you want to achieve, I think the following should do it:

variable "networks" {
  type = list(object({
    label = string
  }))
}

data "vsphere_network" "network" {
  count = length(var.networks)

  name          = var.networks[count.index].label
  datacenter_id = data.vsphere_datacenter.dc.id
}

resource "vsphere_virtual_machine" "vm" {
  # ...

  dynamic "network_interface" {
    for_each = data.vsphere_network.network
    content {
      networkid = network_interface.value.id
    }
  }
}

The key is to use multiple instances of the data resource, with one instance per network you want to connect with, and then generate a network_interface block for each of those instances.

Yes that is absolutely what I was trying to achieve. I will give it a try. I didn’t realize I can do count on data source and peg it against the size of the list

This works great, but now I’m struggling to assign IPs and Netmasks to those networks inside the clone block. Say i have these 2 variable lists:

vsphere_virtual_machine_ipv4_address = [ "172.23.32.115", "172.23.64.200",]
vsphere_virtual_machine_ipv4_mask    = [ "20", "20" ]

And i want to dynamically assign it to the the N interfaces i created:

clone {
  template_uuid = data.vsphere_virtual_machine.template.id

    customize {
      linux_options {
        host_name = var.vsphere_virtual_machine_name
        domain    = var.vsphere_virtual_machine_domain
    }
    dynamic "network_interface" {
     for_each      =  var.vsphere_virtual_machine_ipv4_address
     content  {
      ipv4_address = var.vsphere_virtual_machine_ipv4_address
      ipv4_netmask = var. vsphere_virtual_machine_ipv4_mask
      }
    }

     ipv4_gateway    = var.vsphere_virtual_machine_ipv4_gateway
     dns_server_list = var.vsphere_virtual_machine_dns_list
     dns_suffix_list = var.vsphere_virtual_machine_suffix_list
   }
 }

But i’m not able to iterate over the “vsphere_virtual_machine_ipv4_address” list. I tried using indexes and attributes but it’s not working either.