#!/bin/sh # full_deployment.sh — Full backend cluster deployment for Android Cast # # Usage: # ./ac-scripts/full_deployment.sh [OPTIONS] # # Options: # --phase baseline|db|app|sfu|all (default: all) # --host cast01|cast02|cast03|all (default: all) # --dry-run Print commands without executing # --no-color Disable color output # -h|--help # # This script: # 1. Pulls latest ac/* repos on each node (git pull + submodule update) # 2. Runs populate_lab_setup.sh phases on each node via SSH # 3. Runs Janus SFU deployment on cast02 (phase sfu) # 4. Reloads nginx on cast01 # 5. Runs load-schemas.sh to apply any new SQL migrations # # Prerequisites: # - SSH passwordless access to cast01, cast02, cast03 # - /mnt/repos/ac checkout on each node # set -eu # ── Helpers ────────────────────────────────────────────────────────── RED='\033[0;31m'; GRN='\033[0;32m'; YEL='\033[1;33m'; BLU='\033[0;34m'; RST='\033[0m' if [ "${NO_COLOR:-}" = "1" ] || [ "${1:-}" = "--no-color" ]; then RED=''; GRN=''; YEL=''; BLU=''; RST='' fi log() { printf "%b[%s]%b %s\n" "$BLU" "$(date '+%H:%M:%S')" "$RST" "$*"; } ok() { printf "%b[OK]%b %s\n" "$GRN" "$RST" "$*"; } warn() { printf "%b[WARN]%b %s\n" "$YEL" "$RST" "$*"; } fail() { printf "%b[FAIL]%b %s\n" "$RED" "$RST" "$*" >&2; exit 1; } DRY=0 PHASE="all" TARGET_HOST="all" while [ $# -gt 0 ]; do case "$1" in --dry-run) DRY=1 ;; --no-color) : ;; --phase) shift; PHASE="${1:?phase value required}" ;; --host) shift; TARGET_HOST="${1:?host value required}" ;; -h|--help) sed -n '2,30p' "$0" | sed 's/^# //' exit 0 ;; *) warn "Unknown option: $1" ;; esac shift done SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" DEPLOY_DIR="$(cd "${SCRIPT_DIR}/../ac-deploy/sim/cluster0" && pwd)" NODES="cast01 cast02 cast03" rsh() { local host="$1"; shift if [ "$DRY" = "1" ]; then log "[DRY] ssh $host $*" return 0 fi ssh "$host" "$@" } on_host() { local host="$1" [ "$TARGET_HOST" = "all" ] || [ "$TARGET_HOST" = "$host" ] } # ── Phase helpers ──────────────────────────────────────────────────── phase_sync() { local host="$1" log "$host: pulling latest ac/* repos..." rsh "$host" "cd /mnt/repos/ac && git fetch origin && git checkout next && git pull && git submodule update --init --recursive 2>&1 | tail -5" # Sync critical cluster files from git repo to NFS share (scripts + nginx templates only) rsh "$host" " SRC=/mnt/repos/ac/ac-deploy/sim/cluster0 DST=/shared/cluster [ -d \"\$SRC\" ] || exit 0 for f in nginx/apps-port80.conf nginx/url-shortener-port80.conf \ scripts/load-schemas.sh scripts/configure-nginx.sh \ scripts/deploy-ac-workspace.sh; do [ -f \"\$SRC/\$f\" ] && sudo cp \"\$SRC/\$f\" \"\$DST/\$f\" 2>/dev/null || true done sudo cp -r \"\$SRC/lab-seeds/backend/sql/migrations/\" \"\$DST/lab-seeds/backend/sql/migrations/\" 2>/dev/null || true " ok "$host: sync done" } phase_baseline() { local host="$1" log "$host: running baseline..." rsh "$host" "cd /mnt/repos/ac/ac-deploy/sim/cluster0 && sudo sh populate_lab_setup.sh --phase baseline 2>&1 | tail -10" ok "$host: baseline done" } phase_db() { local host="$1" log "$host: running DB setup..." rsh "$host" "cd /mnt/repos/ac/ac-deploy/sim/cluster0 && sudo sh populate_lab_setup.sh --phase db 2>&1 | tail -10" ok "$host: DB done" } phase_app() { local host="$1" log "$host: running app deploy..." rsh "$host" "cd /mnt/repos/ac/ac-deploy/sim/cluster0 && sudo sh populate_lab_setup.sh --phase app 2>&1 | tail -10" ok "$host: app done" } phase_sfu() { log "cast02: deploying Janus SFU..." # Install Janus if not present rsh cast02 "command -v janus >/dev/null 2>&1 || sudo apk add --no-cache janus-gateway janus-gateway-openrc" # Ensure config files exist (idempotent cp) rsh cast02 " [ -f /etc/janus/janus.jcfg ] || sudo cp /etc/janus/janus.jcfg.sample /etc/janus/janus.jcfg [ -f /etc/janus/janus.transport.http.jcfg ] || sudo cp /etc/janus/janus.transport.http.jcfg.sample /etc/janus/janus.transport.http.jcfg [ -f /etc/janus/janus.transport.websockets.jcfg ] || sudo cp /etc/janus/janus.transport.websockets.jcfg.sample /etc/janus/janus.transport.websockets.jcfg [ -f /etc/janus/janus.plugin.videoroom.jcfg ] || sudo cp /etc/janus/janus.plugin.videoroom.jcfg.sample /etc/janus/janus.plugin.videoroom.jcfg " # Enable and (re)start service rsh cast02 "sudo rc-update add janus-gateway default 2>/dev/null; sudo rc-service janus-gateway restart 2>&1 | tail -3" # Verify Janus is responding rsh cast02 "curl -sf http://localhost:8088/janus/info | python3 -c 'import sys,json; d=json.load(sys.stdin); print(\"Janus\",d[\"version_string\"],\"OK\")'" \ && ok "cast02: Janus SFU is running" \ || warn "cast02: Janus health check failed (may still be starting)" # Deploy SFU signaling service to cast01 workspace log "cast01: deploying SFU signaling service..." rsh cast01 " sudo mkdir -p /var/www/ac/workspace/ac-ms-sfu-signaling if [ -d /mnt/repos/ac/ac-ms-sfu-signaling ]; then sudo rsync -a --delete /mnt/repos/ac/ac-ms-sfu-signaling/ /var/www/ac/workspace/ac-ms-sfu-signaling/ sudo chown -R nginx:nginx /var/www/ac/workspace/ac-ms-sfu-signaling/ 2>/dev/null || true fi " # Apply SFU schema migrations via load-schemas log "cast01: applying SFU schema migrations..." rsh cast01 " cd /mnt/repos/ac/ac-deploy/sim/cluster0 sudo sh scripts/load-schemas.sh 2>&1 | tail -5 " || warn "Schema migration failed (may already be applied)" # Reload nginx with Janus proxy config log "cast01: reloading nginx..." rsh cast01 "sudo /usr/sbin/nginx -t && sudo rc-service nginx reload 2>&1 | tail -2" ok "cast01: nginx reloaded with Janus proxy" } phase_nginx_reload() { log "cast01: reloading nginx..." rsh cast01 "sudo /usr/sbin/nginx -t && sudo rc-service nginx reload 2>&1 | tail -2" ok "cast01: nginx reloaded" } phase_verify() { log "Running cluster verification..." rsh cast01 "cd /mnt/repos/ac/ac-deploy/sim/cluster0 && sh scripts/verify-cluster.sh 2>&1 | tail -20" || warn "verify-cluster returned non-zero" } # ── Main ───────────────────────────────────────────────────────────── log "=== Android Cast Full Deployment ===" log "Phase: $PHASE | Hosts: $TARGET_HOST | Dry: $DRY" echo "" case "$PHASE" in baseline) for h in $NODES; do on_host "$h" && { phase_sync "$h"; phase_baseline "$h"; } done ;; db) for h in $NODES; do on_host "$h" && { phase_sync "$h"; phase_db "$h"; } done ;; app) for h in $NODES; do on_host "$h" && { phase_sync "$h"; phase_app "$h"; } done on_host cast01 && phase_nginx_reload ;; sfu) phase_sync cast02 phase_sync cast01 phase_sfu ;; all) # 1. Sync all nodes for h in $NODES; do on_host "$h" && phase_sync "$h" done # 2. Baseline on all for h in $NODES; do on_host "$h" && phase_baseline "$h" done # 3. DB on cast01 (primary + replicas follow) on_host cast01 && phase_db cast01 # 4. App on all nodes for h in $NODES; do on_host "$h" && phase_app "$h" done # 5. SFU phase_sfu # 6. Verify on_host cast01 && phase_verify ;; *) fail "Unknown phase: $PHASE (use: baseline|db|app|sfu|all)" ;; esac echo "" ok "=== Deployment complete (phase=$PHASE) ==="