Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd333f60ff |
No files matched your search
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-license"
|
name = "tesm-license"
|
||||||
version = "2.0.9"
|
version = "2.0.10"
|
||||||
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
+7
-1
@@ -5,5 +5,11 @@
|
|||||||
#
|
#
|
||||||
# Bewusst KEIN "ALL=(ALL) NOPASSWD: ALL". Der Vorgaenger loeste dasselbe
|
# Bewusst KEIN "ALL=(ALL) NOPASSWD: ALL". Der Vorgaenger loeste dasselbe
|
||||||
# Problem, indem die gesamte Anwendung als root lief.
|
# Problem, indem die gesamte Anwendung als root lief.
|
||||||
Defaults:tesm !requiretty
|
#
|
||||||
|
# Hier stand "Defaults:tesm !requiretty". Auf Debian und Ubuntu ist
|
||||||
|
# requiretty nie gesetzt, die Zeile war also von Anfang an wirkungslos -- und
|
||||||
|
# ab sudo 1.9.16 kennt visudo die Einstellung nicht mehr und lehnt die ganze
|
||||||
|
# Datei ab ("unknown setting: 'requiretty'"). Auf einem frisch aufgesetzten
|
||||||
|
# Server brach die Installation deshalb mitten drin ab. Nicht wieder
|
||||||
|
# hinzufuegen; ein Hygienetest haelt das fest.
|
||||||
tesm ALL=(root) NOPASSWD: /usr/local/lib/tesm/tesm-helper
|
tesm ALL=(root) NOPASSWD: /usr/local/lib/tesm/tesm-helper
|
||||||
@@ -5,5 +5,11 @@
|
|||||||
#
|
#
|
||||||
# Bewusst KEIN "ALL=(ALL) NOPASSWD: ALL". Der Vorgaenger loeste dasselbe
|
# Bewusst KEIN "ALL=(ALL) NOPASSWD: ALL". Der Vorgaenger loeste dasselbe
|
||||||
# Problem, indem die gesamte Anwendung als root lief.
|
# Problem, indem die gesamte Anwendung als root lief.
|
||||||
Defaults:tesm-license !requiretty
|
#
|
||||||
|
# Hier stand "Defaults:tesm-license !requiretty". Auf Debian und Ubuntu ist
|
||||||
|
# requiretty nie gesetzt, die Zeile war also von Anfang an wirkungslos -- und
|
||||||
|
# ab sudo 1.9.16 kennt visudo die Einstellung nicht mehr und lehnt die ganze
|
||||||
|
# Datei ab ("unknown setting: 'requiretty'"). Auf einem frisch aufgesetzten
|
||||||
|
# Server brach die Installation deshalb mitten drin ab. Nicht wieder
|
||||||
|
# hinzufuegen; ein Hygienetest haelt das fest.
|
||||||
tesm-license ALL=(root) NOPASSWD: /usr/local/lib/tesm/tesm-helper
|
tesm-license ALL=(root) NOPASSWD: /usr/local/lib/tesm/tesm-helper
|
||||||
+233
-23
@@ -52,6 +52,7 @@ WITH_DATA=1
|
|||||||
STOP_OLD=1
|
STOP_OLD=1
|
||||||
ADOPT_KEY=1
|
ADOPT_KEY=1
|
||||||
TAG="latest"
|
TAG="latest"
|
||||||
|
ROLLBACK=""
|
||||||
#: Namenszusatz, unter dem ``rename.sh`` eine verdraengte Installation der
|
#: Namenszusatz, unter dem ``rename.sh`` eine verdraengte Installation der
|
||||||
#: Fassung 1.x ablegt. Beide Skripte muessen denselben Wert benutzen; ein
|
#: Fassung 1.x ablegt. Beide Skripte muessen denselben Wert benutzen; ein
|
||||||
#: Hygienetest vergleicht sie.
|
#: Hygienetest vergleicht sie.
|
||||||
@@ -95,6 +96,10 @@ Verwendung: upgrade.sh --app <tesm|tesm-license> [Optionen]
|
|||||||
Vorgabe ist deshalb die Uebernahme.
|
Vorgabe ist deshalb die Uebernahme.
|
||||||
--tag <vX.Y.Z> Bestimmte Version installieren (Vorgabe: latest).
|
--tag <vX.Y.Z> Bestimmte Version installieren (Vorgabe: latest).
|
||||||
Wird nur beachtet, wenn das Release geladen wird.
|
Wird nur beachtet, wenn das Release geladen wird.
|
||||||
|
--rollback [pfad] Einen fehlgeschlagenen Lauf zurueckdrehen: die alte
|
||||||
|
Installation aus der Sicherung wiederherstellen und
|
||||||
|
ihren Dienst wieder einschalten. Ohne Pfad wird die
|
||||||
|
neueste Sicherung dieses Namens genommen.
|
||||||
--dry-run Nur zeigen, was geschehen wuerde
|
--dry-run Nur zeigen, was geschehen wuerde
|
||||||
--yes Keine Rueckfrage
|
--yes Keine Rueckfrage
|
||||||
-h, --help Diese Hilfe
|
-h, --help Diese Hilfe
|
||||||
@@ -122,6 +127,11 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--new-key) ADOPT_KEY=0; shift ;;
|
--new-key) ADOPT_KEY=0; shift ;;
|
||||||
--adopt-key) ADOPT_KEY=1; shift ;; # Vorgabe, hier nur zur Deutlichkeit
|
--adopt-key) ADOPT_KEY=1; shift ;; # Vorgabe, hier nur zur Deutlichkeit
|
||||||
--tag) TAG="${2:?}"; shift 2 ;;
|
--tag) TAG="${2:?}"; shift 2 ;;
|
||||||
|
--rollback)
|
||||||
|
# Der Pfad ist optional: allein genommen heisst es "die neueste".
|
||||||
|
if [[ -n "${2:-}" && "${2:-}" != --* ]]; then ROLLBACK="$2"; shift 2
|
||||||
|
else ROLLBACK="auto"; shift; fi
|
||||||
|
;;
|
||||||
--dry-run) DRY_RUN=1; shift ;;
|
--dry-run) DRY_RUN=1; shift ;;
|
||||||
--yes|-y) ASSUME_YES=1; shift ;;
|
--yes|-y) ASSUME_YES=1; shift ;;
|
||||||
-h|--help) usage; exit 0 ;;
|
-h|--help) usage; exit 0 ;;
|
||||||
@@ -132,6 +142,144 @@ done
|
|||||||
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || { usage; fail "--app fehlt oder ist unbekannt"; }
|
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || { usage; fail "--app fehlt oder ist unbekannt"; }
|
||||||
[[ "$(id -u)" -eq 0 ]] || fail "bitte mit sudo ausfuehren"
|
[[ "$(id -u)" -eq 0 ]] || fail "bitte mit sudo ausfuehren"
|
||||||
|
|
||||||
|
NAME="$APP"
|
||||||
|
[[ -n "$INSTANCE" ]] && NAME="$APP-$INSTANCE"
|
||||||
|
ADMIN="$NAME-admin"
|
||||||
|
NEW_ROOT="/srv/$NAME"
|
||||||
|
STAMP="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BACKUP="/srv/$NAME-upgrade-$STAMP"
|
||||||
|
ALT_KOPIE="$BACKUP/alt"
|
||||||
|
SYSTEM_KOPIE="$BACKUP/system"
|
||||||
|
EXPORT_ALT="$BACKUP/export-alt.json"
|
||||||
|
IMPORT_NEU="$BACKUP/import-neu.json"
|
||||||
|
|
||||||
|
# Alte Einheiten der Vorgaengerfassung. Der Timer gehoert dazu: nur den Dienst
|
||||||
|
# zu stoppen liesse ihn beim naechsten Ablauf wieder anlaufen.
|
||||||
|
# -- Rueckweg ---------------------------------------------------------------- #
|
||||||
|
# Alles, was install.sh unter demselben Namen ueberschreiben wuerde. Bei einem
|
||||||
|
# Upgrade in dasselbe Verzeichnis sind das die Dateien der alten Fassung.
|
||||||
|
SYSTEMDATEIEN=(
|
||||||
|
"/etc/systemd/system/$NAME.service"
|
||||||
|
"/etc/systemd/system/$NAME-monitor.service"
|
||||||
|
"/etc/nginx/sites-available/$NAME"
|
||||||
|
"/etc/logrotate.d/$NAME"
|
||||||
|
"/etc/update-motd.d/50-$NAME"
|
||||||
|
"/etc/tesm/$NAME.env"
|
||||||
|
)
|
||||||
|
|
||||||
|
zurueckrollen() {
|
||||||
|
local sicherung="$1" grund="${2:-}"
|
||||||
|
local alt="$sicherung/alt" system="$sicherung/system"
|
||||||
|
[[ -d "$alt" ]] || fail "In $sicherung fehlt das Verzeichnis 'alt' -- das ist keine Sicherung dieses Skripts."
|
||||||
|
|
||||||
|
# Quelle und Art des Umzugs stehen im Manifest. Aus dem laufenden Aufruf
|
||||||
|
# abzuleiten waere falsch: ein Rueckweg kann Tage spaeter und mit anderen
|
||||||
|
# Schaltern aufgerufen werden -- und beim automatischen Rueckweg steht
|
||||||
|
# IN_PLACE zwar fest, beim spaeteren --rollback aber nicht.
|
||||||
|
local ziel="${SOURCE:-}" gleiches_verzeichnis="${IN_PLACE:-0}" vermerkt
|
||||||
|
if [[ -f "$system/manifest" ]]; then
|
||||||
|
vermerkt="$(awk '$1=="quelle" {print $2}' "$system/manifest" | head -1)"
|
||||||
|
[[ -n "$vermerkt" ]] && ziel="$vermerkt"
|
||||||
|
vermerkt="$(awk '$1=="in-place" {print $2}' "$system/manifest" | head -1)"
|
||||||
|
[[ -n "$vermerkt" ]] && gleiches_verzeichnis="$vermerkt"
|
||||||
|
fi
|
||||||
|
[[ -n "$ziel" ]] || fail "Im Manifest fehlt die Quelle -- bitte --source angeben."
|
||||||
|
|
||||||
|
[[ -n "$grund" ]] && warn "$grund"
|
||||||
|
step "Rueckweg: alten Stand wiederherstellen"
|
||||||
|
|
||||||
|
# Der neue Dienst zuerst -- er haelt sonst Dateien offen, die gleich ersetzt
|
||||||
|
# werden.
|
||||||
|
for unit in "$NAME.service" "$NAME-monitor.service"; do
|
||||||
|
if systemctl list-unit-files "$unit" --no-legend 2>/dev/null | grep -q .; then
|
||||||
|
systemctl disable --now "$unit" >/dev/null 2>&1 || true
|
||||||
|
info "$unit gestoppt"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Verzeichnis: nur bei gleichem Ziel -- bei einer eigenen Instanz war die
|
||||||
|
# alte Installation nie angefasst.
|
||||||
|
if [[ "$gleiches_verzeichnis" == "1" ]]; then
|
||||||
|
rm -rf "$ziel"
|
||||||
|
mkdir -p "$ziel"
|
||||||
|
tar -C "$alt" -cf - . | tar -C "$ziel" -xf -
|
||||||
|
info "$ziel aus der Sicherung wiederhergestellt"
|
||||||
|
[[ -d "$ziel/venv" ]] || warn "Im Backup war kein venv -- der alte Dienst braucht dann noch 'python3 -m venv venv' und seine requirements.txt."
|
||||||
|
else
|
||||||
|
info "$ziel war nicht betroffen (eigene Instanz) -- bleibt, wie es ist"
|
||||||
|
if [[ -d "$NEW_ROOT" && "$NEW_ROOT" != "$ziel" ]]; then
|
||||||
|
rm -rf "$NEW_ROOT"
|
||||||
|
info "$NEW_ROOT entfernt"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Systemdateien zurueck, alles andere entfernen, was der Lauf angelegt hat.
|
||||||
|
local site_wieder=0
|
||||||
|
if [[ -f "$system/manifest" ]]; then
|
||||||
|
while read -r zeile; do
|
||||||
|
case "$zeile" in
|
||||||
|
unit-enabled\ *|site-enabled\ *) continue ;;
|
||||||
|
esac
|
||||||
|
local name; name="$(basename "$zeile")"
|
||||||
|
if [[ -e "$system/$name" ]]; then
|
||||||
|
cp -a "$system/$name" "$zeile"
|
||||||
|
info "wiederhergestellt: $zeile"
|
||||||
|
[[ "$zeile" == /etc/nginx/* ]] && site_wieder=1
|
||||||
|
fi
|
||||||
|
done < <(grep -v '^\(unit\|site\)-enabled ' "$system/manifest" || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
if [[ $site_wieder -eq 1 ]] || [[ -e "/etc/nginx/sites-enabled/$NAME" ]]; then
|
||||||
|
nginx -t >/dev/null 2>&1 && systemctl reload nginx >/dev/null 2>&1 \
|
||||||
|
&& info "nginx neu geladen" || warn "nginx meldet einen Fehler -- bitte 'nginx -t' ansehen"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Und die Dienste wieder einschalten, die vorher liefen.
|
||||||
|
if [[ -f "$system/manifest" ]]; then
|
||||||
|
while read -r _ unit; do
|
||||||
|
systemctl enable --now "$unit" >/dev/null 2>&1 \
|
||||||
|
&& info "$unit wieder eingeschaltet" || warn "$unit liess sich nicht starten"
|
||||||
|
done < <(grep '^unit-enabled ' "$system/manifest" || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Zurueckgerollt"
|
||||||
|
info "Sicherung bleibt liegen: $sicherung"
|
||||||
|
# Nicht ueber ALTE_UNITS: die Liste entsteht erst nach der Quellensuche, und
|
||||||
|
# bei "--rollback" laeuft diese Funktion vorher. Das Manifest weiss es.
|
||||||
|
local hinweis
|
||||||
|
hinweis="$(awk '$1=="unit-enabled" {print $2; exit}' "$system/manifest" 2>/dev/null || true)"
|
||||||
|
info "Zustand pruefen: systemctl status ${hinweis:-$APP.service}"
|
||||||
|
}
|
||||||
|
|
||||||
|
neueste_sicherung() {
|
||||||
|
local kandidat
|
||||||
|
kandidat="$(ls -1dt /srv/"$NAME"-upgrade-*/ 2>/dev/null | head -1)"
|
||||||
|
[[ -n "$kandidat" ]] || return 1
|
||||||
|
printf '%s' "${kandidat%/}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -n "$ROLLBACK" ]]; then
|
||||||
|
if [[ "$ROLLBACK" == "auto" ]]; then
|
||||||
|
ROLLBACK="$(neueste_sicherung)" || fail "Keine Sicherung unter /srv/$NAME-upgrade-* gefunden. Pfad angeben."
|
||||||
|
info "Neueste Sicherung: $ROLLBACK"
|
||||||
|
fi
|
||||||
|
[[ -d "$ROLLBACK" ]] || fail "$ROLLBACK gibt es nicht"
|
||||||
|
if [[ $DRY_RUN -eq 1 ]]; then
|
||||||
|
step "--dry-run: es wuerde $ROLLBACK zurueckgerollt."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [[ $ASSUME_YES -eq 0 ]]; then
|
||||||
|
read -r -p "Stand aus $ROLLBACK wiederherstellen? [j/N] " answer
|
||||||
|
[[ "$answer" =~ ^[jJyY]$ ]] || { echo "Abgebrochen."; exit 0; }
|
||||||
|
fi
|
||||||
|
zurueckrollen "$ROLLBACK"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ab hier wird wirklich installiert -- ein Rueckweg hat oben schon
|
||||||
|
# beendet. Erst jetzt braucht es ein Release und eine Quelle.
|
||||||
|
|
||||||
# --8<-- Bootstrap: Release holen --------------------------------------------
|
# --8<-- Bootstrap: Release holen --------------------------------------------
|
||||||
# Wortgleich in update.sh und upgrade.sh; ein Hygienetest vergleicht die beiden
|
# Wortgleich in update.sh und upgrade.sh; ein Hygienetest vergleicht die beiden
|
||||||
# Bloecke. Zwei eigenstaendige Skripte koennen sich keine Datei teilen, und
|
# Bloecke. Zwei eigenstaendige Skripte koennen sich keine Datei teilen, und
|
||||||
@@ -255,28 +403,55 @@ fi
|
|||||||
[[ -d "$SOURCE" ]] || fail "Die alte Installation $SOURCE gibt es nicht (--source setzen)"
|
[[ -d "$SOURCE" ]] || fail "Die alte Installation $SOURCE gibt es nicht (--source setzen)"
|
||||||
ist_alte_fassung "$SOURCE" || fail "In $SOURCE liegt keine sqlite.db -- das ist keine Installation der Vorgaengerfassung"
|
ist_alte_fassung "$SOURCE" || fail "In $SOURCE liegt keine sqlite.db -- das ist keine Installation der Vorgaengerfassung"
|
||||||
|
|
||||||
NAME="$APP"
|
|
||||||
[[ -n "$INSTANCE" ]] && NAME="$APP-$INSTANCE"
|
|
||||||
ADMIN="$NAME-admin"
|
|
||||||
NEW_ROOT="/srv/$NAME"
|
|
||||||
IN_PLACE=0
|
IN_PLACE=0
|
||||||
[[ "$(cd "$SOURCE" && pwd)" == "$NEW_ROOT" ]] && IN_PLACE=1
|
[[ "$(cd "$SOURCE" && pwd)" == "$NEW_ROOT" ]] && IN_PLACE=1
|
||||||
|
|
||||||
STAMP="$(date +%Y%m%d-%H%M%S)"
|
# Die Units der alten Fassung erkennt man daran, dass sie in genau dieses
|
||||||
BACKUP="/srv/$NAME-upgrade-$STAMP"
|
# Verzeichnis zeigen -- nicht am Namen der Anwendung. Nach einem rename.sh
|
||||||
ALT_KOPIE="$BACKUP/alt"
|
# heisst die *laufende* Installation "tesm", und eine Namensliste haette sie
|
||||||
EXPORT_ALT="$BACKUP/export-alt.json"
|
# gestoppt und deaktiviert, sobald jemand die archivierte 1.x in eine eigene
|
||||||
IMPORT_NEU="$BACKUP/import-neu.json"
|
# Instanz hochzieht.
|
||||||
|
#
|
||||||
|
# Timer und Hilfsdienste tragen keinen Pfad (der Restart-Timer ruft nur
|
||||||
|
# "systemctl restart ..."). Sie kommen ueber den Namen der gefundenen Unit mit.
|
||||||
|
alte_units_finden() {
|
||||||
|
local quelle="$1" gefunden=() datei name runde
|
||||||
|
shopt -s nullglob
|
||||||
|
for datei in /etc/systemd/system/*.service; do
|
||||||
|
grep -qs -- "$quelle/" "$datei" && gefunden+=("$(basename "$datei")")
|
||||||
|
done
|
||||||
|
# Zwei Runden: erst Timer und Helfer, die eine gefundene Unit nennen, dann
|
||||||
|
# noch einmal fuer deren eigene Timer.
|
||||||
|
for runde in 1 2; do
|
||||||
|
for datei in /etc/systemd/system/*.service /etc/systemd/system/*.timer; do
|
||||||
|
name="$(basename "$datei")"
|
||||||
|
[[ " ${gefunden[*]-} " == *" $name "* ]] && continue
|
||||||
|
for treffer in ${gefunden[*]-}; do
|
||||||
|
if grep -qs -- "$treffer" "$datei"; then gefunden+=("$name"); break; fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
printf '%s\n' ${gefunden[*]-}
|
||||||
|
}
|
||||||
|
|
||||||
# Alte Einheiten der Vorgaengerfassung. Der Timer gehoert dazu: nur den Dienst
|
mapfile -t ALTE_UNITS < <(alte_units_finden "$SOURCE")
|
||||||
# zu stoppen liesse ihn beim naechsten Ablauf wieder anlaufen.
|
if [[ ${#ALTE_UNITS[@]} -eq 0 ]]; then
|
||||||
if [[ "$APP" == "tesm" ]]; then
|
if [[ "$SOURCE" == "/srv/$APP" ]]; then
|
||||||
ALTE_UNITS=(tesm.service tesm-check.timer tesm-check.service
|
# Kein Fund, aber die Quelle ist der Hauptpfad: die historischen Namen der
|
||||||
tesm-check-restart.timer tesm-check-restart.service)
|
# Fassung 1.x als Rueckfall.
|
||||||
else
|
if [[ "$APP" == "tesm" ]]; then
|
||||||
ALTE_UNITS=(tesm-license.service)
|
ALTE_UNITS=(tesm.service tesm-check.timer tesm-check.service
|
||||||
|
tesm-check-restart.timer tesm-check-restart.service)
|
||||||
|
else
|
||||||
|
ALTE_UNITS=(tesm-license.service)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ALTE_UNITS=()
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
step "Vorhaben"
|
step "Vorhaben"
|
||||||
info "Anwendung : $APP${INSTANCE:+ (Instanz $INSTANCE)}"
|
info "Anwendung : $APP${INSTANCE:+ (Instanz $INSTANCE)}"
|
||||||
info "Neue Fassung : $RELEASE_HERKUNFT"
|
info "Neue Fassung : $RELEASE_HERKUNFT"
|
||||||
@@ -302,15 +477,44 @@ fi
|
|||||||
|
|
||||||
# -- 1. Sichern -------------------------------------------------------------- #
|
# -- 1. Sichern -------------------------------------------------------------- #
|
||||||
step "Sichern"
|
step "Sichern"
|
||||||
mkdir -p "$ALT_KOPIE"
|
mkdir -p "$ALT_KOPIE" "$SYSTEM_KOPIE"
|
||||||
chmod 700 "$BACKUP"
|
chmod 700 "$BACKUP"
|
||||||
# -a: Rechte und Zeiten bleiben, damit die Kopie auch als Rueckweg taugt.
|
|
||||||
# Das venv der alten Installation bleibt aussen vor -- es ist nachbaubar,
|
# Das venv kommt nur mit, wenn in dasselbe Verzeichnis installiert wird -- dort
|
||||||
# gross, und seine Shebangs zeigen ohnehin auf den alten Pfad.
|
# ersetzt install.sh es, und ohne das alte startet der alte Dienst nach einem
|
||||||
tar -C "$SOURCE" --exclude=venv --exclude=__pycache__ -cf - . | tar -C "$ALT_KOPIE" -xf -
|
# Rueckweg nicht mehr. Bei einer eigenen Instanz bleibt die alte Installation
|
||||||
info "$(du -sh "$ALT_KOPIE" | cut -f1) kopiert (ohne venv)"
|
# unangetastet, dann waere es nur Ballast (und seine Shebangs zeigen auf einen
|
||||||
|
# anderen Pfad).
|
||||||
|
if [[ $IN_PLACE -eq 1 ]]; then
|
||||||
|
tar -C "$SOURCE" --exclude=__pycache__ -cf - . | tar -C "$ALT_KOPIE" -xf -
|
||||||
|
info "$(du -sh "$ALT_KOPIE" | cut -f1) kopiert (mit venv, weil dasselbe Verzeichnis)"
|
||||||
|
else
|
||||||
|
tar -C "$SOURCE" --exclude=venv --exclude=__pycache__ -cf - . | tar -C "$ALT_KOPIE" -xf -
|
||||||
|
info "$(du -sh "$ALT_KOPIE" | cut -f1) kopiert (ohne venv)"
|
||||||
|
fi
|
||||||
[[ -f "$ALT_KOPIE/sqlite.db" ]] || fail "In der Kopie fehlt die Datenbank -- Abbruch"
|
[[ -f "$ALT_KOPIE/sqlite.db" ]] || fail "In der Kopie fehlt die Datenbank -- Abbruch"
|
||||||
|
|
||||||
|
# Und die Systemdateien: bei gleichem Verzeichnis schreibt install.sh Unit,
|
||||||
|
# nginx-Site, logrotate und Banner neu. Ohne Kopie liesse sich der alte Stand
|
||||||
|
# nicht wiederherstellen -- das Verzeichnis allein genuegt nicht.
|
||||||
|
: > "$SYSTEM_KOPIE/manifest"
|
||||||
|
# Woher kam der Stand, und ging es in dasselbe Verzeichnis? Ein spaeterer
|
||||||
|
# Rueckweg darf das nicht raten muessen -- er laeuft womoeglich Tage danach
|
||||||
|
# und mit anderen Schaltern.
|
||||||
|
printf 'quelle %s\n' "$SOURCE" >> "$SYSTEM_KOPIE/manifest"
|
||||||
|
printf 'in-place %s\n' "$IN_PLACE" >> "$SYSTEM_KOPIE/manifest"
|
||||||
|
for pfad in "${SYSTEMDATEIEN[@]}"; do
|
||||||
|
[[ -e "$pfad" ]] || continue
|
||||||
|
cp -a "$pfad" "$SYSTEM_KOPIE/$(basename "$pfad")"
|
||||||
|
printf '%s\n' "$pfad" >> "$SYSTEM_KOPIE/manifest"
|
||||||
|
done
|
||||||
|
# Welche Units liefen, und war die Site eingeschaltet?
|
||||||
|
for unit in "${ALTE_UNITS[@]}"; do
|
||||||
|
systemctl is-enabled "$unit" >/dev/null 2>&1 && printf 'unit-enabled %s\n' "$unit" >> "$SYSTEM_KOPIE/manifest"
|
||||||
|
done
|
||||||
|
[[ -L "/etc/nginx/sites-enabled/$NAME" ]] && printf 'site-enabled %s\n' "$NAME" >> "$SYSTEM_KOPIE/manifest"
|
||||||
|
info "$(grep -c . "$SYSTEM_KOPIE/manifest") Systemdatei(en) und Zustaende vermerkt"
|
||||||
|
|
||||||
# -- 2. Altes System abschalten ---------------------------------------------- #
|
# -- 2. Altes System abschalten ---------------------------------------------- #
|
||||||
if [[ $STOP_OLD -eq 1 ]]; then
|
if [[ $STOP_OLD -eq 1 ]]; then
|
||||||
step "Altes System abschalten"
|
step "Altes System abschalten"
|
||||||
@@ -328,7 +532,13 @@ fi
|
|||||||
step "Neu installieren"
|
step "Neu installieren"
|
||||||
INSTALL_ARGS=(--app "$APP" --yes)
|
INSTALL_ARGS=(--app "$APP" --yes)
|
||||||
[[ -n "$INSTANCE" ]] && INSTALL_ARGS+=(--instance "$INSTANCE")
|
[[ -n "$INSTANCE" ]] && INSTALL_ARGS+=(--instance "$INSTANCE")
|
||||||
bash "$SRC/deploy/install.sh" "${INSTALL_ARGS[@]}" ${EXTRA[0]+"${EXTRA[@]}"}
|
if ! bash "$SRC/deploy/install.sh" "${INSTALL_ARGS[@]}" ${EXTRA[0]+"${EXTRA[@]}"}; then
|
||||||
|
# Hier stand das System bisher halb umgebaut da: alter Dienst aus, neuer
|
||||||
|
# nicht vorhanden. Der Rueckweg bringt es in den Zustand von vorher, damit
|
||||||
|
# ein zweiter Versuch nach der Ursache moeglich ist.
|
||||||
|
zurueckrollen "$BACKUP" "Die Installation ist fehlgeschlagen."
|
||||||
|
fail "Upgrade abgebrochen und zurueckgerollt. Ursache oben nachsehen, dann erneut versuchen."
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $WITH_DATA -eq 0 ]]; then
|
if [[ $WITH_DATA -eq 0 ]]; then
|
||||||
step "Fertig -- ohne Datenuebernahme"
|
step "Fertig -- ohne Datenuebernahme"
|
||||||
|
|||||||
@@ -174,6 +174,24 @@ sudo bash deploy/upgrade.sh --app tesm-license
|
|||||||
|
|
||||||
Eine bestimmte Version statt `latest`: `--tag v2.0.8`.
|
Eine bestimmte Version statt `latest`: `--tag v2.0.8`.
|
||||||
|
|
||||||
|
**Wenn etwas schiefgeht.** Schlägt `install.sh` fehl, dreht `upgrade.sh` den
|
||||||
|
Lauf selbst zurück: der neue Dienst wird gestoppt, das Verzeichnis aus der
|
||||||
|
Sicherung wiederhergestellt und der alte Dienst wieder eingeschaltet. Das
|
||||||
|
Verzeichnis allein genügt dafür nicht -- bei einem Upgrade in dasselbe
|
||||||
|
Verzeichnis schreibt `install.sh` auch systemd-Unit, nginx-Site, logrotate und
|
||||||
|
Banner neu und ersetzt das venv. Die Sicherung enthält deshalb alles davon,
|
||||||
|
und ein Manifest hält fest, woher der Stand kam.
|
||||||
|
|
||||||
|
Später von Hand zurückdrehen, etwa nach einem Lauf, der durchlief aber nicht
|
||||||
|
gefallen hat:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash upgrade.sh --app tesm --rollback # neueste Sicherung
|
||||||
|
sudo bash upgrade.sh --app tesm --rollback /srv/tesm-upgrade-20260908-225428
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Sicherung bleibt danach liegen; gelöscht wird nichts.
|
||||||
|
|
||||||
Ohne `--source` wird die alte Fassung an zwei Stellen gesucht: unter
|
Ohne `--source` wird die alte Fassung an zwei Stellen gesucht: unter
|
||||||
`/srv/<app>` und unter `/srv/<app>-sonnet5`. Der zweite Ort ist der, an den
|
`/srv/<app>` und unter `/srv/<app>-sonnet5`. Der zweite Ort ist der, an den
|
||||||
`rename.sh` sie verschiebt, sobald der Hauptname für die neue Installation
|
`rename.sh` sie verschiebt, sobald der Hauptname für die neue Installation
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-core"
|
name = "tesm-core"
|
||||||
version = "2.0.9"
|
version = "2.0.10"
|
||||||
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
|
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ def create_base_app(
|
|||||||
#: Wortmarke, ohne Zeile darunter; die Marke selbst zeigen beide
|
#: Wortmarke, ohne Zeile darunter; die Marke selbst zeigen beide
|
||||||
#: Anwendungen.
|
#: Anwendungen.
|
||||||
auth_tagline: str = "",
|
auth_tagline: str = "",
|
||||||
app_version: str = "2.0.9",
|
app_version: str = "2.0.10",
|
||||||
built_in_trusted_keys: tuple[str, ...] = (),
|
built_in_trusted_keys: tuple[str, ...] = (),
|
||||||
enable_license: bool = True,
|
enable_license: bool = True,
|
||||||
template_folder: str | None = None,
|
template_folder: str | None = None,
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-licensing-server"
|
name = "tesm-licensing-server"
|
||||||
version = "2.0.9"
|
version = "2.0.10"
|
||||||
description = "Serverhaelfte des TESM-Lizenzprotokolls: ausstellen, erneuern, antworten"
|
description = "Serverhaelfte des TESM-Lizenzprotokolls: ausstellen, erneuern, antworten"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = ["tesm-licensing==2.0.9", "cryptography>=41"]
|
dependencies = ["tesm-licensing==2.0.10", "cryptography>=41"]
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = ["src"]
|
where = ["src"]
|
||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-licensing"
|
name = "tesm-licensing"
|
||||||
version = "2.0.9"
|
version = "2.0.10"
|
||||||
description = "Ed25519-basiertes Lizenz- und Aktivierungsprotokoll fuer TESM und TESM-Lizenzserver"
|
description = "Ed25519-basiertes Lizenz- und Aktivierungsprotokoll fuer TESM und TESM-Lizenzserver"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = ["cryptography>=42"]
|
dependencies = ["cryptography>=42"]
|
||||||
|
|||||||
Reference in new issue
Block a user