Creating vSphere VMs using Ansible

3 minute read

Refreshed June 2026: the original used the vsphere_guest module, the pysphere Python library, Ansible 1.8.4, and vCenter 6.0. All four are gone. vsphere_guest was removed years ago, pysphere is dead, and Python 2 is end of life. This rewrite uses community.vmware.vmware_guest on current ansible-core, and one looped task replaces the three near-identical disk-count tasks the old version needed.

Background

The goal has not changed: define a set of VMs as data and let Ansible build them in vCenter. What changed is the tooling. The modern module, community.vmware.vmware_guest, takes a list of disks directly, so you no longer need a separate task per disk count. The old post had three copies of the same task that differed only in how many disks they defined. That whole pattern goes away.

I have not pointed this at a live vCenter as part of the refresh, so treat the playbook as a current, correct starting point rather than captured output.

Prerequisites

On the control node, install the collection and its Python dependency:

ansible-galaxy collection install community.vmware
pip install pyvmomi

pyvmomi is the replacement for the long-dead pysphere.

Define The VMs As Data

Keep the VM definitions in one place. Each entry carries its own hardware, a list of disks, and its network. Note the modern guest IDs: rhel6_64Guest from the original is well past end of life, so the example uses current ones.

vms:
  - name: ans-web01
    guest_id: ubuntu64Guest
    memory_mb: 256
    num_cpus: 1
    network: vSS-Servers
    disks:
      - size_gb: 10
        type: thin

  - name: ans-db01
    guest_id: rhel9_64Guest
    memory_mb: 1024
    num_cpus: 2
    network: vSS-Servers
    disks:
      - size_gb: 20
        type: thin
      - size_gb: 50
        type: thin

The first VM has one disk, the second has two. The same task handles both because disk is a list.

The Playbook

One play, one task. The disk list for each VM is built by stamping the shared datastore onto every disk entry with the combine filter, which keeps the per-VM data clean.

---
- name: Create vSphere VMs
  hosts: localhost
  connection: local
  gather_facts: false

  vars_prompt:
    - name: vcenter_hostname
      prompt: Enter vCenter hostname
      private: false
      default: vcsa.example.internal
    - name: vcenter_username
      prompt: Enter vCenter username
      private: false
    - name: vcenter_password
      prompt: Enter vCenter password
      private: true

  vars:
    vcenter_datacenter: LAB
    vcenter_datastore: "Tier-3 (NAS01)"
    vcenter_folder: /LAB/vm/ansible-builds
    vms:
      - name: ans-web01
        guest_id: ubuntu64Guest
        memory_mb: 256
        num_cpus: 1
        network: vSS-Servers
        disks:
          - size_gb: 10
            type: thin
      - name: ans-db01
        guest_id: rhel9_64Guest
        memory_mb: 1024
        num_cpus: 2
        network: vSS-Servers
        disks:
          - size_gb: 20
            type: thin
          - size_gb: 50
            type: thin

  tasks:
    - name: Create the VMs
      community.vmware.vmware_guest:
        hostname: "{{ vcenter_hostname }}"
        username: "{{ vcenter_username }}"
        password: "{{ vcenter_password }}"
        validate_certs: false
        datacenter: "{{ vcenter_datacenter }}"
        folder: "{{ vcenter_folder }}"
        name: "{{ item.name }}"
        state: poweredon
        guest_id: "{{ item.guest_id }}"
        hardware:
          memory_mb: "{{ item.memory_mb }}"
          num_cpus: "{{ item.num_cpus }}"
        disk: "{{ item.disks | map('combine', {'datastore': vcenter_datastore}) | list }}"
        networks:
          - name: "{{ item.network }}"
            device_type: vmxnet3
      loop: "{{ vms }}"
      loop_control:
        label: "{{ item.name }}"

Run it:

ansible-playbook create_vms.yml

A few things to call out against the 2015 version:

  • loop replaces the old bare with_items: vms, which is deprecated.
  • become is not needed here at all, so the old sudo: true is gone.
  • validate_certs: false is fine for a lab, but set it to true and trust the vCenter certificate for anything real.
  • For credentials, prefer Ansible Vault or environment variables over vars_prompt. The prompt is kept here only to mirror the original.

Guest IDs

The guest_id values (ubuntu64Guest, rhel9_64Guest, and so on) come from the vSphere API. The 2015 post linked a vSphere 4.1 SDK page that no longer exists. The current list is maintained in the community.vmware.vmware_guest documentation and the vSphere API reference for your vCenter version.

The Newer Direction

community.vmware.vmware_guest is the direct, widely deployed successor to vsphere_guest and the most practical choice if you are coming from the old post. VMware also publishes two newer collections worth knowing about:

  • vmware.vmware, the official collection that is the longer-term direction, with a vmware.vmware.vm module for VM lifecycle.
  • vmware.vmware_rest, which talks to the vSphere REST API instead of pyVmomi.

If you are starting fresh on vCenter 8, it is worth evaluating vmware.vmware alongside the community module.

Conclusion

Same idea as a decade ago, far less playbook. Define the VMs as a list, let one looped task build them, and lean on the disk list instead of duplicating tasks per disk count.

Enjoy!

Comments