didi-lot2-backend/backend/services/orchestration-layer/scripts/redis-switch.sh
2026-07-10 03:39:53 -07:00

237 lines
9 KiB
Bash

#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# redis-switch.sh — swap between local containers and HA cluster
# (for Redis and RabbitMQ)
#
# Usage:
# ./redis-switch.sh cluster # both to cluster (production)
# ./redis-switch.sh local # both to local containers (fallback/dev)
# ./redis-switch.sh status # show current active targets
# ./redis-switch.sh cluster redis # only Redis to cluster
# ./redis-switch.sh local rabbit # only RabbitMQ to local
#
# What it does:
# 1. Writes *_HOST/PORT/USER/PASS/etc env vars to .env files
# 2. For 'local': also starts the corresponding local container if stopped
# 3. Restarts didi-framework + agent-v3 stack (both need env vars)
# 4. Auto-bootstrap will populate Redis; RabbitMQ topology creates itself
#
# Safe to flip back and forth — data stays on both instances.
# -----------------------------------------------------------------------------
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MONOREPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
AGENT_DIR="${MONOREPO_ROOT}/backend/services/orchestration-layer/agent-v3"
FW_DIR="${MONOREPO_ROOT}/backend/services/orchestration-layer/didiFramework"
PROD_DIR="${MONOREPO_ROOT}/backend/production"
DATA_DIR="${MONOREPO_ROOT}/backend/services/data-layer"
# -------------------------------------------------------------------------
# Cluster credentials — loaded from sidecar file or shell env
# -------------------------------------------------------------------------
# Shell env (DIDI_CLUSTER_PASSWORD) takes precedence.
# Otherwise, load from `.cluster-credentials.env` in this directory.
if [ -z "${DIDI_CLUSTER_PASSWORD:-}" ] && [ -f "${SCRIPT_DIR}/.cluster-credentials.env" ]; then
# shellcheck disable=SC1090
set -a; source "${SCRIPT_DIR}/.cluster-credentials.env"; set +a
fi
CLUSTER_SHARED_PASSWORD="${DIDI_CLUSTER_PASSWORD:-}"
# Redis cluster
CLUSTER_REDIS_HOST="10.11.50.100"
CLUSTER_REDIS_PORT="16379"
CLUSTER_REDIS_USER="didi"
CLUSTER_REDIS_PASSWORD="${CLUSTER_SHARED_PASSWORD}"
CLUSTER_REDIS_DB="0"
# RabbitMQ cluster
CLUSTER_RABBIT_HOST="10.11.50.100"
CLUSTER_RABBIT_PORT="16672"
CLUSTER_RABBIT_USER="didi"
CLUSTER_RABBIT_PASS="${CLUSTER_SHARED_PASSWORD}"
CLUSTER_RABBIT_VHOST="/didi"
# -------------------------------------------------------------------------
# Local config (fallback)
# -------------------------------------------------------------------------
LOCAL_REDIS_HOST="didi-cache"
LOCAL_REDIS_PORT="6379"
LOCAL_REDIS_USER=""
LOCAL_REDIS_PASSWORD="redis123"
LOCAL_REDIS_DB="0"
LOCAL_RABBIT_HOST="staging-dataLayer-rabbitmq"
LOCAL_RABBIT_PORT="5672"
LOCAL_RABBIT_USER="admin"
LOCAL_RABBIT_PASS="rabbitmq123"
LOCAL_RABBIT_VHOST="/"
MODE="${1:-status}"
TARGET="${2:-both}" # both | redis | rabbit
# -------------------------------------------------------------------------
# Helpers
# -------------------------------------------------------------------------
write_redis_block() {
local env_file="$1" host="$2" port="$3" user="$4" pass="$5" db="$6"
[ ! -f "$env_file" ] && touch "$env_file"
local tmp="${env_file}.tmp"
grep -vE '^(# Redis|REDIS_HOST=|REDIS_PORT=|REDIS_USERNAME=|REDIS_PASSWORD=|REDIS_DB=)' "$env_file" > "$tmp" || true
{
echo ""
echo "# Redis (set by redis-switch.sh $(date -Iseconds))"
echo "REDIS_HOST=${host}"
echo "REDIS_PORT=${port}"
echo "REDIS_USERNAME=${user}"
echo "REDIS_PASSWORD=${pass}"
echo "REDIS_DB=${db}"
} >> "$tmp"
mv "$tmp" "$env_file"
echo " ✓ Redis env → ${env_file#${MONOREPO_ROOT}/}"
}
write_rabbit_block() {
local env_file="$1" host="$2" port="$3" user="$4" pass="$5" vhost="$6"
[ ! -f "$env_file" ] && touch "$env_file"
local tmp="${env_file}.tmp"
grep -vE '^(# RabbitMQ|RABBITMQ_HOST=|RABBITMQ_PORT=|RABBITMQ_USER=|RABBITMQ_PASS=|RABBITMQ_VHOST=)' "$env_file" > "$tmp" || true
{
echo ""
echo "# RabbitMQ (set by redis-switch.sh $(date -Iseconds))"
echo "RABBITMQ_HOST=${host}"
echo "RABBITMQ_PORT=${port}"
echo "RABBITMQ_USER=${user}"
echo "RABBITMQ_PASS=${pass}"
echo "RABBITMQ_VHOST=${vhost}"
} >> "$tmp"
mv "$tmp" "$env_file"
echo " ✓ RabbitMQ env → ${env_file#${MONOREPO_ROOT}/}"
}
read_env() {
local env="$1" key="$2"
[ -f "$env" ] || { echo ""; return; }
grep -E "^${key}=" "$env" | tail -1 | cut -d= -f2-
}
current_targets() {
local env="${AGENT_DIR}/.env"
local rh=$(read_env "$env" REDIS_HOST)
local rp=$(read_env "$env" REDIS_PORT)
local ru=$(read_env "$env" REDIS_USERNAME)
local qh=$(read_env "$env" RABBITMQ_HOST)
local qp=$(read_env "$env" RABBITMQ_PORT)
local qv=$(read_env "$env" RABBITMQ_VHOST)
echo " Redis → ${rh:-didi-cache}:${rp:-6379} (user: ${ru:-legacy})"
echo " RabbitMQ → ${qh:-staging-dataLayer-rabbitmq}:${qp:-5672}${qv:-/}"
}
ensure_container_running() {
local name="$1" compose_dir="$2" service="$3"
if docker ps --filter "name=${name}" --filter "status=running" --format "{{.Names}}" | grep -q "${name}"; then
echo "${name} already running"
return
fi
if docker ps -a --filter "name=${name}" --format "{{.Names}}" | grep -q "${name}"; then
echo " → Starting stopped ${name}..."
docker start "${name}" > /dev/null
else
echo "${name} missing, recreating via compose..."
(cd "${compose_dir}" && docker compose up -d "${service}" 2>&1 | tail -3)
fi
}
restart_services() {
echo ""
echo "→ Restarting didi-framework..."
(cd "$FW_DIR" && docker compose up -d --force-recreate 2>&1 | tail -3)
echo "→ Restarting agent-v3 stack (API + 12 workers)..."
(cd "$AGENT_DIR" && docker compose up -d --force-recreate 2>&1 | tail -3)
echo "→ Waiting for services..."
for i in $(seq 1 30); do
if docker exec didi-framework wget -qO- http://127.0.0.1:3005/health > /dev/null 2>&1 \
&& curl -sf http://localhost:24803/api/v3/health > /dev/null 2>&1; then
echo " ✓ Both ready (${i}s)"
return
fi
sleep 1
done
echo " ⚠ Timeout waiting for health — check logs"
}
apply_redis_cluster() {
write_redis_block "${AGENT_DIR}/.env" "$CLUSTER_REDIS_HOST" "$CLUSTER_REDIS_PORT" "$CLUSTER_REDIS_USER" "$CLUSTER_REDIS_PASSWORD" "$CLUSTER_REDIS_DB"
write_redis_block "${FW_DIR}/.env" "$CLUSTER_REDIS_HOST" "$CLUSTER_REDIS_PORT" "$CLUSTER_REDIS_USER" "$CLUSTER_REDIS_PASSWORD" "$CLUSTER_REDIS_DB"
}
apply_redis_local() {
ensure_container_running "didi-cache" "$PROD_DIR" "didi-cache"
write_redis_block "${AGENT_DIR}/.env" "$LOCAL_REDIS_HOST" "$LOCAL_REDIS_PORT" "$LOCAL_REDIS_USER" "$LOCAL_REDIS_PASSWORD" "$LOCAL_REDIS_DB"
write_redis_block "${FW_DIR}/.env" "$LOCAL_REDIS_HOST" "$LOCAL_REDIS_PORT" "$LOCAL_REDIS_USER" "$LOCAL_REDIS_PASSWORD" "$LOCAL_REDIS_DB"
}
apply_rabbit_cluster() {
write_rabbit_block "${AGENT_DIR}/.env" "$CLUSTER_RABBIT_HOST" "$CLUSTER_RABBIT_PORT" "$CLUSTER_RABBIT_USER" "$CLUSTER_RABBIT_PASS" "$CLUSTER_RABBIT_VHOST"
}
apply_rabbit_local() {
ensure_container_running "staging-dataLayer-rabbitmq" "$DATA_DIR" "staging-dataLayer-rabbitmq"
write_rabbit_block "${AGENT_DIR}/.env" "$LOCAL_RABBIT_HOST" "$LOCAL_RABBIT_PORT" "$LOCAL_RABBIT_USER" "$LOCAL_RABBIT_PASS" "$LOCAL_RABBIT_VHOST"
}
# -------------------------------------------------------------------------
# Commands
# -------------------------------------------------------------------------
case "$MODE" in
status)
echo "Current active targets (from agent-v3 .env):"
current_targets
echo ""
echo "Local containers:"
docker ps -a --filter "name=didi-cache" --format " didi-cache | {{.Status}}" | head -1
docker ps -a --filter "name=staging-dataLayer-rabbitmq" --format " staging-dataLayer-rabbitmq | {{.Status}}" | head -1
echo ""
echo "Usage: $0 {cluster|local|status} [redis|rabbit|both]"
;;
cluster)
if [ -z "$CLUSTER_SHARED_PASSWORD" ]; then
echo "✘ ERROR: cluster password not set." >&2
echo " Option A: export DIDI_CLUSTER_PASSWORD=..." >&2
echo " Option B: cp ${SCRIPT_DIR}/.cluster-credentials.env.example ${SCRIPT_DIR}/.cluster-credentials.env && edit it" >&2
exit 1
fi
echo "═══ Switching to HA cluster (target: ${TARGET}) ═══"
case "$TARGET" in
both) apply_redis_cluster; apply_rabbit_cluster ;;
redis) apply_redis_cluster ;;
rabbit) apply_rabbit_cluster ;;
*) echo "Unknown target: $TARGET (use: redis, rabbit, both)"; exit 1 ;;
esac
restart_services
echo ""
echo "✓ Cluster active. Bootstrap will auto-populate Redis on startup."
;;
local)
echo "═══ Switching to LOCAL containers (target: ${TARGET}) ═══"
case "$TARGET" in
both) apply_redis_local; apply_rabbit_local ;;
redis) apply_redis_local ;;
rabbit) apply_rabbit_local ;;
*) echo "Unknown target: $TARGET (use: redis, rabbit, both)"; exit 1 ;;
esac
restart_services
echo ""
echo "✓ Local fallback active."
;;
*)
echo "Usage: $0 {cluster|local|status} [redis|rabbit|both]"
exit 1
;;
esac