WilliamLam.com

  • About
    • About
    • Privacy
  • VMware Cloud Foundation
  • VKS
  • Homelab
    • Resources
    • Nested Virtualization
  • VMware Nostalgia
  • Apple
You are here: Home / Automation / Full OVA/OVF property support coming to Terraform provider for vSphere

Full OVA/OVF property support coming to Terraform provider for vSphere

06.11.2020 by William Lam // 23 Comments

Terraform is one of the most popular Infrastructure as Code (IaC) tool out there today and it should come as no surprise there is Terraform provider for vSphere which many of our customers have been using. In fact, VMware just recently released a couple more new providers (here and here) supporting VMware Cloud on AWS and NSX-T solutions respectively.

Although I have used Terraform and the vSphere provider in the past, it has not been my tool of choice for automation as it still lacks a number of basic vSphere capabilities which I require on a regular basis. The most common one being the ability to deploy a Virtual Appliance (OVA/OVF) which has been my biggest barrier and I know this has been a highly requested feature from the community as well.

In early May of this year, I noticed that v1.18 of the vSphere provider finally added support for OVA/OVF deployment and I was pretty excited to give this a try and may even have been the first to kick the tires on this feature? Although OVA/OVF support was added, it looks like support for customizing OVF properties which is commonly included as part of an OVA/OVF would only possible if you are cloning from an existing imported OVA/OVF image. One of the most common use case is to import an OVF/OVA from either your local computer or from a URL and it looks like this use case was not possible.

I filed two Github issues, one for supporting OVF properties for initial OVA/OVF deployment and another regarding a bug I ran into when importing OVA/OVF from a remote URL. Just yesterday, I got the good news that my feature request has been completed and I was given an early drop of the vSphere provider to try out this feature. I may have also hinted to the Engineering team to use my popular Nested ESXi Appliance OVA as a reference test implementation as I knew this was something many customers will want to deploy ๐Ÿ™‚

UPDATE (11/05/21) - Thanks to Ryan Johnson, it looks like there has been some changes to the Terraform Provider for vSphere in how to deploy OVF/OVA. I've gone ahead an updated the example below to reflect these changes, it certainly looks a bit more verbose than before, which is a bit unfortunate from readability standpoint.

UPDATE (06/23/20) - Support for OVA/OVF properties is now available as part of 1.20 of the Terraform Provider for vSphere

Here is a working example of deploying my Nested ESXi OVA both from my local computer as well as from a remote URL:

terraform {
  required_providers {
    vsphere = {
      source  = "hashicorp/vsphere"
      version = ">= 2.0.2"
    }
  }
  required_version = ">= 1.0.10"
}

provider "vsphere" {
  user           = "*protected email*"
  password       = "VMware1!"
  vsphere_server = "192.168.30.3"
  allow_unverified_ssl = true
}

data "vsphere_datacenter" "datacenter" {
  name = "Primp-Datacenter"
}

data "vsphere_datastore" "datastore" {
  name          = "sm-vsanDatastore"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_compute_cluster" "cluster" {
  name          = "Supermicro-Cluster"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_resource_pool" "default" {
  name          = format("%s%s", data.vsphere_compute_cluster.cluster.name, "/Resources/Workload")
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_host" "host" {
  name          = "192.168.30.5"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

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

data "vsphere_folder" "folder" {
  path = "/${data.vsphere_datacenter.datacenter.name}/vm/Workloads"
}

## Remote OVF/OVA Source
data "vsphere_ovf_vm_template" "ovfRemote" {
  name              = "foo"
  disk_provisioning = "thin"
  resource_pool_id  = data.vsphere_resource_pool.default.id
  datastore_id      = data.vsphere_datastore.datastore.id
  host_system_id    = data.vsphere_host.host.id
  remote_ovf_url    = "https://download3.vmware.com/software/vmw-tools/nested-esxi/Nested_ESXi7.0u3_Appliance_Template_v1.ova"
  ovf_network_map = {
      "VM Network" : data.vsphere_network.network.id
  }
}

## Local OVF/OVA Source
data "vsphere_ovf_vm_template" "ovfLocal" {
  name              = "foo"
  disk_provisioning = "thin"
  resource_pool_id  = data.vsphere_resource_pool.default.id
  datastore_id      = data.vsphere_datastore.datastore.id
  host_system_id    = data.vsphere_host.host.id
  local_ovf_path    = "/Volumes/Storage/Software/Nested_ESXi7.0u3c_Appliance_Template_v1.ova"
  ovf_network_map = {
      "VM Network" : data.vsphere_network.network.id
  }
}

## Deployment of VM from Remote OVF
resource "vsphere_virtual_machine" "vmFromRemoteOvf" {
  name                 = "Nested-ESXi-7.0-Terraform-Deploy-1"
  folder               = trimprefix(data.vsphere_folder.folder.path, "/${data.vsphere_datacenter.datacenter.name}/vm")
  datacenter_id        = data.vsphere_datacenter.datacenter.id
  datastore_id         = data.vsphere_datastore.datastore.id
  host_system_id       = data.vsphere_host.host.id
  resource_pool_id     = data.vsphere_resource_pool.default.id
  num_cpus             = data.vsphere_ovf_vm_template.ovfRemote.num_cpus
  num_cores_per_socket = data.vsphere_ovf_vm_template.ovfRemote.num_cores_per_socket
  memory               = data.vsphere_ovf_vm_template.ovfRemote.memory
  guest_id             = data.vsphere_ovf_vm_template.ovfRemote.guest_id
  scsi_type            = data.vsphere_ovf_vm_template.ovfRemote.scsi_type
  nested_hv_enabled    = data.vsphere_ovf_vm_template.ovfRemote.nested_hv_enabled
  dynamic "network_interface" {
      for_each = data.vsphere_ovf_vm_template.ovfRemote.ovf_network_map
      content {
          network_id = network_interface.value
      }
  }
  wait_for_guest_net_timeout = 0
  wait_for_guest_ip_timeout  = 0

  ovf_deploy {
      allow_unverified_ssl_cert = false
      remote_ovf_url            = data.vsphere_ovf_vm_template.ovfRemote.remote_ovf_url
      disk_provisioning         = data.vsphere_ovf_vm_template.ovfRemote.disk_provisioning
      ovf_network_map           = data.vsphere_ovf_vm_template.ovfRemote.ovf_network_map
  }

vapp {
  properties = {
      "guestinfo.hostname" = "tf-nested-esxi-1.primp-industries.com",
      "guestinfo.ipaddress" = "192.168.30.180",
      "guestinfo.netmask" = "255.255.255.0",
      "guestinfo.gateway" = "192.168.30.1",
      "guestinfo.dns" = "192.168.30.1",
      "guestinfo.domain" = "primp-industries.com",
      "guestinfo.ntp" = "pool.ntp.org",
      "guestinfo.password" = "VMware1!23",
      "guestinfo.ssh" = "True"
      }
  }

  lifecycle {
      ignore_changes = [
      annotation,
      disk[0].io_share_count,
      disk[1].io_share_count,
      disk[2].io_share_count,
      vapp[0].properties,
      ]
  }
}

## Deployment of VM from Local OVF
resource "vsphere_virtual_machine" "vmFromLocalOvf" {
  name                 = "Nested-ESXi-7.0-Terraform-Deploy-2"
  folder               = trimprefix(data.vsphere_folder.folder.path, "/${data.vsphere_datacenter.datacenter.name}/vm")
  datacenter_id        = data.vsphere_datacenter.datacenter.id
  datastore_id         = data.vsphere_datastore.datastore.id
  host_system_id       = data.vsphere_host.host.id
  resource_pool_id     = data.vsphere_resource_pool.default.id
  num_cpus             = data.vsphere_ovf_vm_template.ovfLocal.num_cpus
  num_cores_per_socket = data.vsphere_ovf_vm_template.ovfLocal.num_cores_per_socket
  memory               = data.vsphere_ovf_vm_template.ovfLocal.memory
  guest_id             = data.vsphere_ovf_vm_template.ovfLocal.guest_id
  scsi_type            = data.vsphere_ovf_vm_template.ovfLocal.scsi_type
  nested_hv_enabled    = data.vsphere_ovf_vm_template.ovfLocal.nested_hv_enabled
  dynamic "network_interface" {
      for_each = data.vsphere_ovf_vm_template.ovfLocal.ovf_network_map
      content {
      network_id = network_interface.value
      }
  }
  wait_for_guest_net_timeout = 0
  wait_for_guest_ip_timeout  = 0

  ovf_deploy {
      allow_unverified_ssl_cert = false
      local_ovf_path            = data.vsphere_ovf_vm_template.ovfLocal.local_ovf_path
      disk_provisioning         = data.vsphere_ovf_vm_template.ovfLocal.disk_provisioning
      ovf_network_map           = data.vsphere_ovf_vm_template.ovfLocal.ovf_network_map
  }

  vapp {
      properties = {
          "guestinfo.hostname" = "tf-nested-esxi-2.primp-industries.com",
          "guestinfo.ipaddress" = "192.168.30.181",
          "guestinfo.netmask" = "255.255.255.0",
          "guestinfo.gateway" = "192.168.30.1",
          "guestinfo.dns" = "192.168.30.1",
          "guestinfo.domain" = "primp-industries.com",
          "guestinfo.ntp" = "pool.ntp.org",
          "guestinfo.password" = "VMware1!23",
          "guestinfo.ssh" = "True"
      }
  }

  lifecycle {
      ignore_changes = [
      annotation,
      disk[0].io_share_count,
      disk[1].io_share_count,
      disk[2].io_share_count,
      vapp[0].properties,
      ]
  }
}

With this upcoming capability, I think this really opens up the door for more possibilities and may even convince me to start using Terraform on a more regular basis ๐Ÿ˜‰

I am sure many of you are asking when will this be available and happy to say very soon! It looks like the vSphere provider is roughly on a bi-weekly release cadence, so folks should expect to see this available in the next couple of weeks and I will update this blog post once it is available. I will be curious to learn what folks will be deploying and as always, if you have any feedback feel free to leave it here or better yet, file an issue directly in the Github repo.

More from my site

  • Quick Tip - Certificate is not trusted when importing signed OVF/OVA into vCenter Server
  • Auditing vSphere Datastore activities (Download, Upload, Copy, Move, Rename and Delete)
  • Quick Tip - Dynamic OVF input properties using DeploymentOptions
  • Why does Deploy OVF Template operation show vpxd-extension-[uuid]?
  • How to build a customizable Raspberry Pi OS Virtual Appliance (OVA)?

Categories // Automation, vSphere Tags // ova, ovf, Terraform

Comments

  1. *protectedLuke @ThepHuck says

    06/11/2020 at 3:47 pm

    I played with this about a month ago. The biggest blocker I still have is it only deploys to vCenter. I wanted to use Terraform to deploy directly to ESXi and ended up using govc instead, which then I just went back to pcli ๐Ÿ˜‚

    Reply
  2. *protectedBrad Calvert says

    06/13/2020 at 7:54 am

    Does this have everything needed to deploy a VCSA now?

    Reply
  3. *protectedKarthikeyan Raman says

    07/02/2020 at 4:02 am

    Please help here:

    I'm facing the error when using ovf deploy remote url, retired multiple times but same error

    Im recieving the Error: error while importing ovf/ova template, error while uploading the disk ubuntu-bionic-18.04-cloudimg.vmdk error while uploading the file ubuntu-bionic-18.04-cloudimg.vmdk Post "https://esxihostname/nfc/52664264-2800-4db7-abc4-91b312f3efe9/disk-0.vmdk": dial tcp: lookup esxihostname on 127.0.0.11:53: no such host

    Reply
    • William Lam says

      07/02/2020 at 6:51 am

      Please file any issues you have on the Github Terraform Provider for vSphere https://github.com/hashicorp/terraform-provider-vsphere/issues to get further assistance

      Reply
      • *protectedKarthikeyan Raman says

        07/04/2020 at 2:53 am

        Its a simple issue.. sorted out... Thanks for the help
        https://github.com/hashicorp/terraform-provider-vsphere/issues/1096#issuecomment-653136056

        Reply
  4. *protecteddmalhot1 says

    09/07/2020 at 3:55 am

    In your example:
    properties = {
    "guestinfo.hostname" = "tf-nested-esxi-2.primp-industries.com",

    What is the syntax here . What is "guestinfo" and what is "hostname" ?

    How do I extract the name of the properties for my ova ? I used ovatool to fetch details about it but couldn't make out ?

    Reply
    • William Lam says

      09/07/2020 at 5:53 am

      The syntax is based on what is defined in the OVF properties, which you need to inspect using ovftool or by simply looking at the XML. If its not clear, I suggest you take a look at my example and the Nested ESXi Virtual Appliance to get an idea. As a side note, the property key is the same ones you'd use to pass into ovftool if you've used that to deploy any OVF/OVAs that contain OVF properties, so there is nothing new here with respect to Terraform

      Reply
  5. *protectedMiguel Ruiz says

    10/16/2020 at 4:44 pm

    Hi William Lam,

    I know this is a different topic, but I would like to know if it is possible to access ovf properties from vRA 8 blueprints? I have been trying to inject userdata metadata through guestinfo properties without any luck. Any help will be greatly appreciated.

    Regards

    Reply
    • William Lam says

      10/17/2020 at 6:57 am

      Sorry, I don't work with vRA so I can't say what it can or can't do.

      Reply
  6. *protectedanass bekar says

    11/26/2020 at 5:09 am

    doesn't terraform need a vmdk file to deploy from a local ovf?

    Reply
  7. *protectedJose Garces says

    01/28/2021 at 12:33 pm

    Did you test this on vSphere 7?

    On the GitHub vSphere Provider for Terraform repository it mention that one of the requirements is vSphere 6.5

    "Currently, this provider is not tested for vSphere 7, but plans are underway to add support."

    Reply
  8. *protectedJan Andel says

    02/23/2021 at 11:44 pm

    Cant get this to working, when using exactly your example, the Nested ESXi gets deployed, but with 1gb ram and doesnt boot, when I specify 4GB of ram, it boots without NIC, when i specify to add NIC, it boots ok but none of the vapp config is applied, any idea what could cause this? running it against vcenter 7.0d

    Reply
    • *protectedJan Andel says

      02/24/2021 at 4:26 am

      so, it seems that the initial VM is OK with all config, but once terraform does reconfiguration in vCenter, it sets it to 1cpu, 1gb ram and removes networking.

      Reply
  9. *protectedCicek Adam says

    09/19/2021 at 7:34 am

    Is it possible to pull ova file via smb or another protocol?

    Reply
    • William Lam says

      09/19/2021 at 7:43 am

      No, itโ€™s HTTP(s) or local. If you want to see other option, you can file Feature Enhancement in GitHub for TF provider

      Reply
      • *protectedCicek Adam says

        09/19/2021 at 9:25 am

        I managed to get it from datastore and thats enough for me , thanks for quick reply ๐Ÿ™‚

        When you use the URL written under dataStore, which starts like ds:///vmfs...., it locates the file

        What I don't get is, if you want to create a normal vm you don't have to specify host_system_id, then why I need to specify it to create a vm from ovf? :thinking:

        Reply
        • *protectedCicek Adam says

          09/19/2021 at 9:54 am

          Hmmm, dataStore thing didn't work actually ๐Ÿ™ It was okay when terraform planing, but said " unsupported protocol scheme "ds" " while applying.

          Reply
          • William Lam says

            09/19/2021 at 1:07 pm

            As mentioned earlier, there's only two supported methods: remotely over HTTP(s) endpoint OR locally from your filesystem. If you want to have other methods, you need to file an Issue/FR

  10. *protectedNagaratna Reddy says

    11/20/2021 at 7:28 pm

    Hi...the deployment of the vm using ovf is successful but how do I assign ip for that vm

    Reply
  11. *protectedMohsen Pahlevanzadeh says

    02/08/2022 at 4:46 am

    I get the following error:
    Error: error while creating vapp properties config unsupported vApp properties in vapp.properties: [guestinfo.password guestinfo.hostname guestinfo.dns guestinfo.netmask guestinfo.ntp guestinfo.ipaddress guestinfo.gateway guestinfo.domain]

    How can I solve it?

    Reply
  12. *protectedPara92 says

    03/18/2022 at 6:10 pm

    In your config, what is the purpose of the data "vsphere_host" "host" {
    name = "192.168.30.5"

    Reply
    • William Lam says

      03/19/2022 at 1:50 pm

      This is required as part of the underlying vSphere API where an ESXi host must be specified. I'm not sure if the vSphere TF provider allows you to do something like automatically select a random ESXi host within a vSphere Cluster, you can certainly do this using PowerCLI and other imperative tools but not sure if this is possible with vSphere TF provider

      Reply
      • *protectedPara92 says

        03/20/2022 at 1:41 pm

        I haven't seen any methods to auto select a ESXi host either. I just spun up my config in a non-Nested config. The master and worker nodes got distributed among the three ESXi hosts in the cluster. I used "extra_config" instead of vapp to deploy.

        Reply

Thanks for the comment!Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Search

Thank Author

Author

William is Distinguished Platform Engineering Architect in the VMware Cloud Foundation (VCF) Division at Broadcom. His primary focus is helping customers and partners build, run and operate a modern Private Cloud using the VMware Cloud Foundation (VCF) platform.

Connect

  • Bluesky
  • Email
  • GitHub
  • LinkedIn
  • Mastodon
  • Reddit
  • RSS
  • Twitter
  • Vimeo

Recent

  • Programmatically accessing the Broadcom Compatibility Guide (BCG) 05/06/2025
  • Quick Tip - Validating Broadcom Download Tokenย  05/01/2025
  • Supported chipsets for the USB Network Native Driver for ESXi Fling 04/23/2025
  • vCenter Identity Federation with Authelia 04/16/2025
  • vCenter Server Identity Federation with Kanidm 04/10/2025

Advertisment

Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy

Copyright WilliamLam.com © 2025