179 lines
5.6 KiB
Bash
Executable File
179 lines
5.6 KiB
Bash
Executable File
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:-40} # 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 <<EOF
|
||
# Remove stale lock if it exists
|
||
lock="/var/lock/qemu-server/lock-${vmid}.conf"
|
||
if [[ -e "\$lock" ]]; then
|
||
pid=\$(fuser -n file "\$lock" 2>/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
|