Files
easyai-ai-gateway/scripts/deploy-production-release.sh
T
wangbo e05922b0f4 feat(acceptance): 建立同构验收与弹性容量体系
实现本地三节点 K3s 同构环境、脱敏生产快照、Gemini 图片和多参考图视频协议模拟、统一验收报告及故障注入。\n\n新增 Worker 容量控制器、资源与连接预算、任务恢复保护,并将生产验收拆分为 validation 执行和人工 CAS 放量。\n\n验证包括 Go 全量测试、PostgreSQL HTTP 集成测试、go vet、OpenAPI、ShellCheck、前端检查、迁移及发布脚本测试。
2026-07-31 18:02:24 +08:00

123 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
production_host=${AI_GATEWAY_PRODUCTION_HOST:-root@110.42.51.33}
deploy_mode=${AI_GATEWAY_DEPLOY_MODE:-compose}
case $deploy_mode in
compose) default_remote_helper=/usr/local/sbin/easyai-ai-gateway-release ;;
kubernetes) default_remote_helper=/usr/local/sbin/easyai-ai-gateway-cluster-release ;;
*) echo 'AI_GATEWAY_DEPLOY_MODE must be compose or kubernetes' >&2; exit 1 ;;
esac
remote_helper=${AI_GATEWAY_REMOTE_RELEASE_HELPER:-$default_remote_helper}
production_ssh_key=${AI_GATEWAY_PRODUCTION_SSH_KEY:-}
action=deploy
value=
usage() {
cat <<'EOF'
Usage:
scripts/deploy-production-release.sh dist/releases/<git-sha>.json
scripts/deploy-production-release.sh --rollback <historical-git-sha>
scripts/deploy-production-release.sh --status
This command changes production. Run it only after a successful publish
command and an explicit user request to release or deploy to production.
EOF
}
case ${1:-} in
--status)
action=status
[[ $# -eq 1 ]] || { usage >&2; exit 64; }
;;
--rollback)
action=rollback
[[ $# -eq 2 ]] || { usage >&2; exit 64; }
value=$2
;;
-h|--help|'')
usage
[[ ${1:-} == -h || ${1:-} == --help ]] && exit 0
exit 64
;;
*)
[[ $# -eq 1 ]] || { usage >&2; exit 64; }
value=$1
;;
esac
[[ $production_host =~ ^[A-Za-z0-9._-]+@[A-Za-z0-9.-]+$ ]] || {
echo 'AI_GATEWAY_PRODUCTION_HOST must use user@host syntax' >&2
exit 1
}
[[ $remote_helper =~ ^/[A-Za-z0-9._/-]+$ ]] || {
echo 'AI_GATEWAY_REMOTE_RELEASE_HELPER must be an absolute safe path' >&2
exit 1
}
ssh_options=(-o BatchMode=yes)
scp_options=(-q -o BatchMode=yes)
if [[ -n $production_ssh_key ]]; then
[[ $production_ssh_key == /* && -f $production_ssh_key && ! -L $production_ssh_key ]] || {
echo 'AI_GATEWAY_PRODUCTION_SSH_KEY must be an absolute regular file' >&2
exit 1
}
ssh_options+=(-i "$production_ssh_key")
scp_options+=(-i "$production_ssh_key")
fi
if [[ $action == status ]]; then
exec ssh "${ssh_options[@]}" "$production_host" "$remote_helper status"
fi
if [[ $action == rollback ]]; then
[[ $value =~ ^[0-9a-f]{40}$ ]] || {
echo 'rollback release must be a full lowercase Git SHA' >&2
exit 1
}
# shellcheck disable=SC2029 # Both arguments are validated safe tokens above.
ssh "${ssh_options[@]}" "$production_host" "$remote_helper" rollback "$value"
echo "production_rollback=PASS release=$value"
exit 0
fi
manifest=$(cd "$(dirname "$value")" 2>/dev/null && pwd)/$(basename "$value")
[[ -f $manifest && ! -L $manifest ]] || {
echo 'release manifest must be a regular file' >&2
exit 1
}
node "$root/scripts/release-manifest.mjs" validate "$manifest"
source_sha=$(node "$root/scripts/release-manifest.mjs" get "$manifest" sourceSha)
base_sha=$(node "$root/scripts/release-manifest.mjs" get "$manifest" baseReleaseSha)
remote_manifest=/tmp/easyai-ai-gateway-release-$source_sha.json
status_file=$(mktemp)
cleanup() {
rm -f "$status_file"
ssh "${ssh_options[@]}" "$production_host" rm -f -- "$remote_manifest" >/dev/null 2>&1 || true
}
trap cleanup EXIT HUP INT TERM
if ssh "${ssh_options[@]}" "$production_host" "$remote_helper" status >"$status_file" 2>/dev/null; then
node "$root/scripts/release-manifest.mjs" validate "$status_file" >/dev/null
current_sha=$(node "$root/scripts/release-manifest.mjs" get "$status_file" sourceSha)
[[ $current_sha == "$base_sha" ]] || {
printf 'production base changed after publish: current=%s manifest_base=%s\n' \
"$current_sha" "$base_sha" >&2
exit 1
}
else
[[ -z $base_sha ]] || {
echo 'production release status is unavailable for a non-bootstrap manifest' >&2
exit 1
}
fi
scp "${scp_options[@]}" "$manifest" "$production_host:$remote_manifest"
if [[ $deploy_mode == kubernetes ]]; then
"$root/scripts/cluster/install-release-helper.sh"
fi
# shellcheck disable=SC2029 # remote_manifest is derived from a validated full SHA.
ssh "${ssh_options[@]}" "$production_host" "$remote_helper" deploy "$remote_manifest"
echo "production_deploy=PASS release=$source_sha"