#!/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_workspace_bump() { # Bump ac-workspace submodule SHAs from the monorepo clone so the deployment # workspace (/var/www/ac/workspace) gets the latest code on next pull. local host="$1" rsh "$host" " WS=/var/www/ac/workspace MONOREPO=/mnt/repos/ac [ -d \"\$WS/.git\" ] || exit 0 changed=0 for sub in \$(sudo -u nginx git -C \"\$WS\" submodule status 2>/dev/null | awk '{print \$2}'); do local_sha=\$(git -C \"\$MONOREPO/\$sub\" rev-parse HEAD 2>/dev/null) || continue ws_sha=\$(sudo -u nginx git -C \"\$WS/\$sub\" rev-parse HEAD 2>/dev/null) || continue [ \"\$local_sha\" = \"\$ws_sha\" ] && continue sudo -u nginx git -C \"\$WS/\$sub\" fetch origin 2>/dev/null || true sudo -u nginx git -C \"\$WS/\$sub\" checkout \"\$local_sha\" 2>/dev/null || true sudo -u nginx git -C \"\$WS\" add \"\$sub\" 2>/dev/null || true changed=1 done [ \"\$changed\" = '1' ] && sudo -u nginx git -C \"\$WS\" commit -m 'auto-bump submodules from monorepo' 2>/dev/null || true sudo -u nginx git -C \"\$WS\" push origin next 2>/dev/null || true " 2>/dev/null || true } phase_app() { local host="$1" log "$host: running app deploy..." phase_workspace_bump "$host" 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 "Deploying Janus SFU (cluster script)..." rsh cast02 "sudo sh /shared/cluster/scripts/deploy-janus-sfu.sh" \ && ok "cast02: Janus SFU deployed" \ || warn "cast02: deploy-janus-sfu failed" for h in cast01 cast03; do rsh "$h" "sudo sh /shared/cluster/scripts/deploy-janus-sfu.sh" \ && ok "$h: SFU signaling/nginx OK" \ || warn "$h: deploy-janus-sfu failed" done } 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) ==="