When I started automating my homelab using Terraform + Proxmox, everything worked great… until it didn’t.
The Problem
In a push-based deployment (via GitHub Actions), I hit a blocker:
The Proxmox Terraform provider cannot delete a running VM/container.
That means:
- Terraform tries to destroy a resource
- Proxmox rejects it
- Pipeline fails ❌
So the fix is simple in theory:
✅ Check if the VM is running → stop it → then delete it
But Terraform doesn’t handle this natively — so I built a small workaround using curl and jq.
What You Need
Before anything, install:
- curl (for API calls) → https://curl.se/windows/
- jq (for parsing JSON) → https://jqlang.org/download/
Proxmox API Access
You’ll need a Proxmox API token.
Docs:
- https://pve.proxmox.com/wiki/Proxmox_VE_API#API_Tokens
- https://pve.proxmox.com/pve-docs/api-viewer/index.html#/nodes/{node}/qemu/{vmid}/status/current
Set your environment variables (Windows example):
setx TF_VAR_proxmox_api_url "https://YOUR-IP:8006/api2/json"
setx TF_VAR_proxmox_api_token_id "user@pam!token"
setx TF_VAR_proxmox_api_token_secret "your-secret"
Quick Env Variable Ref (Windows)
Temporary:
set MY_VAR=HelloWorld
echo %MY_VAR%
Persistent:
setx MY_VAR "HelloWorld"
System-wide:
setx /m MY_VAR "HelloWorld"
The Fix (Core Idea)
We query the VM status using the Proxmox API:
curl -sk -H "Authorization: PVEAPIToken=USER!TOKEN=SECRET" \
https://IP:8006/api2/json/nodes/NODE/qemu/VMID/status/current
Then extract the state with jq:
jq -r '.data.status'
Putting It Together
Here’s the logic:
STATUS=$(curl -sk -H "$PVE_AUTH" \
"${PVE_API}/nodes/${PVE_NODE}/qemu/${VMID}/status/current" \
| jq -r '.data.status')
if [ "$STATUS" = "running" ]; then
echo "Stopping VM $VMID..."
curl -sk -X POST -H "$PVE_AUTH" \
"${PVE_API}/nodes/${PVE_NODE}/qemu/${VMID}/status/stop"
fi
Now Terraform can safely destroy the VM after this runs.
Top comments (0)