Without this step the model_pricing collection is empty and all LLM costs are recorded as $0. Seed is idempotent — safe on every deploy. Also wait for backend container readiness before running migrations. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
105 lines
5.6 KiB
Bash
Executable file
105 lines
5.6 KiB
Bash
Executable file
#!/bin/bash
|
|
set -e
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Semblance — deploy script (run directly on server)
|
|
# /opt/semblance/deploy.sh
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
DEPLOY_DIR="/opt/semblance"
|
|
FRONTEND_DEST="/var/www/html/semblance"
|
|
|
|
echo "======================================"
|
|
echo "Semblance — starting deployment"
|
|
echo "======================================"
|
|
|
|
cd "$DEPLOY_DIR"
|
|
|
|
# ── Pre-flight ────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[pre-flight] Checking backend/.env..."
|
|
if [ ! -f backend/.env ]; then
|
|
echo "ERROR: backend/.env not found."
|
|
echo " cp backend/.env.example backend/.env && nano backend/.env"
|
|
exit 1
|
|
fi
|
|
|
|
for VAR in SECRET_KEY JWT_SECRET_KEY OPENAI_API_KEY GEMINI_API_KEY; do
|
|
if ! grep -q "^${VAR}=.\+" backend/.env 2>/dev/null; then
|
|
echo "ERROR: $VAR is not set in backend/.env"
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "✓ backend/.env OK"
|
|
|
|
# ── Step 1: Pull latest code ──────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[1/4] Pulling latest code..."
|
|
git pull
|
|
|
|
# ── Step 2: Build frontend (Node in Docker) ───────────────────────────────────
|
|
echo ""
|
|
echo "[2/4] Building frontend..."
|
|
sudo mkdir -p "$FRONTEND_DEST"
|
|
docker compose --profile build run --rm frontend
|
|
sudo chown -R www-data:www-data "$FRONTEND_DEST"
|
|
echo "✓ Frontend deployed to $FRONTEND_DEST"
|
|
|
|
# ── Step 3: Ensure Apache proxy config ───────────────────────────────────────
|
|
echo ""
|
|
echo "[3/4] Ensuring Apache proxy config..."
|
|
CONF="/etc/apache2/sites-enabled/optical-dev.oliver.solutions.conf"
|
|
|
|
if sudo grep -q "semblance_back" "$CONF" 2>/dev/null; then
|
|
echo "✓ Apache semblance config already present"
|
|
# Ensure COOP header is present (needed for MSAL popup auth)
|
|
if ! sudo grep -q "Cross-Origin-Opener-Policy" "$CONF" 2>/dev/null; then
|
|
echo "Adding COOP header for MSAL popup support..."
|
|
sudo sed -i "s|RewriteRule \^ index.html \[L\]|RewriteRule ^ index.html [L]\n Header set Cross-Origin-Opener-Policy \"same-origin-allow-popups\"|" "$CONF"
|
|
sudo apache2ctl configtest && sudo systemctl reload apache2
|
|
echo "✓ COOP header added"
|
|
fi
|
|
else
|
|
echo "Adding semblance blocks to Apache config..."
|
|
sudo sed -i "s|</VirtualHost>| # ----------------------------------------------------------------\n # Semblance — Quart/Hypercorn backend at :5137\n # ----------------------------------------------------------------\n\n # WebSocket (Socket.IO)\n RewriteCond %{HTTP:Upgrade} websocket [NC]\n RewriteCond %{HTTP:Connection} upgrade [NC]\n RewriteRule ^/semblance_back/socket.io/(.*) ws://127.0.0.1:5137/socket.io/\$1 [P,L]\n\n # REST API\n ProxyPass /semblance_back/api/ http://127.0.0.1:5137/api/\n ProxyPassReverse /semblance_back/api/ http://127.0.0.1:5137/api/\n\n # Socket.IO HTTP polling fallback\n ProxyPass /semblance_back/socket.io/ http://127.0.0.1:5137/socket.io/\n ProxyPassReverse /semblance_back/socket.io/ http://127.0.0.1:5137/socket.io/\n\n # Semblance SPA\n Alias /semblance $FRONTEND_DEST\n <Directory $FRONTEND_DEST>\n Options -Indexes +FollowSymLinks\n AllowOverride None\n Require all granted\n RewriteEngine On\n RewriteBase /semblance/\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteRule ^ index.html [L]\n Header set Cross-Origin-Opener-Policy \"same-origin-allow-popups\"\n </Directory>\n\n</VirtualHost>|" "$CONF"
|
|
sudo apache2ctl configtest && sudo systemctl reload apache2
|
|
echo "✓ Apache config updated and reloaded"
|
|
fi
|
|
|
|
# ── Step 4: Rebuild and restart backend + mongo ───────────────────────────────
|
|
echo ""
|
|
echo "[4/5] Rebuilding and restarting Docker services..."
|
|
docker compose up -d --build
|
|
|
|
# Wait for backend to be healthy before running migrations
|
|
echo "Waiting for backend container to be healthy..."
|
|
TRIES=0
|
|
until docker compose exec backend python -c "import sys; sys.exit(0)" 2>/dev/null; do
|
|
TRIES=$((TRIES + 1))
|
|
if [ "$TRIES" -ge 30 ]; then
|
|
echo "ERROR: Backend container did not become ready in time."
|
|
docker compose logs --tail=30 backend
|
|
exit 1
|
|
fi
|
|
sleep 2
|
|
done
|
|
echo "✓ Backend container is ready"
|
|
|
|
# ── Step 5: Run migrations / seed scripts ────────────────────────────────────
|
|
echo ""
|
|
echo "[5/5] Running migrations..."
|
|
|
|
# Seed model pricing (idempotent — safe to run on every deploy)
|
|
echo " → seed_model_pricing.py"
|
|
docker compose exec backend python scripts/seed_model_pricing.py
|
|
echo " ✓ Model pricing seeded"
|
|
|
|
echo ""
|
|
echo "Container status:"
|
|
docker compose ps
|
|
|
|
echo ""
|
|
echo "======================================"
|
|
echo "Deployment complete!"
|
|
echo " https://optical-dev.oliver.solutions/semblance/"
|
|
echo "======================================"
|