terraformterraform-provider-vsphere

Vsphere Terraform data source dynamic blocks


I am tryig to create disk using a dynamic block to match my template, everything works fine if I hardcode the disk block like that

  disk {
    label            = "disk0"
    size             = data.vsphere_virtual_machine.template.disks.0.size
    unit_number      = 0
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
  }
  disk {
    label            = "disk1"
    size             = data.vsphere_virtual_machine.template.disks.1.size
    unit_number      = 1
    thin_provisioned = data.vsphere_virtual_machine.template.disks.1.thin_provisioned
  }  
  disk {
    label            = "disk2"
    size             = data.vsphere_virtual_machine.template.disks.2.size
    unit_number      = 2
    thin_provisioned = data.vsphere_virtual_machine.template.disks.2.thin_provisioned
  }  
  disk {
    label            = "disk3"
    size             = data.vsphere_virtual_machine.template.disks.3.size
    
    unit_number      = 3
    
    thin_provisioned = data.vsphere_virtual_machine.template.disks.3.thin_provisioned
  }

However, when using a dynamic block it fails:

     dynamic "disk" {
        for_each = var.disk
        content {
            label = disk.value["label"]
            size = data.vsphere_virtual_machine.template.disks.${disk.value["index"]}.size
            thin_provisioned = data.vsphere_virtual_machine.template.disks.${disk.value["index"]}.thin_provisioned
            unit_number = disk.value["index"]    
        
        }
     }  
variable "disk" {
  description = "My disks. Such disks. Much wow."
    type = list(map(string))
    default = [
    {
      label = "disk0",
      index = 0
      
    },
    {
      label = "disk1",
      index = 1
     
        
    },
    {
      label = "disk2",
      index = 2
      
    },
    {
      label = "disk3",
      index = 3
   
    }
    
    ]
  }

Finally, i know the interpolation is wrong, but it seems i can't find the correct form to replace the disk index by a dynamic value.

Any help on that would be very much apprecated.

EDITED: POSTED THE ENTIRE CODE

provider "vsphere" {
  user                 = var.vsphere_user
  password             = var.vsphere_password
  vsphere_server       = var.vsphere_server
  allow_unverified_ssl = true
  
}


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

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

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

data "vsphere_network" "network" {
  name          = var.portgroup
  datacenter_id = data.vsphere_datacenter.dc.id
}

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

resource "vsphere_virtual_machine" "linux" {
  count             = var.extra_disk_create ? 0 : 1 
  name              = var.vm_name
  resource_pool_id  = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id      = data.vsphere_datastore.datastore.id

  num_cpus = var.vcpu_count
  memory   = var.memory
  guest_id = data.vsphere_virtual_machine.template.guest_id

  scsi_type = data.vsphere_virtual_machine.template.scsi_type

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

  dynamic "disk" {
  for_each = local.disk
    content {
      label            = disk.key
      size             = disk.value.size
      thin_provisioned = disk.value.thin_provisioned
      unit_number      = disk.value.unit_number    
    }
}
  
  clone {
    template_uuid = data.vsphere_virtual_machine.template.id
    linked_clone = "false"

    customize {
      linux_options {
        host_name = var.vm_name
        domain    = var.domain_name
      }

      network_interface {
        ipv4_address = var.vm_ip
        ipv4_netmask = var.vm_cidr
    }

      ipv4_gateway = var.default_gw
      dns_server_list = var.dns_list
      
    }
  }
}

Variables:

variable "vsphere_server" {
  description = "vcentre Server"
}

variable "vsphere_password" {
  description = "Vcentre Password"
}
variable "vsphere_user" {
  description = "Vcentre Username"
}
variable "vm_root_pass" {
  description = "Root password for the VM"
}
variable "datacenter" {
  description = "datacenter name"
}
variable "datastore" {
  description = "datastore name"
}
variable "cluster" {
  description = "cluster name"
}
variable "portgroup" {
  description = "portgroup name"
}
variable "domain_name" {
  description = "domain name"
}
variable "default_gw" {
  description = "domain name"
}
variable "template_name" {
  description = "template to be used"
}

variable "vm_name" {
  description = "vm_name to be used"
}
variable "vm_ip" {
  description = "vm ip to be used"
}
variable "vm_cidr" {
  description = "vm_cidr"

}
variable "vcpu_count" {
  description = "vm_cidr"
}
variable "memory" {
  description = "vm memory in megabytes"
}

variable "disk_name" {
  description = "vm memory in megabytes"
}
variable "adminpassword" {
  description = "vm memory in megabytes"
}
variable "is_windows_image" {
  description = "vm memory in megabytes"
}
variable "extra_disk_size" {
  description = "vm memory in megabytes"
}
variable "disk_size" {
  description = "vm memory in megabytes"
}
variable "dns_list" {
  description = "vm memory in megabytes"
}
variable "extra_disk_create" {
  description = "vm memory in megabytes"
}


variable "extra_disk" {
  description = "My extra disks. Such extra disks. Much wow."

  }

locals {
  disk = {
    disk0 = {
      size             = data.vsphere_virtual_machine.template.disks.0.size
      unit_number      = 0
      thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
    } 
    disk1 = {
      size             = data.vsphere_virtual_machine.template.disks.1.size
      unit_number      = 1
      thin_provisioned = data.vsphere_virtual_machine.template.disks.1.thin_provisioned
    } 
    disk2 = {
      size             = data.vsphere_virtual_machine.template.disks.2.size
      unit_number      = 2
      thin_provisioned = data.vsphere_virtual_machine.template.disks.2.thin_provisioned
    } 
    disk3 = {
      size             = data.vsphere_virtual_machine.template.disks.3.size
      unit_number      = 3
      thin_provisioned = data.vsphere_virtual_machine.template.disks.3.thin_provisioned
    } 
}

Solution

  • That will not work as you cannot use a list with for_each. I would suggest rewriting the variable to have this look and to be a local variable:

    locals {
      disk = {
        disk0 = {
          size             = data.vsphere_virtual_machine.template.disks.0.size
          unit_number      = 0
          thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
        } # repeat this for the rest of the disks
      }
    }
    

    Then in the dynamic block you should set the following:

    dynamic "disk" {
      for_each = local.disk
        content {
          label            = disk.key
          size             = disk.value.size
          thin_provisioned = disk.value.thin_provisioned
          unit_number      = disk.value.unit_number    
        }
    }