Skip to main content

proxmox_power_button

NetBox plugin that adds Start / Stop / Reboot buttons to the Virtual Machine detail page and drives the corresponding Proxmox VE VM, reflecting the power state back into the NetBox VM status.

Installation

pip install netbox-proxmox-power-button

The distribution is netbox-proxmox-power-button; the importable package — and the name that goes into NetBox's PLUGINS — is proxmox_power_button:

# configuration/plugins.py
PLUGINS = ["proxmox_power_button"]

PLUGINS_CONFIG = {
    "proxmox_power_button": {
        "verify_ssl": True,  # set False only for self-signed lab certs
        "stop_mode": "shutdown",
        "reboot_mode": "reboot",
    },
}

Then run ./manage.py migrate (creates the custom fields) and restart NetBox and its worker.

Behaviour

  • Buttons live in the VM detail page's button bar, before "Add Components" (injected via {% plugin_buttons %}, no custom page).
  • Start — green, mdi-play. Shown only when the VM is not active. On success sets NetBox status → active.
  • Stop — red, mdi-stop. Shown only when the VM is active. On success sets NetBox status → offline.
  • Reboot — orange, mdi-sync. Shown only when the VM is active, to the left of Stop. Leaves status unchanged.
  • NetBox status is updated only after Proxmox confirms the command. If Proxmox is unconfigured/unreachable, the action shows an error and changes nothing (no 500).
  • After a start, the plugin waits 3s and re-queries Proxmox; the status is set to active only if the VM reports running. Stop/reboot are not verified inline (they take too long to settle).

Auditing

One changelog entry per state change, each carrying a readable message (visible in the VM's Changelog tab and in /core/changelog/):

operation changelog entry object saved
start (confirmed running) "Powered on via Proxmox (confirmed running)" yes (status)
stop "Powered off via Proxmox (shutdown sent)" yes (status)
reboot "Rebooted via Proxmox" no — entry written directly
start sent, not yet running none (no state change) no
failure none (no state change) no

Every outcome — including the two "none" rows above — is written to the proxmox_power_button logger (visible in docker compose logs netbox), e.g.:

INFO  … proxmox_power_button user=admin vm=jellyfin: powered on (confirmed running)
ERROR … proxmox_power_button user=admin vm=jellyfin: start failed: VMID 20100 not found …

Data model (custom fields, auto-created by migration)

  • VirtualMachine.vmid — integer, required, min 100. Unique within a cluster (enforced on create, on VMID change, and when moving the VM to another cluster — a move into a cluster that already has that VMID is rejected).
  • Cluster.endpoint — text: host, host:port, or https://host:port.
  • Cluster.token — text: user@realm!tokenid=secret.

The client resolves the target VM by vmid via cluster/resources, so it works for both QEMU and LXC.

Settings (PLUGINS_CONFIG["proxmox_power_button"])

key default meaning
verify_ssl True verify Proxmox TLS cert (set False only for self-signed lab certs)
stop_mode "shutdown" shutdown (graceful ACPI) or stop (hard)
reboot_mode "reboot" reboot (graceful) or reset (hard)

Security

  • Token is stored in a plain-text custom field. It is visible to anyone who can view the cluster — in the UI, in REST API responses for the cluster, and in change-log data. NetBox has no "secret" custom-field type, so:
    • restrict Cluster view permissions to administrators only;
    • use a least-privilege Proxmox API token: only VM.Audit + VM.PowerMgmt, scoped to the specific VMs or pool this plugin should manage — never a root@pam token with datacenter-wide rights. Anyone who can read the field can extract the token and drive the hypervisor directly.
  • Permissions. The buttons render only for users with virtualization.change_virtualmachine, and the action endpoint enforces NetBox's object-scoped permissions: a user whose change permission is constrained (e.g. to one tenant's VMs) gets a 404 on any VM outside that scope — the same behaviour as core NetBox object views.
  • TLS verification is on by default. The Proxmox API token crosses this connection on every power action; leaving verify_ssl at True prevents token theft via MitM. Only set it to False for self-signed lab certificates.
  • Error detail goes to the log, not the browser. Failed actions show a generic message; the full Proxmox/network error (which may contain internal hostnames, URLs, or response bodies) is written to the proxmox_power_button logger.

Notes / caveats

  • Requires NetBox ≥ 4.5.0. The data migration depends on extras.0134_owner and virtualization.0052_gfk_indexes, which first appear in 4.5.0; on 4.4 or older migrate fails with NodeNotFoundError. Bump min_version together with those pins if you ever retarget them. Verified against 4.5.8.
  • Making vmid required means existing VMs without a VMID will fail validation on their next edit until one is set.

Releasing to PyPI

Everything runs through the makefile:

make venv              # one-off: build+twine in .venv-publish (PEP 668-safe)
make bump V=0.2.0      # writes the version to BOTH places, then verifies
make build             # clean + sdist + wheel
make check             # lists both artifacts, asserts contents, twine check
make testpypi          # optional dry run against TestPyPI
make publish           # build + check + upload (asks you to type the version)
make tag               # git tag <version>

Uploads authenticate with username __token__ and a pypi-… API token (~/.pypirc, or TWINE_USERNAME/TWINE_PASSWORD). A version number is burned permanently on upload — it can never be reused, even after deleting the release; hence publish refuses to run without a passing check and a typed confirmation.

The version lives in two places: pyproject.tomlversion, and proxmox_power_button/__init__.pyProxmoxPowerButtonConfig.version. They are not single-sourced on purpose — importing the package to read a version would drag in netbox, absent in a build environment. make bump writes both and make version fails loudly if they ever drift.

make check asserts three things that a broken build would otherwise hide until someone installs the package: the wheel carries the button template (templates/ has no __init__.py, so without [tool.setuptools.package-data] +MANIFEST.in you get a wheel that raises TemplateDoesNotExist on every VM page), the migration, and the licence.

Licence

GPL-2.0-or-later. See LICENSE for the full text; every source file carries an SPDX-License-Identifier: GPL-2.0-or-later header, which is what expresses the "or later" option (the GPL-2 text alone does not).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

netbox_proxmox_power_button-0.1.1.tar.gz (19.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

netbox_proxmox_power_button-0.1.1-py3-none-any.whl (22.3 kB view details)

Uploaded Python 3

File details

Details for the file netbox_proxmox_power_button-0.1.1.tar.gz.

File metadata

File hashes

Hashes for netbox_proxmox_power_button-0.1.1.tar.gz
Algorithm Hash digest
SHA256 57bbdd530e8db628898a59da461c23d04d618cec76f17886128ca0d92f45d945
MD5 fb6c56207677f51841d67383d027c048
BLAKE2b-256 d1699e313f1c53d0f191649784088a885c9758af48b340d0d957b5892f5134fa

See more details on using hashes here.

File details

Details for the file netbox_proxmox_power_button-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for netbox_proxmox_power_button-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 13d04640019122b0170d56c348015371b845d8e4d3252f451faa2a66c4a35fba
MD5 f5da1af7e454b9d7057fe7042d8f09cc
BLAKE2b-256 0224f6e913914615f5071c11f624031c5c4039c32c1b61da6b5d956818723310

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page