"""NAPALM interface getters for an ESXi host. A host has two kinds of interface worth reporting: physical uplinks (``vmnicN``) and VMkernel adapters (``vmkN``), which carry the host's own IP addresses. Port groups are not interfaces; they are reported by ``get_virtual_networks``. """ from __future__ import annotations import ipaddress from typing import Any _DEFAULT_MTU = 1500 _UNASSIGNED = {"", "0.0.0.0"} def _uplink_mtus(host: dict[str, Any]) -> dict[str, int]: """pnic key -> MTU of the standard vSwitch that uses it as an uplink.""" mtus: dict[str, int] = {} for vswitch in host.get("config.network.vswitch") or []: for pnic_key in vswitch.get("pnic", []): mtus[pnic_key] = int(vswitch.get("mtu") or _DEFAULT_MTU) return mtus def _iface(up: bool, description: str, speed: float, mtu: int, mac: str) -> dict[str, Any]: return { "is_up": up, "is_enabled": True, "description": description, "last_flapped": -1.0, "speed": speed, "mtu": mtu, "mac_address": mac.upper(), } def host_interfaces(host: dict[str, Any]) -> dict[str, dict[str, Any]]: """vmnics and vmks in the shape of NAPALM's ``get_interfaces``.""" mtus = _uplink_mtus(host) result: dict[str, dict[str, Any]] = {} for pnic in host.get("config.network.pnic") or []: link = pnic.get("linkSpeed") or {} description = " ".join(p for p in (pnic.get("driver"), pnic.get("pci")) if p) result[pnic["device"]] = _iface( up=bool(link), description=description, speed=float(link.get("speedMb", 0)), mtu=mtus.get(pnic.get("key", ""), _DEFAULT_MTU), mac=pnic.get("mac", ""), ) for vnic in host.get("config.network.vnic") or []: spec = vnic.get("spec") or {} result[vnic["device"]] = _iface( up=True, description=vnic.get("portgroup") or spec.get("portgroup", ""), speed=0.0, mtu=int(spec.get("mtu") or _DEFAULT_MTU), mac=spec.get("mac", ""), ) return result def _ipv4(ip: dict[str, Any]) -> dict[str, dict[str, int]]: address = ip.get("ipAddress", "") if address in _UNASSIGNED: return {} network = ipaddress.IPv4Network(f"0.0.0.0/{ip.get('subnetMask') or '32'}") return {address: {"prefix_length": network.prefixlen}} def _ipv6(ip: dict[str, Any]) -> dict[str, dict[str, int]]: entries = (ip.get("ipV6Config") or {}).get("ipV6Address", []) return {e["ipAddress"]: {"prefix_length": int(e.get("prefixLength", 128))} for e in entries} def host_interfaces_ip(host: dict[str, Any]) -> dict[str, dict[str, Any]]: """Addresses of the VMkernel adapters, as NAPALM's ``get_interfaces_ip``.""" result: dict[str, dict[str, Any]] = {} for vnic in host.get("config.network.vnic") or []: ip = (vnic.get("spec") or {}).get("ip") or {} families = {"ipv4": _ipv4(ip), "ipv6": _ipv6(ip)} families = {k: v for k, v in families.items() if v} if families: result[vnic["device"]] = families return result