#!/usr/bin/env bash # UKRRS Proxmox control wrapper for harness/human use. HARD RULES baked in: # - vmids listed in PROTECTED are never touched (list THIS VM first). # - graceful shutdown only; no reset, no hard stop, no bare down (house rule). # Env: # PVE_LOCAL=1 run ON the pve host itself (pvesh direct) # or PVE_HOST + PVE_TOKEN remote, token format: user@realm!tokenid=secret # PVE_NODE node name (required for vm ops) # PROTECTED required, comma-separated vmids # Usage: # proxmox-ctl.sh vms # proxmox-ctl.sh shutdown # proxmox-ctl.sh start # proxmox-ctl.sh snapshot # Token setup (on the pve host, see REPORT.md appendix B): # pveum user add ukrrs-infra@pam # pveum user token add ukrrs-infra@pam harness -privsep 0 -expire 0 # pveum acl modify /pool/ -user ukrrs-infra@pam -role PVEVMUser set -euo pipefail : "${PROTECTED:?set PROTECTED=vmid1,vmid2,... (this VM must be in the list)}" pvesh_() { if [ "${PVE_LOCAL:-0}" = 1 ]; then command pvesh "$@" else : "${PVE_HOST:?}" "${PVE_TOKEN:?}" command pvesh --host "$PVE_HOST" --api-token "$PVE_TOKEN" "$@" fi } guard() { case ",$PROTECTED," in *",$1,"*) echo "REFUSED: vmid $1 is PROTECTED" >&2; exit 3 ;; esac } cmd=${1:-}; shift || true case "$cmd" in vms) pvesh_ get /cluster/resources --type vm ;; shutdown) [ $# = 1 ] || { echo "usage: $0 shutdown " >&2; exit 2; } guard "$1"; : "${PVE_NODE:?}" pvesh_ create "/nodes/$PVE_NODE/qemu/$1/status/shutdown" --timeout 120 ;; start) [ $# = 1 ] || { echo "usage: $0 start " >&2; exit 2; } guard "$1"; : "${PVE_NODE:?}" pvesh_ create "/nodes/$PVE_NODE/qemu/$1/status/start" ;; snapshot) [ $# = 2 ] || { echo "usage: $0 snapshot " >&2; exit 2; } guard "$1"; : "${PVE_NODE:?}" pvesh_ create "/nodes/$PVE_NODE/qemu/$1/snapshot" snapname="$2" ;; *) echo "usage: $0 vms|shutdown |start |snapshot " >&2 exit 2 ;; esac