initial COM2 system snapshot
This commit is contained in:
258
COM2_FERRARI_REPAIR_ONE_SHOT.sh
Executable file
258
COM2_FERRARI_REPAIR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/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"
|
||||
Reference in New Issue
Block a user