#!/usr/bin/env bash # proxmox-install.sh — one-shot installer for a fresh Proxmox LXC (or # any Debian/Ubuntu host). Fetches a prebuilt release bundle from the # Gitea package registry, extracts it, and hands off to install.sh. # # The bundle itself is slim (~30 MB: orchestrator + agent + deploy # scripts + a live-image/VERSION pointer). install.sh compares that # pointer against /var/lib/vetting/live/VERSION and fetches the # ~300 MB vmlinuz+initrd.img from the registry only when they differ, # so repeated runs cost ~10 s on no-live-image-change releases. # # Usage: # curl -fsSL https://gitea.thewrightserver.net/josh/Vetting/raw/branch/main/deploy/proxmox-install.sh | sudo bash # # Flags / env overrides: # REGISTRY_URL base URL of the Gitea instance hosting the # package registry (default: https://gitea.thewrightserver.net) # PACKAGE_OWNER Gitea owner of the `vetting` package # (default: josh) # FORCE_LIVE_IMAGE=1 or --force-live-image — re-download the live # image even when the on-disk version matches # (useful when the local files got corrupted). set -euo pipefail # ---- style helpers ----------------------------------------------------- # Identical block across proxmox-install.sh, install.sh, pxe-setup.sh. # Inlined (not sourced) so the curl|bash entrypoint renders without a # prior fetch. Respects NO_COLOR, non-TTY, and non-UTF-8 locales. _color=0; _unicode=0 if [[ -t 2 && -z "${NO_COLOR:-}" && "${TERM:-dumb}" != "dumb" ]]; then _color=1 fi case "${LC_ALL:-}${LANG:-}" in *UTF-8*|*utf8*|*UTF8*) _unicode=1 ;; esac if (( _color )); then _B=$'\033[1m'; _D=$'\033[2m'; _R=$'\033[0m' _C=$'\033[1;36m'; _G=$'\033[32m'; _Y=$'\033[33m'; _E=$'\033[31m' else _B=""; _D=""; _R=""; _C=""; _G=""; _Y=""; _E="" fi if (( _unicode )); then _S_STEP="▸"; _S_OK="✓"; _S_WARN="⚠"; _S_FAIL="✗"; _S_INFO="·" _B_TL="╭"; _B_TR="╮"; _B_BL="╰"; _B_BR="╯"; _B_H="─"; _B_V="│" else _S_STEP="-->"; _S_OK="[ok]"; _S_WARN="[!]"; _S_FAIL="[x]"; _S_INFO="*" _B_TL="+"; _B_TR="+"; _B_BL="+"; _B_BR="+"; _B_H="-"; _B_V="|" fi _start_epoch="$(date +%s)"; _step_epoch=""; _quiet_log=""; _spin_pid="" _fmt_dur() { local s=$1 if (( s < 60 )); then printf '%ds' "$s" elif (( s < 3600 )); then printf '%dm %ds' "$((s/60))" "$((s%60))" else printf '%dh %dm' "$((s/3600))" "$(((s%3600)/60))" fi } banner() { local inner=" $1 " w line="" i=0 w=${#inner} while (( i < w )); do line+="${_B_H}"; i=$((i+1)); done printf '\n %s%s%s%s%s\n' "${_C}" "${_B_TL}" "${line}" "${_B_TR}" "${_R}" >&2 printf ' %s%s%s%s%s%s%s%s%s\n' "${_C}" "${_B_V}" "${_R}" "${_B}" "${inner}" "${_R}" "${_C}" "${_B_V}" "${_R}" >&2 printf ' %s%s%s%s%s\n\n' "${_C}" "${_B_BL}" "${line}" "${_B_BR}" "${_R}" >&2 } step() { _step_epoch="$(date +%s)" printf '%s%s%s %s%s%s\n' "${_C}" "${_S_STEP}" "${_R}" "${_B}" "$1" "${_R}" >&2 } ok() { local tail="" if [[ -n "${_step_epoch}" ]]; then tail=" ${_D}($(_fmt_dur $(( $(date +%s) - _step_epoch ))))${_R}" fi printf ' %s%s%s %s%s\n' "${_G}" "${_S_OK}" "${_R}" "$1" "${tail}" >&2 _step_epoch="" } info() { printf ' %s%s %s%s\n' "${_D}" "${_S_INFO}" "$1" "${_R}" >&2; } warn() { printf ' %s%s %s%s\n' "${_Y}" "${_S_WARN}" "$1" "${_R}" >&2; } die() { printf '\n%s%s %s%s\n' "${_E}" "${_S_FAIL}" "$1" "${_R}" >&2 if [[ -n "${_quiet_log:-}" && -s "${_quiet_log}" ]]; then printf ' %s── last 40 lines of output ──%s\n' "${_D}" "${_R}" >&2 tail -n 40 "${_quiet_log}" | sed 's/^/ /' >&2 printf ' %sfull log: %s%s\n' "${_D}" "${_quiet_log}" "${_R}" >&2 fi exit 1 } _SPIN=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏") _start_spin() { (( _color && _unicode )) || return 0 local label="$1" ( local i=0 while :; do printf '\r %s%s%s %s ' "${_C}" "${_SPIN[i]}" "${_R}" "${label}" >&2 i=$(( (i+1) % ${#_SPIN[@]} )) sleep 0.1 done ) & _spin_pid=$! } _stop_spin() { [[ -n "${_spin_pid}" ]] || return 0 kill "${_spin_pid}" 2>/dev/null || true wait "${_spin_pid}" 2>/dev/null || true _spin_pid="" printf '\r\033[2K' >&2 } # run_quiet "