Terraform vSphere interate multiple nested objects of interfaces with for_each

Hello kind strangers,

Through Googling and guides, I have managed to get to a stage where Terraform can successfully plan several vSphere VM resources. This is done using for_each through maps. I would love to expand this by optionally including additional interfaces.

I expanded the map of objects to include sub-objects - if I can call it this, pardon me if not - that allows the definition of additional interfaces as seen below. I am aware that we cannot configure secondary, tertiary etc. gateways so hence why only one gateway element is defined.
`

variable "vcenter_datacenter" {
}

variable "vcenter_cluster" {
}

variable "vcenter_datastore" {
}

variable "site" {
}

variable "env" {
}

variable "domain" {
}

variable "vm_folder" {
  default = "templates"
}

variable "dns_suffix_list" {
  type = list(string)
  default = []
}

variable "time_zone" {
  description = "(Optional) Sets the time zone. The default is UTC."
  type = string
  default = "UTC"  
}

variable "template" {
  default = null
} 

variable "virtual_machines" {
  type = map(object({
	host_name       = string
	num_cpus        = number
	memory          = number
	dns_server_list = list(string)

	networking = object({
	  gateway = string

	  interfaces = list(object({
		portgroup = string
		ipv4_address = string
		ipv4_netmask  = string
	  }))
	})
  }))
}

`

Here is the vSphere VM block:

`

data "vsphere_datacenter" "datacenter" {
  name = var.vcenter_datacenter
}

data "vsphere_compute_cluster" "cluster" {
  name          = var.vcenter_cluster
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_datastore" "datastore" {
  name          = var.vcenter_datastore
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_network" "network" {
  for_each      = var.virtual_machines
  name          = each.value.networking.interfaces.portgroup
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_virtual_machine" "template" {
  name          = var.template
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

resource "vsphere_virtual_machine" "vm" {
  for_each         = var.virtual_machines
  
  name             = "${var.site}${var.env}${each.key}"
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id     = data.vsphere_datastore.datastore.id
  folder           = var.vm_folder

  num_cpus         = each.value.num_cpus
  memory           = each.value.memory
  guest_id         = data.vsphere_virtual_machine.template.guest_id
  #annotation      = each.value.annotation

  disk {
	label            = "disk0"
	size             = data.vsphere_virtual_machine.template.disks[0].size
	thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned
  }

  dynamic "network_interface" {
	for_each = var.virtual_machines.networking

	content{
	  network_id   = data.vsphere_network.network[each.key].id
	  adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
	}
  }

  clone {
	template_uuid = data.vsphere_virtual_machine.template.id

	customize {
	  linux_options {
		host_name = "${var.site}${var.env}${each.value.host_name}"
		domain    = var.domain
		time_zone = var.time_zone
	  }

		  dynamic "network_interface" {
			  for_each = var.virtual_machines.networking

			  content {
		  ipv4_address = each.value.ipv4_address
		  ipv4_netmask = each.value.ipv4_netmask
			}
		  }
	  
	  ipv4_gateway    = var.virtual_machines.networking.gateway
	  dns_server_list = length(each.value.dns_server_list) != 0 ? each.value.dns_server_list : null
	  dns_suffix_list = length(var.dns_suffix_list) != 0 ? var.dns_suffix_list : null
	}
  }
}

`

To test values I simply use an auto.tfvars file like below:
`

vcenter_datacenter = "uk_test"
vcenter_cluster    = "cluster-test"
vcenter_datastore  = "ds-test"

site               = "uk_test_a"
env                = "nprd"
domain             = "test.local"
time_zone          = "Europe/London"

template           = "linux-rhel8-core-x64-packer"

virtual_machines = {
  "vmtest01" = {
	host_name = "vmtest01"
	dns_server_list = ["8.8.8.8", "8.8.4.4"]
	
	num_cpus = 2
	memory = 2048

	networking = {
	  gateway = "1.1.1.1"

	  interfaces = [ 
		{ # First NIC 
		  ipv4_address = "44.33.22.11"
		  ipv4_netmask = 24
		  portgroup = "apps|a"
		},
		{ # Second NIC DHCP
		  ipv4_address = ""
		  ipv4_netmask = ""
		  portgroup = "apps|b"
		} 
	  ]
	}
  },
  "vmtest02" = {
	host_name = "vmtest01"
	dns_server_list = [] # DHCP

	num_cpus = 2
	memory = 2048

	networking = {
	  gateway = ""

	  interfaces = [ 
		{ # NIC with DHCP
		  ipv4_address = ""
		  ipv4_netmask = ""
		  portgroup = "apps|b"
		} 
	  ]
	}
  }
}

`
I am aware I need to do the following:

  • Reference the network or portgroup as of the vsphere_network data block.
  • Have two dynamic network interface blocks. One to define interfaces as part of a resource and another to configure them as part of cloning.

I know the syntax for the dynamic interface blocks is wrong as is the syntax for the gateway and the network data block. I have tried reading several guides and examples but this has now completely whooshed over my head. I simply cannot decipher it any further with my current ability. It gets even more confusing as I think I can use the flatten() function as well as for expression.

Many thanks for your time and patience to assist!