181 lines
7.7 KiB
Bash
181 lines
7.7 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Aktualisierung: laedt das aktuelle Release und ruft dessen install.sh auf.
|
|
# Enthaelt selbst keinerlei Installationslogik.
|
|
#
|
|
# Eine einzelne Datei genuegt -- sie holt sich alles Weitere:
|
|
#
|
|
# curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/deploy/update.sh
|
|
# sudo bash update.sh tesm
|
|
#
|
|
# Auf einer bestehenden Installation liegt sie schon bereit:
|
|
#
|
|
# sudo bash /srv/tesm/deploy/update.sh tesm
|
|
#
|
|
# Laeuft hier die Master-Ausgabe des Lizenzservers, kommt das Release aus dem
|
|
# privaten Repositorium tesm-license-master -- dafuer braucht es einen
|
|
# Zugriffstoken in TESM_RELEASE_TOKEN oder in /etc/tesm-release.token.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
APP="${1:-}"
|
|
TAG="${2:-latest}"
|
|
|
|
# Alles nach dem Tag geht unveraendert an install.sh weiter. Ohne das liesse
|
|
# sich eine benannte Instanz nicht aktualisieren: install.sh leitet den Namen
|
|
# aus "--instance" ab, und ohne den Schalter entstuende neben "tesm-test" eine
|
|
# zweite Installation namens "tesm" -- mit eigener Datenbank, eigener
|
|
# nginx-Site und demselben Port.
|
|
shift $(( $# > 2 ? 2 : $# ))
|
|
EXTRA=("$@")
|
|
|
|
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || {
|
|
echo "Verwendung: update.sh <tesm|tesm-license> [tag] [install.sh-Argumente ...]" >&2
|
|
echo "Beispiel : update.sh tesm latest --instance test" >&2
|
|
exit 2
|
|
}
|
|
|
|
# Repositorium: die Master-Ausgabe des Lizenzservers liegt in einem eigenen,
|
|
# privaten Repositorium, heisst als Installation aber weiter "tesm-license".
|
|
# Erkannt wird sie an der Installation und nicht an einem Schalter -- wer
|
|
# aktualisiert, soll nicht erst wissen muessen, welche Ausgabe hier laeuft.
|
|
# Sonst holte der Aufruf die Ausgabe fuer Sub-Lizenzserver, und der Installer
|
|
# muesste sie abweisen.
|
|
REPO="$APP"
|
|
if [[ "$APP" == "tesm-license" ]]; then
|
|
NAME="$APP"
|
|
for ((i = 0; i < ${#EXTRA[@]}; i++)); do
|
|
[[ "${EXTRA[i]}" == "--instance" ]] && NAME="$APP-${EXTRA[i + 1]:-}"
|
|
done
|
|
# Die Wurzel ist ueberschreibbar, damit ein Test die Erkennung wirklich
|
|
# ausfuehren kann und nicht nur den Quelltext liest.
|
|
if [[ -d "${TESM_SRV_ROOT:-/srv}/$NAME/apps/tesm-license/src/tesm_license/master" ]]; then
|
|
REPO="tesm-license-master"
|
|
echo "==> Master-Ausgabe erkannt -- Release aus $REPO."
|
|
fi
|
|
fi
|
|
|
|
# --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, wahlweise $REPO (Vorgabe: $APP). Setzt: $TAG
|
|
# (aufgeloest) und $SRC (entpacktes Release). Raeumt sein Arbeitsverzeichnis
|
|
# beim Beenden auf.
|
|
#
|
|
# $REPO gibt es, weil Installationsname und Repositorium auseinanderfallen
|
|
# koennen: die Master-Ausgabe des Lizenzservers liegt in
|
|
# "tesm-license-master", die Installation heisst weiter "tesm-license".
|
|
#
|
|
# 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 privates Repositorium -- tesm-license-master -- gibt sein Release nur mit
|
|
# Zugriffstoken heraus. Reihenfolge: Umgebungsvariable, dann eine Datei, die
|
|
# der Betreiber selbst anlegt. Der Installer legt sie nie an: ob ein Token auf
|
|
# dem Server liegt, ist keine Entscheidung eines Skripts.
|
|
TOKEN="${TESM_RELEASE_TOKEN:-}"
|
|
if [[ -z "$TOKEN" && -r /etc/tesm-release.token ]]; then
|
|
TOKEN="$(tr -d '[:space:]' < /etc/tesm-release.token)"
|
|
fi
|
|
|
|
# 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() {
|
|
# Den Ausstiegscode zuerst festhalten: alles danach ueberschreibt ihn.
|
|
local code=$?
|
|
[[ -n "$BOOTSTRAP_WORK" ]] && rm -rf "$BOOTSTRAP_WORK"
|
|
# Wer einen eigenen Abschluss braucht -- etwa einen Rueckweg nach einem
|
|
# Fehlschlag --, definiert "beim_beenden". Ein zweiter "trap ... EXIT" waere
|
|
# der falsche Weg: er wuerde diesen hier ersetzen, und das entpackte Release
|
|
# bliebe unter /tmp liegen.
|
|
declare -F beim_beenden >/dev/null 2>&1 && beim_beenden "$code"
|
|
return "$code"
|
|
}
|
|
trap bootstrap_aufraeumen EXIT
|
|
|
|
release_holen() {
|
|
local repo="${TESM_RELEASE_REPO:-${REPO:-$APP}}" asset
|
|
# Leeres Array und "set -u" vertragen sich nur mit dieser Schreibweise.
|
|
local -a kopf=()
|
|
[[ -n "$TOKEN" ]] && kopf=(-H "Authorization: token $TOKEN")
|
|
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 ${kopf[0]+"${kopf[@]}"} "$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
|
|
[[ -z "$TOKEN" ]] &&
|
|
echo "Ist das Repositorium privat? Dann TESM_RELEASE_TOKEN setzen." >&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 ${kopf[0]+"${kopf[@]}"} -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 ------------------------------------------------------
|
|
|
|
release_holen
|
|
|
|
read -r -p "Version $TAG fuer $APP${EXTRA[0]+ (${EXTRA[*]})} installieren? [j/N] " answer
|
|
[[ "$answer" =~ ^[jJyY]$ ]] || exit 0
|
|
|
|
# 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[@]}"}
|