160 lines
5.4 KiB
Bash
Executable File
160 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
DIR="/opt/hx-ki/com2-stack"
|
|
COMPOSE="$DIR/docker-compose.yml"
|
|
ENVF="$DIR/.env"
|
|
|
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
|
[ -f "$ENVF" ] || { echo "FAIL: missing $ENVF"; exit 1; }
|
|
|
|
cd "$DIR"
|
|
|
|
echo "=== COM2 · MAUTIC INSTALL (ONE-SHOT, NO REBUILD, NO GUESSING) ==="
|
|
|
|
# Load .env as authority (only simple KEY=VALUE lines)
|
|
set -a
|
|
. "$ENVF"
|
|
set +a
|
|
|
|
# Resolve service names from compose (authority: compose)
|
|
MAUTIC_SVC="$(python3 - <<'PY'
|
|
import re, pathlib
|
|
p=pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
|
s=p.read_text()
|
|
m=re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
|
if not m: raise SystemExit("FAIL: no services: block")
|
|
blk=m.group(1)
|
|
# find service with container_name: hxki-mautic
|
|
cur=None
|
|
for line in blk.splitlines():
|
|
mm=re.match(r'^\s{2}([A-Za-z0-9_.-]+):\s*$', line)
|
|
if mm: cur=mm.group(1); continue
|
|
if cur and re.match(r'^\s{4}container_name:\s*hxki-mautic\s*$', line):
|
|
print(cur); raise SystemExit(0)
|
|
raise SystemExit("FAIL: could not find service for container_name: hxki-mautic")
|
|
PY
|
|
)"
|
|
DB_SVC="$(python3 - <<'PY'
|
|
import re, pathlib
|
|
p=pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
|
s=p.read_text()
|
|
m=re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
|
if not m: raise SystemExit("FAIL: no services: block")
|
|
blk=m.group(1)
|
|
# find service with container_name: hxki-mariadb
|
|
cur=None
|
|
for line in blk.splitlines():
|
|
mm=re.match(r'^\s{2}([A-Za-z0-9_.-]+):\s*$', line)
|
|
if mm: cur=mm.group(1); continue
|
|
if cur and re.match(r'^\s{4}container_name:\s*hxki-mariadb\s*$', line):
|
|
print(cur); raise SystemExit(0)
|
|
raise SystemExit("FAIL: could not find service for container_name: hxki-mariadb")
|
|
PY
|
|
)"
|
|
|
|
MA="hxki-mautic"
|
|
MY="hxki-mariadb"
|
|
CA="hx-caddy"
|
|
|
|
echo "[1] Bring up DB + Mautic (no orphans change)"
|
|
docker compose up -d "$DB_SVC" "$MAUTIC_SVC" >/dev/null
|
|
|
|
echo "[2] Hard requirements from .env (NO guessing)"
|
|
req() { local k="$1"; [ -n "${!k:-}" ] || { echo "FAIL: missing $k in $ENVF"; exit 1; }; }
|
|
|
|
req MAUTIC_DB_HOST
|
|
req MAUTIC_DB_NAME
|
|
req MAUTIC_DB_USER
|
|
req MAUTIC_DB_PASSWORD
|
|
req MAUTIC_ADMIN_USERNAME
|
|
req MAUTIC_ADMIN_PASSWORD
|
|
req MAUTIC_ADMIN_EMAIL
|
|
|
|
echo " DB_HOST=$MAUTIC_DB_HOST DB_NAME=$MAUTIC_DB_NAME DB_USER=$MAUTIC_DB_USER DB_PASS=***"
|
|
echo " ADMIN_USER=$MAUTIC_ADMIN_USERNAME ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL ADMIN_PASS=***"
|
|
|
|
echo "[3] Read MariaDB root password (NO guessing: container env)"
|
|
ROOTPW="$(docker inspect "$MY" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
|
| awk -F= '/^(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=/{print $2}' | tail -n1 || true)"
|
|
[ -n "${ROOTPW:-}" ] || { echo "FAIL: MariaDB root password not found in container env"; exit 1; }
|
|
|
|
echo "[4] Wait MariaDB ready (max 60s) + ensure DB exists (no data loss)"
|
|
for i in {1..60}; do
|
|
if docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" -e 'SELECT 1' >/dev/null 2>&1"; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
[ "$i" -eq 60 ] && { echo "FAIL: MariaDB not ready"; docker logs --tail=120 "$MY" || true; exit 1; }
|
|
done
|
|
|
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
|
CREATE DATABASE IF NOT EXISTS \\\`$MAUTIC_DB_NAME\\\`;
|
|
SQL" >/dev/null
|
|
|
|
# If Mautic uses non-root user, ensure it can log in + has grants (still no data loss)
|
|
if [ "$MAUTIC_DB_USER" != "root" ]; then
|
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
|
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" >/dev/null
|
|
fi
|
|
|
|
echo "[5] If already installed -> stop here (local.php present)"
|
|
if docker exec -i "$MA" sh -lc "test -f app/config/local.php"; then
|
|
echo "OK: already installed (app/config/local.php exists)"
|
|
else
|
|
echo "[6] Run Mautic installer inside container (deterministic CLI)"
|
|
# detect console path
|
|
CONSOLE=""
|
|
if docker exec -i "$MA" sh -lc "test -x bin/console"; then
|
|
CONSOLE="bin/console"
|
|
elif docker exec -i "$MA" sh -lc "test -x app/console"; then
|
|
CONSOLE="app/console"
|
|
else
|
|
echo "FAIL: cannot find bin/console or app/console inside $MA"
|
|
docker exec -i "$MA" sh -lc "ls -la" || true
|
|
exit 1
|
|
fi
|
|
|
|
# Run installer (no interaction)
|
|
docker exec -i "$MA" sh -lc "
|
|
php $CONSOLE mautic:install \
|
|
--db_driver=pdo_mysql \
|
|
--db_host=\"$MAUTIC_DB_HOST\" \
|
|
--db_port=3306 \
|
|
--db_name=\"$MAUTIC_DB_NAME\" \
|
|
--db_user=\"$MAUTIC_DB_USER\" \
|
|
--db_password=\"$MAUTIC_DB_PASSWORD\" \
|
|
--admin_firstname=HXKI \
|
|
--admin_lastname=Admin \
|
|
--admin_username=\"$MAUTIC_ADMIN_USERNAME\" \
|
|
--admin_password=\"$MAUTIC_ADMIN_PASSWORD\" \
|
|
--admin_email=\"$MAUTIC_ADMIN_EMAIL\" \
|
|
--no-interaction
|
|
" || { echo "FAIL: mautic:install failed"; docker logs --tail=200 "$MA" || true; exit 1; }
|
|
|
|
echo "[7] Verify local.php created"
|
|
docker exec -i "$MA" sh -lc "test -f app/config/local.php" || { echo "FAIL: install did not create app/config/local.php"; exit 1; }
|
|
echo "OK: installed (local.php present)"
|
|
fi
|
|
|
|
echo "[8] Restart Mautic (clean) and verify Caddy can reach it"
|
|
docker compose up -d --force-recreate "$MAUTIC_SVC" >/dev/null
|
|
|
|
# wait for http from caddy
|
|
for i in {1..60}; do
|
|
if docker exec -i "$CA" sh -lc "wget -qO- http://$MA/ >/dev/null"; then
|
|
echo "OK_CADDY_TO_MAUTIC"
|
|
echo "=== DONE ==="
|
|
exit 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
echo "FAIL: Caddy still cannot reach Mautic after install"
|
|
docker logs --tail=200 "$MA" || true
|
|
exit 1
|