This program was built to workaround the Terraform VMware Cloud Director Provider's inability to set extraConfig guestInfo properties for vCloud VMs.
Support setting guestInfo properties on extraConfig (#822)
This program uses the pyVmomi library to set the properties on guestInfo.
It can be packaged as a single executable using PyInstaller and then called using a Terraform local-exec provisioner.
pipenv install --python "C:\Python38\python.exe"
pipenv shell
python build-pyinstaller.py
A command line and Terraform example are provided.
Set-Location ".\dist"
# credentials
$user = "user"
$password = "password"
# the vcenter attached to the VCD
$vcenterServer = "server-address"
# VDC Organization
$vcdOrg = "vcd-org"
# name of the VM
$vmName = "vm-name"
# gzip+base64 encoded metadata
$metadata = "H4sIAPgThGIC/zTLsQqAMAwE0H/JbAZXt35KaAsW2qQkEQfx321Ft+Pd3QWUWmHsZHaKJthgRlg+PywrU8vDw4RiruSiY1DYnDhmLPMVesd1aJVIFXcx/29vcT8AAAD//wMAIYa2rGkAAAA="
# a path to a file with gzip+base64 encoded userdata;
# required because of the typical length of userdata (and the limitation for cmd line arg size)
$userdataFilePath = "C:\temp\userdata.txt"
./set-vm-guestinfo.py.exe -s $vcenterServer -nossl -u $user -p $password -v $vmName --vcd-org $vcdOrg --encoded-metadata $metadata --encoded-userdata-file "$userdataFilePath"
Parts of the configuration have been omitted or changed for brevity.
variable "vcenter_server" {
description = "The server address for the vcenter attached to vcd"
}
variable "vcenter_username" {
description = "The username for the account for sufficient access to the vcenter attached to vcd"
}
variable "vcenter_password" {
description = "The password for the account with sufficient access to the vcenter attached to vcd"
sensitive = true
}
variable "vcd_org" {
description = "The name of the VCD Organization"
}
variable "vm_name" {
description = "The name for the VM"
}
variable "config_file_content" {
description = "The encoded content that will be written as a file on the guest OS"
type = string
default = ""
}
variable "shell_script_content" {
description = "The string content of the shell script that will be provided to the guest OS (bootstrapper script)"
type = string
default = ""
}
locals {
# this data will be read by cloudbase-init's vmware guestinfo service
# https://cloudbase-init.readthedocs.io/en/latest/services.html#vmware-guestinfo-service
guestinfo_metadata = base64gzip(jsonencode({
"instance-id" : var.vm_name,
"local-hostname" : SomeComputerName,
"admin-username" : Administrator,
"admin-password" : SomePassword
}))
userdata_filename = "${path.module}/${var.vm_name}_userdata"
}
# data that represents a cloudinit configuration
# separated into two parts:
# (1) cloud-config
# (a) sets the time_zone
# (b) writes the calling module provided content to the VM disk
# (2) calling module provided shell script (bootstrap)
data "template_cloudinit_config" "cloudinit" {
gzip = true
base64_encode = true
part {
content_type = "text/cloud-config"
content = <<-EOF
#cloud-config
set_timezone: America/Los_Angeles
write_files:
- encoding: gzip+base64
content: |
${var.config_file_content}
path: C:\Destination
permissions: 755
EOF
}
part {
filename = bootstrap.ps1
content_type = "text/x-shellscript"
content = var.shell_script_content
}
}
# saves the rendered output of the template_cloudinit_config resource
# to a file. The userdata is typically large, so it can't be passed
# to the set_vm_guestinfo.py.exe scripts via environment variables or the cmd line
resource "local_file" "userdata_file" {
content = data.template_cloudinit_config.cloudinit.rendered
filename = local.userdata_filename
}
# creates a vm in a vApp
resource "vcd_vapp_vm" "vapp_vm" {
vapp_name = var.vapp_name
name = var.vm_name
catalog_name = var.catalog_name
template_name = var.template_name
cpus = var.vm_cpus
memory = var.vm_memory * 1024
power_on = var.power_on
}
resource "null_resource" "guestinfo" {
depends_on = [vcd_vapp_vm.vapp_vm]
# this command is idempotent
provisioner "local-exec" {
command = "${path.module}/set-vm-guestinfo.py.exe -s ${var.vcenter_server} -nossl -u ${vcenter_username} -p {$vcenter_password} -v ${var.vm_name} --vcd-org ${var.vcd_org} --encoded-metadata ${local.guestinfo_metadata} --encoded-userdata-file ${local.userdata_filename}"
interpreter = ["PowerShell", "-Command"]
}
}