Hello kind strangers,
Through Googling and guides, I have managed to get to a stage where Terraform can successfully plan several vSphere VM resources. This is done using for_each
through maps. I would love to expand this by optionally including additional interfaces.
I expanded the map of objects to include sub-objects - if I can call it this, pardon me if not - that allows the definition of additional interfaces as seen below. I am aware that we cannot configure secondary, tertiary etc. gateways so hence why only one gateway element is defined.
`
variable "vcenter_datacenter" {
}
variable "vcenter_cluster" {
}
variable "vcenter_datastore" {
}
variable "site" {
}
variable "env" {
}
variable "domain" {
}
variable "vm_folder" {
default = "templates"
}
variable "dns_suffix_list" {
type = list(string)
default = []
}
variable "time_zone" {
description = "(Optional) Sets the time zone. The default is UTC."
type = string
default = "UTC"
}
variable "template" {
default = null
}
variable "virtual_machines" {
type = map(object({
host_name = string
num_cpus = number
memory = number
dns_server_list = list(string)
networking = object({
gateway = string
interfaces = list(object({
portgroup = string
ipv4_address = string
ipv4_netmask = string
}))
})
}))
}
`
Here is the vSphere VM block:
`
data "vsphere_datacenter" "datacenter" {
name = var.vcenter_datacenter
}
data "vsphere_compute_cluster" "cluster" {
name = var.vcenter_cluster
datacenter_id = data.vsphere_datacenter.datacenter.id
}
data "vsphere_datastore" "datastore" {
name = var.vcenter_datastore
datacenter_id = data.vsphere_datacenter.datacenter.id
}
data "vsphere_network" "network" {
for_each = var.virtual_machines
name = each.value.networking.interfaces.portgroup
datacenter_id = data.vsphere_datacenter.datacenter.id
}
data "vsphere_virtual_machine" "template" {
name = var.template
datacenter_id = data.vsphere_datacenter.datacenter.id
}
resource "vsphere_virtual_machine" "vm" {
for_each = var.virtual_machines
name = "${var.site}${var.env}${each.key}"
resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
datastore_id = data.vsphere_datastore.datastore.id
folder = var.vm_folder
num_cpus = each.value.num_cpus
memory = each.value.memory
guest_id = data.vsphere_virtual_machine.template.guest_id
#annotation = each.value.annotation
disk {
label = "disk0"
size = data.vsphere_virtual_machine.template.disks[0].size
thin_provisioned = data.vsphere_virtual_machine.template.disks[0].thin_provisioned
}
dynamic "network_interface" {
for_each = var.virtual_machines.networking
content{
network_id = data.vsphere_network.network[each.key].id
adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
}
}
clone {
template_uuid = data.vsphere_virtual_machine.template.id
customize {
linux_options {
host_name = "${var.site}${var.env}${each.value.host_name}"
domain = var.domain
time_zone = var.time_zone
}
dynamic "network_interface" {
for_each = var.virtual_machines.networking
content {
ipv4_address = each.value.ipv4_address
ipv4_netmask = each.value.ipv4_netmask
}
}
ipv4_gateway = var.virtual_machines.networking.gateway
dns_server_list = length(each.value.dns_server_list) != 0 ? each.value.dns_server_list : null
dns_suffix_list = length(var.dns_suffix_list) != 0 ? var.dns_suffix_list : null
}
}
}
`
To test values I simply use an auto.tfvars
file like below:
`
vcenter_datacenter = "uk_test"
vcenter_cluster = "cluster-test"
vcenter_datastore = "ds-test"
site = "uk_test_a"
env = "nprd"
domain = "test.local"
time_zone = "Europe/London"
template = "linux-rhel8-core-x64-packer"
virtual_machines = {
"vmtest01" = {
host_name = "vmtest01"
dns_server_list = ["8.8.8.8", "8.8.4.4"]
num_cpus = 2
memory = 2048
networking = {
gateway = "1.1.1.1"
interfaces = [
{ # First NIC
ipv4_address = "44.33.22.11"
ipv4_netmask = 24
portgroup = "apps|a"
},
{ # Second NIC DHCP
ipv4_address = ""
ipv4_netmask = ""
portgroup = "apps|b"
}
]
}
},
"vmtest02" = {
host_name = "vmtest01"
dns_server_list = [] # DHCP
num_cpus = 2
memory = 2048
networking = {
gateway = ""
interfaces = [
{ # NIC with DHCP
ipv4_address = ""
ipv4_netmask = ""
portgroup = "apps|b"
}
]
}
}
}
`
I am aware I need to do the following:
- Reference the network or portgroup as of the
vsphere_network
data block. - Have two dynamic network interface blocks. One to define interfaces as part of a resource and another to configure them as part of cloning.
I know the syntax for the dynamic interface blocks is wrong as is the syntax for the gateway and the network data block. I have tried reading several guides and examples but this has now completely whooshed over my head. I simply cannot decipher it any further with my current ability. It gets even more confusing as I think I can use the flatten()
function as well as for
expression.
Many thanks for your time and patience to assist!