Create, provision, and manage KVM virtual machines on Proxmox VE via YAML config and templates. Supports cloud-init, SSH provisioning, dry-run, and full API resilience.
- Ticket + CSRF authentication against the Proxmox API (
requests) deploy: create a VM fromconfig.yaml+ a template, optionally apply cloud-init, then start itlist: show all QEMU VMs on a node (table or JSON)destroy: stop and delete a VM with confirmation--dry-run: validate config + template and show the plan without touching Proxmox- Cloud-init: set user, password, SSH keys, IP config, nameserver, search domain via template fields
- UPID task polling: wait for async Proxmox tasks (create, start, stop, destroy) to finish before proceeding
- Duplicate detection: warns if a VM with the same name already exists
- Optional SSH provisioning: wait for port 22, connect with Paramiko (key and/or password), run a bash script
- Resilience: connect/read timeouts, automatic retries with backoff for transient HTTP (5xx/429) and network issues
- Validation:
config.yaml, templates, and CLI flags are checked before any VM operation - Logging at INFO / DEBUG / ERROR (
--debugor-vfor sanitized API traces) --no-color/NO_COLORfor log-friendly output; explicit exit codes for automation
$ python cli.py deploy -t templates/docker.yaml
Target API: https://pve.example.com:8006 (node: pve)
Template: docker.yaml → VM name 'docker-host'
Resources: 4096 MB RAM, 4 cores, 40 GB disk
OS image: debian-12-genericcloud-amd64 (used as disk source reference)
Cloud-init: user=admin, ssh_keys=1, ip=dhcp
Script: scripts/install_docker.sh
✓ Created VM ID 101
✓ Cloud-init config applied
✓ Started VM 101 (docker-host)
✓ Provisioning finished on 10.0.0.101
$ python cli.py deploy -t templates/docker.yaml --dry-run
Target API: https://pve.example.com:8006 (node: pve)
Template: docker.yaml → VM name 'docker-host'
Resources: 4096 MB RAM, 4 cores, 40 GB disk
Cloud-init: user=admin, ssh_keys=1, ip=dhcp
Script: scripts/install_docker.sh
✓ Dry-run complete — plan is valid. No changes made.
$ python cli.py list
Listing VMs on https://pve.example.com:8006 node=pve
------------------------------------------------------------------------
VMID NAME STATUS MEM(MB) CPUS PID
------------------------------------------------------------------------
100 docker-host running 4096 4 18923
101 nginx-proxy running 2048 2 19450
102 dev-ubuntu stopped 1024 1 -
$ python cli.py destroy --vmid 102
Target: https://pve.example.com:8006 node=pve, VM 102
VM 102: name='dev-ubuntu', status=stopped
Destroy VM 102 ('dev-ubuntu') on node pve? This cannot be undone [y/N]: y
Destroying VM 102 (purge=True)...
✓ VM 102 (dev-ubuntu) destroyed
- Python 3.9+
- A Proxmox VE node and credentials (
user@realm, e.g.root@pam)
cd proxdeploy
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt-
Copy the example config and edit it:
cp config.yaml.example config.yaml
-
Fill in your host, node, username, and defaults.
-
Prefer a password via environment variable:
export PROXDEPLOY_PASSWORD='your-secret'
-
Set
proxmox.verify_ssl: falseonly if you use a self-signed cert. -
Optional API tuning under
proxmox:connect_timeout/read_timeout(seconds)max_retries,retry_backoff_base,retry_max_wait
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General CLI / usage error |
| 2 | Configuration or template validation error |
| 3 | Proxmox authentication / session error |
| 4 | SSH provisioning error |
python cli.py deploy -t templates/docker.yaml
python cli.py deploy -t templates/docker.yaml --dry-run
python cli.py --debug deploy -t templates/docker.yamlAdd cloud-init fields to your template:
name: cloud-vm
memory: 4096
cores: 4
disk: 40
os_image: debian-12-genericcloud-amd64
ci_user: admin
ci_password: changeme
ci_ssh_keys:
- ssh-rsa AAAA...
ci_ip_config: ip=dhcppython cli.py deploy -t templates/cloud-vm.yaml --ssh-key ~/.ssh/id_rsa --user adminIf the template defines script:, deploy waits until SSH is reachable, then runs it:
export PROXDEPLOY_SSH_PASSWORD='guest-root-password'
python cli.py deploy -t templates/docker.yaml --ssh-key ~/.ssh/id_rsa --user root
python cli.py deploy -t templates/nginx.yaml --ssh-key ~/.ssh/id_rsa --ssh-host 192.168.1.80python cli.py list
python cli.py list --format jsonpython cli.py destroy --vmid 105
python cli.py destroy --vmid 105 --forceTemplates are validated before any API call. Unknown keys are rejected. Required keys:
| Field | Required | Description |
|---|---|---|
name |
yes | VM name (non-empty string) |
memory |
yes | RAM in MB (integer >= 16) |
cores |
yes | vCPU count (integer >= 1) |
disk |
yes | Disk size in GB (integer >= 1) |
Optional fields:
| Field | Description |
|---|---|
os_image |
Disk image reference on storage (future / import workflows) |
script |
Local bash file to run over SSH after boot |
bridge |
Network bridge (default defaults.bridge) |
storage |
Storage pool ID (default defaults.storage) |
ostype |
Guest type (default l26) |
vmid |
Fixed VM ID (otherwise next free cluster ID) |
ssh_host |
Guest SSH address (overridden by --ssh-host) |
ssh_password |
SSH password (prefer PROXDEPLOY_SSH_PASSWORD) |
Cloud-init fields (all optional):
| Field | Description |
|---|---|
ci_user |
Cloud-init user |
ci_password |
Cloud-init password |
ci_ssh_keys |
SSH public key(s) — string or list |
ci_ip_config |
IP config string (default ip=dhcp) |
ci_nameserver |
DNS nameserver |
ci_searchdomain |
DNS search domain |
pip install -r requirements-dev.txt
python -m pytest tests/ -v53 tests covering: template validation, config validation, API auth/retries/errors, VM operations, UPID task polling, log sanitization, CLI dry-run/deploy/list/destroy.
cli.py # Click CLI entrypoint (deploy, list, destroy)
proxmox/
api.py # Auth, retries, timeouts, HTTP helpers
vm.py # KVM create / start / stop / destroy / list
tasks.py # UPID async task polling
cloudinit.py # Cloud-init config + disk import
template.py # Template validation + ValidatedTemplate
config_validate.py # config.yaml validation
sanitize.py # Redact secrets in API payloads for logs
exceptions.py # Typed errors + exit codes
guest.py # QEMU guest-agent IPv4 discovery
provision/
ssh.py # TCP wait + Paramiko script run
scripts/ # Example install_*.sh referenced by templates
templates/ # docker.yaml, nginx.yaml, basic-ubuntu.yaml
tests/ # pytest suite (53 tests)
config.yaml.example # Example config (copy to config.yaml)
MIT — see LICENSE.