Fixing Proxmox Terraform Deletes with curl + jq

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:

  1. Terraform tries to destroy a resource
  2. Proxmox rejects it
  3. 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.

Posted in:

Leave a Reply

Your email address will not be published. Required fields are marked *