Christian Manivong c8e472b4c6 feat: NAPALM drivers for VMware ESXi and vCenter
Two drivers from one package, both in the hypervisor role:

- vmware_esxi talks to one host directly: facts, vmnics and vmkernel
  NICs, CDP/LLDP neighbours, sensors, VMs, datastores and port groups.
- vmware_vcenter talks to a vCenter: every VM of every host it manages,
  with the host as the VM's node, plus distributed port groups. It
  reports no interfaces of its own; the hosts' NICs belong to the hosts.

Both implement the HypervisorDriver VM contract: get_vms, get_vm_config,
start/stop/reboot/suspend_vm and the four snapshot methods, and emit raw
device warnings (maintenance mode, disconnected host, config issues,
host managed by a vCenter, free license making the API read-only).

Every read is a PropertyCollector query for the explicit paths in
paths.py, converted by to_plain() into dicts and lists; the parsers
only ever see that. tools/harvest.py dumps exactly those paths to JSON
and tools/sanitize.py scrubs the dump, so a real host can become a test
fixture without code changes. A VM's vmid is its instance UUID, which
survives vMotion and re-registration; a MoRef does not.

Tested against govmomi's vcsim in ESXi and vCenter mode, including real
power and snapshot tasks. Not yet tested against real hardware.
2026-09-24 09:07:30 +02:00

napalm-vmware

NAPALM drivers for VMware vSphere, speaking the vSphere API through pyVmomi:

Driver Endpoint Device in netOrk
vmware_esxi one ESXi host, addressed directly the host: its vmnics, vmkernel NICs, sensors, VMs
vmware_vcenter a vCenter Server the vCenter: every VM it manages, with the ESXi host as the VM's node

Both declare the hypervisor role from napalm-device-types.

Status

Tested against govmomi's vcsim simulator, in both ESXi and vCenter mode, including real power and snapshot tasks. Not yet tested against real hardware: see Harvesting fixtures.

Method ESXi vCenter Source
get_facts ✅ ✅ host hardware + product / about
get_interfaces, get_interfaces_ip ✅ {} vmnics + vmks
get_lldp_neighbors ✅ {} QueryNetworkHint (LLDP, else CDP)
get_environment ✅ ✅ (per host) quick stats + hardware sensors
get_vms ✅ ✅ VMs, templates excluded
get_vm_config ✅ ✅ virtual hardware
start_vm, stop_vm, reboot_vm, suspend_vm ✅ ✅ power tasks / VMware Tools
get_vm_snapshots, create/delete/rollback_vm_snapshot ✅ ✅ snapshot tree
get_vm_storage_pools ✅ ✅ datastores
get_virtual_networks ✅ ✅ (+ dvPortgroups) port groups
get_device_warnings ✅ ✅ raw {code, meta}
VM provisioning, VIBs, updates, host reboot — — out of scope for v1

Unverified assumptions, to be checked against real hardware:

  • the HTTP fingerprints (vmware esxi on the Host Client page, vcenter on the vSphere Client page)
  • the free vSphere Hypervisor license reporting editionKey esxBasic

Requirements

  • HTTPS (443) to the host or vCenter. No SSH.
  • An account that may read the inventory. For power and snapshot actions it also needs Virtual machine → Interaction → Power on/off/Reset/Suspend and Virtual machine → Snapshot management.
  • A paid license for any write. On the free vSphere Hypervisor license the API is read-only; the driver reports vmware_api_read_only and turns the refusal into a readable error.

Install

pip install -e vendor/napalm-device-types/ -e vendor/napalm-vmware/

Usage

from napalm_vmware import VmwareEsxiDriver

driver = VmwareEsxiDriver("esx01.example.lan", "root", "secret",
                          optional_args={"verify_ssl": False})
driver.open()
print(driver.get_facts())
for vm in driver.get_vms():
    print(vm["name"], vm["status"], vm["vmid"])
driver.close()

optional_args: port (default 443), verify_ssl / ssl_verify (default True; ESXi ships a self-signed certificate). Other keys are ignored.

VMs are addressed by name, by vmid, or by MoRef (vm-42). A name shared by two VMs is refused rather than guessed.

Tests

pytest                                   # unit tests, no network
docker run -d --rm -p 127.0.0.1:8989:8989 vmware/vcsim -l 0.0.0.0:8989
docker run -d --rm -p 127.0.0.1:8990:8989 vmware/vcsim -esx -l 0.0.0.0:8989
VCSIM_VCENTER_PORT=8989 VCSIM_ESXI_PORT=8990 pytest -m vcsim

Harvesting fixtures

tools/harvest.py esx01.example.lan root esxi8-dell          # prompts for the password
tools/sanitize.py tools/harvest-out/esxi8-dell.json > tests/fixtures/esxi8-dell.json

harvest.py reads exactly the property paths in napalm_vmware/paths.py, the ones the drivers read. tools/harvest-out/ is gitignored. Read the sanitised file before committing it.

Design notes

One seam. Every read goes through Inventory.collect(type, paths), a PropertyCollector query with explicit paths, and every result is converted by to_plain() into dicts, lists and scalars (managed objects become their MoRef, data objects get a _type). The parsers in napalm_vmware/parse/ only ever see that plain form, so a harvested JSON file and a live host feed them identically. Lazy attribute access on pyVmomi objects is avoided on purpose: it fails on some servers where the individual paths work.

vmid is the instance UUID (config.instanceUuid). It survives vMotion and re-registration and is unique within a vCenter; a MoRef is none of those. The MoRef is reported alongside as moref.

The vCenter device has no interfaces. The hosts' NICs belong to the hosts. Reporting them on the vCenter would attach their MACs to the wrong device. Add a host with vmware_esxi to see its NICs.

Warnings are raw. get_device_warnings() returns {code, meta} only; what a code means is decided in netOrk's WARNING_CATALOG.

S
Description
NAPALM drivers for VMware ESXi and vCenter (vSphere API via pyVmomi)
Readme
159 KiB
Languages
Python 100%