feat/pve-import-download
Provisioning downloaded every cloud image over SSH into /var/lib/vz/template/netork-images, on the node's root filesystem. On a small root that fills up and takes Proxmox down with it (netOrk #480). When the node has an active storage with content type "import" (Proxmox 8.2+), Proxmox now does it itself: download-url with checksum verification into that storage, then import-from as the root disk. The file is named after a hash of the full URL and reused when present. Proxmox takes the format from the extension and has no ".img", so Ubuntu's qcow2 .img is stored as .qcow2 -- a wrong guess fails at import instead of attaching a qcow2 container as a raw disk. Without an import storage, or for an image type Proxmox cannot import, the SSH download is used as before.
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.
Languages
Python
100%