I am working on a project where I am building a "stateful" qa environment that incorporates different Win versions that correspond to different sql versions. For example, for Server 2016 I will have 3 servers with each having a different version of sql. Same thing for 2019, and 2022. I have reached the point where it will read the values correctly but then it is giving me this error:
│ Error: Invalid index
│
│ on main.tf line 60, in resource "vsphere_virtual_machine" "vm":
│ 60: guest_id = data.vsphere_virtual_machine.template[each.value.template].guest_id
│ ├────────────────
│ │ data.vsphere_virtual_machine.template is object with 2 attributes
│ │ each.value.template is "Templates/QA_2016"
│
│ The given key does not identify an element in this collection value.
Here is the code:
`
provider "vsphere" {
vim_keep_alive = 30
user = var.vsphere_user
password = var.vsphere_password
vsphere_server = var.vsphere_server
# If you have a self-signed cert
allow_unverified_ssl = true
}
#### data block see local vars
data "vsphere_datacenter" "dc" {
name = local.dc
}
data "vsphere_compute_cluster" "compute_cluster" {
name = local.cluster
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_datastore" "datastore" {
name = local.datastore
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_network" "network" {
for_each = var.vms
name = each.value.network
datacenter_id = data.vsphere_datacenter.dc.id
}
data "vsphere_virtual_machine" "template" {
for_each = var.vms
name = each.value.template
datacenter_id = data.vsphere_datacenter.dc.id
}
##### Resource Block
resource "vsphere_virtual_machine" "vm" {
for_each = var.vms
datastore_id = data.vsphere_datastore.datastore.id
guest_id = data.vsphere_virtual_machine.template[each.value.template].guest_id
resource_pool_id = data.vsphere_compute_cluster.compute_cluster.id
# host_system_id = "${data.vsphere_datacenter.dc.id}"
firmware = data.vsphere_virtual_machine.template[each.value.template].firmware
num_cpus = local.cpu_count
memory = local.memory
scsi_type = data.vsphere_virtual_machine.template[each.value.template].scsi_type
wait_for_guest_net_timeout = -1
name = each.value.name
`
Here is the vars file:
`
locals {
dc = "DC"
cluster = "The Cluster"
datastore = "Storage_thing"
cpu_count = "4"
memory = "16384"
disk_label = "disk0"
disk_size = "250"
disk_thin = "true"
domain = "my.domain"
dns = ["xx.xx.xx.xx", "xx.xx.xx.xx"]
password = "NotMyPass"
auto_logon = true
auto_logon_count = 1
firmware = "efi"
}
#### Name your vm's here - Terraform will provision what is provided here - Add or comment out VM's as needed
variable "vms" {
type = map(any)
default = {
wqawin16sql14 = {
name = "wqawin16sql14"
network = "vm_network"
template = "Templates/QA_2016"
},
wqawin16sql17 = {
name = "wqawin16sql17"
network = "vm_network"
template = "Templates/QA_2016"
},
}
}
`
Terraform is reporting this error because your
data "vsphere_virtual_machine" "template"
block hasfor_each = var.vms
and so the instance keys of that resource are the keys from your map value:"wqawin16sql14"
and"wqawin16sql17"
.That fails because you're trying to look up an instance using the value of the
template
attribute, which is"Templates/QA_2016"
and therefore doesn't match any of the instance keys.It seems like your goal here is to find one virtual machine for each distinct value of the
template
attributes in your input variable, and then use theguest_id
of each of those VMs to populate theguest_id
of the corresponding instance ofresource "vsphere_virtual_machine" "vm"
.If so, you'll need to make the
for_each
for your data resource be a collection where each element represents a template, rather than having each element represent a virtual machine to manage. One way to achieve that would be to calculate the set of all template values across all of your elements ofvar.vm
, like this:Notice that
name
is now set to justeach.value
becausefor_each
is now just a set of template names, liketoset(["Templates/QA_2016"])
, so the values of this collection are just strings rather than objects with attributes.With this change you should then have only one instance of this data resource whose address will be
data.vmware_virtual_machine.template["Templates/QA_2016"]
. This instance key now does match thetemplate
attribute in both of your VM objects, and so the dynamic lookup of the guest ID based on thetemplate
attribute of each VM object should succeed.