llm-gateway/deploy/deploy.sh
Rene Fichtmueller 3a00ff4d33 feat: initial llm-gateway implementation
- Complete Fastify gateway with 8-stage pipeline
- Circuit breaker (opossum) per model tier
- Rate limiting per caller
- Ban list validation (EN/DE/auto-detected)
- TIP validator (SFF-8024, part numbers, wavelengths)
- Prometheus metrics
- pg-boss async queue
- PostgreSQL audit log + review queue
- 9 prompt templates (TIP, LinkedIn, ShieldX)
- Learning engine scaffolding
- Auto-learning: ban-list, few-shot, routing, prompt optimizer
2026-04-02 22:48:55 +02:00

187 lines
5.4 KiB
Bash
Executable File

#!/bin/bash
# ============================================================
# LLM Gateway — One-command deploy (run locally on Mac)
#
# Usage:
# bash deploy/deploy.sh
# bash deploy/deploy.sh --skip-build # skip local build
# bash deploy/deploy.sh --health-only # just check remote health
# ============================================================
set -euo pipefail
ERIK_HOST="217.154.82.179"
ERIK_USER="root"
REMOTE_DIR="/opt/llm-gateway"
GITEA_BRANCH="main"
HEALTH_URL="http://${ERIK_HOST}:3100/health"
HEALTH_URL_CF="https://llm-gateway.context-x.org/health"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }
section() { echo -e "\n${BLUE}>> $*${NC}"; }
# Parse args
SKIP_BUILD=false
HEALTH_ONLY=false
for arg in "$@"; do
case $arg in
--skip-build) SKIP_BUILD=true ;;
--health-only) HEALTH_ONLY=true ;;
*) warn "Unknown argument: $arg" ;;
esac
done
# -------------------------------------------------------
# Health-only mode
# -------------------------------------------------------
if [[ "$HEALTH_ONLY" == "true" ]]; then
section "Remote health check"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL" 2>/dev/null || echo "000")
BODY=$(curl -s "$HEALTH_URL" 2>/dev/null || echo "{}")
echo " HTTP status: $STATUS"
echo " Response: $BODY"
[[ "$STATUS" == "200" ]] && info "Gateway is healthy." || warn "Gateway may be unhealthy."
exit 0
fi
# -------------------------------------------------------
# 0. Pre-deploy checks
# -------------------------------------------------------
section "0. Pre-deploy checks"
command -v npm >/dev/null || error "npm not found."
command -v git >/dev/null || error "git not found."
command -v ssh >/dev/null || error "ssh not found."
command -v curl >/dev/null || error "curl not found."
# Check we're on main (warn only — don't block)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
if [[ "$CURRENT_BRANCH" != "$GITEA_BRANCH" ]]; then
warn "Current branch is '$CURRENT_BRANCH', not '$GITEA_BRANCH'. Proceeding anyway."
fi
# Check for uncommitted changes
if ! git diff --quiet 2>/dev/null; then
warn "You have uncommitted changes. They will NOT be deployed."
fi
info "Pre-deploy checks passed."
# -------------------------------------------------------
# 1. Local build
# -------------------------------------------------------
section "1. Local build"
if [[ "$SKIP_BUILD" == "true" ]]; then
warn "Skipping local build (--skip-build)"
else
info "Running: npm run build"
npm run build
info "Build successful."
fi
# -------------------------------------------------------
# 2. Push to Gitea
# -------------------------------------------------------
section "2. Pushing to Gitea"
COMMIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
info "Pushing commit $COMMIT_SHA to Gitea ($GITEA_BRANCH)..."
git push origin "$GITEA_BRANCH"
info "Push complete."
# -------------------------------------------------------
# 3. Deploy on Erik
# -------------------------------------------------------
section "3. Deploying on Erik (${ERIK_HOST})"
info "Connecting via SSH..."
# shellcheck disable=SC2087
ssh -o ConnectTimeout=15 "${ERIK_USER}@${ERIK_HOST}" bash << 'REMOTE_SCRIPT'
set -euo pipefail
REMOTE_DIR="/opt/llm-gateway"
LOG_DIR="/var/log/llm-gateway"
echo "[remote] Pulling latest code..."
cd "$REMOTE_DIR"
git fetch origin
git reset --hard origin/main
echo "[remote] Installing dependencies..."
npm install --prefer-offline 2>/dev/null || npm install
echo "[remote] Building..."
npm run build
echo "[remote] Ensuring log directory..."
mkdir -p "$LOG_DIR"
echo "[remote] Restarting PM2 processes..."
if pm2 list | grep -q "llm-gateway"; then
pm2 reload llm-gateway llm-learning --update-env
else
echo "[remote] PM2 processes not found — starting from ecosystem config..."
pm2 start deploy/ecosystem.config.cjs
fi
pm2 save
echo "[remote] Deploy complete."
REMOTE_SCRIPT
info "Remote deploy finished."
# -------------------------------------------------------
# 4. Post-deploy health check
# -------------------------------------------------------
section "4. Post-deploy health check"
MAX_RETRIES=8
RETRY_DELAY=5
info "Waiting ${RETRY_DELAY}s for restart to complete..."
sleep $RETRY_DELAY
for i in $(seq 1 $MAX_RETRIES); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$HEALTH_URL" 2>/dev/null || echo "000")
if [[ "$STATUS" == "200" ]]; then
BODY=$(curl -s --max-time 10 "$HEALTH_URL" 2>/dev/null || echo "{}")
info "Health check PASSED (HTTP 200)"
echo " $BODY"
break
fi
if [[ $i -eq $MAX_RETRIES ]]; then
warn "Health check did not return 200 after ${MAX_RETRIES} attempts."
warn "Check logs on Erik: ssh root@${ERIK_HOST} 'pm2 logs llm-gateway --lines 50'"
exit 1
fi
info " Attempt $i/$MAX_RETRIES — HTTP $STATUS. Retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
done
# -------------------------------------------------------
# 5. Summary
# -------------------------------------------------------
echo ""
echo -e "${GREEN}Deploy successful!${NC}"
echo ""
echo " Commit: $COMMIT_SHA"
echo " Direct: $HEALTH_URL"
echo " Cloudflare: $HEALTH_URL_CF"
echo " PM2 status: ssh root@${ERIK_HOST} 'pm2 status'"
echo " Logs: ssh root@${ERIK_HOST} 'pm2 logs llm-gateway'"
echo ""