230 lines
7.5 KiB
Bash
Executable File
230 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -uo pipefail
|
|
|
|
# Simple interactive toolkit for a Proxmox VE node.
|
|
# Run as root. Uses whiptail for the GUI and does not execute arbitrary input.
|
|
|
|
if [[ $EUID -ne 0 ]]; then
|
|
printf 'Run this script as root, for example: sudo bash %s\n' "$0" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v whiptail >/dev/null 2>&1; then
|
|
printf 'whiptail is required. Install it with: apt install whiptail\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
TMPDIR_TOOLKIT=$(mktemp -d)
|
|
trap 'rm -rf "$TMPDIR_TOOLKIT"' EXIT
|
|
|
|
require_command() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
whiptail --title "Command unavailable" \
|
|
--msgbox "The command '$1' is not installed or not available on this node." 8 70
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
valid_id() {
|
|
[[ "$1" =~ ^[0-9]+$ ]]
|
|
}
|
|
|
|
ask_id() {
|
|
local prompt=$1
|
|
local value
|
|
|
|
value=$(whiptail --title "Enter ID" --inputbox "$prompt" 9 60 3>&1 1>&2 2>&3) || return 1
|
|
|
|
if ! valid_id "$value"; then
|
|
whiptail --title "Invalid ID" --msgbox "Enter a numeric VM or container ID." 8 55
|
|
return 1
|
|
fi
|
|
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
show_output() {
|
|
local title=$1
|
|
shift
|
|
local output="$TMPDIR_TOOLKIT/output.txt"
|
|
local status=0
|
|
|
|
"$@" >"$output" 2>&1 || status=$?
|
|
|
|
if [[ ! -s "$output" ]]; then
|
|
printf 'Command completed with exit status %s; no output.\n' "$status" >"$output"
|
|
elif (( status != 0 )); then
|
|
printf '\nCommand exited with status %s.\n' "$status" >>"$output"
|
|
fi
|
|
|
|
whiptail --title "$title" --textbox "$output" 24 85
|
|
}
|
|
|
|
confirm_action() {
|
|
whiptail --title "Confirm" --yesno "$1" 10 70
|
|
}
|
|
|
|
vm_menu() {
|
|
local choice id
|
|
|
|
while true; do
|
|
choice=$(whiptail --title "Virtual Machines (QEMU)" --menu "Choose an action:" \
|
|
16 72 8 \
|
|
"list" "List VMs (qm list)" \
|
|
"config" "Show VM configuration" \
|
|
"memory" "Show VM memory setting" \
|
|
"unlock" "Unlock a VM" \
|
|
"back" "Back" 3>&1 1>&2 2>&3) || return
|
|
|
|
case "$choice" in
|
|
list)
|
|
require_command qm && show_output "VM list" qm list
|
|
;;
|
|
config|memory|unlock)
|
|
require_command qm || continue
|
|
id=$(ask_id "Enter the VMID:") || continue
|
|
|
|
case "$choice" in
|
|
config) show_output "VM $id configuration" qm config "$id" ;;
|
|
memory) show_output "VM $id memory" bash -c 'qm config "$1" | grep -E "^memory:" || true' _ "$id" ;;
|
|
unlock)
|
|
if confirm_action "Unlock VM $id?\n\nOnly do this if you have confirmed that no task is still running for this VM."; then
|
|
show_output "Unlock VM $id" qm unlock "$id"
|
|
fi
|
|
;;
|
|
esac
|
|
;;
|
|
back) return ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
container_menu() {
|
|
local choice id
|
|
|
|
while true; do
|
|
choice=$(whiptail --title "Containers (LXC)" --menu "Choose an action:" \
|
|
14 72 6 \
|
|
"list" "List containers (pct list)" \
|
|
"config" "Show container configuration" \
|
|
"unlock" "Unlock a container" \
|
|
"back" "Back" 3>&1 1>&2 2>&3) || return
|
|
|
|
case "$choice" in
|
|
list)
|
|
require_command pct && show_output "Container list" pct list
|
|
;;
|
|
config|unlock)
|
|
require_command pct || continue
|
|
id=$(ask_id "Enter the container ID:") || continue
|
|
|
|
if [[ "$choice" == "config" ]]; then
|
|
show_output "Container $id configuration" pct config "$id"
|
|
elif confirm_action "Unlock container $id?\n\nOnly do this if you have confirmed that no task is still running for this container."; then
|
|
show_output "Unlock container $id" pct unlock "$id"
|
|
fi
|
|
;;
|
|
back) return ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
backup_menu() {
|
|
local id
|
|
|
|
require_command vzdump || return
|
|
id=$(ask_id "Enter the VM or container ID to back up:") || return
|
|
|
|
if confirm_action "Start a backup for ID $id using vzdump defaults?\n\nReview your node's backup configuration and storage capacity first."; then
|
|
show_output "Backup ID $id" vzdump "$id"
|
|
fi
|
|
}
|
|
|
|
restore_menu() {
|
|
local choice id archive
|
|
|
|
choice=$(whiptail --title "Restore" --menu "Choose what to restore:" \
|
|
12 72 4 \
|
|
"vm" "Restore a QEMU VM (qmrestore)" \
|
|
"ct" "Restore a container (pct restore)" \
|
|
"back" "Back" 3>&1 1>&2 2>&3) || return
|
|
[[ "$choice" == "back" ]] && return
|
|
|
|
id=$(ask_id "Enter the new VMID or container ID:") || return
|
|
archive=$(whiptail --title "Backup archive" --inputbox \
|
|
"Enter the full path to the vzdump archive:" 9 72 3>&1 1>&2 2>&3) || return
|
|
|
|
if [[ -z "$archive" || ! -f "$archive" ]]; then
|
|
whiptail --title "Archive not found" --msgbox "That file does not exist or is not a regular file." 8 65
|
|
return
|
|
fi
|
|
|
|
if ! confirm_action "Restore '$archive' as ID $id?\n\nRestoring can create or overwrite resources. Confirm the target ID and archive carefully."; then
|
|
return
|
|
fi
|
|
|
|
if [[ "$choice" == "vm" ]]; then
|
|
require_command qmrestore && show_output "Restore VM $id" qmrestore "$archive" "$id"
|
|
else
|
|
require_command pct && show_output "Restore container $id" pct restore "$id" "$archive"
|
|
fi
|
|
}
|
|
|
|
storage_menu() {
|
|
local choice
|
|
|
|
while true; do
|
|
choice=$(whiptail --title "Storage / LVM" --menu "Choose a read-only report:" \
|
|
14 72 6 \
|
|
"pvs" "Physical volumes (pvs)" \
|
|
"vgs" "Volume groups (vgs)" \
|
|
"lvs" "Logical volumes (lvs)" \
|
|
"back" "Back" 3>&1 1>&2 2>&3) || return
|
|
|
|
case "$choice" in
|
|
pvs) require_command pvs && show_output "Physical volumes" pvs ;;
|
|
vgs) require_command vgs && show_output "Volume groups" vgs ;;
|
|
lvs) require_command lvs && show_output "Logical volumes" lvs ;;
|
|
back) return ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
while true; do
|
|
choice=$(whiptail --title "Proxmox VE Toolkit" --menu "Select a task:" \
|
|
21 76 13 \
|
|
"vms" "Virtual machines (QEMU)" \
|
|
"containers" "Containers (LXC)" \
|
|
"backup" "Back up a VM or container (vzdump)" \
|
|
"restore" "Restore a VM or container" \
|
|
"cluster" "Cluster status (pvecm status)" \
|
|
"version" "Proxmox version (pveversion -v)" \
|
|
"storage" "Storage / LVM reports" \
|
|
"perf" "Host performance test (pveperf)" \
|
|
"subscription" "Subscription status" \
|
|
"dab" "Debian Appliance Builder help" \
|
|
"quit" "Exit" 3>&1 1>&2 2>&3) || break
|
|
|
|
case "$choice" in
|
|
vms) vm_menu ;;
|
|
containers) container_menu ;;
|
|
backup) backup_menu ;;
|
|
restore) restore_menu ;;
|
|
cluster) require_command pvecm && show_output "Cluster status" pvecm status ;;
|
|
version) require_command pveversion && show_output "Proxmox VE version" pveversion -v ;;
|
|
storage) storage_menu ;;
|
|
perf)
|
|
if require_command pveperf && confirm_action "Run pveperf?\n\nThis can cause temporary disk activity."; then
|
|
show_output "Host performance" pveperf
|
|
fi
|
|
;;
|
|
subscription) require_command pvesubscription && show_output "Subscription status" pvesubscription get ;;
|
|
dab)
|
|
if require_command dab; then
|
|
show_output "Debian Appliance Builder help" dab help
|
|
fi
|
|
;;
|
|
quit) break ;;
|
|
esac
|
|
done
|