Files
proxmox-snapshot-service/install.sh
T
duffyduckandClaude Opus 5 963463a1a1 Web-Oberflaeche als Dienst, Anmeldung mit den Proxmox-Benutzern
install.sh --with-webexplorer --port <nummer> richtet pvesnap-web.service
ein. Fehlt der Port, bricht das Skript mit einer Erklaerung ab; --port
ohne --with-webexplorer, ein Port ausserhalb 1-65535, etwas anderes als
eine Zahl und Port 8006 (Proxmox selbst) werden ebenfalls abgefangen -
und zwar vor der root-Pruefung, damit ein Tippfehler sofort auffaellt.
--help beschreibt jetzt alle Optionen mit Beispielen.

Port, Adresse und Anmeldeart stehen in /etc/pvesnap/web.conf und lassen
sich dort aendern, ohne die Unit anzufassen.

Angemeldet wird mit den Benutzern von Proxmox VE: dieselbe Maske aus
Benutzer, Passwort und Realm-Auswahl, geprueft ueber POST /access/ticket
auf der lokalen API - also derselbe Weg wie im Proxmox-Webinterface. Alle
Realms funktionieren damit automatisch; Zwei-Faktor-Anmeldungen werden
abgewiesen statt halb durchgewinkt.

Ein gueltiges Passwort allein reicht nicht: zusaetzlich braucht der
Benutzer auf dem Gast das Recht VM.Snapshot (geprueft auf /, /vms,
/vms/<id> und dem Pool). Sonst koennte jeder Proxmox-Benutzer saemtliche
Dateien aller Gaeste lesen. In der Gastliste erscheinen nur erlaubte
Gaeste, root@pam sieht wie in Proxmox alles. Anpassbar ueber
--require-privilege und --allow-user.

Ausserdem: SIGTERM haengt einen offenen Snapshot wieder aus (ohne das
bliebe er bei "systemctl stop" eingebunden), und beim Start werden Reste
von Prozessen abgeraeumt, die es nicht mehr gibt - parallel laufende
Sitzungen bleiben dabei unangetastet.

Auf pvetest01 geprueft: Dienststart ueber systemd, Anmeldemaske mit den
Realms des Hosts, Abweisung ohne und mit falschen Zugangsdaten (401,
protokolliert mit Absender-IP), Zugriff ohne Recht (403 auf Snapshot-
Liste und Oeffnen), vollstaendiger Ablauf als Berechtigter bis zum
Datei-Download, Abmelden macht die Sitzung ungueltig, und SIGTERM
hinterlaesst weder rbd-Maps noch Mountpunkte.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 10:15:56 +02:00

247 lines
8.6 KiB
Bash
Executable File

#!/bin/bash
# ---------------------------------------------------------------------
# pvesnap - Installation
#
# Aufruf: ./install.sh [Optionen]
#
# --with-webexplorer Web-Oberflaeche zusaetzlich als Dienst
# einrichten (pvesnap-web.service).
# Erfordert --port.
# --port <nummer> Port fuer die Web-Oberflaeche, z.B. 8823
# --bind <adresse> Adresse, auf der sie lauscht
# (Vorgabe: 0.0.0.0 = alle)
# --no-start installieren, aber Dienste nicht starten
# --force auch ohne erkanntes Proxmox VE installieren
# -h, --help diese Hilfe
#
# Beispiele:
# ./install.sh
# ./install.sh --with-webexplorer --port 8823
# ./install.sh --with-webexplorer --port 8443 --bind 10.0.0.5
#
# Die Web-Oberflaeche meldet Benutzer gegen Proxmox VE an - dieselben
# Zugangsdaten und Realms wie im Proxmox-Webinterface.
# ---------------------------------------------------------------------
set -euo pipefail
LIB_DIR="/usr/lib/pvesnap"
BIN="/usr/local/bin/pvesnap"
CONF_DIR="/etc/pvesnap"
CONF="${CONF_DIR}/pvesnap.conf"
STATE_DIR="/var/lib/pvesnap"
DOC_DIR="/usr/share/doc/pvesnap"
UNIT="/etc/systemd/system/pvesnap.service"
WEB_UNIT="/etc/systemd/system/pvesnap-web.service"
WEB_CONF="${CONF_DIR}/web.conf"
SRC="$(cd "$(dirname "$0")" && pwd)"
START=1
FORCE=0
WEB=0
WEB_PORT=""
WEB_BIND="0.0.0.0"
while [ $# -gt 0 ]; do
case "$1" in
--with-webexplorer) WEB=1 ;;
--port) WEB_PORT="${2:-}"; shift ;;
--port=*) WEB_PORT="${1#*=}" ;;
--bind) WEB_BIND="${2:-}"; shift ;;
--bind=*) WEB_BIND="${1#*=}" ;;
--no-start) START=0 ;;
--force) FORCE=1 ;;
-h|--help) sed -n '2,24p' "$0" | sed 's/^#[[:space:]]\{0,1\}//'; exit 0 ;;
*) echo "Unbekannte Option: $1" >&2
echo "Hilfe mit: $0 --help" >&2; exit 1 ;;
esac
shift
done
info() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m==>\033[0m %s\n' "$*" >&2; }
fail() { printf '\033[1;31m==>\033[0m %s\n' "$*" >&2; exit 1; }
# --- Web-Oberflaeche: Angaben pruefen ---------------------------------
if [ "$WEB" -eq 1 ]; then
if [ -z "$WEB_PORT" ]; then
fail "--with-webexplorer benoetigt einen Port.
Beispiel: ./install.sh --with-webexplorer --port 8823
Hilfe mit: $0 --help"
fi
case "$WEB_PORT" in
''|*[!0-9]*) fail "--port erwartet eine Zahl, bekommen: '$WEB_PORT'" ;;
esac
if [ "$WEB_PORT" -lt 1 ] || [ "$WEB_PORT" -gt 65535 ]; then
fail "--port muss zwischen 1 und 65535 liegen (bekommen: $WEB_PORT)"
fi
if [ "$WEB_PORT" -eq 8006 ]; then
fail "Port 8006 gehoert dem Proxmox-Webinterface - bitte einen anderen waehlen."
fi
if ss -ltn 2>/dev/null | grep -qE "[:.]${WEB_PORT}[[:space:]]"; then
warn "Auf Port ${WEB_PORT} lauscht bereits etwas - der Dienst wird sich "
warn "moeglicherweise nicht starten lassen."
fi
[ -n "$WEB_BIND" ] || fail "--bind erwartet eine Adresse"
elif [ -n "$WEB_PORT" ]; then
fail "--port wirkt nur zusammen mit --with-webexplorer."
fi
[ "$(id -u)" -eq 0 ] || fail "Bitte als root ausfuehren (sudo ./install.sh)."
command -v python3 >/dev/null 2>&1 || fail "python3 wird benoetigt."
python3 - <<'PY' || fail "Python 3.7 oder neuer wird benoetigt."
import sys
sys.exit(0 if sys.version_info >= (3, 7) else 1)
PY
if ! command -v pvesh >/dev/null 2>&1; then
if [ "$FORCE" -eq 1 ]; then
warn "pvesh nicht gefunden - installiere trotzdem (--force)."
START=0
else
fail "pvesh nicht gefunden. pvesnap gehoert auf einen Proxmox-VE-Host.
Mit --force laesst sich die Installation trotzdem erzwingen."
fi
fi
command -v systemctl >/dev/null 2>&1 || fail "systemd wird benoetigt."
[ -d "${SRC}/pvesnap" ] || fail "Verzeichnis 'pvesnap' nicht gefunden (Aufruf aus dem Projektordner?)."
# --- Programm ---------------------------------------------------------
info "Installiere Programm nach ${LIB_DIR}"
rm -rf "${LIB_DIR}/pvesnap"
install -d -m 0755 "${LIB_DIR}"
cp -r "${SRC}/pvesnap" "${LIB_DIR}/pvesnap"
find "${LIB_DIR}/pvesnap" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true
chmod -R go-w "${LIB_DIR}/pvesnap"
info "Installiere Startbefehle"
install_command() { # $1 = Befehlsname, $2 = Python-Modul
cat > "/usr/local/bin/$1" <<EOF
#!/bin/sh
# von install.sh erzeugt
PYTHONPATH="${LIB_DIR}\${PYTHONPATH:+:\$PYTHONPATH}" exec /usr/bin/python3 -m $2 "\$@"
EOF
chmod 0755 "/usr/local/bin/$1"
info " /usr/local/bin/$1"
}
install_command pvesnap pvesnap
install_command pvesnap-explorer pvesnap.explorer
install_command pvesnap-web pvesnap.web
# --- Konfiguration ----------------------------------------------------
install -d -m 0755 "${CONF_DIR}" "${STATE_DIR}" "${DOC_DIR}"
if [ -f "${CONF}" ]; then
info "Vorhandene Konfiguration bleibt unveraendert: ${CONF}"
install -m 0644 "${SRC}/config/pvesnap.conf.example" "${CONF_DIR}/pvesnap.conf.example"
else
info "Lege Beispielkonfiguration an: ${CONF}"
install -m 0640 "${SRC}/config/pvesnap.conf.example" "${CONF}"
install -m 0644 "${SRC}/config/pvesnap.conf.example" "${CONF_DIR}/pvesnap.conf.example"
NEW_CONFIG=1
fi
if [ -f "${SRC}/README.md" ]; then
install -m 0644 "${SRC}/README.md" "${DOC_DIR}/README.md"
fi
# --- systemd ----------------------------------------------------------
info "Installiere systemd-Unit ${UNIT}"
install -m 0644 "${SRC}/systemd/pvesnap.service" "${UNIT}"
systemctl daemon-reload
info "Pruefe Konfiguration"
if ! "${BIN}" --config "${CONF}" check; then
warn "Die Konfiguration ist noch nicht vollstaendig - Dienst wird nicht gestartet."
START=0
fi
if systemctl enable pvesnap.service >/dev/null 2>&1; then
info "Dienst beim Systemstart aktiviert"
else
warn "Dienst konnte nicht aktiviert werden - bitte 'systemctl enable pvesnap' pruefen."
fi
# --- Web-Oberflaeche als Dienst ---------------------------------------
if [ "$WEB" -eq 1 ]; then
info "Richte Web-Oberflaeche als Dienst ein (Port ${WEB_PORT})"
cat > "${WEB_CONF}" <<EOF
# Aufrufparameter von pvesnap-web.service
# Nach Aenderungen: systemctl restart pvesnap-web
#
# --auth pve Anmeldung mit den Benutzern von Proxmox VE (empfohlen)
# --auth token Zugangsschluessel in der Adresse
# --auth none ohne jede Anmeldung - nur in vertrauenswuerdigen Netzen
#
# Sichtbar ist ein Gast nur fuer Benutzer, die darauf das Recht aus
# --require-privilege besitzen (Vorgabe: VM.Snapshot). Mit --allow-user
# lassen sich einzelne Benutzer generell zulassen.
PVESNAP_WEB_ARGS=--bind ${WEB_BIND} --port ${WEB_PORT} --auth pve
EOF
chmod 0640 "${WEB_CONF}"
install -m 0644 "${SRC}/systemd/pvesnap-web.service" "${WEB_UNIT}"
systemctl daemon-reload
if systemctl enable pvesnap-web.service >/dev/null 2>&1; then
info "Web-Oberflaeche beim Systemstart aktiviert"
else
warn "pvesnap-web konnte nicht aktiviert werden."
fi
fi
if [ "$START" -eq 1 ]; then
info "Starte Dienst"
systemctl restart pvesnap.service
sleep 1
systemctl --no-pager --lines=5 status pvesnap.service || true
if [ "$WEB" -eq 1 ]; then
info "Starte Web-Oberflaeche"
systemctl restart pvesnap-web.service
sleep 1
systemctl --no-pager --lines=3 status pvesnap-web.service || true
fi
else
warn "Dienste wurden nicht gestartet."
fi
cat <<EOF
Fertig.
Konfiguration bearbeiten : pvesnap config (ncurses-Editor)
nano ${CONF}
Konfiguration pruefen : pvesnap check
Uebersicht : pvesnap status
VMs und Gruppen : pvesnap vms
Testlauf ohne Aenderung : pvesnap run --force --dry-run
Nach Aenderungen : systemctl reload pvesnap
Protokoll : journalctl -u pvesnap -f
Dateien aus einem Snapshot holen:
pvesnap-explorer zwei Fenster wie im Midnight Commander
pvesnap-web im Browser durchsehen und herunterladen
EOF
if [ "$WEB" -eq 1 ]; then
cat <<EOF
Web-Oberflaeche laeuft als Dienst:
Adresse : http://<IP-dieses-Hosts>:${WEB_PORT}/
Anmeldung : Benutzer von Proxmox VE (gleiche Zugangsdaten wie dort)
Einstellungen : ${WEB_CONF}
Status : systemctl status pvesnap-web
Protokoll : journalctl -u pvesnap-web -f
Sichtbar ist ein Gast nur fuer Benutzer mit dem Recht VM.Snapshot darauf;
root@pam sieht alles. Anzupassen in ${WEB_CONF}.
EOF
fi
if [ "${NEW_CONFIG:-0}" -eq 1 ]; then
cat <<EOF
Hinweis: In der Beispielkonfiguration sind alle Gruppen mit "enabled = no"
angelegt. Erst nach dem Aktivieren einer Gruppe werden Snapshots erstellt.
EOF
fi