changes to the processing
This commit is contained in:
+235
-127
@@ -9,171 +9,276 @@ SECRETS_FILE="$SCRIPT_DIR/.mongo-secrets.env"
|
||||
RESET_MONGO_DATA=0
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--reset-mongo-data|-r)
|
||||
RESET_MONGO_DATA=1
|
||||
;;
|
||||
esac
|
||||
case "$arg" in
|
||||
--reset-mongo-data|-r)
|
||||
RESET_MONGO_DATA=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
ensure_mongo_secrets() {
|
||||
if [ -f "$SECRETS_FILE" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$SECRETS_FILE"
|
||||
fi
|
||||
if [ -f "$SECRETS_FILE" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "$SECRETS_FILE"
|
||||
fi
|
||||
|
||||
if [ -z "${MONGO_INITDB_ROOT_PASSWORD:-}" ]; then
|
||||
MONGO_INITDB_ROOT_PASSWORD="$(openssl rand -hex 24)"
|
||||
fi
|
||||
if [ -z "${MONGO_APP_PASSWORD:-}" ]; then
|
||||
MONGO_APP_PASSWORD="$(openssl rand -hex 24)"
|
||||
fi
|
||||
if [ -z "${MONGO_INITDB_ROOT_PASSWORD:-}" ]; then
|
||||
MONGO_INITDB_ROOT_PASSWORD="$(openssl rand -hex 24)"
|
||||
fi
|
||||
if [ -z "${MONGO_APP_PASSWORD:-}" ]; then
|
||||
MONGO_APP_PASSWORD="$(openssl rand -hex 24)"
|
||||
fi
|
||||
|
||||
cat > "$SECRETS_FILE" <<EOF
|
||||
cat > "$SECRETS_FILE" <<EOF
|
||||
MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME:-website_root}
|
||||
MONGO_INITDB_ROOT_PASSWORD=$MONGO_INITDB_ROOT_PASSWORD
|
||||
MONGO_APP_USER=${MONGO_APP_USER:-website_app}
|
||||
MONGO_APP_PASSWORD=$MONGO_APP_PASSWORD
|
||||
EOF
|
||||
chmod 600 "$SECRETS_FILE"
|
||||
# shellcheck disable=SC1090
|
||||
source "$SECRETS_FILE"
|
||||
export MONGO_INITDB_ROOT_USERNAME MONGO_INITDB_ROOT_PASSWORD MONGO_APP_USER MONGO_APP_PASSWORD
|
||||
chmod 600 "$SECRETS_FILE"
|
||||
# shellcheck disable=SC1090
|
||||
source "$SECRETS_FILE"
|
||||
export MONGO_INITDB_ROOT_USERNAME MONGO_INITDB_ROOT_PASSWORD MONGO_APP_USER MONGO_APP_PASSWORD
|
||||
}
|
||||
|
||||
ensure_mongo_app_user() {
|
||||
if "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" exec -T mongodb mongosh --quiet \
|
||||
--username "$MONGO_INITDB_ROOT_USERNAME" \
|
||||
--password "$MONGO_INITDB_ROOT_PASSWORD" \
|
||||
--authenticationDatabase admin \
|
||||
--eval '
|
||||
if "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" exec -T mongodb mongosh --quiet \
|
||||
--username "$MONGO_INITDB_ROOT_USERNAME" \
|
||||
--password "$MONGO_INITDB_ROOT_PASSWORD" \
|
||||
--authenticationDatabase admin \
|
||||
--eval '
|
||||
const appDatabase = process.env.MONGO_DB_NAME || "Invario_Website";
|
||||
const appUser = process.env.MONGO_APP_USER || "website_app";
|
||||
const appPassword = process.env.MONGO_APP_PASSWORD;
|
||||
|
||||
if (!appPassword) {
|
||||
throw new Error("Missing MONGO_APP_PASSWORD");
|
||||
throw new Error("Missing MONGO_APP_PASSWORD");
|
||||
}
|
||||
|
||||
const appDb = db.getSiblingDB(appDatabase);
|
||||
if (!appDb.getUser(appUser)) {
|
||||
appDb.createUser({
|
||||
user: appUser,
|
||||
pwd: appPassword,
|
||||
roles: [{ role: "readWrite", db: appDatabase }],
|
||||
});
|
||||
print("created app user");
|
||||
appDb.createUser({
|
||||
user: appUser,
|
||||
pwd: appPassword,
|
||||
roles: [{ role: "readWrite", db: appDatabase }],
|
||||
});
|
||||
print("created app user");
|
||||
} else {
|
||||
appDb.updateUser(appUser, {
|
||||
pwd: appPassword,
|
||||
roles: [{ role: "readWrite", db: appDatabase }],
|
||||
});
|
||||
print("updated app user");
|
||||
appDb.updateUser(appUser, {
|
||||
pwd: appPassword,
|
||||
roles: [{ role: "readWrite", db: appDatabase }],
|
||||
});
|
||||
print("updated app user");
|
||||
}
|
||||
'
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[WARNUNG] App-User konnte nicht synchronisiert werden; der bestehende Mongo-Volume-Stand verwendet wahrscheinlich andere Root-Credentials. Falls das ein frischer Dev-Stand ist, starte mit MONGO_RESET_DATA=1 neu." >&2
|
||||
return 0
|
||||
echo "[WARNUNG] App-User konnte nicht synchronisiert werden; der bestehende Mongo-Volume-Stand verwendet wahrscheinlich andere Root-Credentials. Falls das ein frischer Dev-Stand ist, starte mit MONGO_RESET_DATA=1 neu." >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
wait_for_mongo_ready() {
|
||||
local timeout_seconds=180
|
||||
local interval=2
|
||||
local elapsed=0
|
||||
local mongo_container_id=""
|
||||
local container_state=""
|
||||
local health_status=""
|
||||
local timeout_seconds=180
|
||||
local interval=2
|
||||
local elapsed=0
|
||||
local mongo_container_id=""
|
||||
local container_state=""
|
||||
local health_status=""
|
||||
|
||||
mongo_container_id="$("${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps -q mongodb 2>/dev/null || true)"
|
||||
if [ -z "$mongo_container_id" ]; then
|
||||
echo "[FEHLER] MongoDB-Container wurde nicht gefunden." >&2
|
||||
return 1
|
||||
fi
|
||||
mongo_container_id="$("${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps -q mongodb 2>/dev/null || true)"
|
||||
if [ -z "$mongo_container_id" ]; then
|
||||
echo "[FEHLER] MongoDB-Container wurde nicht gefunden." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
while [ $elapsed -lt $timeout_seconds ]; do
|
||||
container_state="$(${DOCKER_CMD[@]} inspect -f '{{.State.Status}} {{if .State.Health}}{{.State.Health.Status}}{{end}}' "$mongo_container_id" 2>/dev/null || true)"
|
||||
health_status="${container_state#* }"
|
||||
if [ "$health_status" = "healthy" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "${container_state%% *}" = "running" ] && [ -z "$health_status" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "${container_state%% *}" = "exited" ] || [ "${container_state%% *}" = "dead" ]; then
|
||||
break
|
||||
fi
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
done
|
||||
while [ $elapsed -lt $timeout_seconds ]; do
|
||||
container_state="$(${DOCKER_CMD[@]} inspect -f '{{.State.Status}} {{if .State.Health}}{{.State.Health.Status}}{{end}}' "$mongo_container_id" 2>/dev/null || true)"
|
||||
health_status="${container_state#* }"
|
||||
if [ "$health_status" = "healthy" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "${container_state%% *}" = "running" ] && [ -z "$health_status" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "${container_state%% *}" = "exited" ] || [ "${container_state%% *}" = "dead" ]; then
|
||||
break
|
||||
fi
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
done
|
||||
|
||||
echo "[FEHLER] MongoDB wurde nicht rechtzeitig gestartet. Status: ${container_state:-unbekannt}" >&2
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps mongodb >&2 || true
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" logs --tail 80 mongodb >&2 || true
|
||||
return 1
|
||||
echo "[FEHLER] MongoDB wurde nicht rechtzeitig gestartet. Status: ${container_state:-unbekannt}" >&2
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps mongodb >&2 || true
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" logs --tail 80 mongodb >&2 || true
|
||||
return 1
|
||||
}
|
||||
|
||||
resolve_docker_cmd() {
|
||||
if docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(docker)
|
||||
return 0
|
||||
fi
|
||||
if docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(docker)
|
||||
return 0
|
||||
fi
|
||||
|
||||
if sudo -n docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(sudo docker)
|
||||
return 0
|
||||
fi
|
||||
if sudo -n docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(sudo docker)
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v sudo >/dev/null 2>&1 && [ -t 0 ]; then
|
||||
echo "Docker-Zugriff ohne Gruppe erkannt. Verwende sudo docker (ggf. Passwortabfrage)."
|
||||
if sudo docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(sudo docker)
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
if command -v sudo >/dev/null 2>&1 && [ -t 0 ]; then
|
||||
echo "Docker-Zugriff ohne Gruppe erkannt. Verwende sudo docker (ggf. Passwortabfrage)."
|
||||
if sudo docker info >/dev/null 2>&1; then
|
||||
DOCKER_CMD=(sudo docker)
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[FEHLER] Kein Zugriff auf den Docker Daemon (/var/run/docker.sock)." >&2
|
||||
echo "Führe das Script mit sudo aus oder füge deinen User zur docker-Gruppe hinzu:" >&2
|
||||
echo " sudo usermod -aG docker $USER" >&2
|
||||
echo "Danach neu einloggen und Script erneut starten." >&2
|
||||
exit 3
|
||||
echo "[FEHLER] Kein Zugriff auf den Docker Daemon (/var/run/docker.sock)." >&2
|
||||
echo "Führe das Script mit sudo aus oder füge deinen User zur docker-Gruppe hinzu:" >&2
|
||||
echo " sudo usermod -aG docker $USER" >&2
|
||||
echo "Danach neu einloggen und Script erneut starten." >&2
|
||||
exit 3
|
||||
}
|
||||
|
||||
compose() {
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" "$@"
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" "$@"
|
||||
}
|
||||
|
||||
is_truthy() {
|
||||
case "${1:-}" in
|
||||
1|true|TRUE|yes|YES|on|ON)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
case "${1:-}" in
|
||||
1|true|TRUE|yes|YES|on|ON)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
reset_mongo_data_if_requested() {
|
||||
if ! is_truthy "${MONGO_RESET_DATA:-0}" && [ "$RESET_MONGO_DATA" -ne 1 ]; then
|
||||
return 0
|
||||
fi
|
||||
if ! is_truthy "${MONGO_RESET_DATA:-0}" && [ "$RESET_MONGO_DATA" -ne 1 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[WARNUNG] Setze den MongoDB-Volume-Stand zurück, damit die aktuellen Secrets neu initialisiert werden." >&2
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" down -v --remove-orphans
|
||||
echo "[WARNUNG] Setze den MongoDB-Volume-Stand zurück, damit die aktuellen Secrets neu initialisiert werden." >&2
|
||||
"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" down -v --remove-orphans
|
||||
}
|
||||
|
||||
build_website_image() {
|
||||
if compose build website; then
|
||||
return 0
|
||||
fi
|
||||
if compose build website; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[WARNUNG] Standard-Build fehlgeschlagen, versuche Legacy-Build ohne BuildKit erneut..." >&2
|
||||
DOCKER_BUILDKIT=0 COMPOSE_DOCKER_CLI_BUILD=0 compose build website
|
||||
echo "[WARNUNG] Standard-Build fehlgeschlagen, versuche Legacy-Build ohne BuildKit erneut..." >&2
|
||||
DOCKER_BUILDKIT=0 COMPOSE_DOCKER_CLI_BUILD=0 compose build website
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# WATCHER LOGIK FÜR ALLE TENANT AKTIONEN (add, remove, restart)
|
||||
# ============================================================================
|
||||
watcher_loop() {
|
||||
local trigger_dir="$1"
|
||||
echo "[INFO] Tenant Watcher gestartet. Lausche in $trigger_dir..."
|
||||
|
||||
while true; do
|
||||
for file in "$trigger_dir"/*.json; do
|
||||
# Überspringen, wenn keine Dateien da sind
|
||||
[ -f "$file" ] || continue
|
||||
|
||||
echo "[INFO] Verarbeite Trigger: $file"
|
||||
|
||||
# JSON auslesen (mit jq oder grep als Fallback)
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
ACTION=$(jq -r '.action // "add"' "$file" 2>/dev/null || echo "add")
|
||||
SLUG=$(jq -r '.slug // empty' "$file" 2>/dev/null || true)
|
||||
PORT=$(jq -r '.port // empty' "$file" 2>/dev/null || true)
|
||||
PASS=$(jq -r '.password // empty' "$file" 2>/dev/null || true)
|
||||
else
|
||||
# Fallback, falls jq nicht installiert ist
|
||||
ACTION=$(grep -o '"action": *"[^"]*"' "$file" | cut -d'"' -f4 || echo "add")
|
||||
[ -z "$ACTION" ] && ACTION="add"
|
||||
SLUG=$(grep -o '"slug": *"[^"]*"' "$file" | cut -d'"' -f4 || true)
|
||||
PORT=$(grep -o '"port": *[0-9]*' "$file" | cut -d':' -f2 | tr -d ' ' || true)
|
||||
PASS=$(grep -o '"password": *"[^"]*"' "$file" | cut -d'"' -f4 || true)
|
||||
fi
|
||||
|
||||
if [ -z "$SLUG" ]; then
|
||||
echo "[ERROR] Ungültige Payload in $file (Slug fehlt). Wird gelöscht." >&2
|
||||
rm -f "$file"
|
||||
continue
|
||||
fi
|
||||
|
||||
case "$ACTION" in
|
||||
"add")
|
||||
if [ -n "$PORT" ] && [ -n "$PASS" ]; then
|
||||
if "$SCRIPT_DIR/manage-tenant.sh" add "$SLUG" "$PORT" "$PASS"; then
|
||||
echo "[SUCCESS] Tenant bereitgestellt: $SLUG"
|
||||
else
|
||||
echo "[ERROR] Fehler beim Bereitstellen von: $SLUG" >&2
|
||||
fi
|
||||
else
|
||||
echo "[ERROR] Fehlende Port/Passwort-Daten für add in $file" >&2
|
||||
fi
|
||||
;;
|
||||
"remove")
|
||||
if "$SCRIPT_DIR/manage-tenant.sh" remove "$SLUG"; then
|
||||
echo "[SUCCESS] Tenant gelöscht: $SLUG"
|
||||
else
|
||||
echo "[ERROR] Fehler beim Löschen von: $SLUG" >&2
|
||||
fi
|
||||
;;
|
||||
"restart")
|
||||
if "$SCRIPT_DIR/manage-tenant.sh" restart-tenant "$SLUG"; then
|
||||
echo "[SUCCESS] Tenant neu gestartet: $SLUG"
|
||||
else
|
||||
echo "[ERROR] Fehler beim Neustart von: $SLUG" >&2
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unbekannte Aktion ($ACTION) in $file" >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
# Nach Verarbeitung Datei restlos löschen
|
||||
rm -f "$file"
|
||||
done
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
start_tenant_watcher() {
|
||||
local trigger_dir="$SCRIPT_DIR/triggers"
|
||||
local pid_file="$SCRIPT_DIR/.watcher.pid"
|
||||
local log_file="$SCRIPT_DIR/watcher.log"
|
||||
|
||||
# Erstelle Trigger-Verzeichnis
|
||||
if [ ! -d "$trigger_dir" ]; then
|
||||
mkdir -p "$trigger_dir"
|
||||
chmod 777 "$trigger_dir"
|
||||
fi
|
||||
|
||||
# Beende alten Watcher, falls dieser noch läuft
|
||||
if [ -f "$pid_file" ]; then
|
||||
local old_pid
|
||||
old_pid=$(cat "$pid_file")
|
||||
if kill -0 "$old_pid" 2>/dev/null; then
|
||||
echo "Beende alten Watcher-Prozess (PID: $old_pid)..."
|
||||
kill "$old_pid" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Starte den Watcher im Hintergrund
|
||||
echo "Starte asynchronen Tenant-Watcher im Hintergrund..."
|
||||
watcher_loop "$trigger_dir" >> "$log_file" 2>&1 &
|
||||
|
||||
# Speichere die PID
|
||||
echo $! > "$pid_file"
|
||||
echo "Watcher läuft! Logs findest du in: $log_file"
|
||||
}
|
||||
# ============================================================================
|
||||
|
||||
|
||||
export SESSION_COOKIE_SECURE="0"
|
||||
export INSTANCE_TLS_MODE="development"
|
||||
export INSTANCE_PARENT_DOMAIN="${INSTANCE_PARENT_DOMAIN:-meine-domain}"
|
||||
@@ -189,8 +294,8 @@ ensure_mongo_secrets
|
||||
|
||||
# Ensure required runtime files exist before building
|
||||
if [ ! -f "$SCRIPT_DIR/gunicorn.conf.py" ]; then
|
||||
echo "[FEHLER] gunicorn.conf.py fehlt in $SCRIPT_DIR. Bitte prüfen." >&2
|
||||
exit 2
|
||||
echo "[FEHLER] gunicorn.conf.py fehlt in $SCRIPT_DIR. Bitte prüfen." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
resolve_docker_cmd
|
||||
@@ -203,7 +308,7 @@ wait_for_mongo_ready
|
||||
ensure_mongo_app_user
|
||||
compose up -d --no-deps website
|
||||
|
||||
# Wait for website to become healthy (simple HTTP check)
|
||||
# Wait for website to become healthy
|
||||
check_url="http://localhost:4999"
|
||||
timeout_seconds=60
|
||||
interval=2
|
||||
@@ -211,22 +316,25 @@ elapsed=0
|
||||
|
||||
echo "Warte auf Website (${check_url}) bis ${timeout_seconds}s..."
|
||||
while [ $elapsed -lt $timeout_seconds ]; do
|
||||
if curl -sS --max-time 2 "$check_url" >/dev/null 2>&1; then
|
||||
echo "Website erreichbar nach ${elapsed}s"
|
||||
break
|
||||
fi
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
if curl -sS --max-time 2 "$check_url" >/dev/null 2>&1; then
|
||||
echo "Website erreichbar nach ${elapsed}s"
|
||||
break
|
||||
fi
|
||||
sleep $interval
|
||||
elapsed=$((elapsed + interval))
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $timeout_seconds ]; then
|
||||
echo "[FEHLER] Website nicht erreichbar nach ${timeout_seconds}s. Sammle Diagnosedaten..."
|
||||
echo "--- docker compose ps ---"
|
||||
compose ps || true
|
||||
echo "--- docker logs website (tail 200) ---"
|
||||
"${DOCKER_CMD[@]}" logs --tail 200 website-website-1 || true
|
||||
echo "Bitte prüfe Container-Logs und nginx-Konfiguration."
|
||||
echo "[FEHLER] Website nicht erreichbar nach ${timeout_seconds}s. Sammle Diagnosedaten..."
|
||||
echo "--- docker compose ps ---"
|
||||
compose ps || true
|
||||
echo "--- docker logs website (tail 200) ---"
|
||||
"${DOCKER_CMD[@]}" logs --tail 200 website-website-1 || true
|
||||
echo "Bitte prüfe Container-Logs und nginx-Konfiguration."
|
||||
fi
|
||||
|
||||
echo "Website stack is running on http://localhost:4999"
|
||||
echo "Provisioning creates self-signed certs per subdomain when needed."
|
||||
echo "Provisioning creates self-signed certs per subdomain when needed."
|
||||
|
||||
# STARTET DEN WATCHER DIREKT HIER IM SCRIPT
|
||||
start_tenant_watcher
|
||||
Reference in New Issue
Block a user