Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9342d384c |
@@ -135,3 +135,19 @@ Entwicklungsrepository, ebenso die Tests.
|
|||||||
* **CSRF-Schutz überhaupt.** Der Vorgänger hatte keinen.
|
* **CSRF-Schutz überhaupt.** Der Vorgänger hatte keinen.
|
||||||
* **Rechte werden serverseitig geprüft**, nicht nur im Template ausgeblendet.
|
* **Rechte werden serverseitig geprüft**, nicht nur im Template ausgeblendet.
|
||||||
* **Verschachtelte Datenbankverbindungen sind ein Fehler**, kein Deadlock.
|
* **Verschachtelte Datenbankverbindungen sind ein Fehler**, kein Deadlock.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Von einer Installation der Fassung 1.x
|
||||||
|
|
||||||
|
Eine einzelne Datei genügt -- sie lädt das Release selbst:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm-license/raw/branch/main/deploy/upgrade.sh
|
||||||
|
sudo bash upgrade.sh --app tesm-license
|
||||||
|
```
|
||||||
|
|
||||||
|
Sichert die alte Installation, schaltet sie ab, installiert diese Fassung und
|
||||||
|
übernimmt die Daten. Einzelheiten und was **nicht** mitkommt:
|
||||||
|
[docs/BETRIEB.md](docs/BETRIEB.md).
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-license"
|
name = "tesm-license"
|
||||||
version = "2.0.8"
|
version = "2.0.9"
|
||||||
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
description = "TESM-Lizenzserver -- Kunden, Tickets, Lizenzen, Aktivierung"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
+3
-3
@@ -3,8 +3,8 @@
|
|||||||
# Benennt eine Installation um -- aus einer Instanz wird die Hauptinstallation
|
# Benennt eine Installation um -- aus einer Instanz wird die Hauptinstallation
|
||||||
# (oder umgekehrt).
|
# (oder umgekehrt).
|
||||||
#
|
#
|
||||||
# sudo bash deploy/rename.sh --app tesm --from tesm-opus --to tesm
|
# sudo bash deploy/rename.sh --app tesm --from tesm-test --to tesm
|
||||||
# sudo bash deploy/rename.sh --app tesm-license --from tesm-license-opus \
|
# sudo bash deploy/rename.sh --app tesm-license --from tesm-license-test \
|
||||||
# --to tesm-license
|
# --to tesm-license
|
||||||
#
|
#
|
||||||
# Der Name steckt an mehr Stellen, als man beim Verschieben eines Verzeichnisses
|
# Der Name steckt an mehr Stellen, als man beim Verschieben eines Verzeichnisses
|
||||||
@@ -51,7 +51,7 @@ usage() {
|
|||||||
Verwendung: rename.sh --app <tesm|tesm-license> --from <alt> --to <neu> [Optionen]
|
Verwendung: rename.sh --app <tesm|tesm-license> --from <alt> --to <neu> [Optionen]
|
||||||
|
|
||||||
--app <name> Welche Anwendung (Pflicht)
|
--app <name> Welche Anwendung (Pflicht)
|
||||||
--from <name> Bisheriger Installationsname, z.B. tesm-opus (Pflicht)
|
--from <name> Bisheriger Installationsname, z.B. tesm-test (Pflicht)
|
||||||
--to <name> Neuer Installationsname, z.B. tesm (Pflicht)
|
--to <name> Neuer Installationsname, z.B. tesm (Pflicht)
|
||||||
--suffix <text> Namenszusatz fuer eine beiseite geschobene Installation
|
--suffix <text> Namenszusatz fuer eine beiseite geschobene Installation
|
||||||
der Fassung 1.x (Vorgabe: sonnet5)
|
der Fassung 1.x (Vorgabe: sonnet5)
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ check_in_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Name einer Installation auf diesem Host: entweder die Hauptinstallation
|
# Name einer Installation auf diesem Host: entweder die Hauptinstallation
|
||||||
# ("tesm") oder eine benannte Instanz daneben ("tesm-opus"). Mehr als diese
|
# ("tesm") oder eine benannte Instanz daneben ("tesm-test"). Mehr als diese
|
||||||
# beiden Formen gibt es nicht -- so kann keine erfundene Zeichenkette einen
|
# beiden Formen gibt es nicht -- so kann keine erfundene Zeichenkette einen
|
||||||
# Pfad ausserhalb des vorgesehenen Namensraums erzeugen.
|
# Pfad ausserhalb des vorgesehenen Namensraums erzeugen.
|
||||||
check_app_key() {
|
check_app_key() {
|
||||||
|
|||||||
+96
-58
@@ -1,89 +1,127 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Bootstrapper: laedt ein Release herunter und ruft dessen install.sh auf.
|
# Aktualisierung: laedt das aktuelle Release und ruft dessen install.sh auf.
|
||||||
# Enthaelt selbst keinerlei Installationslogik.
|
# Enthaelt selbst keinerlei Installationslogik.
|
||||||
#
|
#
|
||||||
# Zwei Fallen des Vorgaengers sind hier bewusst vermieden:
|
# Eine einzelne Datei genuegt -- sie holt sich alles Weitere:
|
||||||
# * Der Tag "latest" wird ueber die API aufgeloest, nie direkt in die
|
#
|
||||||
# Download-URL geschrieben. Gitea liefert sonst mit HTTP 200 ein
|
# curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/deploy/update.sh
|
||||||
# automatisch erzeugtes Quell-Snapshot statt des echten Release-Assets.
|
# sudo bash update.sh tesm
|
||||||
# * Nach dem Entpacken wird geprueft, dass ein install.sh existiert -- faengt
|
#
|
||||||
# denselben Fehler ein zweites Mal ab.
|
# Auf einer bestehenden Installation liegt sie schon bereit:
|
||||||
|
#
|
||||||
|
# sudo bash /srv/tesm/deploy/update.sh tesm
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Ein Wagenruecklauf im Paket macht jedes Shell-Skript auf dem Ziel
|
|
||||||
# unbrauchbar ("bad interpreter"). Die Pruefung darf dabei nicht selbst
|
|
||||||
# von einem Zusatzpaket abhaengen: mit "file" -- das auf einem schlanken
|
|
||||||
# Server fehlt -- endete sie in "command not found", grep bekam nichts zu
|
|
||||||
# sehen, und das Skript machte weiter, als waere alles in Ordnung.
|
|
||||||
hat_crlf() {
|
|
||||||
local cr
|
|
||||||
cr="$(printf '\r')"
|
|
||||||
# -U (binaer lesen) ist unter Linux ohne Wirkung, auf einer Windows-Buildmaschine
|
|
||||||
# aber entscheidend: dort entfernt grep den Wagenruecklauf beim Lesen und
|
|
||||||
# findet deshalb nie einen.
|
|
||||||
LC_ALL=C grep -qU "$cr" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
APP="${1:-}"
|
APP="${1:-}"
|
||||||
TAG="${2:-latest}"
|
TAG="${2:-latest}"
|
||||||
|
|
||||||
# Alles nach dem Tag geht unveraendert an install.sh weiter. Ohne das liesse
|
# Alles nach dem Tag geht unveraendert an install.sh weiter. Ohne das liesse
|
||||||
# sich eine benannte Instanz nicht aktualisieren: install.sh leitet den Namen
|
# sich eine benannte Instanz nicht aktualisieren: install.sh leitet den Namen
|
||||||
# aus "--instance" ab, und ohne den Schalter entstuende neben "tesm-opus" eine
|
# aus "--instance" ab, und ohne den Schalter entstuende neben "tesm-test" eine
|
||||||
# zweite Installation namens "tesm" -- mit eigener Datenbank, eigener
|
# zweite Installation namens "tesm" -- mit eigener Datenbank, eigener
|
||||||
# nginx-Site und demselben Port.
|
# nginx-Site und demselben Port.
|
||||||
shift $(( $# > 2 ? 2 : $# ))
|
shift $(( $# > 2 ? 2 : $# ))
|
||||||
EXTRA=("$@")
|
EXTRA=("$@")
|
||||||
# Bezugsquelle. Die Vorgaben zeigen dorthin, wo die Releases tatsaechlich
|
|
||||||
# liegen -- ein Platzhalter wie "gitea.example.invalid" macht das Skript auf
|
|
||||||
# jedem Host unbrauchbar, und genau das war hier der Fall.
|
|
||||||
#
|
|
||||||
# Das Repository heisst wie die Anwendung; getrennte Repositorien, getrennte
|
|
||||||
# Releases. Der Anhang heisst "<repo>-<tag>.tar.gz", siehe unten.
|
|
||||||
BASE="${TESM_RELEASE_BASE:-https://gitea.int.eertmoed.net}"
|
|
||||||
OWNER="${TESM_RELEASE_OWNER:-alientim}"
|
|
||||||
|
|
||||||
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || {
|
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || {
|
||||||
echo "Verwendung: update.sh <tesm|tesm-license> [tag] [install.sh-Argumente ...]" >&2
|
echo "Verwendung: update.sh <tesm|tesm-license> [tag] [install.sh-Argumente ...]" >&2
|
||||||
echo "Beispiel : update.sh tesm latest --instance opus" >&2
|
echo "Beispiel : update.sh tesm latest --instance test" >&2
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
REPO="${TESM_RELEASE_REPO:-$APP}"
|
# --8<-- Bootstrap: Release holen --------------------------------------------
|
||||||
|
# Wortgleich in update.sh und upgrade.sh; ein Hygienetest vergleicht die beiden
|
||||||
|
# Bloecke. Zwei eigenstaendige Skripte koennen sich keine Datei teilen, und
|
||||||
|
# beide sollen als **einzelne Datei** genuegen: auf das Zielsystem legen,
|
||||||
|
# ausfuehren, fertig -- auf einer 1.2.8 liegt nichts von diesem Projekt.
|
||||||
|
#
|
||||||
|
# Erwartet: $APP und $TAG. Setzt: $TAG (aufgeloest) und $SRC (entpacktes
|
||||||
|
# Release). Raeumt sein Arbeitsverzeichnis beim Beenden auf.
|
||||||
|
#
|
||||||
|
# Zwei Fallen des Vorgaengers sind hier vermieden:
|
||||||
|
# * Der Tag "latest" wird ueber die API aufgeloest, nie direkt in die
|
||||||
|
# Download-URL geschrieben. Gitea liefert sonst mit HTTP 200 ein
|
||||||
|
# automatisch erzeugtes Quell-Snapshot statt des echten Release-Anhangs.
|
||||||
|
# * Nach dem Entpacken wird geprueft, dass ein install.sh existiert.
|
||||||
|
BASE="${TESM_RELEASE_BASE:-https://gitea.int.eertmoed.net}"
|
||||||
|
OWNER="${TESM_RELEASE_OWNER:-alientim}"
|
||||||
|
|
||||||
WORK="$(mktemp -d /tmp/tesm-update-XXXXXX)"
|
# Ein Wagenruecklauf im Paket macht jedes Shell-Skript auf dem Ziel unbrauchbar
|
||||||
trap 'rm -rf "$WORK"' EXIT # anders als im Vorgaenger wird aufgeraeumt
|
# ("bad interpreter"). Die Pruefung darf dabei nicht selbst von einem
|
||||||
|
# Zusatzpaket abhaengen: mit "file" -- das auf einem schlanken Server fehlt --
|
||||||
|
# endete sie in "command not found", grep bekam nichts zu sehen, und das Skript
|
||||||
|
# machte weiter, als waere alles in Ordnung.
|
||||||
|
hat_crlf() {
|
||||||
|
local cr
|
||||||
|
cr="$(printf '\r')"
|
||||||
|
# -U (binaer lesen) ist unter Linux ohne Wirkung, auf einer
|
||||||
|
# Windows-Buildmaschine aber entscheidend: dort entfernt grep den
|
||||||
|
# Wagenruecklauf beim Lesen und findet deshalb nie einen.
|
||||||
|
LC_ALL=C grep -qU "$cr" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
if [[ "$TAG" == "latest" ]]; then
|
BOOTSTRAP_WORK=""
|
||||||
echo "==> Ermittle aktuellen Release-Tag ..."
|
bootstrap_aufraeumen() { [[ -n "$BOOTSTRAP_WORK" ]] && rm -rf "$BOOTSTRAP_WORK"; }
|
||||||
TAG="$(curl -fsS "$BASE/api/v1/repos/$OWNER/$REPO/releases/latest" \
|
trap bootstrap_aufraeumen EXIT
|
||||||
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')"
|
|
||||||
echo " $TAG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ASSET="$REPO-$TAG.tar.gz"
|
release_holen() {
|
||||||
echo "==> Lade $ASSET ..."
|
local repo="${TESM_RELEASE_REPO:-$APP}" asset
|
||||||
curl -fsSL -o "$WORK/$ASSET" "$BASE/$OWNER/$REPO/releases/download/$TAG/$ASSET"
|
for werkzeug in curl tar python3 find; do
|
||||||
|
command -v "$werkzeug" >/dev/null 2>&1 || {
|
||||||
|
echo "Auf diesem System fehlt $werkzeug -- ohne das geht es nicht." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
BOOTSTRAP_WORK="$(mktemp -d /tmp/tesm-release-XXXXXX)"
|
||||||
|
|
||||||
echo "==> Entpacke ..."
|
if [[ "$TAG" == "latest" ]]; then
|
||||||
tar -xzf "$WORK/$ASSET" -C "$WORK"
|
echo "==> Ermittle aktuellen Release-Tag ..."
|
||||||
# Drei Ebenen, nicht zwei: release.sh packt mit dem Praefix "<name>/", also
|
TAG="$(curl -fsS "$BASE/api/v1/repos/$OWNER/$repo/releases/latest" \
|
||||||
# liegt das Skript unter <name>/deploy/install.sh. Mit "-maxdepth 2" fand die
|
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')" || {
|
||||||
# Suche nie etwas -- und die Fehlermeldung schob es auf den Download.
|
echo "Kein Release gefunden unter $BASE/$OWNER/$repo." >&2
|
||||||
SRC="$(find "$WORK" -maxdepth 3 -name install.sh -path '*/deploy/*' -printf '%h/..\n' | head -1)"
|
echo "Andere Quelle: TESM_RELEASE_BASE, TESM_RELEASE_OWNER, TESM_RELEASE_REPO." >&2
|
||||||
[[ -n "$SRC" ]] || { echo "Im Paket fehlt deploy/install.sh -- Download unbrauchbar." >&2; exit 1; }
|
return 1
|
||||||
SRC="$(cd "$SRC" && pwd)"
|
}
|
||||||
|
echo " $TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Pruefe auf CRLF (Windows-Buildmaschinen) ..."
|
asset="$repo-$TAG.tar.gz"
|
||||||
if hat_crlf "$SRC/deploy/install.sh"; then
|
echo "==> Lade $asset ..."
|
||||||
echo "Das Paket enthaelt CRLF-Zeilenenden. Beim Paketieren fehlte" >&2
|
curl -fsSL -o "$BOOTSTRAP_WORK/$asset" \
|
||||||
echo "'git -c core.autocrlf=false archive'." >&2
|
"$BASE/$OWNER/$repo/releases/download/$TAG/$asset" || {
|
||||||
exit 1
|
echo "Download fehlgeschlagen: $BASE/$OWNER/$repo/releases/download/$TAG/$asset" >&2
|
||||||
fi
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "==> Entpacke ..."
|
||||||
|
tar -xzf "$BOOTSTRAP_WORK/$asset" -C "$BOOTSTRAP_WORK"
|
||||||
|
# Drei Ebenen, nicht zwei: release.sh packt mit dem Praefix "<name>/", also
|
||||||
|
# liegt das Skript unter <name>/deploy/install.sh. Mit "-maxdepth 2" fand die
|
||||||
|
# Suche nie etwas -- und die Fehlermeldung schob es auf den Download.
|
||||||
|
SRC="$(find "$BOOTSTRAP_WORK" -maxdepth 3 -name install.sh -path '*/deploy/*' \
|
||||||
|
-printf '%h/..\n' | head -1)"
|
||||||
|
[[ -n "$SRC" ]] || {
|
||||||
|
echo "Im Paket fehlt deploy/install.sh -- Download unbrauchbar." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
SRC="$(cd "$SRC" && pwd)"
|
||||||
|
|
||||||
|
echo "==> Pruefe auf CRLF (Windows-Buildmaschinen) ..."
|
||||||
|
if hat_crlf "$SRC/deploy/install.sh"; then
|
||||||
|
echo "Das Paket enthaelt CRLF-Zeilenenden. Beim Paketieren fehlte" >&2
|
||||||
|
echo "'git -c core.autocrlf=false archive'." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
# --8<-- Ende Bootstrap ------------------------------------------------------
|
||||||
|
|
||||||
|
release_holen
|
||||||
|
|
||||||
read -r -p "Version $TAG fuer $APP${EXTRA[0]+ (${EXTRA[*]})} installieren? [j/N] " answer
|
read -r -p "Version $TAG fuer $APP${EXTRA[0]+ (${EXTRA[*]})} installieren? [j/N] " answer
|
||||||
[[ "$answer" =~ ^[jJyY]$ ]] || exit 0
|
[[ "$answer" =~ ^[jJyY]$ ]] || exit 0
|
||||||
|
|
||||||
exec sudo bash "$SRC/deploy/install.sh" --app "$APP" --yes ${EXTRA[0]+"${EXTRA[@]}"}
|
# Kein exec: sonst laeuft die Aufraeumfalle nie, und jedes Update liesse ein
|
||||||
|
# entpacktes Release unter /tmp liegen.
|
||||||
|
bash "$SRC/deploy/install.sh" --app "$APP" --yes ${EXTRA[0]+"${EXTRA[@]}"}
|
||||||
|
|||||||
+122
-8
@@ -2,10 +2,17 @@
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Upgrade vom Stand SONNET5 (Version 1.x) auf diese Fassung -- mit Datenuebernahme.
|
# Upgrade vom Stand SONNET5 (Version 1.x) auf diese Fassung -- mit Datenuebernahme.
|
||||||
#
|
#
|
||||||
# Aufruf (aus dem entpackten Release-Verzeichnis):
|
# Eine einzelne Datei genuegt -- sie holt sich das Release selbst:
|
||||||
|
#
|
||||||
|
# curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/deploy/upgrade.sh
|
||||||
|
# sudo bash upgrade.sh --app tesm
|
||||||
|
#
|
||||||
|
# Auf einer 1.2.8 liegt nichts von diesem Projekt; alles andere waere die
|
||||||
|
# falsche Voraussetzung. Liegt das Skript in einem entpackten Release, wird
|
||||||
|
# dessen install.sh benutzt statt eines Downloads:
|
||||||
|
#
|
||||||
# sudo bash deploy/upgrade.sh --app tesm
|
# sudo bash deploy/upgrade.sh --app tesm
|
||||||
# sudo bash deploy/upgrade.sh --app tesm-license
|
# sudo bash deploy/upgrade.sh --app tesm --instance test --source /srv/tesm
|
||||||
# sudo bash deploy/upgrade.sh --app tesm --instance opus --source /srv/tesm
|
|
||||||
#
|
#
|
||||||
# Der Ablauf ist die Vorgabe und braucht keine Schalter:
|
# Der Ablauf ist die Vorgabe und braucht keine Schalter:
|
||||||
#
|
#
|
||||||
@@ -44,9 +51,15 @@ DRY_RUN=0
|
|||||||
WITH_DATA=1
|
WITH_DATA=1
|
||||||
STOP_OLD=1
|
STOP_OLD=1
|
||||||
ADOPT_KEY=1
|
ADOPT_KEY=1
|
||||||
|
TAG="latest"
|
||||||
#: 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.
|
||||||
|
#:
|
||||||
|
#: Auf einer echten 1.2.8 gibt es das **nicht** -- dort liegt die Installation
|
||||||
|
#: unter ihrem Hauptnamen. Der Zusatz entsteht erst, wenn ``rename.sh`` den
|
||||||
|
#: Hauptnamen fuer die neue Fassung braucht. Deshalb ist er der zweite Ort, an
|
||||||
|
#: dem gesucht wird, nicht der erste.
|
||||||
ARCHIV_SUFFIX="sonnet5"
|
ARCHIV_SUFFIX="sonnet5"
|
||||||
|
|
||||||
#: Nur fuer die Ausgabe: wurde die Quelle selbst gefunden oder angegeben?
|
#: Nur fuer die Ausgabe: wurde die Quelle selbst gefunden oder angegeben?
|
||||||
@@ -80,6 +93,8 @@ Verwendung: upgrade.sh --app <tesm|tesm-license> [Optionen]
|
|||||||
erzeugen, statt den alten zu uebernehmen. Dann muessen
|
erzeugen, statt den alten zu uebernehmen. Dann muessen
|
||||||
alle Kunden den Ausstellerwechsel bestaetigen -- die
|
alle Kunden den Ausstellerwechsel bestaetigen -- die
|
||||||
Vorgabe ist deshalb die Uebernahme.
|
Vorgabe ist deshalb die Uebernahme.
|
||||||
|
--tag <vX.Y.Z> Bestimmte Version installieren (Vorgabe: latest).
|
||||||
|
Wird nur beachtet, wenn das Release geladen wird.
|
||||||
--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
|
||||||
@@ -92,7 +107,7 @@ Beispiele:
|
|||||||
sudo bash deploy/upgrade.sh --app tesm
|
sudo bash deploy/upgrade.sh --app tesm
|
||||||
|
|
||||||
# Daneben, zum Vergleich, alte Installation bleibt unangetastet:
|
# Daneben, zum Vergleich, alte Installation bleibt unangetastet:
|
||||||
sudo bash deploy/upgrade.sh --app tesm --instance opus --keep-old-running
|
sudo bash deploy/upgrade.sh --app tesm --instance test --keep-old-running
|
||||||
USAGE
|
USAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +121,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--keep-old-running) STOP_OLD=0; shift ;;
|
--keep-old-running) STOP_OLD=0; shift ;;
|
||||||
--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 ;;
|
||||||
--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 ;;
|
||||||
@@ -115,7 +131,103 @@ 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"
|
||||||
[[ -f "$SCRIPT_DIR/install.sh" ]] || fail "install.sh fehlt neben diesem Skript"
|
|
||||||
|
# --8<-- Bootstrap: Release holen --------------------------------------------
|
||||||
|
# Wortgleich in update.sh und upgrade.sh; ein Hygienetest vergleicht die beiden
|
||||||
|
# Bloecke. Zwei eigenstaendige Skripte koennen sich keine Datei teilen, und
|
||||||
|
# beide sollen als **einzelne Datei** genuegen: auf das Zielsystem legen,
|
||||||
|
# ausfuehren, fertig -- auf einer 1.2.8 liegt nichts von diesem Projekt.
|
||||||
|
#
|
||||||
|
# Erwartet: $APP und $TAG. Setzt: $TAG (aufgeloest) und $SRC (entpacktes
|
||||||
|
# Release). Raeumt sein Arbeitsverzeichnis beim Beenden auf.
|
||||||
|
#
|
||||||
|
# Zwei Fallen des Vorgaengers sind hier vermieden:
|
||||||
|
# * Der Tag "latest" wird ueber die API aufgeloest, nie direkt in die
|
||||||
|
# Download-URL geschrieben. Gitea liefert sonst mit HTTP 200 ein
|
||||||
|
# automatisch erzeugtes Quell-Snapshot statt des echten Release-Anhangs.
|
||||||
|
# * Nach dem Entpacken wird geprueft, dass ein install.sh existiert.
|
||||||
|
BASE="${TESM_RELEASE_BASE:-https://gitea.int.eertmoed.net}"
|
||||||
|
OWNER="${TESM_RELEASE_OWNER:-alientim}"
|
||||||
|
|
||||||
|
# Ein Wagenruecklauf im Paket macht jedes Shell-Skript auf dem Ziel unbrauchbar
|
||||||
|
# ("bad interpreter"). Die Pruefung darf dabei nicht selbst von einem
|
||||||
|
# Zusatzpaket abhaengen: mit "file" -- das auf einem schlanken Server fehlt --
|
||||||
|
# endete sie in "command not found", grep bekam nichts zu sehen, und das Skript
|
||||||
|
# machte weiter, als waere alles in Ordnung.
|
||||||
|
hat_crlf() {
|
||||||
|
local cr
|
||||||
|
cr="$(printf '\r')"
|
||||||
|
# -U (binaer lesen) ist unter Linux ohne Wirkung, auf einer
|
||||||
|
# Windows-Buildmaschine aber entscheidend: dort entfernt grep den
|
||||||
|
# Wagenruecklauf beim Lesen und findet deshalb nie einen.
|
||||||
|
LC_ALL=C grep -qU "$cr" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOTSTRAP_WORK=""
|
||||||
|
bootstrap_aufraeumen() { [[ -n "$BOOTSTRAP_WORK" ]] && rm -rf "$BOOTSTRAP_WORK"; }
|
||||||
|
trap bootstrap_aufraeumen EXIT
|
||||||
|
|
||||||
|
release_holen() {
|
||||||
|
local repo="${TESM_RELEASE_REPO:-$APP}" asset
|
||||||
|
for werkzeug in curl tar python3 find; do
|
||||||
|
command -v "$werkzeug" >/dev/null 2>&1 || {
|
||||||
|
echo "Auf diesem System fehlt $werkzeug -- ohne das geht es nicht." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
done
|
||||||
|
BOOTSTRAP_WORK="$(mktemp -d /tmp/tesm-release-XXXXXX)"
|
||||||
|
|
||||||
|
if [[ "$TAG" == "latest" ]]; then
|
||||||
|
echo "==> Ermittle aktuellen Release-Tag ..."
|
||||||
|
TAG="$(curl -fsS "$BASE/api/v1/repos/$OWNER/$repo/releases/latest" \
|
||||||
|
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')" || {
|
||||||
|
echo "Kein Release gefunden unter $BASE/$OWNER/$repo." >&2
|
||||||
|
echo "Andere Quelle: TESM_RELEASE_BASE, TESM_RELEASE_OWNER, TESM_RELEASE_REPO." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
echo " $TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
asset="$repo-$TAG.tar.gz"
|
||||||
|
echo "==> Lade $asset ..."
|
||||||
|
curl -fsSL -o "$BOOTSTRAP_WORK/$asset" \
|
||||||
|
"$BASE/$OWNER/$repo/releases/download/$TAG/$asset" || {
|
||||||
|
echo "Download fehlgeschlagen: $BASE/$OWNER/$repo/releases/download/$TAG/$asset" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "==> Entpacke ..."
|
||||||
|
tar -xzf "$BOOTSTRAP_WORK/$asset" -C "$BOOTSTRAP_WORK"
|
||||||
|
# Drei Ebenen, nicht zwei: release.sh packt mit dem Praefix "<name>/", also
|
||||||
|
# liegt das Skript unter <name>/deploy/install.sh. Mit "-maxdepth 2" fand die
|
||||||
|
# Suche nie etwas -- und die Fehlermeldung schob es auf den Download.
|
||||||
|
SRC="$(find "$BOOTSTRAP_WORK" -maxdepth 3 -name install.sh -path '*/deploy/*' \
|
||||||
|
-printf '%h/..\n' | head -1)"
|
||||||
|
[[ -n "$SRC" ]] || {
|
||||||
|
echo "Im Paket fehlt deploy/install.sh -- Download unbrauchbar." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
SRC="$(cd "$SRC" && pwd)"
|
||||||
|
|
||||||
|
echo "==> Pruefe auf CRLF (Windows-Buildmaschinen) ..."
|
||||||
|
if hat_crlf "$SRC/deploy/install.sh"; then
|
||||||
|
echo "Das Paket enthaelt CRLF-Zeilenenden. Beim Paketieren fehlte" >&2
|
||||||
|
echo "'git -c core.autocrlf=false archive'." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
# --8<-- Ende Bootstrap ------------------------------------------------------
|
||||||
|
|
||||||
|
# Woher kommt install.sh? Liegt dieses Skript in einem entpackten Release,
|
||||||
|
# nimm dessen Verzeichnis -- wer ein Paket ausgepackt hat, will nicht, dass
|
||||||
|
# ungefragt ein anderes geladen wird. Sonst hol das Release.
|
||||||
|
if [[ -f "$SCRIPT_DIR/install.sh" ]]; then
|
||||||
|
SRC="$REPO_DIR"
|
||||||
|
RELEASE_HERKUNFT="$SRC (entpacktes Release neben diesem Skript)"
|
||||||
|
else
|
||||||
|
release_holen || fail "Das Release liess sich nicht holen."
|
||||||
|
RELEASE_HERKUNFT="$TAG von $BASE/$OWNER"
|
||||||
|
fi
|
||||||
|
|
||||||
# -- Wo liegt die alte Fassung? ---------------------------------------------- #
|
# -- Wo liegt die alte Fassung? ---------------------------------------------- #
|
||||||
# Zwei Orte kommen in Frage, und der zweite ist der Grund fuer diesen Block:
|
# Zwei Orte kommen in Frage, und der zweite ist der Grund fuer diesen Block:
|
||||||
@@ -132,8 +244,9 @@ if [[ -z "$SOURCE" ]]; then
|
|||||||
done
|
done
|
||||||
if [[ -z "$SOURCE" ]]; then
|
if [[ -z "$SOURCE" ]]; then
|
||||||
warn "Keine Installation der Fassung 1.x gefunden. Gesucht wurde in:"
|
warn "Keine Installation der Fassung 1.x gefunden. Gesucht wurde in:"
|
||||||
warn " /srv/$APP"
|
warn " /srv/$APP (dort liegt sie normalerweise)"
|
||||||
warn " /srv/$APP-$ARCHIV_SUFFIX (dorthin verschiebt rename.sh sie)"
|
warn " /srv/$APP-$ARCHIV_SUFFIX (dorthin verschiebt rename.sh sie, falls"
|
||||||
|
warn " der Hauptname schon vergeben war)"
|
||||||
[[ -f "/srv/$APP/data/app.db" ]] && warn "Unter /srv/$APP liegt die laufende Installation dieser Fassung."
|
[[ -f "/srv/$APP/data/app.db" ]] && warn "Unter /srv/$APP liegt die laufende Installation dieser Fassung."
|
||||||
fail "Bitte --source setzen."
|
fail "Bitte --source setzen."
|
||||||
fi
|
fi
|
||||||
@@ -166,6 +279,7 @@ fi
|
|||||||
|
|
||||||
step "Vorhaben"
|
step "Vorhaben"
|
||||||
info "Anwendung : $APP${INSTANCE:+ (Instanz $INSTANCE)}"
|
info "Anwendung : $APP${INSTANCE:+ (Instanz $INSTANCE)}"
|
||||||
|
info "Neue Fassung : $RELEASE_HERKUNFT"
|
||||||
info "Alt : $SOURCE${info_quelle:+ (automatisch gefunden)}"
|
info "Alt : $SOURCE${info_quelle:+ (automatisch gefunden)}"
|
||||||
info "Neu : $NEW_ROOT$([[ $IN_PLACE -eq 1 ]] && echo ' << dasselbe Verzeichnis')"
|
info "Neu : $NEW_ROOT$([[ $IN_PLACE -eq 1 ]] && echo ' << dasselbe Verzeichnis')"
|
||||||
info "Sicherung : $ALT_KOPIE"
|
info "Sicherung : $ALT_KOPIE"
|
||||||
@@ -214,7 +328,7 @@ 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 "$SCRIPT_DIR/install.sh" "${INSTALL_ARGS[@]}" ${EXTRA[0]+"${EXTRA[@]}"}
|
bash "$SRC/deploy/install.sh" "${INSTALL_ARGS[@]}" ${EXTRA[0]+"${EXTRA[@]}"}
|
||||||
|
|
||||||
if [[ $WITH_DATA -eq 0 ]]; then
|
if [[ $WITH_DATA -eq 0 ]]; then
|
||||||
step "Fertig -- ohne Datenuebernahme"
|
step "Fertig -- ohne Datenuebernahme"
|
||||||
|
|||||||
+31
-9
@@ -105,19 +105,26 @@ Eine bereits eingerichtete HTTPS-Konfiguration bleibt erhalten, auch ohne
|
|||||||
|
|
||||||
### Ohne Quellbaum: `update.sh`
|
### Ohne Quellbaum: `update.sh`
|
||||||
|
|
||||||
Liegt kein entpacktes Release vor, holt `update.sh` es selbst -- es lädt das
|
`update.sh` genügt als **einzelne Datei**. Auf einem System, auf dem noch nichts
|
||||||
Release-Asset, entpackt es und ruft dessen `install.sh` auf:
|
von diesem Projekt liegt:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash /opt/tesm/deploy/update.sh tesm
|
curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/deploy/update.sh
|
||||||
sudo bash /opt/tesm-license/deploy/update.sh tesm-license
|
sudo bash update.sh tesm
|
||||||
|
```
|
||||||
|
|
||||||
|
Auf einer bestehenden Installation liegt sie schon bereit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash /srv/tesm/deploy/update.sh tesm
|
||||||
|
sudo bash /srv/tesm-license/deploy/update.sh tesm-license
|
||||||
```
|
```
|
||||||
|
|
||||||
Alles nach dem Tag geht unverändert an `install.sh` weiter -- das ist der Weg,
|
Alles nach dem Tag geht unverändert an `install.sh` weiter -- das ist der Weg,
|
||||||
eine **benannte Instanz** zu aktualisieren:
|
eine **benannte Instanz** zu aktualisieren:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash /opt/tesm-opus/deploy/update.sh tesm latest --instance opus
|
sudo bash /srv/tesm/deploy/update.sh tesm
|
||||||
```
|
```
|
||||||
|
|
||||||
Ohne `--instance` entstünde daneben eine zweite Installation namens `tesm`, mit
|
Ohne `--instance` entstünde daneben eine zweite Installation namens `tesm`, mit
|
||||||
@@ -147,11 +154,26 @@ Ein eigenes Skript, weil dabei mehr passiert als ein Dateiabgleich: die alte
|
|||||||
Fassung hat ein anderes Schema, andere Rechteschlüssel und ein anderes
|
Fassung hat ein anderes Schema, andere Rechteschlüssel und ein anderes
|
||||||
Exportformat.
|
Exportformat.
|
||||||
|
|
||||||
|
Auch `upgrade.sh` genügt als **einzelne Datei** -- und das ist hier der
|
||||||
|
Regelfall: auf einer 1.2.8 liegt nichts von dieser Fassung.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/deploy/upgrade.sh
|
||||||
|
sudo bash upgrade.sh --app tesm
|
||||||
|
```
|
||||||
|
|
||||||
|
Sie lädt das aktuelle Release, entpackt es und benutzt dessen `install.sh`.
|
||||||
|
Liegt das Skript in einem entpackten Release, wird dieses benutzt statt eines
|
||||||
|
Downloads -- wer ein Paket ausgepackt hat, will nicht, dass ungefragt ein
|
||||||
|
anderes geladen wird:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash deploy/upgrade.sh --app tesm
|
sudo bash deploy/upgrade.sh --app tesm
|
||||||
sudo bash deploy/upgrade.sh --app tesm-license
|
sudo bash deploy/upgrade.sh --app tesm-license
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Eine bestimmte Version statt `latest`: `--tag v2.0.8`.
|
||||||
|
|
||||||
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
|
||||||
@@ -184,7 +206,7 @@ Export des Vorgängers und taugt deshalb auch als Rückweg.
|
|||||||
und die alte bleibt vollständig liegen:
|
und die alte bleibt vollständig liegen:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash deploy/upgrade.sh --app tesm --instance opus --keep-old-running --port 5100 --http-port 8080
|
sudo bash deploy/upgrade.sh --app tesm --instance test --keep-old-running --port 5100 --http-port 8080
|
||||||
```
|
```
|
||||||
|
|
||||||
**Was nicht mitkommt** -- und warum:
|
**Was nicht mitkommt** -- und warum:
|
||||||
@@ -280,7 +302,7 @@ die niemand mehr füllte.
|
|||||||
Von Hand prüfen:
|
Von Hand prüfen:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo /usr/local/lib/tesm/tesm-motd --app tesm --root /srv/tesm-opus
|
sudo /usr/local/lib/tesm/tesm-motd --app tesm --root /srv/tesm-test
|
||||||
```
|
```
|
||||||
|
|
||||||
Der Aufruf im Banner ist mit `timeout 3` und `|| true` abgesichert: ein
|
Der Aufruf im Banner ist mit `timeout 3` und `|| true` abgesichert: ein
|
||||||
@@ -295,8 +317,8 @@ entfernt -- nur dieses, nichts anderes in dem Verzeichnis.
|
|||||||
Aus einer Instanz die Hauptinstallation machen (oder umgekehrt):
|
Aus einer Instanz die Hauptinstallation machen (oder umgekehrt):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash deploy/rename.sh --app tesm --from tesm-opus --to tesm
|
sudo bash deploy/rename.sh --app tesm --from tesm-test --to tesm
|
||||||
sudo bash deploy/rename.sh --app tesm-license --from tesm-license-opus --to tesm-license
|
sudo bash deploy/rename.sh --app tesm-license --from tesm-license-test --to tesm-license
|
||||||
```
|
```
|
||||||
|
|
||||||
Der Name steckt an mehr Stellen als im Verzeichnisnamen, und drei davon sind
|
Der Name steckt an mehr Stellen als im Verzeichnisnamen, und drei davon sind
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-core"
|
name = "tesm-core"
|
||||||
version = "2.0.8"
|
version = "2.0.9"
|
||||||
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.8",
|
app_version: str = "2.0.9",
|
||||||
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,
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class CoreConfig:
|
|||||||
"""Technischer Kurzname, z. B. ``tesm`` -- Namensraum fuer Pfade und Units."""
|
"""Technischer Kurzname, z. B. ``tesm`` -- Namensraum fuer Pfade und Units."""
|
||||||
|
|
||||||
site_key: str
|
site_key: str
|
||||||
"""Name *dieser Installation* auf dem Host, z. B. ``tesm-opus``.
|
"""Name *dieser Installation* auf dem Host, z. B. ``tesm-test``.
|
||||||
|
|
||||||
Weicht vom ``app_key`` ab, sobald neben der Hauptinstallation eine zweite
|
Weicht vom ``app_key`` ab, sobald neben der Hauptinstallation eine zweite
|
||||||
Instanz laeuft. Alles, was ausserhalb von ``/srv/<name>`` liegt und damit
|
Instanz laeuft. Alles, was ausserhalb von ``/srv/<name>`` liegt und damit
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-licensing-server"
|
name = "tesm-licensing-server"
|
||||||
version = "2.0.8"
|
version = "2.0.9"
|
||||||
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.8", "cryptography>=41"]
|
dependencies = ["tesm-licensing==2.0.9", "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.8"
|
version = "2.0.9"
|
||||||
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