How to for_each through a list(objects) in Terraform

1.9k Views Asked by At

i am trying to do for_each in a map(object) type for creating a vsphere vm using terraform. below is the codes that I have written.

instances.tf

resource "vsphere_virtual_machine" "vm" {
  for_each = var.virtual_machines
  # vm-name
  name             = each.key
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  tags             = [data.vsphere_tag.tag[each.key].id]

  guest_id  = data.vsphere_virtual_machine.template.guest_id
  scsi_type = data.vsphere_virtual_machine.template.scsi_type
  # guest_id  = data.vsphere_virtual_machine.template[each.key].guest_id
  # scsi_type = data.vsphere_virtual_machine.template[each.key].scsi_type

  num_cpus = each.value.system_cores

  memory = each.value.system_memory

  wait_for_guest_ip_timeout  = 0
  wait_for_guest_net_timeout = 0

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

  #Storage
  disk {
    label            = each.value.disk_label[0]
    size             = each.value.system_disk_size
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
    # thin_provisioned = data.vsphere_virtual_machine.template[each.key].disks.0.thin_provisioned
  }

  disk {
    label            = each.value.disk_label[1]
    size             = each.value.system_disk_size
    unit_number = 1
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
    # thin_provisioned = data.vsphere_virtual_machine.template[each.key].disks.0.thin_provisioned
  }

  #cloning from template
  clone {
    template_uuid = data.vsphere_virtual_machine.template.id
    # template_uuid = data.vsphere_virtual_machine.template[each.key].id

    customize {
      linux_options {

        host_name = each.value.system_name
        domain    = each.value.system_domain

      }

      network_interface {
        ipv4_address = each.value.system_ipv4_address
        ipv4_netmask = each.value.system_ipv4_netmask
      }

      ipv4_gateway = each.value.system_ipv4_gateway
    }

  }

}

i have declared other values and there is the map(object) i have in variables.tf


variable "virtual_machines" {
  type = map(object({
    system_disk_size     = number
    system_cores         = number
    system_memory        = number
    system_ipv4_address  = string
    system_name          = string
    system_domain        = string
    vsphere_tag_category = string
    vsphere_tag          = string
    disk_label           = list(string)
    system_ipv4_address  = list(string)
  }))

terraform.tfvars

virtual_machines = {
  server-1 = {
    system_cores         = 2
    system_memory        = 2048
    system_ipv4_address  = ""
    system_disk_size     = 140
    system_name          = "terraformvm"
    system_domain        = "example.com"
    vsphere_tag_category = "test_category"
    vsphere_tag          = "test_tag"
    disk_label           = ["disk0", "disk1"]
    system_ipv4_address  = ["ip1", "1p2"]
  }

But i am getting the below error.

│ Error: Incorrect attribute value type
│ 
│   on Instances.tf line 57, in resource "vsphere_virtual_machine" "vm":
│   57:         ipv4_address = each.value.system_ipv4_address
│     ├────────────────
│     │ each.value.system_ipv4_address is list of string with 2 elements
│ 
│ Inappropriate value for attribute "ipv4_address": string required.

can anyone tell me how to access each value in system_ipv4_address? Thanks in advance

2

There are 2 best solutions below

9
On

If you need the whole list

each.value.system_ipv4_gateway[*]

If you need the first element for example

each.value.system_ipv4_gateway[0]

This attribute requires a string, so if you need to use both the ip addresses you need to define multiple interfaces. And apply one element to each one

0
On

the error is in terraform.tfvars, the correct way is written multiples VM stack into statement, this is works for me

virtual_machines = {
  server-1 = {
    system_cores         = 2
    system_memory        = 2048
    system_ipv4_address  = "10.10.10.1"
    system_disk_size     = 140
    system_name          = "terraformvm-1"
    system_domain        = "example.com"
    vsphere_tag_category = "test_category"
    vsphere_tag          = "test_tag"
    disk_label           = ["disk0", "disk1"]
  }
server-2 = {
    system_cores         = 2
    system_memory        = 2048
    system_ipv4_address  = "10.10.10.2"
    system_disk_size     = 140
    system_name          = "terraformvm-2"
    system_domain        = "example.com"
    vsphere_tag_category = "test_category"
    vsphere_tag          = "test_tag"
    disk_label           = ["disk0", "disk1"]
  }