#!/usr/bin/env sh set -euC ################################################################################ ## Constants readonly apiurl=https://192.168.51.81:8006/api2/json ## FIXME: There seems to be a problem with file upload where the task is ## registered to `node051` no matter what node we are actually uploading to? For ## now, let us just use `node051` everywhere. readonly node=node051 readonly tmpdir=/tmp/proxmox-provision-$RANDOM$RANDOM mkdir $tmpdir ################################################################################ ## Parse arguments username= password= vmids= help () { cat <<EOF Usage: $0 [OPTION...] [ID...] Authentication options: --username STR Username, with provider (eg. niols@pve) --password STR Password If not provided via the command line, username and password will be looked for in a '.proxmox' file in the current working directory, the username on the first line, and the password on the second. Others: -h|-?|--help Show this help and exit EOF } die () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; exit 2; } die_with_help () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; help; exit 2; } while [ $# -gt 0 ]; do argument=$1 shift case $argument in --username) readonly username=$1; shift ;; --password) readonly password=$1; shift ;; -h|-\?|--help) help; exit 0 ;; -*) die_with_help 'Unknown argument: `%s`.' "$argument" ;; *) vmids="$vmids $argument" ;; esac done if [ -z "$username" ] || [ -z "$password" ]; then if [ -f .proxmox ]; then { read username; read password; } < .proxmox else die_with_help 'Required: `--username` and `--password`.\n' fi fi ################################################################################ ## Getting started printf 'Authenticating...' response=$( http \ --verify no \ POST $apiurl/access/ticket \ "username=$username" \ "password=$password" ) readonly ticket=$(echo "$response" | jq -r .data.ticket) readonly csrfToken=$(echo "$response" | jq -r .data.CSRFPreventionToken) printf ' done.\n' acquire_lock () { until mkdir $tmpdir/lock-$1 2>/dev/null; do sleep 1; done } release_lock () { rmdir $tmpdir/lock-$1 } proxmox () { acquire_lock proxmox http \ --verify no \ --form \ "$@" \ "Cookie:PVEAuthCookie=$ticket" \ "CSRFPreventionToken:$csrfToken" release_lock proxmox } ## Synchronous variant for when the `proxmox` function would just respond an ## UPID in the `data` JSON field. proxmox_sync () ( response=$(proxmox "$@") upid=$(echo "$response" | jq -r .data) while :; do response=$(proxmox GET $apiurl/nodes/$node/tasks/$upid/status) status=$(echo "$response" | jq -r .data.status) case $status in running) sleep 1 ;; stopped) break ;; *) die 'unexpected status: `%s`' "$status" ;; esac done ) ################################################################################ ## Stop VM stop_vm () { printf 'Stopping VM %d...\n' $1 proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/stop \ 'overrule-shutdown'==1 printf 'done stopping VM %d.\n' $1 } ################################################################################ ## Delete VM delete_vm () { printf 'Deleting VM %d...\n' $1 proxmox_sync DELETE $apiurl/nodes/$node/qemu/$1 \ 'destroy-unreferenced-disks'==1 \ 'purge'==1 printf 'done deleting VM %d.\n' $1 } ################################################################################ ## Main loop printf 'Removing VMs%s...\n' "$vmids" remove_vm () { stop_vm $1 delete_vm $1 } for vmid in $vmids; do remove_vm $vmid & done wait printf 'done removing VMs%s.\n' "$vmids" ################################################################################ ## Cleanup rm -Rf $tmpdir