SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Load the .env file that lives beside the script set -a # automatically export assignments source "${SCRIPT_DIR}/.env" set +a # ---- login ---- login=$(curl -s -k -d "username=${USERNAME}&password=${PASSWORD}" \ "https://${ADDR}:8006/api2/json/access/ticket") echo "=== LOGIN RESPONSE ===" echo "$login" echo "======================" # Extract ticket & CSRF TICKET=$(echo "$login" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4) CSRF=$(echo "$login" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4) echo "Ticket: $TICKET" echo "CSRF : $CSRF" echo "-------------------" # ------------------------------------------------- # Helper: wait for a Proxmox task to finish # ------------------------------------------------- wait_task() { local upid="$1" local timeout=${2:-120} # seconds (default 2 min) local interval=2 local elapsed=0 while (( elapsed < timeout )); do result=$(curl -s -k \ -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/nodes/${ADDR}/tasks/${upid}/status") status=$(echo "$result" | jq -r '.data.status') exitstatus=$(echo "$result" | jq -r '.data.exitstatus') if [[ "$status" == "stopped" ]]; then if [[ "$exitstatus" == "OK" ]]; then return 0 else echo "Task $upid finished with error: $exitstatus" >&2 return 1 fi fi sleep "$interval" (( elapsed += interval )) done echo "Task $upid timed out after $timeout seconds" >&2 return 1 } # ------------------------------------------------- force_stop_vm_ssh() { local vmid=$1 local node=$2 # e.g. pve01 # SSH to the node (assumes key‑based auth or passwordless login) ssh root@"${node}" bash </dev/null | awk '{print \$1}') [[ -n "\$pid" ]] && kill -9 "\$pid" rm -f "\$lock" fi # Stop the VM qm stop "${vmid}" # Wait until it reports stopped while qm status "${vmid}" | grep -q running; do sleep 1; done EOF echo "VM $vmid on node $node is now stopped." } while true; do echo "Select an option:" echo "1) get nodes" echo "2) get vm" echo "3) create vm" echo "4) power vm" echo "5) delete vm" echo "6) Exit" printf "Enter choice [1-6]: " read choice case $choice in 1) # Show only VM IDs and names curl -s -k -b "PVEAuthCookie=${TICKET}" -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/cluster/resources?type=vm" | jq '.data[] | {vmid, name, status, node}' ;; 2) curl -s -k -b "PVEAuthCookie=${TICKET}" -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/cluster/resources?type=vm" | jq . ;; 3) echo "PrintID:" read id echo "PintNAME:" read name curl -k -X POST \ -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ -d "vmid=${id}&name=${name}&memory=2048&net0=virtio,bridge=vmbr0" \ https://${ADDR}:8006/api2/json/nodes/${ADDR}/qemu ;; 4) echo "PrintID:" read id curl -k -X POST \ -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ https://${ADDR}:8006/api2/json/nodes/${ADDR}/qemu/${id}/status/start ;; 5) echo "PrintID:"; read id # ------------------------------------------------- # 1️⃣ Find the node that actually hosts the VM # ------------------------------------------------- VM_INFO=$(curl -s -k -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/cluster/resources?type=vm") VM_NODE=$(echo "$VM_INFO" | jq -r --arg id "$id" \ '.data[] | select(.vmid == ($id|tonumber)) | .node') if [[ -z "$VM_NODE" ]]; then echo "Could not locate VM $id" continue fi echo "VM $id is on node $VM_NODE" # ------------------------------------------------- # 2️⃣ Stop the VM via API and wait for the task # ------------------------------------------------- stop_resp=$(curl -s -k -X POST \ -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/nodes/${VM_NODE}/qemu/${id}/status/stop") stop_upid=$(echo "$stop_resp" | jq -r '.data') echo "Stop task UPID: $stop_upid" if ! wait_task "$stop_upid"; then echo "Failed to stop VM $id – aborting delete." continue fi echo "VM $id is now stopped." # ------------------------------------------------- # 3️⃣ Destroy the VM via API and wait for the task # ------------------------------------------------- destroy_resp=$(curl -s -k -X POST \ -b "PVEAuthCookie=${TICKET}" \ -H "CSRFPreventionToken: ${CSRF}" \ "https://${ADDR}:8006/api2/json/nodes/${VM_NODE}/qemu/${id}/destroy") destroy_upid=$(echo "$destroy_resp" | jq -r '.data') echo "Destroy task UPID: $destroy_upid" if wait_task "$destroy_upid"; then echo "VM $id successfully removed." else echo "Failed to destroy VM $id." fi ;; 6) echo "Goodbye!"; exit 0 ;; *) echo "Invalid choice, try again." ;; esac done