219 lines
7.0 KiB
Bash
Executable File
219 lines
7.0 KiB
Bash
Executable File
#!/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 <<SQL
|
||
DO \$\$
|
||
BEGIN
|
||
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${PG_USER}') THEN
|
||
CREATE ROLE ${PG_USER} LOGIN;
|
||
END IF;
|
||
ALTER ROLE ${PG_USER} WITH PASSWORD '${PG_PASSWORD}';
|
||
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = '${PG_DB}') THEN
|
||
CREATE DATABASE ${PG_DB} OWNER ${PG_USER};
|
||
END IF;
|
||
END
|
||
\$\$;
|
||
SQL
|
||
echo "OK: Postgres User/DB/PW aligned: ${PG_USER}/${PG_DB}"
|
||
|
||
echo
|
||
echo "[3] MARIADB Root-Reset (Recovery-Container) + Mautic User/DB fix – Volume bleibt"
|
||
# Volume/Bind für /var/lib/mysql ermitteln
|
||
MOUNT_SRC="$(docker inspect hxki-mariadb --format '{{range .Mounts}}{{if eq .Destination "/var/lib/mysql"}}{{.Source}}{{end}}{{end}}')"
|
||
MOUNT_NAME="$(docker inspect hxki-mariadb --format '{{range .Mounts}}{{if eq .Destination "/var/lib/mysql"}}{{.Name}}{{end}}{{end}}')"
|
||
IMG="$(docker inspect hxki-mariadb --format '{{.Config.Image}}')"
|
||
|
||
if [[ -n "$MOUNT_NAME" ]]; then
|
||
VOLARG="-v ${MOUNT_NAME}:/var/lib/mysql"
|
||
elif [[ -n "$MOUNT_SRC" ]]; then
|
||
VOLARG="-v ${MOUNT_SRC}:/var/lib/mysql"
|
||
else
|
||
echo "FAIL: Konnte MariaDB /var/lib/mysql Mount nicht ermitteln."
|
||
exit 1
|
||
fi
|
||
|
||
# Mautic stoppen damit es nicht dauernd hämmert
|
||
docker stop hxki-mautic >/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" <<SQL
|
||
FLUSH PRIVILEGES;
|
||
ALTER USER IF EXISTS 'root'@'localhost' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||
ALTER USER IF EXISTS 'root'@'%' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||
|
||
CREATE DATABASE IF NOT EXISTS ${MAUTIC_DB_NAME};
|
||
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||
ALTER USER '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||
GRANT ALL PRIVILEGES ON ${MAUTIC_DB_NAME}.* TO '${MAUTIC_DB_USER}'@'%';
|
||
FLUSH PRIVILEGES;
|
||
SQL
|
||
|
||
# Recovery runter
|
||
docker rm -f hxki-mariadb-recover >/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
|