98 lines
2.1 KiB
Bash
98 lines
2.1 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -Eeuo pipefail
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Logging / Errors
|
||
|
|
########################################
|
||
|
|
|
||
|
|
_ts() { date '+%F %T'; }
|
||
|
|
|
||
|
|
log() { echo "[$(_ts)] $*"; }
|
||
|
|
info() { log "INFO: $*"; }
|
||
|
|
warn() { log "WARN: $*"; }
|
||
|
|
die() { log "ERROR: $*"; exit 1; }
|
||
|
|
|
||
|
|
on_error() {
|
||
|
|
die "Failed at line $1: $2 (exit=$3)"
|
||
|
|
}
|
||
|
|
setup_traps() {
|
||
|
|
trap 'on_error $LINENO "$BASH_COMMAND" "$?"' ERR
|
||
|
|
}
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Preconditions
|
||
|
|
########################################
|
||
|
|
|
||
|
|
need_cmd() {
|
||
|
|
for c in "$@"; do
|
||
|
|
command -v "$c" >/dev/null 2>&1 || die "Missing command: $c"
|
||
|
|
done
|
||
|
|
}
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Proxmox helpers
|
||
|
|
########################################
|
||
|
|
|
||
|
|
pve_bridge_exists() {
|
||
|
|
[[ -d "/sys/class/net/$1/bridge" ]]
|
||
|
|
}
|
||
|
|
|
||
|
|
pve_storage_exists() {
|
||
|
|
pvesm status --storage "$1" >/dev/null 2>&1
|
||
|
|
}
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Template handling
|
||
|
|
########################################
|
||
|
|
|
||
|
|
pve_template_ensure_debian12() {
|
||
|
|
local tpl="debian-12-standard_12.12-1_amd64.tar.zst"
|
||
|
|
local store="$1"
|
||
|
|
|
||
|
|
if ! pveam list "$store" >/dev/null 2>&1; then
|
||
|
|
warn "pveam storage '$store' not available for templates; falling back to 'local'"
|
||
|
|
store="local"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if ! pveam list "$store" | awk '{print $2}' | grep -qx "$tpl"; then
|
||
|
|
info "Downloading CT template to $store: $tpl"
|
||
|
|
pveam update
|
||
|
|
pveam download "$store" "$tpl"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "$store:vztmpl/$tpl"
|
||
|
|
}
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Cluster-wide CTID
|
||
|
|
########################################
|
||
|
|
|
||
|
|
pve_next_free_ctid() {
|
||
|
|
local used
|
||
|
|
used="$(pvesh get /cluster/resources --type vm | awk 'NR>1 {print $1}' | sort -n)"
|
||
|
|
|
||
|
|
for id in $(seq 100 9999); do
|
||
|
|
if ! echo "$used" | grep -qx "$id"; then
|
||
|
|
echo "$id"
|
||
|
|
return
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
die "No free CTID found"
|
||
|
|
}
|
||
|
|
|
||
|
|
########################################
|
||
|
|
# Networking
|
||
|
|
########################################
|
||
|
|
|
||
|
|
pve_build_net0() {
|
||
|
|
local bridge="$1"
|
||
|
|
local ip="$2"
|
||
|
|
|
||
|
|
if [[ "$ip" == "dhcp" ]]; then
|
||
|
|
echo "name=eth0,bridge=$bridge,ip=dhcp"
|
||
|
|
else
|
||
|
|
echo "name=eth0,bridge=$bridge,ip=$ip"
|
||
|
|
fi
|
||
|
|
}
|