Files
napalm-vmware/tests/test_sanitize.py
T
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

98 lines
3.5 KiB
Python

"""tools/sanitize.py: scrub a harvest dump before it becomes a fixture."""
from __future__ import annotations
import importlib.util
from pathlib import Path
_spec = importlib.util.spec_from_file_location(
"sanitize", Path(__file__).parent.parent / "tools" / "sanitize.py"
)
sanitize = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(sanitize)
def _dump():
return {
"about": {"instanceUuid": "35bb7c82-8526-5aa7-a886-cd7f8e6be786"},
"licenses": [{"licenseKey": "AAAAA-BBBBB-CCCCC-DDDDD-EEEEE", "editionKey": "esxBasic"}],
"objects": {
"HostSystem": [
{
"_moref": "host-21",
"name": "esx01.corp.example.com",
"hardware.systemInfo": {"serialNumber": "CZJ1234567"},
"config.network.dnsConfig": {
"hostName": "esx01",
"domainName": "corp.example.com",
"address": ["10.1.2.3"],
},
"config.network.pnic": [{"mac": "3c:ec:ef:01:02:03"}],
"summary.managementServerIp": "0.0.0.0",
}
],
"VirtualMachine": [
{
"_moref": "vm-7",
"name": "payroll-db",
"config.instanceUuid": "5003a1b2-0000-1111-2222-333344445555",
"config.hardware.device": [
{"backing": {"fileName": "[ds1] payroll-db/payroll-db.vmdk"}},
{"macAddress": "00:50:56:aa:bb:cc"},
],
"guest.net": [{"ipAddress": ["10.1.2.50", "fe80::1"]}],
}
],
},
}
def _text(data):
import json
return json.dumps(data)
class TestSanitize:
def test_sensitive_values_are_gone_everywhere(self):
clean = _text(sanitize.sanitize(_dump()))
for secret in (
"35bb7c82",
"AAAAA-BBBBB",
"esx01",
"corp.example.com",
"CZJ1234567",
"10.1.2.3",
"3c:ec:ef",
"payroll-db",
"5003a1b2",
"00:50:56:aa:bb:cc",
"10.1.2.50",
):
assert secret not in clean, secret
def test_structure_and_harmless_values_survive(self):
clean = sanitize.sanitize(_dump())
vm = clean["objects"]["VirtualMachine"][0]
assert vm["_moref"] == "vm-7"
assert clean["licenses"][0]["editionKey"] == "esxBasic"
assert clean["objects"]["HostSystem"][0]["summary.managementServerIp"] == "0.0.0.0"
path = vm["config.hardware.device"][0]["backing"]["fileName"]
assert path.startswith("[ds1] ") and path.endswith(".vmdk")
def test_placeholders_are_stable(self):
"""The same original value maps to the same placeholder, so references
between objects (a VM's name inside its disk path) still line up."""
clean = sanitize.sanitize(_dump())
vm = clean["objects"]["VirtualMachine"][0]
path = vm["config.hardware.device"][0]["backing"]["fileName"]
assert path == f"[ds1] {vm['name']}/{vm['name']}.vmdk"
def test_valid_shapes(self):
clean = sanitize.sanitize(_dump())
host = clean["objects"]["HostSystem"][0]
assert host["config.network.pnic"][0]["mac"].count(":") == 5
ip = clean["objects"]["VirtualMachine"][0]["guest.net"][0]["ipAddress"]
assert ip[0].startswith("192.0.2.")
assert ip[1].startswith("2001:db8::")