3dfcff30e7
Servers now have git repos initialized tracking origin/main. Step 3 does git pull --ff-only instead of rsync. Frontend dist is still rsynced since it's gitignored. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
555 lines
20 KiB
Bash
Executable File
555 lines
20 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# TimeMaster – Deployment & Update Script
|
||
# Lokal ausführen – verbindet sich per SSH auf Produktivserver
|
||
#
|
||
# Usage:
|
||
# ./update.sh [OPTIONS]
|
||
#
|
||
# Options:
|
||
# --no-tests Tests überspringen
|
||
# --no-frontend Frontend-Build und -Sync überspringen
|
||
# --server 137 Nur Server 192.168.1.137
|
||
# --server 164 Nur Server 192.168.1.164
|
||
# --server both Beide Server (Standard)
|
||
# --dry-run Alle Befehle ausgeben, aber NICHT ausführen
|
||
# --help Diese Hilfe anzeigen
|
||
#
|
||
# Schritte (Reihenfolge ist kritisch):
|
||
# 1. Tests auf Server 137 ausführen (via SSH)
|
||
# 2. Frontend bauen (lokal, npm run build)
|
||
# 3. git pull origin main auf Server(n)
|
||
# 4. Alembic-Migration auf Server ausführen
|
||
# 5. Service neustarten
|
||
# 6. Health-Check (3 Versuche)
|
||
# 7. Frontend-Dist synchronisieren
|
||
# 8. Abschlussbericht
|
||
# =============================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
# =============================================================================
|
||
# KONFIGURATION
|
||
# =============================================================================
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
BACKEND_DIR="$SCRIPT_DIR/backend"
|
||
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
||
|
||
SERVER_137="root@192.168.1.137"
|
||
SERVER_164="root@192.168.1.164"
|
||
REMOTE_PATH="/opt/timemaster"
|
||
REMOTE_VENV="$REMOTE_PATH/backend/venv"
|
||
|
||
HEALTH_RETRIES=3
|
||
HEALTH_WAIT=3
|
||
|
||
# =============================================================================
|
||
# FARBEN & AUSGABE
|
||
# =============================================================================
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
BOLD='\033[1m'
|
||
RESET='\033[0m'
|
||
|
||
step() { echo -e "\n${BLUE}${BOLD}▶ $*${RESET}"; }
|
||
ok() { echo -e " ${GREEN}✓ $*${RESET}"; }
|
||
fail() { echo -e " ${RED}✗ $*${RESET}"; }
|
||
warn() { echo -e " ${YELLOW}⚠ $*${RESET}"; }
|
||
info() { echo -e " ${RESET}$*${RESET}"; }
|
||
hr() { echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"; }
|
||
|
||
die() {
|
||
echo ""
|
||
fail "$1"
|
||
echo ""
|
||
hr
|
||
echo -e "${RED}${BOLD} ABBRUCH: $1${RESET}"
|
||
hr
|
||
print_summary
|
||
exit 1
|
||
}
|
||
|
||
# =============================================================================
|
||
# ARGUMENT-PARSING
|
||
# =============================================================================
|
||
OPT_TESTS=true
|
||
OPT_FRONTEND=true
|
||
OPT_SERVER="both"
|
||
OPT_DRYRUN=false
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--no-tests)
|
||
OPT_TESTS=false
|
||
shift ;;
|
||
--no-frontend)
|
||
OPT_FRONTEND=false
|
||
shift ;;
|
||
--server)
|
||
if [[ -z "${2:-}" ]]; then
|
||
die "--server benötigt einen Wert: 137, 164 oder both"
|
||
fi
|
||
OPT_SERVER="$2"
|
||
if [[ "$OPT_SERVER" != "137" && "$OPT_SERVER" != "164" && "$OPT_SERVER" != "both" ]]; then
|
||
die "--server muss 137, 164 oder both sein (nicht: $OPT_SERVER)"
|
||
fi
|
||
shift 2 ;;
|
||
--dry-run)
|
||
OPT_DRYRUN=true
|
||
shift ;;
|
||
--help|-h)
|
||
# Zeige nur den Header-Kommentarblock (bis zur ersten Leerzeile im Kommentar-Block)
|
||
awk '/^#!/{next} /^#/{sub(/^# ?/,""); print; next} /^[^#]/{exit}' "$0"
|
||
exit 0 ;;
|
||
*)
|
||
die "Unbekanntes Argument: $1 (--help für Hilfe)"
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# Server-Liste aufbauen
|
||
SERVERS=()
|
||
case "$OPT_SERVER" in
|
||
137) SERVERS=("$SERVER_137") ;;
|
||
164) SERVERS=("$SERVER_164") ;;
|
||
both) SERVERS=("$SERVER_137" "$SERVER_164") ;;
|
||
esac
|
||
|
||
# =============================================================================
|
||
# ZUSAMMENFASSUNGS-TRACKING
|
||
# =============================================================================
|
||
START_TIME=$(date +%s)
|
||
declare -A STEP_STATUS # name → "OK" | "FAIL" | "SKIP" | "WARN"
|
||
declare -a STEP_ORDER=()
|
||
|
||
step_record() {
|
||
local name="$1" status="$2"
|
||
STEP_STATUS["$name"]="$status"
|
||
STEP_ORDER+=("$name")
|
||
}
|
||
|
||
print_summary() {
|
||
local end_time elapsed
|
||
end_time=$(date +%s)
|
||
elapsed=$(( end_time - START_TIME ))
|
||
|
||
echo ""
|
||
hr
|
||
echo -e "${BOLD} Abschlussbericht (Dauer: ${elapsed}s)${RESET}"
|
||
hr
|
||
for name in "${STEP_ORDER[@]}"; do
|
||
local status="${STEP_STATUS[$name]}"
|
||
case "$status" in
|
||
OK) echo -e " ${GREEN}✓ $name${RESET}" ;;
|
||
FAIL) echo -e " ${RED}✗ $name${RESET}" ;;
|
||
SKIP) echo -e " ${YELLOW}– $name (übersprungen)${RESET}" ;;
|
||
WARN) echo -e " ${YELLOW}⚠ $name${RESET}" ;;
|
||
esac
|
||
done
|
||
hr
|
||
}
|
||
|
||
# =============================================================================
|
||
# HILFSFUNKTIONEN
|
||
# =============================================================================
|
||
|
||
# Führt einen Befehl aus oder gibt ihn im Dry-Run nur aus
|
||
run_cmd() {
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} $*"
|
||
return 0
|
||
fi
|
||
"$@"
|
||
}
|
||
|
||
# SSH-Befehl mit Fehlerbehandlung
|
||
run_ssh() {
|
||
local server="$1"
|
||
shift
|
||
local cmd="$*"
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} ssh $server \"$cmd\""
|
||
return 0
|
||
fi
|
||
if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" "$cmd"; then
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# rsync mit Fehlerbehandlung
|
||
run_rsync() {
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} rsync $*"
|
||
return 0
|
||
fi
|
||
rsync "$@"
|
||
}
|
||
|
||
# SSH-Erreichbarkeit prüfen
|
||
check_ssh() {
|
||
local server="$1"
|
||
if $OPT_DRYRUN; then
|
||
info "Dry-Run: SSH-Check für $server übersprungen"
|
||
return 0
|
||
fi
|
||
if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" "true" 2>/dev/null; then
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# =============================================================================
|
||
# HEADER
|
||
# =============================================================================
|
||
hr
|
||
echo -e "${BOLD} TimeMaster Deployment Script${RESET}"
|
||
echo -e " Datum: $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo -e " Server: ${SERVERS[*]}"
|
||
echo -e " Tests: $(if $OPT_TESTS; then echo "ja"; else echo "nein (--no-tests)"; fi)"
|
||
echo -e " Frontend: $(if $OPT_FRONTEND; then echo "ja"; else echo "nein (--no-frontend)"; fi)"
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}${BOLD}Modus: DRY-RUN (keine Änderungen werden durchgeführt)${RESET}"
|
||
fi
|
||
hr
|
||
|
||
# =============================================================================
|
||
# PRE-FLIGHT: Lokale Verzeichnisse prüfen
|
||
# =============================================================================
|
||
step "Pre-Flight: Lokale Verzeichnisse prüfen"
|
||
|
||
if [[ ! -d "$BACKEND_DIR" ]]; then
|
||
die "Backend-Verzeichnis nicht gefunden: $BACKEND_DIR"
|
||
fi
|
||
ok "Backend-Verzeichnis vorhanden: $BACKEND_DIR"
|
||
|
||
if $OPT_FRONTEND; then
|
||
if [[ ! -d "$FRONTEND_DIR" ]]; then
|
||
die "Frontend-Verzeichnis nicht gefunden: $FRONTEND_DIR"
|
||
fi
|
||
if [[ ! -f "$FRONTEND_DIR/package.json" ]]; then
|
||
die "package.json nicht gefunden: $FRONTEND_DIR/package.json"
|
||
fi
|
||
ok "Frontend-Verzeichnis vorhanden: $FRONTEND_DIR"
|
||
fi
|
||
|
||
# SSH-Erreichbarkeit aller Zielserver prüfen
|
||
for server in "${SERVERS[@]}"; do
|
||
step "Pre-Flight: SSH-Verbindung zu $server prüfen"
|
||
if check_ssh "$server"; then
|
||
ok "SSH-Verbindung zu $server erfolgreich"
|
||
else
|
||
die "SSH-Verbindung zu $server fehlgeschlagen.\n Prüfe: ssh $server\n SSH-Key konfiguriert?"
|
||
fi
|
||
done
|
||
|
||
step_record "Pre-Flight" "OK"
|
||
|
||
# =============================================================================
|
||
# SCHRITT 1: TESTS (auf Server 137)
|
||
# =============================================================================
|
||
if ! $OPT_TESTS; then
|
||
step "Schritt 1: Tests (übersprungen via --no-tests)"
|
||
step_record "1. Tests" "SKIP"
|
||
else
|
||
step "Schritt 1: Tests auf $SERVER_137 ausführen"
|
||
info "Befehl: cd /opt/timemaster/backend && source venv/bin/activate && python -m pytest -x -q"
|
||
|
||
TEST_CMD="cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && python -m pytest -x -q 2>&1"
|
||
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} ssh $SERVER_137 \"$TEST_CMD\""
|
||
step_record "1. Tests" "SKIP"
|
||
else
|
||
TEST_OUTPUT=$(ssh -o ConnectTimeout=30 -o BatchMode=yes "$SERVER_137" "$TEST_CMD" 2>&1) || true
|
||
TEST_RC=${PIPESTATUS[0]:-$?}
|
||
|
||
# Ausgabe der Tests anzeigen
|
||
echo "$TEST_OUTPUT" | while IFS= read -r line; do
|
||
info "$line"
|
||
done
|
||
|
||
# Prüfen ob Tests fehlgeschlagen (pytest gibt RC != 0 bei Fehler)
|
||
if echo "$TEST_OUTPUT" | grep -qE "^(FAILED|ERROR|[0-9]+ failed)"; then
|
||
fail "Tests FEHLGESCHLAGEN"
|
||
echo ""
|
||
echo -e " ${RED}Fehlerdetails:${RESET}"
|
||
echo "$TEST_OUTPUT" | grep -A 5 -E "^(FAILED|ERROR)" | while IFS= read -r line; do
|
||
echo -e " $line"
|
||
done
|
||
step_record "1. Tests" "FAIL"
|
||
die "Tests fehlgeschlagen – Deploy abgebrochen. Keine Dateien wurden auf den Server übertragen."
|
||
fi
|
||
|
||
# Erfolgsmeldung aus pytest-Ausgabe extrahieren
|
||
PASSED_LINE=$(echo "$TEST_OUTPUT" | grep -E "passed" | tail -1 || echo "")
|
||
if [[ -n "$PASSED_LINE" ]]; then
|
||
ok "Tests bestanden: $PASSED_LINE"
|
||
else
|
||
ok "Tests abgeschlossen ohne Fehler"
|
||
fi
|
||
step_record "1. Tests" "OK"
|
||
fi
|
||
fi
|
||
|
||
# =============================================================================
|
||
# SCHRITT 2: FRONTEND BAUEN
|
||
# =============================================================================
|
||
if ! $OPT_FRONTEND; then
|
||
step "Schritt 2: Frontend-Build (übersprungen via --no-frontend)"
|
||
step_record "2. Frontend-Build" "SKIP"
|
||
else
|
||
step "Schritt 2: Frontend bauen (npm run build)"
|
||
info "Verzeichnis: $FRONTEND_DIR"
|
||
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} cd $FRONTEND_DIR && npm run build"
|
||
step_record "2. Frontend-Build" "SKIP"
|
||
else
|
||
BUILD_OUTPUT=$(cd "$FRONTEND_DIR" && npm run build 2>&1) || BUILD_RC=$?
|
||
BUILD_RC=${BUILD_RC:-0}
|
||
|
||
if [[ $BUILD_RC -ne 0 ]]; then
|
||
fail "Frontend-Build FEHLGESCHLAGEN (Exit-Code: $BUILD_RC)"
|
||
echo ""
|
||
echo -e " ${RED}Build-Ausgabe:${RESET}"
|
||
echo "$BUILD_OUTPUT" | tail -30 | while IFS= read -r line; do
|
||
echo -e " $line"
|
||
done
|
||
step_record "2. Frontend-Build" "FAIL"
|
||
die "Frontend-Build fehlgeschlagen – Deploy abgebrochen."
|
||
fi
|
||
|
||
if [[ ! -d "$FRONTEND_DIR/dist" ]]; then
|
||
step_record "2. Frontend-Build" "FAIL"
|
||
die "Frontend-Build scheinbar erfolgreich, aber dist/-Verzeichnis fehlt: $FRONTEND_DIR/dist"
|
||
fi
|
||
|
||
DIST_SIZE=$(du -sh "$FRONTEND_DIR/dist" | cut -f1)
|
||
ok "Frontend gebaut: $FRONTEND_DIR/dist ($DIST_SIZE)"
|
||
step_record "2. Frontend-Build" "OK"
|
||
fi
|
||
fi
|
||
|
||
# =============================================================================
|
||
# SCHRITT 3, 4, 5, 6, 7: PRO SERVER AUSFÜHREN
|
||
# =============================================================================
|
||
SERVER_RESULTS=()
|
||
ALL_SERVERS_OK=true
|
||
|
||
for server in "${SERVERS[@]}"; do
|
||
SERVER_SHORT="${server##*@}" # "192.168.1.137" aus "root@192.168.1.137"
|
||
echo ""
|
||
hr
|
||
echo -e "${BOLD} Server: $server${RESET}"
|
||
hr
|
||
|
||
SERVER_OK=true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# SCHRITT 3: git pull vom Gitea
|
||
# -------------------------------------------------------------------------
|
||
step "[$SERVER_SHORT] Schritt 3: git pull (origin/main)"
|
||
|
||
GIT_PULL_CMD="git config --global --add safe.directory $REMOTE_PATH 2>/dev/null; cd $REMOTE_PATH && git pull --ff-only origin main 2>&1"
|
||
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} ssh $server \"$GIT_PULL_CMD\""
|
||
step_record "3. git pull [$SERVER_SHORT]" "SKIP"
|
||
else
|
||
GIT_OUTPUT=$(ssh -o ConnectTimeout=30 -o BatchMode=yes "$server" "$GIT_PULL_CMD" 2>&1)
|
||
GIT_RC=$?
|
||
echo "$GIT_OUTPUT" | while IFS= read -r line; do info "$line"; done
|
||
if [ $GIT_RC -eq 0 ]; then
|
||
ok "git pull erfolgreich"
|
||
step_record "3. git pull [$SERVER_SHORT]" "OK"
|
||
else
|
||
fail "git pull FEHLGESCHLAGEN (Exit-Code: $GIT_RC)"
|
||
step_record "3. git pull [$SERVER_SHORT]" "FAIL"
|
||
SERVER_OK=false
|
||
ALL_SERVERS_OK=false
|
||
warn "Server $server wird übersprungen (git pull fehlgeschlagen)"
|
||
continue
|
||
fi
|
||
fi
|
||
|
||
# -------------------------------------------------------------------------
|
||
# SCHRITT 4: Alembic-Migration
|
||
# -------------------------------------------------------------------------
|
||
step "[$SERVER_SHORT] Schritt 4: Alembic-Migration"
|
||
MIGRATE_CMD="cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic upgrade head 2>&1"
|
||
info "Befehl: $MIGRATE_CMD"
|
||
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} ssh $server \"$MIGRATE_CMD\""
|
||
step_record "4. Migration [$SERVER_SHORT]" "SKIP"
|
||
else
|
||
MIGRATE_OUTPUT=$(ssh -o ConnectTimeout=30 -o BatchMode=yes "$server" "$MIGRATE_CMD" 2>&1) || MIGRATE_RC=$?
|
||
MIGRATE_RC=${MIGRATE_RC:-0}
|
||
|
||
echo "$MIGRATE_OUTPUT" | while IFS= read -r line; do
|
||
info "$line"
|
||
done
|
||
|
||
if [[ $MIGRATE_RC -ne 0 ]]; then
|
||
fail "Alembic-Migration FEHLGESCHLAGEN (Exit-Code: $MIGRATE_RC)"
|
||
echo ""
|
||
warn "Service wird NICHT neugestartet (DB-Schema könnte inkonsistent sein)"
|
||
echo ""
|
||
echo -e " ${RED}Letzte 20 Server-Log-Zeilen:${RESET}"
|
||
ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" \
|
||
"journalctl -u timemaster -n 20 --no-pager 2>/dev/null || echo '(keine Logs verfügbar)'" \
|
||
| while IFS= read -r line; do echo -e " $line"; done
|
||
echo ""
|
||
echo -e " ${YELLOW}Diagnose-Befehle:${RESET}"
|
||
echo -e " ssh $server 'cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic current'"
|
||
echo -e " ssh $server 'cd $REMOTE_PATH/backend && source $REMOTE_VENV/bin/activate && alembic history --verbose'"
|
||
step_record "4. Migration [$SERVER_SHORT]" "FAIL"
|
||
SERVER_OK=false
|
||
ALL_SERVERS_OK=false
|
||
warn "Server $server wird übersprungen (Migration fehlgeschlagen, Service NICHT neugestartet)"
|
||
continue
|
||
fi
|
||
|
||
# Prüfe ob Migration "up to date" ist (kein Fehler, aber auch keine Änderung)
|
||
if echo "$MIGRATE_OUTPUT" | grep -qi "already up to date\|no migrations"; then
|
||
ok "Migration: bereits aktuell (keine neuen Migrationen)"
|
||
else
|
||
ok "Migration erfolgreich"
|
||
fi
|
||
step_record "4. Migration [$SERVER_SHORT]" "OK"
|
||
fi
|
||
|
||
# -------------------------------------------------------------------------
|
||
# SCHRITT 5: Service neustarten
|
||
# -------------------------------------------------------------------------
|
||
step "[$SERVER_SHORT] Schritt 5: Service neustarten"
|
||
|
||
if run_ssh "$server" "systemctl restart timemaster"; then
|
||
ok "Service neugestartet"
|
||
step_record "5. Service-Restart [$SERVER_SHORT]" "OK"
|
||
else
|
||
RESTART_RC=$?
|
||
fail "systemctl restart timemaster FEHLGESCHLAGEN (Exit-Code: $RESTART_RC)"
|
||
echo ""
|
||
echo -e " ${RED}Letzte 30 Journal-Zeilen:${RESET}"
|
||
ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" \
|
||
"journalctl -u timemaster -n 30 --no-pager 2>/dev/null || echo '(keine Logs verfügbar)'" \
|
||
| while IFS= read -r line; do echo -e " $line"; done
|
||
echo ""
|
||
echo -e " ${YELLOW}Diagnose-Befehle:${RESET}"
|
||
echo -e " ssh $server 'systemctl status timemaster'"
|
||
echo -e " ssh $server 'journalctl -u timemaster -n 100 --no-pager'"
|
||
step_record "5. Service-Restart [$SERVER_SHORT]" "FAIL"
|
||
SERVER_OK=false
|
||
ALL_SERVERS_OK=false
|
||
warn "Server $server: Service-Start fehlgeschlagen"
|
||
continue
|
||
fi
|
||
|
||
# -------------------------------------------------------------------------
|
||
# SCHRITT 6: Health-Check
|
||
# -------------------------------------------------------------------------
|
||
step "[$SERVER_SHORT] Schritt 6: Health-Check (${HEALTH_RETRIES} Versuche, ${HEALTH_WAIT}s Pause)"
|
||
|
||
if $OPT_DRYRUN; then
|
||
echo -e " ${YELLOW}[DRY-RUN]${RESET} ssh $server 'curl -sf http://localhost:8000/health'"
|
||
step_record "6. Health-Check [$SERVER_SHORT]" "SKIP"
|
||
else
|
||
HEALTH_OK=false
|
||
for attempt in $(seq 1 $HEALTH_RETRIES); do
|
||
info "Versuch $attempt/$HEALTH_RETRIES..."
|
||
HEALTH_OUTPUT=$(ssh -o ConnectTimeout=10 -o BatchMode=yes "$server" \
|
||
"curl -sf --connect-timeout 5 --max-time 10 http://localhost:8000/health 2>&1") \
|
||
&& HEALTH_RC=0 || HEALTH_RC=$?
|
||
|
||
if [[ $HEALTH_RC -eq 0 ]]; then
|
||
ok "Health-Check erfolgreich (Versuch $attempt): $HEALTH_OUTPUT"
|
||
HEALTH_OK=true
|
||
break
|
||
else
|
||
warn "Versuch $attempt fehlgeschlagen"
|
||
if [[ $attempt -lt $HEALTH_RETRIES ]]; then
|
||
info "Warte ${HEALTH_WAIT}s..."
|
||
sleep "$HEALTH_WAIT"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
if ! $HEALTH_OK; then
|
||
fail "Health-Check nach $HEALTH_RETRIES Versuchen FEHLGESCHLAGEN"
|
||
echo ""
|
||
warn "Service läuft möglicherweise nicht korrekt. Log-Befehle:"
|
||
echo -e " ${YELLOW}ssh $server 'journalctl -u timemaster -n 50 --no-pager'${RESET}"
|
||
echo -e " ${YELLOW}ssh $server 'systemctl status timemaster'${RESET}"
|
||
echo -e " ${YELLOW}ssh $server 'curl -v http://localhost:8000/health'${RESET}"
|
||
step_record "6. Health-Check [$SERVER_SHORT]" "WARN"
|
||
SERVER_OK=false
|
||
ALL_SERVERS_OK=false
|
||
# KEIN Abbruch hier – nur Warnung, Frontend noch synchronisieren
|
||
else
|
||
step_record "6. Health-Check [$SERVER_SHORT]" "OK"
|
||
fi
|
||
fi
|
||
|
||
# -------------------------------------------------------------------------
|
||
# SCHRITT 7: Frontend-Dist synchronisieren
|
||
# -------------------------------------------------------------------------
|
||
if ! $OPT_FRONTEND; then
|
||
step "[$SERVER_SHORT] Schritt 7: Frontend-Sync (übersprungen via --no-frontend)"
|
||
step_record "7. Frontend-Sync [$SERVER_SHORT]" "SKIP"
|
||
else
|
||
step "[$SERVER_SHORT] Schritt 7: Frontend-Dist synchronisieren"
|
||
info "rsync: $FRONTEND_DIR/dist/ → $server:$REMOTE_PATH/frontend/dist/"
|
||
|
||
if [[ ! -d "$FRONTEND_DIR/dist" ]] && ! $OPT_DRYRUN; then
|
||
warn "dist/-Verzeichnis nicht gefunden: $FRONTEND_DIR/dist"
|
||
warn "Frontend-Build wurde eventuell nicht ausgeführt (--no-frontend?)"
|
||
step_record "7. Frontend-Sync [$SERVER_SHORT]" "WARN"
|
||
else
|
||
if run_rsync -avz --delete \
|
||
"$FRONTEND_DIR/dist/" \
|
||
"$server:$REMOTE_PATH/frontend/dist/" ; then
|
||
ok "Frontend-Dist synchronisiert"
|
||
step_record "7. Frontend-Sync [$SERVER_SHORT]" "OK"
|
||
else
|
||
RSYNC_FE_RC=$?
|
||
fail "Frontend-rsync FEHLGESCHLAGEN (Exit-Code: $RSYNC_FE_RC)"
|
||
fail "Befehl war: rsync -avz --delete $FRONTEND_DIR/dist/ $server:$REMOTE_PATH/frontend/dist/"
|
||
step_record "7. Frontend-Sync [$SERVER_SHORT]" "FAIL"
|
||
SERVER_OK=false
|
||
ALL_SERVERS_OK=false
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
if $SERVER_OK; then
|
||
SERVER_RESULTS+=("${GREEN}✓ $server${RESET}")
|
||
else
|
||
SERVER_RESULTS+=("${YELLOW}⚠ $server (mit Warnungen/Fehlern)${RESET}")
|
||
fi
|
||
|
||
done # Ende Server-Schleife
|
||
|
||
# =============================================================================
|
||
# ABSCHLUSSBERICHT
|
||
# =============================================================================
|
||
echo ""
|
||
hr
|
||
echo -e "${BOLD} Server-Ergebnisse:${RESET}"
|
||
for result in "${SERVER_RESULTS[@]}"; do
|
||
echo -e " $result"
|
||
done
|
||
|
||
print_summary
|
||
|
||
if $ALL_SERVERS_OK; then
|
||
echo -e "${GREEN}${BOLD} DEPLOYMENT ERFOLGREICH${RESET}"
|
||
else
|
||
echo -e "${YELLOW}${BOLD} DEPLOYMENT MIT WARNUNGEN ABGESCHLOSSEN${RESET}"
|
||
echo -e "${YELLOW} Bitte die Fehlermeldungen oben prüfen.${RESET}"
|
||
fi
|
||
hr
|
||
|
||
exit 0
|