#!/bin/bash # --------------------------------------------------------------------- # pvesnap - Installation # # Aufruf: ./install.sh [Optionen] # # --with-webexplorer Web-Oberflaeche zusaetzlich als Dienst # einrichten (pvesnap-web.service). # Erfordert --port. # --port Port fuer die Web-Oberflaeche, z.B. 8823 # --bind 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" </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}" </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 <:${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 <