feat/vm-cpu-type
A VM created without a cpu argument gets Proxmox's API default, kvm64: no
AES-NI and no AVX. MongoDB 5.0 and later exit with "Illegal instruction" on
it, which is how a Graylog provisioned through netOrk failed (netork#494).
Every VM built by hand in the same cluster uses host or x86-64-v2-AES; only
the ones this driver created were left on kvm64.
create_vm_from_cloud_init now always passes cpu=, defaulting to x86-64-v2-AES
as the Proxmox GUI does since PVE 8, and takes cpu_type for a different one.
get_vm_cpu_types() lists x86-64-v2-AES (default), x86-64-v3 and host. The
named models carry the cpuinfo flags they add over qemu64, following
Proxmox's own definitions (CPUConfig.pm), and are available when the node's
CPU has all of them, read from /nodes/{node}/status. host lists the node's
own flags, so on a CPU without AVX it does not pretend to offer any.
A model asked for by name is checked against the node before a VMID is
allocated: one the CPU cannot run would only fail at VM start, after the disk
import, leaving a half-built VM behind. The default is not checked, so a
plain create costs no extra API call. VMCpuTypeDict is imported for type
checking only, so this works with an older napalm_device_types.
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%