Files
hx-ki.com2/COM2_FERRARI_REPAIR_ONE_SHOT.sh
2026-03-06 15:22:40 +00:00

259 lines
9.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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"