Consolidate approved policies and add local lease, document CAS, commit, candidate and environment gates. Preserve conservative recovery and cleanup limits.
225 lines
8.0 KiB
Bash
Executable File
225 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Chat-Agent-System 多环境与服务管理脚本 (env-service.sh)
|
|
#
|
|
# 支持环境:
|
|
# shared : 共享知识库基础设施 (pgvector / regulations-db)
|
|
# dev : 开发环境服务 (端口 8080, DB 5433, 数据隔离 ./data/dev)
|
|
# test : 测试环境服务 (端口 8081, DB 5434, 数据隔离 ./data/test)
|
|
# main : 生产环境服务 (端口 8000, DB 5435, 数据隔离 ./data/main)
|
|
# all : 所有环境
|
|
#
|
|
# 支持命令: start | stop | restart | rebuild | status | ps | logs | down
|
|
# =============================================================================
|
|
|
|
set -eo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
ENV_TARGET="${1:-}"
|
|
ACTION="${2:-}"
|
|
|
|
show_usage() {
|
|
cat <<EOF
|
|
用法:
|
|
$0 <shared|dev|test|main|all> <start|stop|restart|rebuild|status|ps|logs|down>
|
|
|
|
示例:
|
|
$0 shared start # 启动共享知识库基础服务
|
|
$0 dev start # 启动开发分支环境
|
|
$0 dev rebuild # 重建镜像并重建容器(合入代码后使用)
|
|
$0 test start # 启动测试分支环境
|
|
$0 main start # 启动主分支生产环境
|
|
$0 all status # 查看所有环境服务状态
|
|
$0 dev logs # 查看开发环境日志
|
|
$0 dev stop # 停止开发环境
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
if [[ -z "${ENV_TARGET}" || -z "${ACTION}" ]]; then
|
|
show_usage
|
|
fi
|
|
|
|
# Reject invalid requests and unauthorized writes before configuration, storage,
|
|
# network or Docker operations. The guard verifies the live supervisor lease.
|
|
case "${ENV_TARGET}" in
|
|
shared|dev|test|main|all) ;;
|
|
*) show_usage ;;
|
|
esac
|
|
case "${ACTION}" in
|
|
status|ps|logs) ;;
|
|
start|stop|restart|rebuild|down)
|
|
python3 "${SCRIPT_DIR}/agentctl.py" guard env --target "${ENV_TARGET}"
|
|
python3 "${SCRIPT_DIR}/agentctl.py" --repo "${ROOT_DIR}" guard env --target "${ENV_TARGET}"
|
|
;;
|
|
*) show_usage ;;
|
|
esac
|
|
cd "${ROOT_DIR}"
|
|
|
|
# 确保环境变量配置文件与存储目录存在
|
|
prepare_env_file() {
|
|
local target="$1"
|
|
local env_file="configs/.env.${target}"
|
|
local env_example="configs/.env.${target}.example"
|
|
|
|
if [[ ! -f "${env_file}" ]]; then
|
|
if [[ -f "${env_example}" ]]; then
|
|
echo "[提示] 配置文件 ${env_file} 不存在,正在从 ${env_example} 自动初始化..."
|
|
cp "${env_example}" "${env_file}"
|
|
fi
|
|
fi
|
|
|
|
# 确保隔离数据目录存在
|
|
# 确保隔离数据目录与法规目录存在
|
|
if [[ "${target}" == "shared" ]]; then
|
|
mkdir -p "data/shared/kb"
|
|
mkdir -p ".regulations/intake" ".regulations/library" ".regulations/quarantine" ".regulations/work"
|
|
else
|
|
mkdir -p "data/${target}/workspaces"
|
|
fi
|
|
}
|
|
|
|
# 确保 Docker 共享网络已创建
|
|
ensure_shared_network() {
|
|
if ! docker network ls --format '{{.Name}}' | grep -q '^chat-agent-shared-net$'; then
|
|
echo "[网络] 创建共享基础设施 Docker 网络: chat-agent-shared-net..."
|
|
docker network create chat-agent-shared-net >/dev/null 2>&1 || true
|
|
fi
|
|
}
|
|
|
|
run_compose() {
|
|
local target="$1"
|
|
local act="$2"
|
|
local compose_file="docker-compose.${target}.yml"
|
|
local env_file="configs/.env.${target}"
|
|
|
|
if [[ ! -f "${compose_file}" ]]; then
|
|
echo "[错误] 找不到编排文件: ${compose_file}"
|
|
exit 1
|
|
fi
|
|
|
|
# status/ps/logs 为只读查询,不隐式创建配置或数据目录
|
|
if [[ "${act}" != "status" && "${act}" != "ps" && "${act}" != "logs" ]]; then
|
|
prepare_env_file "${target}"
|
|
fi
|
|
|
|
local env_args=()
|
|
# 根 .env 提供跨环境共用的模型、检索与认证配置;环境文件仅覆盖端口、
|
|
# 数据库和其他环境差异。后声明的 env-file 优先级更高。
|
|
if [[ -f ".env" ]]; then
|
|
env_args+=(--env-file ".env")
|
|
fi
|
|
if [[ -f "${env_file}" ]]; then
|
|
env_args+=(--env-file "${env_file}")
|
|
fi
|
|
# Wave 2C: optional pinned image digests from candidate-images-apply.sh
|
|
local images_file="configs/.env.${target}.images"
|
|
local pinned=0
|
|
if [[ -f "${images_file}" ]]; then
|
|
env_args+=(--env-file "${images_file}")
|
|
if grep -q '^PINNED_IMAGE_MODE=1' "${images_file}" 2>/dev/null; then
|
|
pinned=1
|
|
fi
|
|
fi
|
|
|
|
case "${act}" in
|
|
start)
|
|
ensure_shared_network
|
|
echo "==> [${target}] 启动服务 (${compose_file})..."
|
|
if [[ "${pinned}" -eq 1 && ( "${target}" == "test" || "${target}" == "main" ) ]]; then
|
|
echo "==> [${target}] pinned image mode: up -d --no-build"
|
|
docker compose -f "${compose_file}" "${env_args[@]}" up -d --no-build
|
|
else
|
|
docker compose -f "${compose_file}" "${env_args[@]}" up -d
|
|
fi
|
|
echo "==> [${target}] 服务已启动"
|
|
;;
|
|
stop)
|
|
echo "==> [${target}] 停止服务..."
|
|
docker compose -f "${compose_file}" "${env_args[@]}" stop
|
|
;;
|
|
restart)
|
|
ensure_shared_network
|
|
echo "==> [${target}] 重启现有容器(不会重建镜像)..."
|
|
docker compose -f "${compose_file}" "${env_args[@]}" restart
|
|
;;
|
|
rebuild)
|
|
ensure_shared_network
|
|
if [[ "${pinned}" -eq 1 && ( "${target}" == "test" || "${target}" == "main" ) ]]; then
|
|
echo "==> [${target}] pinned image mode: recreate from pinned digests (refusing docker build)"
|
|
docker compose -f "${compose_file}" "${env_args[@]}" up -d --no-build --force-recreate
|
|
echo "==> [${target}] 已按 pin 重建容器(未重新 build 镜像)"
|
|
else
|
|
echo "==> [${target}] 重建镜像并重建容器..."
|
|
docker compose -f "${compose_file}" "${env_args[@]}" up -d --build
|
|
echo "==> [${target}] 镜像与容器已更新"
|
|
fi
|
|
;;
|
|
status|ps)
|
|
echo "------------------------------------------------------------"
|
|
echo "环境: [${target}] (编排: ${compose_file})"
|
|
if [[ "${pinned}" -eq 1 ]]; then
|
|
echo "image pin: ${images_file}"
|
|
fi
|
|
echo "------------------------------------------------------------"
|
|
docker compose -f "${compose_file}" "${env_args[@]}" ps
|
|
echo ""
|
|
;;
|
|
logs)
|
|
docker compose -f "${compose_file}" "${env_args[@]}" logs -f --tail=100
|
|
;;
|
|
down)
|
|
echo "==> [${target}] 清理并下线容器..."
|
|
docker compose -f "${compose_file}" "${env_args[@]}" down
|
|
;;
|
|
*)
|
|
echo "[错误] 未知操作: ${act}"
|
|
show_usage
|
|
;;
|
|
esac
|
|
}
|
|
|
|
case "${ENV_TARGET}" in
|
|
shared|dev|test|main)
|
|
run_compose "${ENV_TARGET}" "${ACTION}"
|
|
;;
|
|
all)
|
|
case "${ACTION}" in
|
|
start)
|
|
run_compose "shared" "start"
|
|
run_compose "dev" "start"
|
|
run_compose "test" "start"
|
|
run_compose "main" "start"
|
|
;;
|
|
stop|down)
|
|
run_compose "dev" "${ACTION}"
|
|
run_compose "test" "${ACTION}"
|
|
run_compose "main" "${ACTION}"
|
|
run_compose "shared" "${ACTION}"
|
|
;;
|
|
status|ps)
|
|
run_compose "shared" "status"
|
|
run_compose "dev" "status"
|
|
run_compose "test" "status"
|
|
run_compose "main" "status"
|
|
;;
|
|
rebuild)
|
|
run_compose "shared" "rebuild"
|
|
run_compose "dev" "rebuild"
|
|
run_compose "test" "rebuild"
|
|
run_compose "main" "rebuild"
|
|
;;
|
|
*)
|
|
echo "[错误] 'all' 仅支持 start | stop | down | rebuild | status 操作"
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
echo "[错误] 未知环境目标: ${ENV_TARGET}"
|
|
show_usage
|
|
;;
|
|
esac
|