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.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
"""Opening and closing a vSphere API session.
|
||||
|
||||
Kept apart from everything else because it is the only code that opens a
|
||||
socket; the tests replace it wholesale.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ssl
|
||||
from typing import Any
|
||||
|
||||
from pyVim.connect import Disconnect, SmartConnect
|
||||
|
||||
|
||||
def _ssl_context(verify: bool) -> ssl.SSLContext:
|
||||
context = ssl.create_default_context()
|
||||
if not verify:
|
||||
# ESXi hosts ship a self-signed certificate; most homelab and many
|
||||
# production hosts keep it.
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
return context
|
||||
|
||||
|
||||
def connect( # pragma: no cover - opens a live session
|
||||
host: str, port: int, user: str, password: str, *, verify_ssl: bool, timeout: int
|
||||
) -> Any:
|
||||
return SmartConnect(
|
||||
host=host,
|
||||
port=port,
|
||||
user=user,
|
||||
pwd=password,
|
||||
sslContext=_ssl_context(verify_ssl),
|
||||
httpConnectionTimeout=timeout,
|
||||
)
|
||||
|
||||
|
||||
def disconnect(si: Any) -> None: # pragma: no cover - talks to a live session
|
||||
Disconnect(si)
|
||||
|
||||
|
||||
def alive(si: Any) -> bool: # pragma: no cover - talks to a live session
|
||||
try:
|
||||
si.CurrentTime()
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
Reference in New Issue
Block a user