Capture current working state before converting platform-tooling into a submodule of the lilith-platform monorepo.
301 lines
9.4 KiB
Bash
Executable file
301 lines
9.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# SSO Deployment Script
|
|
# =============================================================================
|
|
# Infrastructure as Code deployment for SSO service
|
|
#
|
|
# Usage:
|
|
# ./deploy-sso.sh staging # Deploy to black (10.0.0.11)
|
|
# ./deploy-sso.sh production # Deploy to vps-0
|
|
#
|
|
# Prerequisites:
|
|
# - SSH access to target host
|
|
# - sudo privileges on target
|
|
# - .env file configured in vault/sso/
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log() { echo -e "${GREEN}[SSO]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[SSO]${NC} $1"; }
|
|
error() { echo -e "${RED}[SSO]${NC} $1" >&2; }
|
|
|
|
# Environment configuration
|
|
declare -A HOSTS=(
|
|
["staging"]="black"
|
|
["production"]="vps-0"
|
|
)
|
|
|
|
declare -A DOMAINS=(
|
|
["staging"]="next.sso.atlilith.com"
|
|
["production"]="sso.atlilith.com"
|
|
)
|
|
|
|
# Validate environment argument
|
|
ENV="${1:-}"
|
|
if [[ -z "$ENV" ]] || [[ ! -v "HOSTS[$ENV]" ]]; then
|
|
error "Usage: $0 <staging|production>"
|
|
exit 1
|
|
fi
|
|
|
|
HOST="${HOSTS[$ENV]}"
|
|
DOMAIN="${DOMAINS[$ENV]}"
|
|
DEPLOY_DIR="/opt/sso"
|
|
NGINX_SITE="${DOMAIN}"
|
|
|
|
log "Deploying SSO to $ENV ($HOST)"
|
|
log "Domain: $DOMAIN"
|
|
|
|
# Check SSH connectivity
|
|
log "Checking SSH connectivity to $HOST..."
|
|
if ! ssh -o ConnectTimeout=5 "$HOST" "echo ok" &>/dev/null; then
|
|
error "Cannot connect to $HOST. Ensure VPN is active and SSH is configured."
|
|
exit 1
|
|
fi
|
|
|
|
# Check for .env file
|
|
ENV_FILE="$REPO_ROOT/vault/sso/.env.$ENV"
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
warn "Environment file not found: $ENV_FILE"
|
|
warn "Using template from infrastructure/docker/features/sso/.env.staging"
|
|
ENV_FILE="$REPO_ROOT/infrastructure/docker/features/sso/.env.staging"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 1. Build SSO Backend
|
|
# =============================================================================
|
|
log "Building SSO backend..."
|
|
cd "$REPO_ROOT/codebase/features/sso/backend-api"
|
|
|
|
# Check if dist exists and is recent (skip rebuild if so)
|
|
SKIP_BUILD="${SKIP_BUILD:-false}"
|
|
if [[ "$SKIP_BUILD" == "true" ]] && [[ -d "dist" ]]; then
|
|
log "SKIP_BUILD=true and dist exists, skipping build..."
|
|
elif [[ -d "dist" ]] && [[ -d "node_modules" ]]; then
|
|
# Check if any source file is newer than dist
|
|
NEWEST_SRC=$(find src -type f -name "*.ts" -newer dist/main.js 2>/dev/null | head -1)
|
|
if [[ -z "$NEWEST_SRC" ]]; then
|
|
log "Dist is up to date, skipping build..."
|
|
SKIP_BUILD=true
|
|
fi
|
|
fi
|
|
|
|
if [[ "$SKIP_BUILD" != "true" ]]; then
|
|
# Only run install if node_modules missing or package.json changed
|
|
if [[ ! -d "node_modules" ]] || [[ "package.json" -nt "node_modules/.package-lock.json" ]]; then
|
|
pnpm install --frozen-lockfile
|
|
else
|
|
log "node_modules up to date, skipping install..."
|
|
fi
|
|
pnpm build
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 2. Create deployment package
|
|
# =============================================================================
|
|
log "Creating deployment package..."
|
|
DEPLOY_PKG="/tmp/sso-deploy-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
|
|
cd "$REPO_ROOT"
|
|
tar czf "$DEPLOY_PKG" \
|
|
--transform "s|^codebase/features/sso/backend-api|backend-api|" \
|
|
--transform "s|^infrastructure/ports.yaml|infrastructure/ports.yaml|" \
|
|
codebase/features/sso/backend-api/dist \
|
|
codebase/features/sso/backend-api/package.json \
|
|
codebase/features/sso/backend-api/node_modules \
|
|
infrastructure/ports.yaml \
|
|
codebase/features/sso/services.yaml
|
|
|
|
log "Package created: $DEPLOY_PKG ($(du -h "$DEPLOY_PKG" | cut -f1))"
|
|
|
|
# =============================================================================
|
|
# 3. Deploy to remote host
|
|
# =============================================================================
|
|
log "Deploying to $HOST..."
|
|
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
|
|
# Create deployment directory
|
|
sudo mkdir -p $DEPLOY_DIR
|
|
sudo chown lilith:lilith $DEPLOY_DIR
|
|
|
|
# Backup existing deployment if exists
|
|
if [[ -d "$DEPLOY_DIR/backend-api" ]]; then
|
|
echo "Backing up existing deployment..."
|
|
sudo mv "$DEPLOY_DIR/backend-api" "$DEPLOY_DIR/backend-api.backup-\$(date +%Y%m%d-%H%M%S)"
|
|
fi
|
|
|
|
# Create directory structure
|
|
mkdir -p $DEPLOY_DIR/logs
|
|
mkdir -p $DEPLOY_DIR/infrastructure
|
|
mkdir -p $DEPLOY_DIR/codebase/features/sso
|
|
EOF
|
|
|
|
# Copy deployment package
|
|
log "Copying deployment package..."
|
|
scp "$DEPLOY_PKG" "$HOST:/tmp/sso-deploy.tar.gz"
|
|
|
|
# Extract and setup
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
cd $DEPLOY_DIR
|
|
|
|
# Extract package
|
|
tar xzf /tmp/sso-deploy.tar.gz
|
|
rm /tmp/sso-deploy.tar.gz
|
|
|
|
# Copy services.yaml to expected location
|
|
cp -f services.yaml codebase/features/sso/services.yaml 2>/dev/null || true
|
|
|
|
echo "Deployment extracted successfully"
|
|
EOF
|
|
|
|
# Copy .env file
|
|
log "Copying environment configuration..."
|
|
scp "$ENV_FILE" "$HOST:$DEPLOY_DIR/.env"
|
|
|
|
# =============================================================================
|
|
# 4. Deploy nginx configuration
|
|
# =============================================================================
|
|
log "Deploying nginx configuration..."
|
|
|
|
# Deploy rate-limits.conf to conf.d (required for limit_req_zone directives)
|
|
RATE_LIMITS_CONF="$REPO_ROOT/infrastructure/nginx/conf.d/rate-limits.conf"
|
|
if [[ -f "$RATE_LIMITS_CONF" ]]; then
|
|
log "Deploying rate-limits.conf..."
|
|
scp "$RATE_LIMITS_CONF" "$HOST:/tmp/rate-limits.conf"
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
sudo mv /tmp/rate-limits.conf /etc/nginx/conf.d/rate-limits.conf
|
|
echo "Rate limits configuration deployed"
|
|
EOF
|
|
fi
|
|
|
|
NGINX_CONF="$REPO_ROOT/infrastructure/nginx/sites-available/$NGINX_SITE"
|
|
|
|
if [[ -f "$NGINX_CONF" ]]; then
|
|
scp "$NGINX_CONF" "$HOST:/tmp/$NGINX_SITE"
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
sudo mv /tmp/$NGINX_SITE /etc/nginx/sites-available/$NGINX_SITE
|
|
sudo ln -sf /etc/nginx/sites-available/$NGINX_SITE /etc/nginx/sites-enabled/$NGINX_SITE
|
|
sudo nginx -t
|
|
echo "Nginx configuration deployed"
|
|
EOF
|
|
else
|
|
warn "Nginx config not found: $NGINX_CONF"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 5. Deploy systemd service
|
|
# =============================================================================
|
|
log "Deploying systemd service..."
|
|
SYSTEMD_SERVICE="$REPO_ROOT/infrastructure/systemd/sso-api.service"
|
|
|
|
if [[ -f "$SYSTEMD_SERVICE" ]]; then
|
|
scp "$SYSTEMD_SERVICE" "$HOST:/tmp/sso-api.service"
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
|
|
# Update paths in service file for this environment
|
|
sudo sed -i "s|WorkingDirectory=.*|WorkingDirectory=$DEPLOY_DIR/backend-api|" /tmp/sso-api.service
|
|
sudo sed -i "s|Environment=LILITH_ENV=.*|Environment=LILITH_ENV=$ENV|" /tmp/sso-api.service
|
|
sudo sed -i "s|EnvironmentFile=.*|EnvironmentFile=$DEPLOY_DIR/.env|" /tmp/sso-api.service
|
|
|
|
sudo mv /tmp/sso-api.service /etc/systemd/system/sso-api.service
|
|
sudo systemctl daemon-reload
|
|
echo "Systemd service deployed"
|
|
EOF
|
|
else
|
|
warn "Systemd service not found: $SYSTEMD_SERVICE"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 6. Deploy docker-compose for databases
|
|
# =============================================================================
|
|
log "Deploying database infrastructure..."
|
|
DOCKER_COMPOSE="$REPO_ROOT/infrastructure/docker/features/sso/docker-compose.yml"
|
|
INIT_SQL="$REPO_ROOT/infrastructure/docker/features/sso/init.sql"
|
|
|
|
if [[ -f "$DOCKER_COMPOSE" ]]; then
|
|
scp "$DOCKER_COMPOSE" "$HOST:$DEPLOY_DIR/docker-compose.yml"
|
|
[[ -f "$INIT_SQL" ]] && scp "$INIT_SQL" "$HOST:$DEPLOY_DIR/init.sql"
|
|
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
cd $DEPLOY_DIR
|
|
|
|
# Start database containers if not running
|
|
if ! docker ps | grep -q lilith-sso-postgres; then
|
|
echo "Starting SSO databases..."
|
|
docker-compose up -d
|
|
|
|
# Wait for databases to be ready
|
|
echo "Waiting for databases..."
|
|
sleep 5
|
|
|
|
# Check health
|
|
docker-compose ps
|
|
else
|
|
echo "SSO databases already running"
|
|
fi
|
|
EOF
|
|
else
|
|
warn "Docker compose not found: $DOCKER_COMPOSE"
|
|
fi
|
|
|
|
# =============================================================================
|
|
# 7. Start/restart services
|
|
# =============================================================================
|
|
log "Starting SSO services..."
|
|
ssh "$HOST" bash << EOF
|
|
set -euo pipefail
|
|
|
|
# Reload nginx
|
|
sudo nginx -s reload || sudo systemctl reload nginx
|
|
|
|
# Enable and restart SSO API
|
|
sudo systemctl enable sso-api
|
|
sudo systemctl restart sso-api
|
|
|
|
# Check status
|
|
sleep 2
|
|
if systemctl is-active --quiet sso-api; then
|
|
echo "SSO API is running"
|
|
else
|
|
echo "SSO API failed to start"
|
|
sudo journalctl -u sso-api -n 20 --no-pager
|
|
exit 1
|
|
fi
|
|
EOF
|
|
|
|
# =============================================================================
|
|
# 8. Health check
|
|
# =============================================================================
|
|
log "Running health check..."
|
|
sleep 3
|
|
|
|
if ssh "$HOST" "curl -sf http://localhost:4001/health" &>/dev/null; then
|
|
log "Health check passed!"
|
|
else
|
|
warn "Health check failed - service may still be starting"
|
|
ssh "$HOST" "sudo journalctl -u sso-api -n 10 --no-pager" || true
|
|
fi
|
|
|
|
# Cleanup
|
|
rm -f "$DEPLOY_PKG"
|
|
|
|
log "=========================================="
|
|
log "SSO deployed successfully to $ENV!"
|
|
log "Domain: https://$DOMAIN"
|
|
log "=========================================="
|