Christian Manivong 9264cdcba9 feat(vm_provision_mixin): create_vm_from_cloud_init downloads cloud images directly
Replaces the template-clone flow with: create empty VM shell, download the
cloud image on the node (cached by filename, optional checksum verification),
qm importdisk, attach as scsi0. NIC config, snippet upload, ssh keys, disk
resize, and start remain unchanged (already generic).

New helpers: _run_node_command (strict SSH exec with custom timeout and
non-zero-exit detection, unlike the best-effort _exec_ssh_command),
_download_cloud_image (idempotent download + checksum check),
_find_default_image_storage (content=images discovery, mirrors the existing
snippet-storage discovery).

24 tests pass (10 new: _run_node_command x2, _download_cloud_image x4, plus
rewrites of the 4 existing create_vm_from_cloud_init tests for the new flow).
2026-07-07 10:37:36 +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
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%