259 lines
9.3 KiB
Bash
Executable File
259 lines
9.3 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)"
|
||
BK="/opt/hx-ki/backups/com2-ferrari-$TS"
|
||
|
||
mkdir -p "$BK"
|
||
echo "=== COM2 · FERRARI REPAIR ONE-SHOT (no guessing) ==="
|
||
echo "Compose: $F"
|
||
echo "Env: $ENVF"
|
||
echo "Backup: $BK"
|
||
echo
|
||
|
||
[ -f "$F" ] || { echo "FAIL: FEHLT $F"; exit 1; }
|
||
cp -a "$F" "$BK/docker-compose.yml.pre" || true
|
||
[ -f "$ENVF" ] && cp -a "$ENVF" "$BK/.env.pre" || true
|
||
|
||
# --- helpers ---------------------------------------------------------------
|
||
die(){ echo "FAIL: $*" ; exit 1; }
|
||
|
||
# find candidates from many places, newest first
|
||
collect_kv_candidates() {
|
||
local key="$1"
|
||
# search in .env files + compose backups + docker-compose.yml* (only small grep)
|
||
find /opt/hx-ki -maxdepth 6 -type f \
|
||
\( -iname ".env" -o -iname "*.env" -o -iname "docker-compose*.yml" -o -iname "docker-compose*.yml.*" -o -iname "*.yml.bak*" \) \
|
||
-printf "%T@ %p\n" 2>/dev/null | sort -nr | awk '{ $1=""; sub(/^ /,""); print }' |
|
||
while read -r p; do
|
||
[ -f "$p" ] || continue
|
||
# exact KEY=VALUE lines only
|
||
awk -v k="$key" -F= '
|
||
$1==k {
|
||
v=$0; sub(/^[^=]+= /,"",v); sub(/^[^=]+=/,"",v);
|
||
gsub(/\r/,"",v);
|
||
if (v!="" && v !~ /CHANGE_ME|CHANGEME|changeme/) { print v }
|
||
}' "$p" 2>/dev/null | head -n 5
|
||
done | awk 'NF' | awk '!seen[$0]++' | head -n 30
|
||
}
|
||
|
||
ensure_net() {
|
||
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||
}
|
||
|
||
stop_host_caddy() {
|
||
if systemctl is-active --quiet caddy 2>/dev/null; then
|
||
echo "[0] Stoppe host-caddy (systemd) – Ports 80/443 frei"
|
||
systemctl stop caddy
|
||
fi
|
||
}
|
||
|
||
compose_down() {
|
||
cd "$DIR"
|
||
docker compose down --remove-orphans || true
|
||
}
|
||
|
||
compose_up() {
|
||
cd "$DIR"
|
||
docker compose up -d --remove-orphans
|
||
}
|
||
|
||
# Test Postgres password by real connection
|
||
pg_try_pw() {
|
||
local user="$1" pw="$2"
|
||
docker exec -e PGPASSWORD="$pw" hxki-postgres sh -lc "psql -U '$user' -d postgres -tAc 'select 1' >/dev/null 2>&1"
|
||
}
|
||
|
||
# Ensure DB exists (create if missing) using admin user
|
||
pg_ensure_db() {
|
||
local admin_user="$1" admin_pw="$2" db="$3"
|
||
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||
"psql -U '$admin_user' -d postgres -tAc \"select 1 from pg_database where datname='${db}'\" | grep -q 1 || psql -U '$admin_user' -d postgres -c \"create database \\\"${db}\\\"\" >/dev/null"
|
||
}
|
||
|
||
# Ensure role exists + password (only if missing)
|
||
pg_ensure_role() {
|
||
local admin_user="$1" admin_pw="$2" role="$3" role_pw="$4"
|
||
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||
"psql -U '$admin_user' -d postgres -tAc \"select 1 from pg_roles where rolname='${role}'\" | grep -q 1 || psql -U '$admin_user' -d postgres -c \"create role \\\"${role}\\\" login password '${role_pw}'\" >/dev/null"
|
||
}
|
||
|
||
# grant owner if needed
|
||
pg_set_owner() {
|
||
local admin_user="$1" admin_pw="$2" db="$3" owner="$4"
|
||
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||
"psql -U '$admin_user' -d postgres -c \"alter database \\\"${db}\\\" owner to \\\"${owner}\\\"\" >/dev/null 2>&1 || true"
|
||
}
|
||
|
||
# MariaDB root auth test (real)
|
||
my_root_try_pw() {
|
||
local pw="$1"
|
||
docker exec hxki-mariadb sh -lc "mysqladmin ping -uroot -p'$pw' --silent >/dev/null 2>&1"
|
||
}
|
||
|
||
# MariaDB user auth test
|
||
my_user_try_pw() {
|
||
local user="$1" pw="$2" db="$3"
|
||
docker exec hxki-mariadb sh -lc "mysql -u'$user' -p'$pw' -D'$db' -e 'select 1' >/dev/null 2>&1"
|
||
}
|
||
|
||
# Ensure mautic db/user exists (create only if missing; uses root)
|
||
my_ensure_mautic() {
|
||
local rootpw="$1" db="$2" user="$3" userpw="$4"
|
||
docker exec hxki-mariadb sh -lc "
|
||
mysql -uroot -p'$rootpw' -e \"CREATE DATABASE IF NOT EXISTS \\\`$db\\\`;\" >/dev/null &&
|
||
mysql -uroot -p'$rootpw' -e \"CREATE USER IF NOT EXISTS '$user'@'%' IDENTIFIED BY '$userpw';\" >/dev/null &&
|
||
mysql -uroot -p'$rootpw' -e \"GRANT ALL PRIVILEGES ON \\\`$db\\\`.* TO '$user'@'%'; FLUSH PRIVILEGES;\" >/dev/null
|
||
"
|
||
}
|
||
|
||
# --- start ---------------------------------------------------------------
|
||
[ -d "$DIR" ] || die "FEHLT: $DIR"
|
||
stop_host_caddy
|
||
ensure_net
|
||
|
||
echo "[1] Orchester runter (sauber)"
|
||
compose_down
|
||
|
||
echo "[2] Starte NUR DBs (damit wir Credentials echt testen können)"
|
||
cd "$DIR"
|
||
docker compose up -d hxki-postgres hxki-mariadb || die "DB-Start fehlgeschlagen"
|
||
|
||
# --- discover postgres admin user (from container env) ----------------------
|
||
PG_ADMIN_USER="$(docker inspect hxki-postgres --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '$1=="POSTGRES_USER"{print $2}' | tail -n 1)"
|
||
[ -n "$PG_ADMIN_USER" ] || die "POSTGRES_USER nicht gefunden in hxki-postgres Env"
|
||
|
||
# Candidate passwords from old state
|
||
echo "[3] Suche Postgres-Passwort (no guessing: scan + real login test)"
|
||
mapfile -t PG_PWS < <(collect_kv_candidates "POSTGRES_PASSWORD")
|
||
# also accept PG_PASSWORD style keys
|
||
mapfile -t PG_PWS2 < <(collect_kv_candidates "PG_PASSWORD")
|
||
PG_PWS+=( "${PG_PWS2[@]}" )
|
||
# de-dupe
|
||
PG_PWS=( $(printf "%s\n" "${PG_PWS[@]}" | awk 'NF' | awk '!seen[$0]++') )
|
||
|
||
PG_ADMIN_PW=""
|
||
for pw in "${PG_PWS[@]}"; do
|
||
if pg_try_pw "$PG_ADMIN_USER" "$pw"; then
|
||
PG_ADMIN_PW="$pw"; break
|
||
fi
|
||
done
|
||
[ -n "$PG_ADMIN_PW" ] || die "Kein funktionierendes Postgres-Passwort gefunden (scan+test)."
|
||
|
||
echo " OK: Postgres auth funktioniert für user=$PG_ADMIN_USER"
|
||
|
||
# --- discover mariadb root pw ---------------------------------------------
|
||
echo "[4] Suche MariaDB root Passwort (scan + real ping test)"
|
||
mapfile -t MYROOT_PWS < <(collect_kv_candidates "MARIADB_ROOT_PASSWORD")
|
||
mapfile -t MYROOT_PWS2 < <(collect_kv_candidates "MYSQL_ROOT_PASSWORD")
|
||
MYROOT_PWS+=( "${MYROOT_PWS2[@]}" )
|
||
MYROOT_PWS=( $(printf "%s\n" "${MYROOT_PWS[@]}" | awk 'NF' | awk '!seen[$0]++') )
|
||
|
||
MY_ROOT_PW=""
|
||
for pw in "${MYROOT_PWS[@]}"; do
|
||
if my_root_try_pw "$pw"; then
|
||
MY_ROOT_PW="$pw"; break
|
||
fi
|
||
done
|
||
[ -n "$MY_ROOT_PW" ] || die "Kein funktionierendes MariaDB root Passwort gefunden (scan+test)."
|
||
|
||
echo " OK: MariaDB root auth funktioniert"
|
||
|
||
# --- read target vars from compose/env (but align with OLD secrets) ---------
|
||
# Extract current target DB names from compose env placeholders (.env)
|
||
# If not present, fall back to container env default
|
||
PG_DB="${PG_DB:-}"
|
||
PG_USER="${PG_USER:-}"
|
||
if [ -f "$ENVF" ]; then
|
||
# shellcheck disable=SC1090
|
||
set -a; source "$ENVF" 2>/dev/null || true; set +a
|
||
fi
|
||
|
||
# Ensure defaults if env missing
|
||
: "${PG_USER:=$PG_ADMIN_USER}"
|
||
: "${PG_DB:=n8n}"
|
||
|
||
# Mautic target vars
|
||
: "${MAUTIC_DB_NAME:=mautic}"
|
||
: "${MAUTIC_DB_USER:=mautic}"
|
||
# try recover MAUTIC_DB_PASSWORD from old state too
|
||
mapfile -t MAUTIC_PWS < <(collect_kv_candidates "MAUTIC_DB_PASSWORD")
|
||
MAUTIC_DB_PASSWORD="${MAUTIC_DB_PASSWORD:-${MAUTIC_PWS[0]:-}}"
|
||
|
||
# If not found, we do NOT invent: we only proceed if we can validate, else stop.
|
||
if [ -z "${MAUTIC_DB_PASSWORD:-}" ]; then
|
||
die "MAUTIC_DB_PASSWORD nicht gefunden im alten Zustand. (Bitte in alten .env/Backups vorhanden machen.)"
|
||
fi
|
||
|
||
echo "[5] Schreibe kanonische .env (nur funktionierende Secrets, kein CHANGE_ME)"
|
||
cp -a "$ENVF" "$BK/.env.prewrite" 2>/dev/null || true
|
||
|
||
cat > "$ENVF" <<ENV
|
||
# === CANONICAL (recovered + validated) ===
|
||
# Postgres (n8n)
|
||
PG_USER=${PG_USER}
|
||
PG_PASSWORD=${PG_ADMIN_PW}
|
||
PG_DB=${PG_DB}
|
||
|
||
# Mautic (MariaDB)
|
||
MAUTIC_DB_NAME=${MAUTIC_DB_NAME}
|
||
MAUTIC_DB_USER=${MAUTIC_DB_USER}
|
||
MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD}
|
||
MAUTIC_DB_ROOT_PASSWORD=${MY_ROOT_PW}
|
||
|
||
# n8n public vars (leave if you already had them in compose via defaults)
|
||
N8N_HOST=${N8N_HOST:-localhost}
|
||
N8N_PROTOCOL=${N8N_PROTOCOL:-http}
|
||
ENV
|
||
|
||
echo "[6] Postgres: stelle sicher, dass DB für n8n existiert (create only if missing)"
|
||
pg_ensure_db "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_DB"
|
||
pg_ensure_role "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_USER" "$PG_ADMIN_PW" || true
|
||
pg_set_owner "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_DB" "$PG_USER" || true
|
||
echo " OK: Postgres DB/Role geprüft"
|
||
|
||
echo "[7] MariaDB: stelle sicher, dass mautic DB/User passt (create/grant only if needed)"
|
||
# if mautic user auth already works, we don't touch grants
|
||
if my_user_try_pw "$MAUTIC_DB_USER" "$MAUTIC_DB_PASSWORD" "$MAUTIC_DB_NAME"; then
|
||
echo " OK: mautic user auth OK – keine Änderungen an MariaDB nötig"
|
||
else
|
||
echo " INFO: mautic user auth FAIL – setze DB/User/Grants deterministisch via root"
|
||
my_ensure_mautic "$MY_ROOT_PW" "$MAUTIC_DB_NAME" "$MAUTIC_DB_USER" "$MAUTIC_DB_PASSWORD" || die "MariaDB repair failed"
|
||
echo " OK: MariaDB DB/User/Grants gesetzt"
|
||
fi
|
||
|
||
echo "[8] Validate Compose"
|
||
cd "$DIR"
|
||
docker compose config >/dev/null || die "Compose ist nicht valide."
|
||
|
||
echo "[9] Orchester hoch"
|
||
docker compose up -d --remove-orphans
|
||
|
||
echo
|
||
echo "=== HARD CHECKS (facts) ==="
|
||
echo "[A] Container Status"
|
||
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-' || true
|
||
|
||
echo
|
||
echo "[B] Logs (tail 30)"
|
||
echo "--- hxki-n8n ---"
|
||
docker logs --tail=30 hxki-n8n || true
|
||
echo "--- hxki-mautic ---"
|
||
docker logs --tail=30 hxki-mautic || true
|
||
echo "--- hxki-web ---"
|
||
docker logs --tail=30 hxki-web || true
|
||
|
||
echo
|
||
echo "[C] Caddy -> Upstreams (internal reachability)"
|
||
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N' || true
|
||
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC' || true
|
||
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-web/ >/dev/null && echo OK_CADDY_TO_WEB || echo FAIL_CADDY_TO_WEB' || true
|
||
|
||
echo
|
||
echo "=== DONE ==="
|
||
echo "Backup: $BK"
|