chore(deploy): entkoppelte Self-Update-Skripte pro Server
Jeder Server aktualisiert sich eigenstaendig aus dem Repo – kein
Cross-Server-SSH, kein "both". 137 und 164 komplett getrennt.
- server-update.sh: laeuft AUF dem Server (git pull --ff-only → alembic
upgrade head → restart → health). Guard: bricht ab wenn venv fehlt.
- push-frontend.sh: lokal, baut Frontend + rsync dist/ an EINEN Server
(Node laeuft nicht auf den Servern, dist ist gitignored). Guard gegen
Ausfuehrung auf einem Zielserver.
- deploy.sh + update.sh stillgelegt (Abbruch-Stubs): deploy.sh rsyncte den
Arbeitsbaum in den Server-git-Baum und verschmutzte ihn (git pull brach);
update.sh koppelte beide Server ("both").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,107 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
# ============================================================
|
# =============================================================================
|
||||||
# deploy.sh – Lokal ausführen, deployt auf 192.168.1.137
|
# STILLGELEGT – nicht mehr verwenden.
|
||||||
# Usage:
|
#
|
||||||
# ./deploy.sh → nur sync + restart
|
# Dieses Skript rsyncte das lokale Arbeitsverzeichnis in den git-Baum des
|
||||||
# ./deploy.sh --migrate → sync + alembic upgrade + restart
|
# Servers und verschmutzte ihn dadurch (spätere 'git pull' schlugen fehl).
|
||||||
# ./deploy.sh --setup → erstes Setup auf dem Server
|
#
|
||||||
# ============================================================
|
# Neuer, entkoppelter Ablauf (jeder Server macht sich selbst):
|
||||||
set -e
|
# 1. Lokal: git add -A && git commit && git push origin main
|
||||||
|
# 2. Server: ssh root@<host> 'cd /opt/timemaster && ./server-update.sh'
|
||||||
SERVER="root@192.168.1.137"
|
# 3. Frontend (falls geändert, lokal): ./push-frontend.sh <137|164>
|
||||||
REMOTE="/opt/timemaster"
|
# =============================================================================
|
||||||
LOCAL="$(cd "$(dirname "$0")" && pwd)"
|
echo "deploy.sh ist stillgelegt. Nutze: git push → server-update.sh (auf dem Server) → push-frontend.sh (lokal)." >&2
|
||||||
|
exit 1
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
log() { echo -e "${GREEN}==>${NC} $1"; }
|
|
||||||
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
||||||
|
|
||||||
# ── Erstes Setup ──────────────────────────────────────────────────────────────
|
|
||||||
if [[ "$1" == "--setup" ]]; then
|
|
||||||
log "Erstes Server-Setup wird ausgeführt..."
|
|
||||||
|
|
||||||
ssh "$SERVER" "apt-get update -q && apt-get install -y \
|
|
||||||
python3.12 python3.12-venv python3.12-dev \
|
|
||||||
postgresql postgresql-contrib \
|
|
||||||
redis-server nginx \
|
|
||||||
git build-essential libpq-dev curl"
|
|
||||||
|
|
||||||
ssh "$SERVER" "mkdir -p $REMOTE/backend $REMOTE/frontend/dist"
|
|
||||||
|
|
||||||
log "Dateien übertragen..."
|
|
||||||
rsync -avz --exclude='__pycache__' --exclude='*.pyc' --exclude='.env' \
|
|
||||||
--exclude='venv/' --exclude='.git/' \
|
|
||||||
"$LOCAL/" "$SERVER:$REMOTE/"
|
|
||||||
|
|
||||||
ssh "$SERVER" bash << 'REMOTE_SETUP'
|
|
||||||
set -e
|
|
||||||
cd /opt/timemaster/backend
|
|
||||||
|
|
||||||
# venv
|
|
||||||
python3.12 -m venv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install --upgrade pip -q
|
|
||||||
pip install -r requirements.txt -q
|
|
||||||
|
|
||||||
# PostgreSQL
|
|
||||||
systemctl enable --now postgresql
|
|
||||||
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='timemaster'" | grep -q 1 || \
|
|
||||||
sudo -u postgres psql -c "CREATE ROLE timemaster LOGIN PASSWORD 'timemaster_secret_CHANGE_ME';"
|
|
||||||
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='timemaster_db'" | grep -q 1 || \
|
|
||||||
sudo -u postgres psql -c "CREATE DATABASE timemaster_db OWNER timemaster;"
|
|
||||||
|
|
||||||
# Redis
|
|
||||||
systemctl enable --now redis-server
|
|
||||||
|
|
||||||
# .env
|
|
||||||
if [ ! -f .env ]; then
|
|
||||||
cp .env.example .env
|
|
||||||
echo ""
|
|
||||||
echo "⚠️ WICHTIG: .env auf dem Server anpassen!"
|
|
||||||
echo " ssh root@192.168.1.137 'nano /opt/timemaster/backend/.env'"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# systemd service
|
|
||||||
cp /opt/timemaster/timemaster.service /etc/systemd/system/
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
echo "✓ Setup abgeschlossen"
|
|
||||||
echo "Nächster Schritt: .env befüllen, dann: ./deploy.sh --migrate"
|
|
||||||
REMOTE_SETUP
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Normaler Deploy ───────────────────────────────────────────────────────────
|
|
||||||
log "Sync → $SERVER:$REMOTE/backend"
|
|
||||||
rsync -avz --progress \
|
|
||||||
--exclude='__pycache__' \
|
|
||||||
--exclude='*.pyc' \
|
|
||||||
--exclude='.env' \
|
|
||||||
--exclude='venv/' \
|
|
||||||
--exclude='.git/' \
|
|
||||||
--exclude='tests/' \
|
|
||||||
"$LOCAL/backend/" "$SERVER:$REMOTE/backend/"
|
|
||||||
|
|
||||||
# Frontend build + sync (falls vorhanden)
|
|
||||||
if [ -d "$LOCAL/frontend/dist" ]; then
|
|
||||||
log "Frontend sync..."
|
|
||||||
rsync -avz "$LOCAL/frontend/dist/" "$SERVER:$REMOTE/frontend/dist/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Migration (optional) ──────────────────────────────────────────────────────
|
|
||||||
if [[ "$1" == "--migrate" ]]; then
|
|
||||||
log "Alembic upgrade head..."
|
|
||||||
ssh "$SERVER" "cd $REMOTE/backend && source venv/bin/activate && alembic upgrade head"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Service neu starten ───────────────────────────────────────────────────────
|
|
||||||
log "Service restart..."
|
|
||||||
ssh "$SERVER" "systemctl restart timemaster && sleep 2 && systemctl is-active timemaster"
|
|
||||||
|
|
||||||
log "Logs (letzte 20 Zeilen):"
|
|
||||||
ssh "$SERVER" "journalctl -u timemaster -n 20 --no-pager"
|
|
||||||
|
|
||||||
log "✓ Deploy abgeschlossen → http://192.168.1.137:8000/health"
|
|
||||||
|
|||||||
Executable
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# push-frontend.sh – LOKAL auf dem Dev-Rechner ausführen
|
||||||
|
#
|
||||||
|
# Baut das Frontend und liefert die dist/ an GENAU EINEN Server.
|
||||||
|
# Nötig, weil auf den Servern kein Node läuft und frontend/dist gitignored ist
|
||||||
|
# (server-update.sh kann das Frontend also nicht selbst bauen).
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./push-frontend.sh 137 # → root@192.168.1.137
|
||||||
|
# ./push-frontend.sh 164 # → root@192.168.1.164
|
||||||
|
# ./push-frontend.sh 137 --no-build # bestehendes dist/ nur syncen
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
||||||
|
REMOTE_PATH="/opt/timemaster"
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'; RED='\033[0;31m'; NC='\033[0m'
|
||||||
|
log() { echo -e "${GREEN}==>${NC} $*"; }
|
||||||
|
die() { echo -e "${RED}[FEHLER]${NC} $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
TARGET="${1:-}"
|
||||||
|
case "$TARGET" in
|
||||||
|
137) SERVER="root@192.168.1.137" ;;
|
||||||
|
164) SERVER="root@192.168.1.164" ;;
|
||||||
|
*) die "Server angeben: 137 oder 164 (z.B. ./push-frontend.sh 137)" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Schutz: nicht versehentlich auf dem Zielserver ausführen
|
||||||
|
for ip in 192.168.1.137 192.168.1.164; do
|
||||||
|
[[ " $(hostname -I 2>/dev/null) " == *" $ip "* ]] && die "Läuft auf einem Zielserver – nur lokal auf dem Dev-Rechner ausführen."
|
||||||
|
done
|
||||||
|
|
||||||
|
DO_BUILD=true
|
||||||
|
[[ "${2:-}" == "--no-build" ]] && DO_BUILD=false
|
||||||
|
|
||||||
|
if $DO_BUILD; then
|
||||||
|
log "npm run build"
|
||||||
|
( cd "$FRONTEND_DIR" && npm run build ) || die "Frontend-Build fehlgeschlagen."
|
||||||
|
fi
|
||||||
|
[[ -f "$FRONTEND_DIR/dist/index.html" ]] || die "dist/index.html fehlt – erst bauen."
|
||||||
|
|
||||||
|
log "rsync dist/ → $SERVER:$REMOTE_PATH/frontend/dist/"
|
||||||
|
rsync -az --delete "$FRONTEND_DIR/dist/" "$SERVER:$REMOTE_PATH/frontend/dist/" \
|
||||||
|
|| die "rsync fehlgeschlagen (SSH-Key/Host-Key prüfen)."
|
||||||
|
|
||||||
|
log "✓ Frontend auf $TARGET aktualisiert"
|
||||||
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# server-update.sh – AUF dem jeweiligen Server ausführen (nicht lokal!)
|
||||||
|
#
|
||||||
|
# Aktualisiert GENAU DIESEN Server eigenständig aus dem Gitea-Repo:
|
||||||
|
# git pull → alembic upgrade head → service restart → health-check
|
||||||
|
#
|
||||||
|
# Jeder Server macht sich selbst – kein Cross-Server-SSH, kein "both".
|
||||||
|
# 137 und 164 sind komplett entkoppelt.
|
||||||
|
#
|
||||||
|
# Frontend: wird NICHT hier gebaut (kein Node auf den Servern, dist ist
|
||||||
|
# gitignored). Frontend liefert der Dev-Rechner separat per push-frontend.sh.
|
||||||
|
#
|
||||||
|
# Usage (auf dem Server):
|
||||||
|
# cd /opt/timemaster && ./server-update.sh
|
||||||
|
# ./server-update.sh --no-migrate # nur pull + restart
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REMOTE="/opt/timemaster"
|
||||||
|
SERVICE="timemaster"
|
||||||
|
HEALTH_URL="http://localhost:8000/health"
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||||
|
log() { echo -e "${GREEN}==>${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
||||||
|
die() { echo -e "${RED}[FEHLER]${NC} $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
DO_MIGRATE=true
|
||||||
|
[[ "${1:-}" == "--no-migrate" ]] && DO_MIGRATE=false
|
||||||
|
|
||||||
|
# ── Sicherstellen, dass wir wirklich auf einem Server sind ────────────────────
|
||||||
|
[[ -d "$REMOTE/backend/venv" ]] || die "venv fehlt ($REMOTE/backend/venv) – falscher Host? Dieses Skript läuft AUF dem Server."
|
||||||
|
cd "$REMOTE"
|
||||||
|
git config --global --add safe.directory "$REMOTE" 2>/dev/null || true
|
||||||
|
|
||||||
|
# ── 1. Repo aktualisieren ─────────────────────────────────────────────────────
|
||||||
|
log "git pull --ff-only origin main"
|
||||||
|
if ! git pull --ff-only origin main; then
|
||||||
|
die "git pull fehlgeschlagen. Arbeitsbaum sauber? ('git status' prüfen, ggf. 'git stash')."
|
||||||
|
fi
|
||||||
|
log "Jetzt auf: $(git log --oneline -1)"
|
||||||
|
|
||||||
|
# ── 2. Migration ──────────────────────────────────────────────────────────────
|
||||||
|
if $DO_MIGRATE; then
|
||||||
|
log "alembic upgrade head"
|
||||||
|
( cd "$REMOTE/backend" && source venv/bin/activate && alembic upgrade head ) \
|
||||||
|
|| die "Migration fehlgeschlagen – Service wird NICHT neugestartet (Schema evtl. inkonsistent)."
|
||||||
|
else
|
||||||
|
warn "Migration übersprungen (--no-migrate)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 3. Service neustarten ─────────────────────────────────────────────────────
|
||||||
|
log "systemctl restart $SERVICE"
|
||||||
|
systemctl restart "$SERVICE"
|
||||||
|
sleep 2
|
||||||
|
state="$(systemctl is-active "$SERVICE" || true)"
|
||||||
|
[[ "$state" == "active" ]] || { journalctl -u "$SERVICE" -n 30 --no-pager; die "Service nicht aktiv ($state)."; }
|
||||||
|
log "Service aktiv"
|
||||||
|
|
||||||
|
# ── 4. Health-Check ───────────────────────────────────────────────────────────
|
||||||
|
if curl -sf --max-time 10 "$HEALTH_URL" >/dev/null; then
|
||||||
|
log "Health OK ($HEALTH_URL)"
|
||||||
|
else
|
||||||
|
warn "Health-Check fehlgeschlagen – Logs prüfen: journalctl -u $SERVICE -n 50"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "✓ Update abgeschlossen auf $(hostname)"
|
||||||
@@ -1,554 +1,16 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# TimeMaster – Deployment & Update Script
|
# STILLGELEGT – nicht mehr verwenden.
|
||||||
# Lokal ausführen – verbindet sich per SSH auf Produktivserver
|
|
||||||
#
|
#
|
||||||
# Usage:
|
# Alte Variante: lokal starten, SSHt in BEIDE Server ("both") und deployt sie
|
||||||
# ./update.sh [OPTIONS]
|
# gekoppelt. Nicht gewünscht – 137 und 164 sollen entkoppelt sein, jeder Server
|
||||||
|
# aktualisiert sich selbst.
|
||||||
#
|
#
|
||||||
# Options:
|
# Neuer, entkoppelter Ablauf:
|
||||||
# --no-tests Tests überspringen
|
# 1. Lokal: git add -A && git commit && git push origin main
|
||||||
# --no-frontend Frontend-Build und -Sync überspringen
|
# 2. Server: ssh root@<host> 'cd /opt/timemaster && ./server-update.sh'
|
||||||
# --server 137 Nur Server 192.168.1.137
|
# (jeder Server einzeln, unabhängig – kein Cross-Server-SSH)
|
||||||
# --server 164 Nur Server 192.168.1.164
|
# 3. Frontend (falls geändert, lokal): ./push-frontend.sh <137|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
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
echo "update.sh ist stillgelegt. Nutze: git push → server-update.sh (auf dem Server) → push-frontend.sh (lokal)." >&2
|
||||||
set -euo pipefail
|
exit 1
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# 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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user