create_vm_from_cloud_init takes the same qcow2/raw cloud images netOrk offers for Proxmox. ESXi can neither boot nor download them, so the driver does both: download with checksum check and one retry, convert with qemu-img to a streamOptimized VMDK (cached by URL), import through a minimal OVF descriptor over NFC, pin requested MACs, grow the disk, and attach a NoCloud seed ISO placed next to the VM's files. NoCloud rather than guestinfo because it needs nothing in the guest; the user-data installs open-vm-tools, which the driver declares as its guest agent. A failure after the import removes the VM again. Placement is a pure decision over inventory rows: a connected host outside maintenance mode that sees the datastore and every port group, with the resource pool and VM folder found by walking up to the datacenter -- one path for a standalone host and for a vCenter. Two faults vcsim surfaced and the tests now pin: a chunked upload body next to a Content-Length is refused with 500, so the disk goes up as a sized file object that also reports lease progress; and a device edit replaces the device as sent, so disk and NIC edits start from the live objects, backing included (vcsim panicked on a disk without one). destroy_vm, get_vm_status, get_network_targets (port groups with their fixed VLAN) and get_image_storages complete the contract. reboot_host on ESXi uses RebootHost_Task and refuses outside maintenance mode: force=True would cut power to running VMs. Tested against vcsim in ESXi and vCenter mode, end to end.
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} |
reboot_host |
✅ (maintenance mode only) | — | RebootHost_Task |
create_vm_from_cloud_init, destroy_vm, get_vm_status |
✅ | ✅ | see Provisioning |
get_network_targets, get_image_storages |
✅ | ✅ | port groups, datastores |
| VIBs, updates | — | — | not yet |
Unverified assumptions, to be checked against real hardware:
- the HTTP fingerprints (
vmware esxion the Host Client page,vcenteron the vSphere Client page) - the free vSphere Hypervisor license reporting
editionKeyesxBasic
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.
- For provisioning:
qemu-img(packageqemu-utils) where the driver runs, and HTTPS from there to every ESXi host that may receive a VM -- through a vCenter the disk upload goes straight to the host, not via the vCenter. - A paid license for any write. On the free vSphere Hypervisor license
the API is read-only; the driver reports
vmware_api_read_onlyand 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), image_cache_dir (where
converted cloud images are kept; default a directory under the system temp
dir). 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.
Provisioning
create_vm_from_cloud_init takes the same cloud images netOrk's catalog
offers for Proxmox (qcow2/raw):
- The image is downloaded where the driver runs, its checksum verified (one
retry), and converted with
qemu-imgto a streamOptimized VMDK. The VMDK is cached by URL inimage_cache_dir; the download is not kept. - A host is chosen that is connected, not in maintenance mode, and sees the datastore and every requested port group (the named datastore, or the one with the most free space).
- The VM is created from a minimal OVF descriptor (PVSCSI disk, VMXNET3 NICs) and the disk streamed in over NFC.
- Requested MACs are pinned, the disk grown to
disk_resize_gb, and a NoCloud seed ISO (user-data, meta-data, network-config) uploaded next to the VM's files and attached as a CD-ROM on a new SATA controller. - The VM is powered on. Any failure after step 3 removes the VM again.
A port group fixes its VLAN, so get_network_targets reports each one with
kind="portgroup", vlan_aware=False and its fixed_vlan_tag; a NIC asking
for a different vlan_tag is refused. The guest agent netOrk installs is
open-vm-tools (GUEST_AGENT_PACKAGES), which reports the IP address back.
Unverified until #305: that each distribution's cloud kernel carries the PVSCSI and VMXNET3 drivers.
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.