#!/usr/bin/env bash set -euo pipefail DIR="/opt/hx-ki/com2-stack" F="$DIR/docker-compose.yml" ENVF="$DIR/.env" NET="hxki-internal" TS="$(date +%Y%m%d-%H%M%S)" BKDIR="/opt/hx-ki/backups/com2-db-align-$TS" mkdir -p "$BKDIR" echo "=== COM2 DB ALIGN (one-shot) ===" echo "Compose: $F" echo "Env: $ENVF" echo "Backup: $BKDIR" [ -f "$F" ] || { echo "FEHLT: $F"; exit 1; } [ -f "$ENVF" ] || { echo "FEHLT: $ENVF"; exit 1; } cp -a "$F" "$BKDIR/docker-compose.yml" cp -a "$ENVF" "$BKDIR/.env" # Netzwerk muss existieren (external) docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null # --- .env laden (ohne zu crashen wenn Leerzeilen/Kommentare) --- set -a # shellcheck disable=SC1090 source <(grep -v '^\s*#' "$ENVF" | sed '/^\s*$/d') set +a need_real_pw() { local k="$1"; local v="${!k:-}" if [[ -z "$v" || "$v" =~ CHANGE_ME|CHANGEME|changeme ]]; then return 0; fi return 1 } echo echo "[0] Secrets prüfen (keine Platzhalter erlaubt)" if need_real_pw PG_PASSWORD || need_real_pw MARIADB_ROOT_PASSWORD || need_real_pw MAUTIC_DB_PASSWORD; then echo "WARN: In $ENVF sind Platzhalter/fehlende Werte." echo " Ich frage jetzt EINMAL nach echten Passwörtern und schreibe sie nach $ENVF." echo if need_real_pw PG_PASSWORD; then read -r -s -p "PG_PASSWORD (für Postgres User hxki): " PG_PASSWORD; echo fi if need_real_pw MARIADB_ROOT_PASSWORD; then read -r -s -p "MARIADB_ROOT_PASSWORD (neues Root-PW für MariaDB): " MARIADB_ROOT_PASSWORD; echo fi if need_real_pw MAUTIC_DB_PASSWORD; then read -r -s -p "MAUTIC_DB_PASSWORD (für MariaDB User mautic): " MAUTIC_DB_PASSWORD; echo fi # Minimaler .env Patch (nur Keys, die wir brauchen) # Backup ist schon in BKDIR. awk -v pg="$PG_PASSWORD" -v mr="$MARIADB_ROOT_PASSWORD" -v mp="$MAUTIC_DB_PASSWORD" ' BEGIN{done_pg=done_mr=done_mp=0} /^PG_PASSWORD=/{print "PG_PASSWORD="pg; done_pg=1; next} /^MARIADB_ROOT_PASSWORD=/{print "MARIADB_ROOT_PASSWORD="mr; done_mr=1; next} /^MAUTIC_DB_PASSWORD=/{print "MAUTIC_DB_PASSWORD="mp; done_mp=1; next} {print} END{ if(!done_pg) print "PG_PASSWORD="pg if(!done_mr) print "MARIADB_ROOT_PASSWORD="mr if(!done_mp) print "MAUTIC_DB_PASSWORD="mp } ' "$ENVF" > "$ENVF.tmp" && mv "$ENVF.tmp" "$ENVF" echo "OK: $ENVF aktualisiert (Backup: $BKDIR/.env)" fi # Reload .env after potential patch set -a # shellcheck disable=SC1090 source <(grep -v '^\s*#' "$ENVF" | sed '/^\s*$/d') set +a : "${PG_USER:=hxki}" : "${PG_DB:=n8n}" : "${MAUTIC_DB_USER:=mautic}" : "${MAUTIC_DB_NAME:=mautic}" echo echo "[1] Orchester: sicher hoch (damit DB-Container laufen)" cd "$DIR" docker compose up -d --remove-orphans echo echo "[2] POSTGRES align (User+DB+PW) – Volume bleibt" # Wir gehen als postgres-OS-User rein (nicht als DB-User), damit kein Passwort-Raten nötig ist. docker exec -u postgres -i hxki-postgres psql -d postgres </dev/null 2>&1 || true # MariaDB stoppen (damit Volume frei ist) docker stop hxki-mariadb >/dev/null 2>&1 || true # Recovery-Container starten (ohne Grants, ohne Network) docker rm -f hxki-mariadb-recover >/dev/null 2>&1 || true docker run -d --name hxki-mariadb-recover $VOLARG --entrypoint mysqld "$IMG" \ --skip-grant-tables --skip-networking --socket=/tmp/mysqld.sock >/dev/null # Warten bis Socket da ist for i in {1..40}; do if docker exec hxki-mariadb-recover sh -lc 'test -S /tmp/mysqld.sock'; then break; fi sleep 0.25 done docker exec hxki-mariadb-recover sh -lc 'test -S /tmp/mysqld.sock' || { echo "FAIL: MariaDB recover socket nicht bereit"; docker logs --tail=80 hxki-mariadb-recover; exit 1; } # Root-PW setzen + Mautic DB/User fixen docker exec -i hxki-mariadb-recover sh -lc "mariadb --protocol=socket -uroot -S /tmp/mysqld.sock" </dev/null # MariaDB wieder hoch über Compose (mit NEUEM Root-PW in .env) cd "$DIR" docker compose up -d --remove-orphans hxki-mariadb # kurz warten sleep 2 # Mautic wieder hoch docker compose up -d --remove-orphans hxki-mautic echo "OK: MariaDB Root-PW + Mautic DB/User aligned." echo echo "[4] Services neu hoch (n8n/web/caddy) und harte Checks" docker compose up -d --remove-orphans echo echo "[A] Container Status" docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true echo echo "[B] Netzwerk-Mitglieder ($NET)" docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort echo echo "[C] Caddy -> Upstreams (intern, 10s Retry)" check_up() { local name="$1" url="$2" for i in {1..20}; do if docker exec hx-caddy sh -lc "wget -qO- '$url' >/dev/null 2>&1"; then echo "OK_CADDY_TO_${name}" return 0 fi sleep 0.5 done echo "FAIL_CADDY_TO_${name}" return 1 } FAIL=0 check_up WEB "http://hxki-web:3000/" || FAIL=1 check_up N8N "http://hxki-n8n:5678/" || FAIL=1 check_up MAUTIC "http://hxki-mautic:80/" || FAIL=1 echo echo "[D] Logs (kurz)" echo "--- n8n ---" docker logs --tail=40 hxki-n8n || true echo "--- mautic ---" docker logs --tail=40 hxki-mautic || true echo "--- web ---" docker logs --tail=40 hxki-web || true echo "--- caddy ---" docker logs --tail=40 hx-caddy || true echo if [[ "$FAIL" -eq 0 ]]; then echo "=== OK: COM2 ist wieder stabil (DBs aligned, Upstreams erreichbar) ===" else echo "=== WARN: DBs aligned, aber mind. ein Upstream ist noch nicht erreichbar (siehe FAIL_*) ===" echo "Backup liegt hier: $BKDIR" fi