Christian Manivong 20fcf2ebc3 fix: four real defects the fourteen failing tests were pointing at
Closes netork#115.

The suite had been red long enough that it stopped being read. Four of the
fourteen failures were the tests being right.

`interfaces_mixin.py` used `re.match` without importing `re`, so
`get_mac_address_table` raised NameError against any node with a Linux bridge.
The tests never reached that line: they mocked the API call underneath
`_exec_ssh_command`, which takes two positional arguments where the doubles
accepted one, and which base64-wraps the command — so a fixture keyed on
"bridge fdb" appearing in the text matched nothing and the helper returned "".
They mock `_exec_ssh_command` itself now, which is the driver's own seam.

`is_alive` called `_resolve_node()`, which returns early without touching the
API whenever a node was configured through optional_args. A dead connection
reported itself alive. It probes `GET /version` now.

The documented `realm` optional_arg was read into `self._realm` in `__init__`
and then never used. Proxmox authenticates against "<user>@<realm>" and rejects
a bare username, so the option had no effect and callers had to know to type the
realm themselves.

`get_vlans` filtered out entries with no member ports on one return path while
the OVS path returned them, so a configured SDN VNet was visible or invisible
depending on which branch ran. A VNet exists on the node whether or not anything
is attached to it, and netOrk's VLAN discovery reads this.

`get_ipv6_neighbors_table` was simply missing and fell through to NAPALM's stub;
it is implemented against `ip -6 neigh show`, dropping FAILED entries.

The rest were stale tests. The DNS fixture put an FQDN where a search domain
belongs, which made `get_facts` build "pve1.pve1.example.com" and look like a
driver bug. The LLDP fixture was a simplified shape that real `lldpcli show
neighbors summary` does not produce — the parser matches on the ", via: LLDP"
that follows the interface name. And `test_bridge_vlan_show_parsing` covered a
fallback that was replaced by VM-config scanning, asserting an "interfaces" key
this method has never returned; it is now a test of the fallback that exists.
2026-08-21 13:22:03 +07:00
2026-05-29 09:24:39 +02:00
2026-05-29 09:24:39 +02:00
2026-05-29 09:24:39 +02:00
2026-05-29 09:24:39 +02:00

napalm-proxmox

A NAPALM driver for Proxmox VE nodes.

It supports all three networking domains of Proxmox VE:

Domain Description
Classic Linux /etc/network/interfaces, Linux bridges, VLANs
SDN Zones (VLAN, QinQ, VXLAN, EVPN), VNets, subnets
OVS Open vSwitch bridges, bonds, and internal ports

Requirements

  • Python ≥ 3.9
  • NAPALM ≥ 5.0.0
  • proxmoxer ≥ 2.0.0
  • netaddr ≥ 0.9.0
  • requests ≥ 2.31.0

Installation

pip install napalm-proxmox

Or directly from source:

git clone https://github.com/example/napalm-proxmox.git
cd napalm-proxmox
pip install -e .

Usage

Password authentication

from napalm import get_network_driver

driver = get_network_driver("proxmox")
device = driver(
    hostname="pve1.example.com",
    username="root",
    password="secret",
    optional_args={
        "realm": "pam",       # default: "pam"
        "port": 8006,         # default: 8006
        "verify_ssl": True,   # default: True
    },
)

with device:
    facts = device.get_facts()
    print(facts)
    # {'vendor': 'Proxmox Server Solutions GmbH', 'model': 'PowerEdge R640',
    #  'hostname': 'pve1', 'os_version': 'Proxmox VE 8.2.4', ...}

    interfaces = device.get_interfaces()
    interfaces_ip = device.get_interfaces_ip()
    vlans = device.get_vlans()
    network_instances = device.get_network_instances()

API token authentication

device = driver(
    hostname="pve1.example.com",
    username="napalm",
    password="",
    optional_args={
        "token_name": "napalm@pam!napalm-token",
        "token_value": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    },
)

Targeting a specific node

In a multi-node cluster the driver auto-detects the node by matching the hostname against the cluster's node list. You can also pin a specific node:

device = driver(
    hostname="pve-cluster.example.com",  # cluster VIP
    username="root",
    password="secret",
    optional_args={"node": "pve2"},
)

Supported NAPALM methods

Method Notes
open / close Password + API token auth
is_alive Checks /api2/json/version
get_facts vendor, model, hostname, os_version, uptime, interface_list, fqdn
get_interfaces eth, bridge, OVS bridge/bond; speed, MTU, MAC, status
get_interfaces_ip IPv4/IPv6 from classic ifaces + SDN subnet gateways
get_interfaces_counters From node/netstat RRD data
get_environment CPU %, memory (bytes), hardware temperature sensors
get_arp_table Reads /proc/net/arp via exec endpoint
get_mac_address_table bridge fdb show (Linux) + ovs-appctl fdb/show (OVS)
get_vlans SDN VNet tags + bridge vlan show
get_network_instances SDN zones (VLAN→L2VPN, EVPN→L3VRF) + default instance
get_ntp_servers From node/ntp API
get_ntp_stats Parses chronyc / ntpq -pn output
get_snmp_information Parses /etc/snmp/snmpd.conf
get_users Proxmox access/users API + local /etc/passwd
get_config /etc/network/interfaces + SDN config; sanitize support
load_merge_candidate / load_replace_candidate String or file
compare_config Unified diff
commit_config Writes /etc/network/interfaces + ifreload -a
discard_config / rollback Revert candidate
get_lldp_neighbors lldpcli show neighbors via exec
get_lldp_neighbors_detail Full LLDP detail
get_ipv6_neighbors_table ip -6 neigh show
ping Linux ping via exec endpoint
traceroute traceroute -n via exec endpoint
cli Arbitrary command execution via exec endpoint
get_route_to ip route show via exec endpoint

Not implemented (raise NotImplementedError): get_bgp_config, get_bgp_neighbors, get_bgp_neighbors_detail, get_optics, get_probes_config, get_probes_results, get_firewall_policies

Optional arguments

Argument Type Default Description
port int 8006 Proxmox API port
verify_ssl bool True Verify TLS certificate
realm str "pam" PAM realm for password auth
node str auto Override target node name
token_name str None API token identifier (user@realm!tokenid)
token_value str None API token secret

Development

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run tests with coverage
pytest --cov=napalm_proxmox --cov-report=term-missing

# Lint
ruff check napalm_proxmox

Architecture

napalm_proxmox/
├── __init__.py     # Exports ProxmoxDriver
├── driver.py       # ProxmoxDriver — all NAPALM methods
└── utils.py        # MAC normalisation, CIDR parsing, ARP/OVS parsers
tests/
├── conftest.py          # Shared fixtures and mock API payloads
├── test_connection.py   # open / close / is_alive
├── test_get_facts.py    # get_facts
├── test_interfaces.py   # get_interfaces, get_interfaces_ip, get_interfaces_counters
├── test_environment.py  # get_environment
├── test_sdn.py          # get_vlans, get_network_instances
├── test_ovs_and_arp.py  # get_arp_table, get_mac_address_table, ARP/OVS utils
├── test_misc.py         # NTP, SNMP, users, config, ping, traceroute, CLI, LLDP
└── test_utils.py        # Unit tests for napalm_proxmox.utils

License

Apache License 2.0 — see LICENSE.

S
Description
No description provided
Readme
657 KiB
Languages
Python 100%