A Python-based Rundeck node source plugin that dynamically imports virtual machines and containers from a Proxmox cluster.
- Discovers all VMs (QEMU) and containers (LXC) from a Proxmox cluster
- Automatically extracts IP addresses when available
- Tags nodes with Proxmox metadata (node name, VM ID, type, status)
- Supports filtering by VM type (VMs only, containers only, or both)
- Configurable authentication and connection settings
- Python 3.6 or higher
- Rundeck 3.x or higher
- Access to a Proxmox cluster with API access
The plugin attempts to detect IP addresses using multiple methods:
For QEMU VMs:
- Primary method: Uses QEMU Guest Agent to query network interfaces (requires agent enabled and VM running)
- Fallback: Extracts IP from VM configuration if statically assigned
- Automatically filters out invalid values like 'dhcp', 'auto', etc.
For LXC Containers:
- Extracts IP from container configuration (
ipconfig0or network interfaces) - Filters out invalid values like 'dhcp', 'auto', etc.
Note: For QEMU VMs using DHCP, the QEMU Guest Agent is the most reliable method to get the actual assigned IP address. Ensure:
- QEMU Guest Agent is installed and running inside the VM
- Guest Agent is enabled in Proxmox VM configuration (
agent: 1) - VM is running
The easiest way to use this is as a proper Rundeck plugin. See INSTALL.md for detailed installation instructions.
Quick start:
- Build the plugin:
./build-plugin.sh - Copy
proxmox-node-source.zipto your Rundecklibextdirectory - Install Python dependencies on Rundeck server:
pip3 install proxmoxer requests pyyaml - Restart Rundeck
- Configure the plugin in your Rundeck project settings
-
Install dependencies using uv:
uv sync
-
Make the script executable:
chmod +x proxmox-node-source.py
-
Run the script using uv:
uv run ./proxmox-node-source.py --help
-
Install Python dependencies:
pip install -r requirements.txt
-
Make the script executable:
chmod +x proxmox-node-source.py
If you prefer to use it as a script-based resource model source without the plugin wrapper:
- Copy the script to your Rundeck server
- Install Python dependencies:
pip3 install proxmoxer requests pyyaml - Configure as a Script-based Resource Model Source in Rundeck
When installed as a Rundeck plugin (see INSTALL.md):
- In Rundeck, go to your Project Settings
- Navigate to "Resource Model Sources"
- Add a new "Proxmox Node Source" resource model source
- Configure the following fields:
- Proxmox Host: Your Proxmox hostname or IP address
- Proxmox User: Username with realm (e.g.,
root@pam) - Proxmox Password Storage Path: (Optional) Path to password in Rundeck Key Storage (e.g.,
keys/proxmox/password) - Proxmox Password: (Optional) Direct password (leave blank if using key storage)
- Proxmox Port: API port (default: 8006)
- Verify SSL: Enable SSL certificate verification
- Include VMs: Include QEMU VMs (default: true)
- Include Containers: Include LXC containers (default: true)
- Default Username: Default username for nodes (default: root)
- Output Format: Output format (default: yaml)
- Node Filter: (Optional) Rundeck node filter string to apply before returning nodes
Security Note: It's recommended to use Rundeck Key Storage for the password instead of entering it directly. Store the password in Key Storage and reference it using the "Proxmox Password Storage Path" field.
-
In Rundeck, go to your Project Settings
-
Navigate to "Resource Model Sources"
-
Add a new "Script" resource model source
-
Configure the following:
Script File:
/path/to/proxmox-node-source.pyScript Arguments:
--proxmox-host your-proxmox-host.example.com --proxmox-user root@pam --proxmox-password your-password --proxmox-port 8006 --default-username root --output-format yamlAdditional Options:
--output-format {json,yaml,xml}: Output format (default: yaml)--verify-ssl: Enable SSL certificate verification--no-vms: Exclude VMs, only include containers--no-containers: Exclude containers, only include VMs--node-filter FILTER: Apply Rundeck node filter before returning nodes
Note: When used as a plugin, configuration is passed via environment variables (RD_CONFIG_*) automatically. The script also accepts command-line arguments for local testing.
Use your Proxmox username and password:
--proxmox-user root@pam
--proxmox-password your-password
Proxmox also supports API tokens. You can use them by setting:
--proxmox-user your-token-id
--proxmox-password your-token-secret
Each node imported from Proxmox includes the following attributes:
proxmox_node: The Proxmox node name where the VM/container is hostedproxmox_vmid: The VM/container IDproxmox_type: Either 'qemu' or 'lxc'proxmox_status: Current status (running, stopped, etc.)proxmox_running_status: Running status ('running' or 'stopped')ip_address: IP address of the VM/container (when available)
proxmox_cores: Number of CPU cores allocatedproxmox_sockets: Number of CPU sockets (VMs only)proxmox_memory_mb: Allocated memory in megabytesproxmox_maxmem_bytes: Maximum memory in bytesproxmox_maxdisk_bytes: Maximum disk space in bytesproxmox_template: Whether this is a template ('true' or 'false')proxmox_agent: QEMU agent status ('enabled' or 'disabled', VMs only)proxmox_ostype: Operating system type (e.g., 'l26' for Linux, 'ubuntu' for containers)proxmox_description: VM/container description/notes from Proxmoxproxmox_swap_mb: Swap space in megabytes (containers only)proxmox_hostname: Container hostname (containers only)
The plugin attempts to detect the operating system for each VM/container:
For QEMU VMs (with QEMU Guest Agent enabled and running):
os_name: OS name (e.g., "Ubuntu", "CentOS")os_version: OS version (e.g., "22.04", "7")os_version_id: OS version IDos_pretty_name: Full OS name (e.g., "Ubuntu 22.04.3 LTS")os_id: OS identifier (e.g., "ubuntu", "centos")os_kernel: Kernel release (e.g., "5.15.0-72-generic")os_kernel_version: Full kernel version
For LXC Containers:
os_name: OS name derived from ostype (e.g., "Ubuntu", "Debian", "Alpine Linux")os_hostname: Container hostname (may contain OS hints)
Fallback (when detailed OS info not available):
os_family: OS family name derived from ostype (e.g., "Linux", "Windows 10", "Windows 11")proxmox_ostype: Basic OS type identifier from Proxmox config
Note: For QEMU VMs, detailed OS detection requires:
- QEMU Guest Agent installed and running inside the VM
- Guest Agent enabled in Proxmox VM configuration (
agent: 1) - VM must be running
proxmox_uptime_seconds: Uptime in seconds since last startproxmox_cpu_usage: Current CPU usage (0.0 to 1.0)proxmox_mem_used_bytes: Current memory usage in bytesproxmox_cpus: Number of CPUsproxmox_maxcpu: Maximum CPU usageproxmox_netin_bytes: Total network bytes receivedproxmox_netout_bytes: Total network bytes sentproxmox_diskread_bytes: Total disk bytes readproxmox_diskwrite_bytes: Total disk bytes writtenproxmox_disk_used_bytes: Current disk usage in bytes
Nodes are automatically tagged with:
proxmox: All nodes from Proxmoxvmorcontainer: Type of resourceqemuorlxc: Technical type{node_name}: The Proxmox node name- Any custom tags defined in Proxmox (if the VM/container has tags configured)
The plugin supports pre-filtering nodes using Rundeck's node filter syntax. This allows you to filter nodes before they are returned to Rundeck, reducing the number of nodes imported.
Filters use the format attribute: value where multiple clauses are space-separated and ANDed together:
- Basic matching:
hostname: dev.*- matches nodes with hostname matching regexdev.* - Exact match:
proxmox_status: running- matches nodes with exact status "running" - Negation:
!osFamily: windows- excludes nodes with osFamily "windows" - Multiple values (OR):
hostname: dev1,dev2- matches nodes with hostname "dev1" OR "dev2" - Tag filtering (AND):
tags: web+prod- matches nodes with both "web" AND "prod" tags - Tag filtering (OR):
tags: web,prod- matches nodes with either "web" OR "prod" tags - Combined:
tags: web+prod hostname: dev.* !osFamily: windows- matches nodes with tags "web" AND "prod", hostname matching "dev.*", and osFamily NOT "windows"
Filter by status:
proxmox_status: running
Filter by type:
proxmox_type: qemu
Filter by tags (must have both):
tags: production+appserver
Filter by tags (either one):
tags: web,api
Filter by hostname pattern:
hostname: dev.*
Exclude stopped nodes:
!proxmox_status: stopped
Complex filter (production web servers on specific node):
tags: production+web proxmox_node: pve1 proxmox_status: running
In Rundeck Plugin Configuration:
- In the plugin configuration, find the "Node Filter" field
- Enter your filter string (e.g.,
tags: production+web proxmox_status: running) - Save the configuration
Via Command Line:
uv run ./proxmox-node-source.py \
--proxmox-host your-proxmox-host.example.com \
--proxmox-user root@pam \
--proxmox-password your-password \
--node-filter "tags: production+web proxmox_status: running"Available Filter Attributes:
- Standard Rundeck attributes:
nodename,hostname,username,osFamily,tags,description - Proxmox-specific attributes:
proxmox_node,proxmox_vmid,proxmox_type,proxmox_status,proxmox_running_status,ip_address - Configuration attributes:
proxmox_cores,proxmox_memory_mb,proxmox_ostype, etc. - OS detection attributes:
os_name,os_version,os_family, etc.
Note: Filters are applied after fetching all nodes from Proxmox but before returning them to Rundeck. This means the filter runs locally in the plugin, not on the Proxmox server.
The plugin supports three output formats compatible with Rundeck:
-
YAML (default): Rundeck resource-yml format
--output-format yaml
-
XML: Rundeck resource-xml format
--output-format xml
-
JSON: Rundeck resource-json format
--output-format json
The default format is YAML. All formats include the same node information (name, hostname, username, tags, attributes, etc.) and are compatible with Rundeck's Resource Model Source plugins.
If you get "Couldn't authenticate user" errors:
-
Username Format: Ensure the username includes the realm:
- For root user:
root@pamorroot@pve - For other users:
username@pamorusername@pve - The realm (
@pamor@pve) is required
- For root user:
-
Password Verification: Double-check the password is correct
-
API Access: Ensure the user has API access enabled:
- Log into Proxmox web UI
- Go to Datacenter → Permissions → Users
- Verify the user exists and has appropriate roles
- API access is typically enabled by default for users with roles
-
Two-Factor Authentication (2FA): If 2FA is enabled, password authentication may not work. Use an API token instead:
- In Proxmox web UI: Datacenter → Permissions → API Tokens
- Create a token for your user
- Use format:
--proxmox-user TOKENID@REALMand--proxmox-password TOKEN_SECRET
-
Test API Access Manually:
curl -k -d "username=root@pam&password=YOUR_PASSWORD" \ https://YOUR_PROXMOX_HOST:8006/api2/json/access/ticketIf this fails, the issue is with Proxmox configuration, not the script.
-
Time Synchronization: Ensure system time is synchronized (NTP)
- Verify the Proxmox host is reachable from the Rundeck server
- Check firewall rules for port 8006
- Ensure SSL certificate issues are handled (use
--verify-sslif certificates are valid) - Test network connectivity:
telnet YOUR_PROXMOX_HOST 8006
- Check that the Proxmox user has sufficient permissions to list VMs and containers
- Verify the script has execute permissions
- Check Rundeck logs for script execution errors
- Test the script manually from the command line
- Ensure the user has at least "PVEAuditor" role or higher on the datacenter
If IP addresses are not being detected:
-
For QEMU VMs with DHCP:
- Ensure QEMU Guest Agent is installed and running inside the VM
- Verify Guest Agent is enabled in Proxmox VM configuration (
agent: 1) - Check that the VM is running (agent queries only work on running VMs)
- Test agent connectivity in Proxmox UI (should show IP in VM summary)
-
For QEMU VMs with static IPs:
- Verify the IP is configured in the VM's network settings
- Check that the config doesn't just contain 'dhcp' (which is filtered out)
-
For LXC Containers:
- Ensure IP is configured in
ipconfig0or network interface settings - Verify the IP format is correct (e.g.,
ip=192.168.1.100/24)
- Ensure IP is configured in
-
General:
- If IPs are not found, nodes will use
{name}.localas hostname - The
ip_addressattribute will be empty if no IP is detected - You can manually configure IP addresses in Rundeck if needed
- If IPs are not found, nodes will use
Test the plugin manually using uv:
uv run ./proxmox-node-source.py \
--proxmox-host your-proxmox-host.example.com \
--proxmox-user root@pam \
--proxmox-password your-password \
--default-username root \
--output-format yamlOr if you've installed dependencies with pip and activated a virtual environment:
./proxmox-node-source.py \
--proxmox-host your-proxmox-host.example.com \
--proxmox-user root@pam \
--proxmox-password your-password \
--default-username root \
--output-format yamlThis should output YAML (default) with all discovered nodes. You can also use --output-format json or --output-format xml to get different formats.
This plugin is licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later).
See the LICENSE file or the header of proxmox-node-source.py for full license details.