185 lines
7.5 KiB
Bash
Executable file
185 lines
7.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Bifröst lokal starten: PostgreSQL, Migrationen, DB-Dienst, Web und Worker in einem Terminal (Logs mit Präfix).
|
|
# Strg+C stoppt alles, was das Skript gestartet hat; die Container laufen weiter.
|
|
#
|
|
# scripts/dev.sh # Web auf http://127.0.0.1:8765, Worker, DB-Dienst PostgreSQL (Port 8791)
|
|
# scripts/dev.sh --oracle # dazu Oracle-Container und DB-Dienst für Oracle (Port 8792)
|
|
# scripts/dev.sh --port 8000 # anderer Port für Web
|
|
# scripts/dev.sh --setup # Ersteinrichtung: .env anlegen, Master-Key, Demo-Nutzer
|
|
# scripts/dev.sh --reset # von null: lokale Datenbank und data/ löschen (mit Rückfrage), dann wie
|
|
# # --setup und zusätzlich die Demo-Workspaces anlegen (aiw demo)
|
|
# scripts/dev.sh --reset --yes # ohne Rückfrage; mit --oracle auch die Oracle-Daten
|
|
#
|
|
# Die DB-Dienste registriert man einmal in Bifröst als Datenbank-Treiber (Administration → Datenbank-Treiber);
|
|
# das Skript zeigt URL und Schlüssel beim Start.
|
|
# Einstellungen kommen aus .env. Für lokale Quellen setzt das Skript AIW_DB_ALLOW_LOCAL und AIW_MCP_ALLOW_LOCAL
|
|
# auf true, sofern .env nichts anderes sagt.
|
|
set -euo pipefail
|
|
|
|
ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
cd "$ROOT"
|
|
|
|
PORT=8765
|
|
ORACLE=false
|
|
SETUP=false
|
|
RESET=false
|
|
YES=false
|
|
# Schlüssel nur für die lokal gestarteten DB-Dienste
|
|
DEV_KEY="dev-schluessel-12345678"
|
|
|
|
# Hilfe: der Kommentarblock am Anfang
|
|
usage() { awk 'NR > 1 && /^#/ { sub(/^# ?/, ""); print; next } NR > 1 { exit }' "$0"; }
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--oracle) ORACLE=true ;;
|
|
--port) PORT=${2:?Port fehlt}; shift ;;
|
|
--setup) SETUP=true ;;
|
|
--reset) RESET=true; SETUP=true ;;
|
|
--yes) YES=true ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Unbekannte Option: $1"; usage; exit 1 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
say() { printf '\033[1m==> %s\033[0m\n' "$*"; }
|
|
fail() { printf '\033[31m%s\033[0m\n' "$*" >&2; exit 1; }
|
|
|
|
# Zeilen eines Prozesses mit Namen versehen (portabel, auch mit der Bash von macOS)
|
|
prefix() { while IFS= read -r line; do printf '[%-6s] %s\n' "$1" "$line"; done; }
|
|
|
|
port_busy() { lsof -nP -iTCP:"$1" -sTCP:LISTEN >/dev/null 2>&1; }
|
|
|
|
env_value() { grep -E "^$1=" .env 2>/dev/null | tail -1 | cut -d= -f2-; }
|
|
|
|
command -v docker >/dev/null || fail "Docker fehlt."
|
|
command -v uv >/dev/null || fail "uv fehlt (https://docs.astral.sh/uv/)."
|
|
|
|
# Von null: lokale Daten löschen. .env bleibt (Master-Key, Demo-Passwort), Docker-Images auch.
|
|
if $RESET; then
|
|
port_busy "$PORT" && fail "Auf Port $PORT läuft noch etwas (Bifröst?). Erst stoppen, dann --reset."
|
|
echo "Gelöscht werden ALLE lokalen Daten von Bifröst: Datenbank (Workspaces, Chats, Nutzer, Modelle, API-Keys,"
|
|
echo "Einstellungen) samt Shop-Datenbank der Demo, dazu Uploads, Git-Cache und Demo-Repositories unter data/."
|
|
$ORACLE && echo "Mit --oracle zusätzlich die Daten des Oracle-Containers."
|
|
if ! $YES; then
|
|
# Ohne Terminal (Skript, CI) nicht auf eine Antwort warten: dort ausdrücklich --yes
|
|
[ -t 0 ] || fail "Abgebrochen, nichts gelöscht: Die Rückfrage braucht ein Terminal (sonst --yes)."
|
|
printf "Fortfahren? Zum Bestätigen 'ja' eingeben: "
|
|
read -r answer || answer=""
|
|
[ "$answer" = "ja" ] || fail "Abgebrochen, nichts gelöscht."
|
|
fi
|
|
say "PostgreSQL-Container und -Daten löschen"
|
|
docker compose rm -sfv postgres >/dev/null
|
|
docker volume rm -f ai-workspace_aiw-postgres >/dev/null
|
|
if $ORACLE; then
|
|
say "Oracle-Container und -Daten löschen"
|
|
docker compose --profile oracle rm -sfv oracle >/dev/null
|
|
docker volume rm -f ai-workspace_aiw-oracle >/dev/null
|
|
fi
|
|
# Ablagen aus .env, sofern sie im Projekt liegen; data/ immer
|
|
for dir in data "$(env_value AIW_UPLOAD_DIR)" "$(env_value AIW_GIT_CACHE_DIR)"; do
|
|
[ -n "$dir" ] || continue
|
|
case "$dir" in
|
|
/*|*..*) echo "Übersprungen (außerhalb des Projekts, bitte selbst prüfen): $dir" ;;
|
|
*) if [ -e "$dir" ]; then say "$dir/ löschen"; rm -rf -- "$dir"; fi ;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
if $SETUP; then
|
|
if [ -f .env ]; then
|
|
say ".env gibt es schon, bleibt unverändert"
|
|
else
|
|
say ".env aus .env.example anlegen"
|
|
cp .env.example .env
|
|
fi
|
|
uv sync
|
|
if [ -z "$(env_value AIW_SECRET_KEY)" ]; then
|
|
say "Master-Key erzeugen (AIW_SECRET_KEY)"
|
|
key=$(uv run aiw gen-key | tail -1)
|
|
grep -q '^AIW_SECRET_KEY=' .env && sed -i '' '/^AIW_SECRET_KEY=/d' .env
|
|
printf 'AIW_SECRET_KEY=%s\n' "$key" >> .env
|
|
fi
|
|
if [ -z "$(env_value AIW_DEMO_PASSWORD)" ]; then
|
|
echo "Hinweis: AIW_DEMO_PASSWORD in .env setzen, sonst ist die Demo-Anmeldung (admin, entwicklung, fachbereich, freigabe) aus."
|
|
fi
|
|
fi
|
|
|
|
[ -f .env ] || fail "Keine .env. Ersteinrichtung mit: scripts/dev.sh --setup"
|
|
[ -n "${AIW_SECRET_KEY:-$(env_value AIW_SECRET_KEY)}" ] || fail "AIW_SECRET_KEY fehlt in .env (scripts/dev.sh --setup)."
|
|
port_busy "$PORT" && fail "Port $PORT ist belegt (läuft Bifröst schon?). Anderer Port: --port 8000"
|
|
|
|
say "PostgreSQL starten (127.0.0.1:55433)"
|
|
docker compose up -d --wait postgres
|
|
|
|
say "Migrationen"
|
|
uv run aiw migrate
|
|
$SETUP && { say "Demo-Nutzer anlegen"; uv run aiw seed-demo; }
|
|
|
|
: "${AIW_DB_ALLOW_LOCAL:=$(env_value AIW_DB_ALLOW_LOCAL)}"
|
|
: "${AIW_MCP_ALLOW_LOCAL:=$(env_value AIW_MCP_ALLOW_LOCAL)}"
|
|
export AIW_DB_ALLOW_LOCAL=${AIW_DB_ALLOW_LOCAL:-true}
|
|
export AIW_MCP_ALLOW_LOCAL=${AIW_MCP_ALLOW_LOCAL:-true}
|
|
export AIW_WORKER_HTTP_HOST=${AIW_WORKER_HTTP_HOST:-127.0.0.1}
|
|
export AIW_COOKIE_SECURE=${AIW_COOKIE_SECURE:-false}
|
|
export PYTHONUNBUFFERED=1
|
|
|
|
trap 'trap - INT TERM EXIT; echo; say "Stoppe Web, Worker und DB-Dienste"; kill 0 2>/dev/null; wait 2>/dev/null' INT TERM EXIT
|
|
PIDS=()
|
|
|
|
HINTS=()
|
|
|
|
# DB-Dienst starten, außer er läuft schon auf dem Port
|
|
db_service() {
|
|
local engine=$1 port=$2
|
|
if curl -sf "http://127.0.0.1:$port/ready" >/dev/null 2>&1; then
|
|
say "DB-Dienst $engine läuft schon auf Port $port (Schlüssel muss $DEV_KEY sein)"
|
|
else
|
|
port_busy "$port" && fail "Port $port ist belegt, aber dort antwortet kein DB-Dienst."
|
|
say "DB-Dienst $engine starten (Port $port)"
|
|
(cd services/db-mcp && DBMCP_API_KEYS="dev:$DEV_KEY" DBMCP_ALLOW_LOCAL=true DBMCP_PORT=$port \
|
|
DBMCP_BIND=127.0.0.1 "$ROOT/.venv/bin/python" -m "dbmcp.$engine" 2>&1 | prefix "$engine") &
|
|
PIDS+=($!)
|
|
for _ in $(seq 50); do curl -sf "http://127.0.0.1:$port/ready" >/dev/null 2>&1 && break; sleep 0.2; done
|
|
fi
|
|
HINTS+=("$engine: URL http://localhost:$port/mcp Schlüssel des Dienstes $DEV_KEY")
|
|
}
|
|
|
|
if $ORACLE; then
|
|
say "Oracle starten (127.0.0.1:55434, Service FREEPDB1; der erste Start dauert ein paar Minuten)"
|
|
docker compose --profile oracle up -d --wait oracle
|
|
db_service oracle 8792
|
|
fi
|
|
db_service postgres 8791
|
|
|
|
if $RESET; then
|
|
say "Demo-Workspaces anlegen (aiw demo)"
|
|
uv run aiw demo
|
|
fi
|
|
|
|
say "Web starten: http://127.0.0.1:$PORT"
|
|
(uv run aiw web --port "$PORT" 2>&1 | prefix web) &
|
|
PIDS+=($!)
|
|
say "Worker starten"
|
|
(uv run aiw worker 2>&1 | prefix worker) &
|
|
PIDS+=($!)
|
|
|
|
if $RESET; then
|
|
say "Fertig von null. Noch offen: als admin ein Modell einrichten (Administration → Modelle und Zugänge)."
|
|
say "Alles Weitere (Munin, Hugin, Dokumenten-Auslese, Bitbucket …): docs/checkliste.md"
|
|
say "DB-Dienste (PostgreSQL ist für die Demo schon registriert):"
|
|
else
|
|
say "DB-Dienste, einmalig registrieren unter Administration → Datenbank-Treiber, dann Tools abrufen und einstufen:"
|
|
fi
|
|
for hint in "${HINTS[@]}"; do echo " $hint"; done
|
|
|
|
# Endet ein Prozess (z. B. Fehler beim Start), alles stoppen
|
|
while true; do
|
|
for pid in "${PIDS[@]}"; do
|
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
fail "Ein Prozess hat sich beendet (siehe Log oben)."
|
|
fi
|
|
done
|
|
sleep 1
|
|
done
|