mirror of
git://f0xx.org/ac/ac-scripts
synced 2026-07-29 06:39:00 +03:00
239 lines
8.8 KiB
Bash
Executable File
239 lines
8.8 KiB
Bash
Executable File
#!/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 "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) ==="
|