#!/usr/bin/env env bash set -euo pipefail SSH="ssh -i ~/.ssh/5G-SSH-Key.pem -p 2222 -o StrictHostKeyChecking=no root@localhost" SCP="scp -i ~/.ssh/5G-SSH-Key.pem -P 2222 -o StrictHostKeyChecking=no" VM="root@localhost" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" echo "=== P5G Marvis Deploy ===" # ── 1. Copy source to VM ─────────────────────────────────────────────────── echo "→ Syncing source to VM at /opt/p5g-marvis …" $SSH "mkdir -p /opt/p5g-marvis/app/routers /opt/p5g-marvis/app/services /opt/p5g-marvis/app/ui" $SCP "$SCRIPT_DIR/requirements.txt" "$VM:/opt/p5g-marvis/" $SCP "$SCRIPT_DIR/app/main.py" "$VM:/opt/p5g-marvis/app/" $SCP "$SCRIPT_DIR/app/config.py" "$VM:/opt/p5g-marvis/app/" $SCP "$SCRIPT_DIR/app/__init__.py" "$VM:/opt/p5g-marvis/app/" 2>/dev/null || true $SCP "$SCRIPT_DIR/app/routers/__init__.py" "$VM:/opt/p5g-marvis/app/routers/" 2>/dev/null || true $SCP "$SCRIPT_DIR/app/routers/network.py" "$VM:/opt/p5g-marvis/app/routers/" $SCP "$SCRIPT_DIR/app/routers/alerts.py" "$VM:/opt/p5g-marvis/app/routers/" $SCP "$SCRIPT_DIR/app/routers/query.py" "$VM:/opt/p5g-marvis/app/routers/" $SCP "$SCRIPT_DIR/app/services/__init__.py" "$VM:/opt/p5g-marvis/app/services/" 2>/dev/null || true $SCP "$SCRIPT_DIR/app/services/prometheus.py" "$VM:/opt/p5g-marvis/app/services/" $SCP "$SCRIPT_DIR/app/services/alertmanager.py" "$VM:/opt/p5g-marvis/app/services/" $SCP "$SCRIPT_DIR/app/services/ai.py" "$VM:/opt/p5g-marvis/app/services/" $SCP "$SCRIPT_DIR/app/ui/index.html" "$VM:/opt/p5g-marvis/app/ui/" # ── 2. Install Python deps on VM ─────────────────────────────────────────── echo "→ Installing Python dependencies …" $SSH "python3 -m pip install -q -r /opt/p5g-marvis/requirements.txt" # ── 3. Systemd service ───────────────────────────────────────────────────── echo "→ Installing systemd service …" $SSH "cat > /etc/systemd/system/p5g-marvis.service << 'UNIT' [Unit] Description=P5G Marvis AI Assistant After=network.target [Service] Type=simple WorkingDirectory=/opt/p5g-marvis ExecStart=/usr/bin/python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8095 --workers 1 Restart=on-failure RestartSec=5 Environment=MARVIS_PROMETHEUS_URL=http://127.0.0.1:9090 Environment=MARVIS_PROMETHEUS_PREFIX=/prometheus Environment=MARVIS_ALERTMANAGER_URL=http://127.0.0.1:9093 Environment=MARVIS_AI_MODE=rule [Install] WantedBy=multi-user.target UNIT" $SSH "systemctl daemon-reload && systemctl enable --now p5g-marvis" $SSH "sleep 2 && systemctl is-active p5g-marvis && echo 'Service OK'" # ── 4. Register route with Traefik (file provider) ───────────────────────── echo "→ Registering Traefik route …" $SCP "$SCRIPT_DIR/traefik-marvis.yml" "$VM:/etc/athonet/traefik/marvis.yml" # Add file provider to traefik.yml if not already present $SSH "python3 << 'PY' f = '/etc/athonet/traefik/traefik.yml' src = open(f).read() if 'file:' not in src: src = src.replace( ' endpoint: \"http://127.0.0.1:8089/traefik\"', ' endpoint: \"http://127.0.0.1:8089/traefik\"\n file:\n filename: \"/etc/athonet/traefik/marvis.yml\"\n watch: true' ) open(f, 'w').write(src) print('Traefik file provider added') else: print('Traefik file provider already configured') PY" echo "→ Restarting Traefik …" $SSH "podman restart traefik && sleep 2 && podman ps | grep traefik" # ── 5. Patch NCM React bundle ────────────────────────────────────────────── echo "→ Patching NCM frontend …" $SCP "$SCRIPT_DIR/patch-ncm.py" "$VM:/tmp/patch-ncm.py" $SSH "python3 /tmp/patch-ncm.py" $SSH "podman restart ncm && sleep 2 && podman ps | grep ncm" echo "" echo "=== Deploy complete ===" echo "" echo " Marvis standalone: https://localhost:8443/core/marvis/" echo " In NCM sidebar: https://localhost:8443/ncm/marvis" echo " API docs: https://localhost:8443/core/marvis/api/docs" echo "" echo " To change AI mode (on VM):" echo " systemctl edit p5g-marvis" echo " # Add: Environment=MARVIS_AI_MODE=openai" echo " # Add: Environment=MARVIS_OPENAI_API_KEY=sk-..." echo " systemctl restart p5g-marvis"