1
votes

I am creating a module for VM creation in VMware, and I'm looking to clone a VM template. The hangup is when adding more disks than just the single disk that the template provides or adding a disk in the future if needed.

I don't know if adding another disk section in the virtual machine resource and setting the variable type to map using interpolation syntax would work.

It would be nice if there was a way to use something like jinja for templating.

Module work in progress:

data "vsphere_datacenter" "dc" {
  name = "${var.vmw_dc}"
}

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

data "vsphere_resource_pool" "pool" {
  name          = "${var.vmw_cluster}"
  datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

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

resource "vsphere_virtual_machine" "vm" {
  name             = "${var.vm_name}"
  resource_pool_id = "${data.vsphere_resource_pool.pool.id}"
  datastore_id     = "${data.vsphere_datastore.datastore.id}"

  num_cpus = "${var.vm_cpu}"
  memory   = "${var.vm_mem}"
  guest_id = "${var.vm_GuestType}"

  network_interface {
    network_id = "${data.vsphere_network.network.id}"
  }

  disk {
    label = "disk0"
    size  = 20
  }
  disk {
    label = "${var.vm_disk.*.label, count.index}"
  }
}

Doing this as a non-module would be easy. Just have a bunch of resource declarations like the above code, or creating a module and just passing the variables through in module per VM needing created.

The above would work for a single disk VM if you ignore the second Disk declaration. But if I need to add the second disk then a second disk declaration is needed and a third and so on.

So I want to be sure, if creating a map or a list of map variable that contains Disk2 through X, then in the second disk declaration the other disks will get rendered when executing terraform plan.

"vm_disk" = {
  Disk2 = {label=X,Size=X,Position=X},
  Disk3 = {label=X,Size=X,Position=X},
  Disk4 = {label=X,Size=X,Position=X},
}
2
Can you post the code you have written and explain how it doesn't do what you want it to do?ydaetskcoR
@ydaetskcoR Edited post to include more information. Just looking if what im thinking is feasible as a module.rmtilson

2 Answers

1
votes

There's not currently a way to have dynamic amounts of sub resources in Terraform so you can't simply use something like:

resource "vsphere_virtual_machine" "vm" {
  ...
  disk {
    count = "${length(var.disks)}"
    ...
  }
}

In other providers such as AWS your module could create an instance without any ebs_block_device sub resources of the aws_instance resource but then use separate aws_ebs_volume resources to create separate disks and then attach with the aws_volume_attachment resource which, because they are all top level resources, allow you to use the count meta parameter to dynamically set the amount of volumes each instance gets.

While the VSphere provider does offer a separate vsphere_virtual_disk resource the only way to attach these separate disk resources to a VM is by using the attach parameter of the disk sub resource so you would be unable to dynamically attach different amounts of disks in your module.

1
votes

Any sub resource in terraform that has the same name, like disk and network for vsphere_virtual_machine, is just an array of objects. So you can change

disk {
  label = "disk0"
  size  = 20
}
disk {
  label = "disk1"
  size  = 20
}

to something like

disk = [
  {
    label = "disk0"
    size = 20
  },
  {
    label = "disk0"
    size = 20
  }
]

From there it's pretty easy to see that you could just create a variable or some other logic that builds the array and just assign it to disks.

disk = ${var.disks}