Bisher warnte der Installer "Auf Port 8823 lauscht bereits etwas" - dabei war das der eigene, laufende Dienst. Der Hinweis war also falsch und verdeckte zugleich einen echten Fall: wenn wirklich etwas Fremdes den Port haelt. Jetzt wird unterschieden. Laeuft pvesnap-web, wird das als Normalfall einer Aktualisierung behandelt und der Dienst angehalten, bevor der Code unter ihm ausgetauscht wird - beim Stoppen bekommt er sein SIGTERM und haengt offene Snapshots sauber aus. Am Ende faehrt er wieder hoch. Haelt dagegen ein anderer Prozess den Port, steht die Warnung weiterhin da, jetzt mit der Angabe, wer es ist (ss -ltnp). Bewusst kein "pvesnap-explorer --cleanup" an der Stelle: das wuerde auch die Einbindungen einer Sitzung loesen, die jemand gerade in einem anderen Terminal offen hat. Geprueft: Installation ueber den laufenden Dienst hinweg (anhalten, ersetzen, wieder starten, HTTP 401 = Anmeldemaske), und mit einem fremden Prozess auf dem Port (Warnung samt PID, Dienste nicht gestartet). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
318 lines
12 KiB
Bash
Executable File
318 lines
12 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
|
|
# --no-install-deps fehlende Werkzeuge (parted, exfatprogs) nicht
|
|
# nachinstallieren
|
|
# --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
|
|
DEPS=1
|
|
WEB_RUNNING=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 ;;
|
|
--no-install-deps) DEPS=0 ;;
|
|
--force) FORCE=1 ;;
|
|
-h|--help) sed -n '2,27p' "$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
|
|
# Laeuft unsere eigene Web-Oberflaeche schon, gehoert ihr der Port auch -
|
|
# das ist kein Konflikt, sondern der Normalfall bei einer Aktualisierung.
|
|
# Sie wird weiter unten gestoppt, bevor der Code ausgetauscht wird.
|
|
if systemctl is-active --quiet pvesnap-web.service 2>/dev/null; then
|
|
WEB_RUNNING=1
|
|
elif ss -ltn 2>/dev/null | grep -qE "[:.]${WEB_PORT}[[:space:]]"; then
|
|
warn "Auf Port ${WEB_PORT} lauscht bereits etwas anderes - der Dienst"
|
|
warn "wird sich moeglicherweise nicht starten lassen."
|
|
ss -ltnp 2>/dev/null | grep -E "[:.]${WEB_PORT}[[:space:]]" | sed 's/^/ /' >&2 || true
|
|
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?)."
|
|
|
|
# --- Werkzeuge fuer Transfer-Laufwerke -------------------------------------
|
|
# Transfer-Laufwerke sind Abbilddateien, die auf dem Host formatiert und
|
|
# eingehaengt werden. Dafuer braucht es eine Partitionstabelle (parted) und
|
|
# einen Formatierer je Dateisystem.
|
|
have_tool() {
|
|
command -v "$1" >/dev/null 2>&1 && return 0
|
|
for d in /usr/local/sbin /usr/sbin /sbin; do
|
|
[ -x "$d/$1" ] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
if [ "$DEPS" -eq 1 ]; then
|
|
MISSING=""
|
|
have_tool parted || MISSING="${MISSING} parted"
|
|
have_tool mkfs.exfat || MISSING="${MISSING} exfatprogs"
|
|
|
|
if [ -n "$MISSING" ]; then
|
|
info "Fehlende Werkzeuge fuer Transfer-Laufwerke:${MISSING}"
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
info "Installiere:${MISSING}"
|
|
# shellcheck disable=SC2086
|
|
if DEBIAN_FRONTEND=noninteractive apt-get install -y ${MISSING}; then
|
|
info "Werkzeuge installiert"
|
|
else
|
|
warn "Installation fehlgeschlagen - Transfer-Laufwerke lassen sich"
|
|
warn "dann nur mit den vorhandenen Dateisystemen anlegen."
|
|
fi
|
|
else
|
|
warn "apt-get nicht gefunden - bitte von Hand:${MISSING}"
|
|
fi
|
|
fi
|
|
|
|
fi
|
|
|
|
# --- Laufendes anhalten -----------------------------------------------
|
|
# Der Code wird gleich ersetzt. Die Web-Oberflaeche kann dabei noch Snapshots
|
|
# eingebunden haben - sie bekommt beim Stoppen ihr SIGTERM und haengt sauber
|
|
# aus. Wuerde sie einfach weiterlaufen, blieben rbd-Zuordnungen und
|
|
# Mountpunkte einer Fassung stehen, die es nicht mehr gibt.
|
|
if [ "$WEB_RUNNING" -eq 1 ]; then
|
|
info "Web-Oberflaeche laeuft - halte sie fuer die Aktualisierung an"
|
|
if systemctl stop pvesnap-web.service; then
|
|
info " angehalten, Port ${WEB_PORT} ist frei"
|
|
else
|
|
warn " liess sich nicht anhalten - bitte pruefen:"
|
|
warn " systemctl status pvesnap-web"
|
|
fi
|
|
fi
|
|
|
|
# Bewusst kein "pvesnap-explorer --cleanup" an dieser Stelle: das wuerde auch
|
|
# die Einbindungen einer Sitzung loesen, die jemand gerade in einem anderen
|
|
# Terminal offen hat. Wer nach einem Absturz aufraeumen will, ruft es selbst.
|
|
|
|
# --- 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
|
|
install_command pvesnap-recovery pvesnap.recovery_ui
|
|
|
|
# --- 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
|
|
|
|
Einen Snapshot als Maschine starten:
|
|
pvesnap-recovery Uebersicht und Assistent
|
|
pvesnap-recovery live 100 --exchange ja
|
|
abgeschottet ohne Netz, mit Austauschverzeichnis
|
|
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
|