Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform interpolation data sources

Tags:

terraform

I am configuring Terraform to provision virtual machines in VMware. Each VM will be assigned a second network adapter connected with a specific VLAN. The VLAN is assigned based on the name of the VM

The data sources seem to query just fine, as they all exist. However, I cannot pass the count.index into the network_id in the network_interface section. I have already tried the following:

  1. network_id = "${data.vsphere_network.network1."${var.policy_name}".id}"

  2. network_id = "${"${format("%s", "data.vsphere_network.network1.${count.index}.id")}"}"

  3. network_id = "${format("%s", "$${data.vsphere_network.network1.${count.index}.id")}"

The only way it works is if I directly assign:

network_id = "${data.vsphere_network.network1.0.id}"

where 0 is the instance.

 data "vsphere_network" "network1" {
  count = "${var.count}"
  name = "${var.network_name1}-${format("%02d", count.index + var.start_index)}"
  datacenter_id = "${data.vsphere_datacenter.datacenter.id}"
 }


 network_interface {
    network_id = "${data.vsphere_network.network1.0.id}" 
    adapter_type = "vmxnet3"
    use_static_mac = "${var.static_mac}"
 }

I expect VLAN 01 to be assigned to VM01. VLAN 02 to be assigned to VM02, going all the way up to 48(since that is the number of VLANs I have)

like image 721
szn Avatar asked Mar 17 '26 06:03

szn


1 Answers

The following example uses Terraform 0.12 features to declare that there should be one instance per network and to identify each instance by its network id so that adding and removing networks in future will cause the appropriate instances to be added/removed too:

data "vsphere_network" "network1" {
  count = var.count
  name = "${var.network_name1}-${format("%02d", count.index + var.start_index)}"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

resource "vsphere_virtual_machine" "per_network" {
  # Create one VM per network and identify them using the
  # id value of each one.
  for_each = { for net in data.vsphere_network.network1 : net.id => net }

  # (...other virtual machine arguments...)

  network_interface {
    # each.key is the key from the map in for_each, which is
    # the network id in this case
    network_id = each.key
  }
}

Using for_each here has two key advantages:

  • It makes it clearer to a future reader that the intent is to create one VM per network, because the network data resource is referenced directly in the for_each expression.

  • It allows you to choose the keys by which Terraform will identify each of the instances when it tracks them in the state. Because the virtual machines are uniquely identified by their networks in this case, we use the network interface id and thus Terraform will be able to infer correctly that e.g. adding a new network should cause a new VM to be created, and removing a network should cause only the corresponding VM to be destroyed.

like image 116
Martin Atkins Avatar answered Mar 22 '26 00:03

Martin Atkins