Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Using terraform to clone a virtual machine on VMware vSphere infrastructure

This is a example script to clone and deploy multiple Linux vCenter Virtual Machines on VMware vSphere vCenter server infrastructure using hashicorp terraform scripts. In my VMware infrastructure I already have configured virtual datacenter, cluster, network and datastore. There is Linux VM template exists in the infrastructure. This template will be used to clone new VMs.

Here I have 4 terraform code files written. First file contains 3 variables and it has vCenter server FQDN/IP, username and password mentioned which will be used to authenticate to vCenter server.

Download this this script here Terraform_vSphere_Clone_Linux_VM.zip or it is also available on github.com/janviudapi.

#Login information for vCenter Server:- credential.tf
variable "vCenter_user" {
  description = "Username to connect to vCenter Server"
  type        = string
  default     = "administrator@vsphere.local"
}

variable "vCenter_password" {
  description = "Password to connect to vCenter Server"
  type        = string
  default     = "Computer@123"
}

variable "vCenter_server" {
  description = "IP or DNS name to connect to vCenter server"
  type        = string
  default     = "192.168.34.20"
}

Second file is for vSphere Provider which will download required Terraform vSphere plugins from hashicorp repository and login to vCenter server.

#vSphere Provider and login to vCenter server:- provider.tf
terraform {
  required_providers {
    vsphere = {
      source = "hashicorp/vsphere"
      #version = ">= x.y.z"
    }
  }
  #required_version = ">= 0.13"
}

provider "vsphere" {
  user                 = var.vCenter_user
  password             = var.vCenter_password
  vsphere_server       = var.vCenter_server
  allow_unverified_ssl = true
}

In the next file I have mentioned datacenter, cluster, virtual network, datastore variables names where cloned VM will be created using VM template name. For new virtual machines information I have mentioned hash table map. In the table I mentioned new names of the VM, CPU and memory.

#vCenter Server infrastructure and new VM entity information:- variable.tf
variable "datacenter" {
  description = "Virtual Datacenter name where VM will be placed"
  type        = string
  default     = "Asgard"
}

variable "cluster" {
  description = "Password to connect to vCenter Server"
  type        = string
  default     = "Bifrost"
}

variable "network" {
  description = "IP or DNS name to connect to vCenter server"
  type        = string
  default     = "VM Network"
}

variable "datastore" {
  description = "IP or DNS name to connect to vCenter server"
  type        = string
  default     = "StarLord_Datastore01"
}

variable "template" {
  description = "IP or DNS name to connect to vCenter server"
  type        = string
  default     = "Wakanda_Ubuntu_01"
}

variable "vminfo" {
  type = map(object({
    vm     = string
    cpu    = string
    memory = string
  }))
  default = {
    "dev" = {
      vm     = "galaxy"
      cpu    = "1"
      memory = "1024"
    }
    "prod" = {
      vm     = "gardian"
      cpu    = "2"
      memory = "2048"
    }
  }
}

In the last main.tf file, I have mentioned actual code to clone and deploy virtual machines. I am not creating new datacenter, cluster, network, datastore and template, instead gathering information from existing VMware entities as terraform datasource, and will be using same information to create VMs.

#New Virtual Machine cloning deployment core code:- main.tf
data "vsphere_datacenter" "datacenter" {
  name = var.datacenter
}

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

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

data "vsphere_datastore" "datastore" {
  name          = var.datastore
  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.vminfo
  name             = each.value["vm"]
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id     = data.vsphere_datastore.datastore.id
  num_cpus         = each.value["cpu"]
  memory           = each.value["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]
  }
  disk {
    label            = "${each.value["vm"]}-disk0"
    size             = data.vsphere_virtual_machine.template.disks.0.size
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
  }
  clone {
    template_uuid = data.vsphere_virtual_machine.template.id
    customize {
      linux_options {
        host_name = each.value["vm"]
        domain    = "example.com"
      }
      network_interface {
        #  ipv4_address = "172.16.11.10"
        #  ipv4_netmask = 24
      }
      #ipv4_gateway = "172.16.11.1"
    }
  }
}

Create all files under one folder and run the command terraform init to initialize the project and it will download required vSphere plugins for terraform. It will also do the basic validation of the .tf script files as there are no basic errors.

Terraform VMware vSphere esxi vcenter clone virutalization hashicorp vcenter server vcsa devops appliance new virtual machine cloning template virtual network datastore cluster datastore .jpg

PS E:\Scripts\Terraform\ritesh\vm_creation> terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/vsphere from the dependency lock file
- Using previously-installed hashicorp/vsphere v2.2.0

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
PS E:\Scripts\Terraform\ritesh\vm_creation>

Run terraform plan to see if any changes are required in the VMware infrastructure, it will gather the information.

PS E:\Scripts\Terraform\ritesh\vm_creation> terraform plan

To actual create clone VMs in on vCenter server run command terraform apply --auto-approve, it takes some time to deploy.

Check to resolve the error: Terraform VMware vSphere Virtual Machine cloning Operating system not found

PS E:\Scripts\Terraform\ritesh\vm_creation> terraform apply --auto-approve
data.vsphere_datacenter.datacenter: Reading...
data.vsphere_datacenter.datacenter: Read complete after 0s [id=datacenter-3]
data.vsphere_network.network: Reading...
data.vsphere_datastore.datastore: Reading...
data.vsphere_compute_cluster.cluster: Reading...
data.vsphere_virtual_machine.template: Reading...
data.vsphere_network.network: Read complete after 0s [id=network-12]
data.vsphere_datastore.datastore: Read complete after 0s [id=datastore-11]     
data.vsphere_compute_cluster.cluster: Read complete after 0s [id=domain-c13001]
data.vsphere_virtual_machine.template: Read complete after 0s [id=422a010e-6459-05cb-38fb-6360bbda149b]
vsphere_virtual_machine.vm["prod"]: Refreshing state... [id=4202778d-02c9-339f-0d11-b3c7ca779ba3]
vsphere_virtual_machine.vm["dev"]: Refreshing state... [id=42023dd7-f6a7-9e25-ebba-1489493fe2de]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # vsphere_virtual_machine.vm["dev"] will be created
  + resource "vsphere_virtual_machine" "vm" {
      + annotation                              = (known after apply)
      + boot_retry_delay                        = 10000
      + change_version                          = (known after apply)
      + cpu_limit                               = -1
      + cpu_share_count                         = (known after apply)
      + cpu_share_level                         = "normal"
      + datastore_id                            = "datastore-11"
      + default_ip_address                      = (known after apply)
      + ept_rvi_mode                            = "automatic"
      + firmware                                = "bios"
      + force_power_off                         = true
      + guest_id                                = "ubuntu64Guest"
      + guest_ip_addresses                      = (known after apply)
      + hardware_version                        = (known after apply)
      + host_system_id                          = (known after apply)
      + hv_mode                                 = "hvAuto"
      + id                                      = (known after apply)
      + ide_controller_count                    = 2
      + imported                                = (known after apply)
      + latency_sensitivity                     = "normal"
      + memory                                  = 1024
      + memory_limit                            = -1
      + memory_share_count                      = (known after apply)
      + memory_share_level                      = "normal"
      + migrate_wait_timeout                    = 30
      + moid                                    = (known after apply)
      + name                                    = "galaxy"
      + num_cores_per_socket                    = 1
      + num_cpus                                = 1
      + power_state                             = (known after apply)
      + poweron_timeout                         = 300
      + reboot_required                         = (known after apply)
      + resource_pool_id                        = "resgroup-13002"
      + run_tools_scripts_after_power_on        = true
      + run_tools_scripts_after_resume          = true
      + run_tools_scripts_before_guest_shutdown = true
      + run_tools_scripts_before_guest_standby  = true
      + sata_controller_count                   = 0
      + scsi_bus_sharing                        = "noSharing"
      + scsi_controller_count                   = 1
      + scsi_type                               = "lsilogic"
      + shutdown_wait_timeout                   = 3
      + storage_policy_id                       = (known after apply)
      + swap_placement_policy                   = "inherit"
      + tools_upgrade_policy                    = "manual"
      + uuid                                    = (known after apply)
      + vapp_transport                          = (known after apply)
      + vmware_tools_status                     = (known after apply)
      + vmx_path                                = (known after apply)
      + wait_for_guest_ip_timeout               = 0
      + wait_for_guest_net_routable             = true
      + wait_for_guest_net_timeout              = 5

      + clone {
          + template_uuid = "422a010e-6459-05cb-38fb-6360bbda149b"
          + timeout       = 30

          + customize {
              + timeout = 10

              + linux_options {
                  + domain       = "example.com"
                  + host_name    = "galaxy"
                  + hw_clock_utc = true
                }

              + network_interface {}
            }
        }

      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = ""
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "galaxy-disk0"
          + path              = (known after apply)
          + size              = 100
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 0
          + uuid              = (known after apply)
          + write_through     = false
        }

      + network_interface {
          + adapter_type          = "e1000"
          + bandwidth_limit       = -1
          + bandwidth_reservation = 0
          + bandwidth_share_count = (known after apply)
          + bandwidth_share_level = "normal"
          + device_address        = (known after apply)
          + key                   = (known after apply)
          + mac_address           = (known after apply)
          + network_id            = "network-12"
        }
    }

  # vsphere_virtual_machine.vm["prod"] will be created
  + resource "vsphere_virtual_machine" "vm" {
      + annotation                              = (known after apply)
      + boot_retry_delay                        = 10000
      + change_version                          = (known after apply)
      + cpu_limit                               = -1
      + cpu_share_count                         = (known after apply)
      + cpu_share_level                         = "normal"
      + datastore_id                            = "datastore-11"
      + default_ip_address                      = (known after apply)
      + ept_rvi_mode                            = "automatic"
      + firmware                                = "bios"
      + force_power_off                         = true
      + guest_id                                = "ubuntu64Guest"
      + guest_ip_addresses                      = (known after apply)
      + hardware_version                        = (known after apply)
      + host_system_id                          = (known after apply)
      + hv_mode                                 = "hvAuto"
      + id                                      = (known after apply)
      + ide_controller_count                    = 2
      + imported                                = (known after apply)
      + latency_sensitivity                     = "normal"
      + memory                                  = 2048
      + memory_limit                            = -1
      + memory_share_count                      = (known after apply)
      + memory_share_level                      = "normal"
      + migrate_wait_timeout                    = 30
      + moid                                    = (known after apply)
      + name                                    = "gardian"
      + num_cores_per_socket                    = 1
      + num_cpus                                = 2
      + power_state                             = (known after apply)
      + poweron_timeout                         = 300
      + reboot_required                         = (known after apply)
      + resource_pool_id                        = "resgroup-13002"
      + run_tools_scripts_after_power_on        = true
      + run_tools_scripts_after_resume          = true
      + run_tools_scripts_before_guest_shutdown = true
      + run_tools_scripts_before_guest_standby  = true
      + sata_controller_count                   = 0
      + scsi_bus_sharing                        = "noSharing"
      + scsi_controller_count                   = 1
      + scsi_type                               = "lsilogic"
      + shutdown_wait_timeout                   = 3
      + storage_policy_id                       = (known after apply)
      + swap_placement_policy                   = "inherit"
      + tools_upgrade_policy                    = "manual"
      + uuid                                    = (known after apply)
      + vapp_transport                          = (known after apply)
      + vmware_tools_status                     = (known after apply)
      + vmx_path                                = (known after apply)
      + wait_for_guest_ip_timeout               = 0
      + wait_for_guest_net_routable             = true
      + wait_for_guest_net_timeout              = 5

      + clone {
          + template_uuid = "422a010e-6459-05cb-38fb-6360bbda149b"
          + timeout       = 30

          + customize {
              + timeout = 10

              + linux_options {
                  + domain       = "example.com"
                  + host_name    = "gardian"
                  + hw_clock_utc = true
                }

              + network_interface {}
            }
        }

      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = ""
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "gardian-disk0"
          + path              = (known after apply)
          + size              = 100
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 0
          + uuid              = (known after apply)
          + write_through     = false
        }

      + network_interface {
          + adapter_type          = "e1000"
          + bandwidth_limit       = -1
          + bandwidth_reservation = 0
          + bandwidth_share_count = (known after apply)
          + bandwidth_share_level = "normal"
          + device_address        = (known after apply)
          + key                   = (known after apply)
          + mac_address           = (known after apply)
          + network_id            = "network-12"
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.
vsphere_virtual_machine.vm["prod"]: Creating...
vsphere_virtual_machine.vm["dev"]: Creating...
vsphere_virtual_machine.vm["prod"]: Still creating... [10s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [10s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [20s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [20s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [30s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [30s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [40s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [40s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [50s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [50s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m0s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m0s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m10s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m10s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m20s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m20s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m30s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m30s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m40s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m40s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [1m50s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [1m50s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m0s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m0s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m10s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m10s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m20s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m20s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m30s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m30s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m40s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m40s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [2m50s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [2m50s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [3m0s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m1s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [3m10s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m11s elapsed]
vsphere_virtual_machine.vm["prod"]: Still creating... [3m20s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m21s elapsed]
vsphere_virtual_machine.vm["prod"]: Creation complete after 3m25s [id=4202422c-016b-7f0f-1f54-9eb75f68793f]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m31s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m41s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [3m51s elapsed]
vsphere_virtual_machine.vm["dev"]: Still creating... [4m1s elapsed]
vsphere_virtual_machine.vm["dev"]: Creation complete after 4m4s [id=4202d570-026d-f9a8-f662-43d63da83e1d]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
PS E:\Scripts\Terraform\ritesh\vm_creation>

While terraform is getting deploying VMs, you can verify in the vSphere Client (vCenter Portal), VMs are getting created in the recent tasks and check the VM hardware.

VMware vSphere vCenter vcsa server vsphere client virtual machine clone create customize reconfiguration hcl hashicop datastore network cpu memory vm hardware snpshots permissions updates tfvar script devops automation.jpg

Useful Articles
Terraform module clone VMware vSphere Linux and Windows virtual machine
VMWARE VSPHERE UPDATE MANAGER (VUM) - IMPORTING ESXI ISO AND CREATE UPGRADE BASELINE 
VMWARE VSPHERE UPDATE MANAGER (VUM) - UPGRADE ESXI OS 
ESXi 6.0 update offline bundle via esxcli commandline: DependencyError VIB bootbank requires VSAN ImageProfile
ESXi 6.5 upgrade bundle via command line: No Space Left On Device Error
Registering HPE ILO amplifier pack (Hardware support manager) with vCenter 7 Lifecycle manager
VMware LifeCycle Manager import updates bundle and patch ESXi server
How to update a patch on an ESXi host via command line
Add a Trusted Root Certificate to the Certificate Store VMware Photon OS
Patching update VMware vCenter Server Appliance from a zipped update bundle Web server
Powershell GUI VMware ESXi custom patch bundle builder
Create a custom TCPIP stack on ESXi server - VMware PowerCLI GUI

Go Back



Comment

Blog Search

Page Views

11383119

Follow me on Blogarama