From 197d3b619db96e220795a94e95a29b8b02eacabc Mon Sep 17 00:00:00 2001 From: Anton Afanasyeu Date: Sun, 28 Jun 2026 22:28:08 +0200 Subject: [PATCH] ac-scripts: add full_deployment.sh for complete cluster deployment Co-authored-by: Cursor --- full_deployment.sh | 201 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 full_deployment.sh diff --git a/full_deployment.sh b/full_deployment.sh new file mode 100755 index 0000000..5895423 --- /dev/null +++ b/full_deployment.sh @@ -0,0 +1,201 @@ +#!/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" + 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 " + mkdir -p /var/www/ac/workspace/ac-ms-sfu-signaling + if [ -d /mnt/repos/ac/ac-ms-sfu-signaling ]; then + rsync -a --delete /mnt/repos/ac/ac-ms-sfu-signaling/ /var/www/ac/workspace/ac-ms-sfu-signaling/ + 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) ==="