Reputation: 13
Question: How can I iterate through a nested map to assign string values for a data resource block?
Context: Working on a requirement to deploy multiple VMs via OVA template using the vsphere provider 2.0 on terraform.
As the network interfaces will vary according to the environment, the OVA template will only include the "global" network interface common to all VMs in any environment.
I am using the vsphere_network data resource to retrieve the distributed virtual port group ID for each network interface being assigned to the VMs.
Currently stuck on a variable interpolation to iterate through this info to assign to each vm resource in terraform.
1 vsphere network data block to iterate all DVPG ids, and 1 vm resource block to deploy all vms with those DVPGs using dynamic network interface block
VM Configuration Variable:
variable "vmconfig" {
description = "Map of VM name => Configs "
type = map(object({
name = string
cpus = number
memory = number
folder = string
remote_ovf = string
netint = map(string)
}))
default = {}
}
.tfvars:
vmconfig = {
"vm1" = {
name = "vm1"
cpus = 4
memory = 16384
folder = "foo/bary"
remote_ovf = "foo.bar.ova"
netint = {
nic1 = "segment1",
nic2 = "segment2",
nic3 = "segment3",
nic4 = "segment4"
}
},
"vm2" = {...}, etc.
Calling the variable above into a local var:
locals {
vm_values = { for name, config in var.vmconfig : name => {
vm_name = config.name
num_cpus = config.cpus
memory = config.memory
folder = config.folder
remote_ovf_url = config.remote_ovf
netint = config.netint
}
}
}
Trying to iterate through each value for netint inside the data resource block using for_each instead of count(listed as best practices for the vm type being deployed):
data "vsphere_network" "nicint" {
for_each = local.vm_values
name = each.value.netint
datacenter_id = data.vsphere_datacenter.dc.id
}
This data resource block is then called inside the VM resource block using dynamic:
resource "vsphere_virtual_machine" "vm" {
.
.
.
dynamic "network_interface" {
for_each = data.vsphere_network.nicint
content {
network_id = network_interface.value.id
}
}
}
The issue I'm having is iterating through each value inside netint, I get the inkling that I might be missing something trivial here, would appreciate your support in defining that for_each iteration accurately so that multiple vsphere_network data sources are available programmatically using that one data block.
I have tried the following variations for iterating in the data block:
data "vsphere_network" "nicint" {
for_each = {for k,v in local.vm_values : k => v.netint}
name = each.value
datacenter_id = data.vsphere_datacenter.dc.id
}
Error I get is: Inappropriate value for attribute "name": string required each.value is a map of string with 4 elements
I tried using merge, it works! BUT it ended up creating duplicates for each VM and wouldn't modify an existing resource, but destroy and create another.
Another local variable created to map the network interface segments:
netint_map = merge([
for vmtype, values in var.vmconfig:
{
for netint in values.netint:
"${vmtype}-${netint}" => {vmtype = vmtype, netint = netint}
}
]...)
data "vsphere_network" "nicint" {
for_each = local.netint_map
name = each.value
datacenter_id = data.vsphere_datacenter.dc.id
}
Dear Hivemind, please guide me to optimize this effectively - thank you!!
Upvotes: 1
Views: 1924
Reputation: 238081
Your merge is correct. So I just post it here for reference:
locals {
netint_map = merge([
for vmtype, values in var.vmconfig:
{
for netint in values.netint:
"${vmtype}-${netint}" => {vmtype = vmtype, netint = netint}
}
]...)
}
data "vsphere_network" "nicint" {
for_each = local.netint_map
name = each.value
datacenter_id = data.vsphere_datacenter.dc.id
}
I think the issue is with your dynamic block. namely, instead of for_each = data.vsphere_network.nicint
you should iterate over nicint
from your variable, not data source.
resource "vsphere_virtual_machine" "vm" {
for_each = var.vmconfig
#...
dynamic "network_interface" {
for_each = toset(each.value.netint)
content {
network_id = data.vsphere_network.nicint["${each.key}-${network_interface.key}"].id
}
}
}
Upvotes: 1