How to import existing VMWare virtual machines into Terraform

Prospective students on the course “Infrastructure as a code in Ansible”, as well as everyone interested, we invite you to take part in an open webinar on the topic “Managing Kubernetes with Kubespray”

And according to the established tradition, we are sharing with you the translation of a useful article.


Terraform Is a terrific tool for automating infrastructure management. All parameters of your infrastructure can be written in the form of a code, which will be maintained by the corresponding group. This means that your infrastructure will be transparent and not subject to unexpected changes.

Originally posted on the blog techbeatly; other related articles are also available there.

Read also: HashiCorp Certified Terraform Associate Curriculum & Tips

You may already know that you can import existing infrastructure into Terraform, and then further manage this infrastructure in Terraform. In general, this is a fairly common process for cloud infrastructure, however, I noticed that some engineers are having difficulties importing their existing VMWare virtual machines. So I wrote this quick tutorial on how to import existing VMWare virtual machines into Terraform. This will be demonstrated using the example of importing one virtual machine.

Step 1. Retrieving information about an existing virtual machine from VMWare vCenter

Log in to VMWare vCenter and locate the virtual machine data. You will need data such as datacenter, virtual machine folder, virtual machine name, cpu, memory, disk etc.

If your virtual machine has special configuration options, such as additional disks, additional network adapters, or non-standard hardware specifications, be sure to include them in the Terraform code.

Step 2. Generating Terraform Code for an Existing Virtual Machine

There is no way in Terraform to import existing infrastructure into Terraform code. Instead, you have to write a Terraform configuration that matches your infrastructure and import it.

Below is the Terraform code I wrote for a virtual machine with the following path and name: /DC1/vm/DEV/DEV2

See file content vmware-import-vm.tf.

provider "vsphere" {
  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 "vsphere_datacenter" "dc" {
  name = "DC1"
}

data "vsphere_datastore" "datastore" {
  name          = "datastore1"
  datacenter_id = data.vsphere_datacenter.dc.id
}

data "vsphere_compute_cluster" "cluster" {
  name          = "AZ1"
  datacenter_id = data.vsphere_datacenter.dc.id
}

data "vsphere_network" "network" {
  name          = "VM Network"
  datacenter_id = data.vsphere_datacenter.dc.id
}

resource "vsphere_virtual_machine" "vm" {
  name             = "DEV2"
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id     = data.vsphere_datastore.datastore.id

  wait_for_guest_net_timeout = 0
  wait_for_guest_ip_timeout  = 0

  # only if you DO NOT want to wait for an IP address
  wait_for_guest_net_routable = false

  num_cpus = 1
  memory   = 2048
  #guest_id = "other3xLinux64Guest"

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

  
  disk {
    label            = "disk0"
    size             = 20
    thin_provisioned = false
  }
}

I have also declared several variables to pass VMWare credentials.

$ cat variables.tf 
variable "vsphereuser" {}
variable "vspherepassword" {}

In this example, I am passing my VMWare vCenter credentials using environment variables (see example below).

$ export TFVARvsphereuser="Administrator@lab.local"
$ export TFVARvspherepassword='mypassword'

Step 3. Initializing the Terraform Code

When the code is ready, it will need to be initialized using the command terraform initwhich will check the environment and install the necessary plugins and providers.

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/vsphere...
- Installing hashicorp/vsphere v1.24.2...
- Installed hashicorp/vsphere v1.24.2 (signed by HashiCorp)

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.

* hashicorp/vsphere: version = "~> 1.24.2"

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.

Let’s check the current state controlled by Terraform:

$ terraform show
No state.

Yes, we haven’t launched yet.

Note. What happens if I execute the command terraform apply? It’s simple, the system will try to allocate resources for the virtual machine, but this attempt will fail. The system will inform you that the virtual machine named DEV2 already exists. Be that as it may, in this example, this is not our case.

Step 4. Import the virtual machine into the Terraform state

So now everything is ready to import our existing virtual machine into Terraform state.

$ terraform import vsphere_virtual_machine.vm /DC1/vm/DEV/DEV2
vsphere_virtual_machine.vm: Importing from ID "/DC1/vm/DEV/DEV2"...
vsphere_virtual_machine.vm: Import prepared!
  Prepared vsphere_virtual_machine for import
vsphere_virtual_machine.vm: Refreshing state... [id=4219040f-5842-ba52-b7e4-cd9064c1f36c]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Done, now our virtual machine is part of the Terraform state and can be manipulated from Terraform by doing things like adding a new interface, a new hard drive, and so on.

This can be verified by running the command terraform show again.

$ terraform show
# vsphere_virtual_machine.vm:
resource "vsphere_virtual_machine" "vm" {
    boot_delay                              = 0
    boot_retry_delay                        = 10000
    boot_retry_enabled                      = false
    change_version                          = "2020-11-03T08:33:13.180937Z"
    cpu_hot_add_enabled                     = false
    cpu_hot_remove_enabled                  = false
    cpu_limit                               = -1
    cpu_performance_counters_enabled        = false
    cpu_reservation                         = 0
    cpu_share_count                         = 1000
    cpu_share_level                         = "normal"
    custom_attributes                       = {}
    datastore_id                            = "datastore-13"
    efi_secure_boot_enabled                 = false
    enable_disk_uuid                        = false
    enable_logging                          = true
    ept_rvi_mode                            = "automatic"
    extra_config                            = {}
    firmware                                = "bios"
    folder                                  = "DEV"
    force_power_off                         = true
    guest_id                                = "rhel7_64Guest"
    guest_ip_addresses                      = []
    hardware_version                        = 14
    host_system_id                          = "host-12"
    hv_mode                                 = "hvAuto"
    id                                      = "4219040f-5842-ba52-b7e4-cd9064c1f36c"
    ide_controller_count                    = 2
    imported                                = true
    latency_sensitivity                     = "normal"
    memory                                  = 2048
    memory_hot_add_enabled                  = false
    memory_limit                            = -1
    memory_reservation                      = 0
    memory_share_count                      = 20480
    memory_share_level                      = "normal"
    migrate_wait_timeout                    = 30
    moid                                    = "vm-47"
    name                                    = "DEV2"
    nested_hv_enabled                       = false
    num_cores_per_socket                    = 1
    num_cpus                                = 1
    pci_device_id                           = []
    poweron_timeout                         = 300
    reboot_required                         = false
    resource_pool_id                        = "resgroup-8"
    run_tools_scripts_after_power_on        = true
    run_tools_scripts_after_resume          = true
    run_tools_scripts_before_guest_reboot   = false
    run_tools_scripts_before_guest_shutdown = true
    run_tools_scripts_before_guest_standby  = true
    sata_controller_count                   = 1
    scsi_bus_sharing                        = "noSharing"
    scsi_controller_count                   = 1
    scsi_type                               = "pvscsi"
    shutdown_wait_timeout                   = 3
    swap_placement_policy                   = "inherit"
    sync_time_with_host                     = false
    tags                                    = []
    uuid                                    = "4219040f-5842-ba52-b7e4-cd9064c1f36c"
    vapp_transport                          = []
    vmware_tools_status                     = "guestToolsRunning"
    vmx_path                                = "DEV2/DEV2.vmx"
    wait_for_guest_ip_timeout               = 0
    wait_for_guest_net_routable             = true
    wait_for_guest_net_timeout              = 5

    cdrom {
        client_device  = false
        datastore_id   = "datastore-13"
        device_address = "sata:0:0"
        key            = 16000
        path           = "ISO/rhel-server-7.7-x86_64-dvd.iso"
    }

    disk {
        attach           = false
        controller_type  = "scsi"
        datastore_id     = "datastore-13"
        device_address   = "scsi:0:0"
        disk_mode        = "persistent"
        disk_sharing     = "sharingNone"
        eagerly_scrub    = false
        io_limit         = -1
        io_reservation   = 0
        io_share_count   = 1000
        io_share_level   = "normal"
        keep_on_remove   = true
        key              = 2000
        label            = "disk0"
        path             = "DEV2/DEV2.vmdk"
        size             = 20
        thin_provisioned = false
        unit_number      = 0
        uuid             = "6000C29b-c4f0-764a-9054-a042931350c4"
        write_through    = false
    }
}

Conclusion

If you plan to manage configuration inside the virtual machine operating system, remember to use the appropriate provisioners

See the resource documentation for details vsphere_virtual_machine

The complete code is available on GitHub in the repository terraform-vmware-demos.


Learn more about the course “Infrastructure as a code in Ansible”

Register for an open lesson on the topic “Managing Kubernetes with Kubespray”

GET A DISCOUNT

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *