Overlay-only extract left files added by the newer version behind after a rollback (2026-10-26: after rolling back ops-batch, deploy/ new scripts were still present). Before every extract, delete app-dir contents except work/ (task worktrees), then extract; backup tarballs also exclude work/, so worktrees are preserved on both deploy and rollback.
81 lines
2.5 KiB
Bash
Executable File
81 lines
2.5 KiB
Bash
Executable File
#!/bin/sh
|
||
# 回滚:VM 侧运行,把主机恢复到最近一份代码备份包并重启验证。
|
||
#
|
||
# 用法:deploy/rollback.sh <host> [user]
|
||
# host:主机 IP 或域名(必填);user:SSH 用户(默认 root)。
|
||
#
|
||
# 密码:与 deploy.sh 同款规则——绝不接受密码参数、不读 env 文件、
|
||
# 不打印任何密钥;SSH 密码由交互提示或调用方通道提供;需要代理时
|
||
# 用环境变量 SSH_PROXY_CMD 传入 ProxyCommand,未设则直连。
|
||
#
|
||
# 回滚边界:只回代码,不回数据库(理由见 deploy.sh 头注释与
|
||
# deploy/README.md:数据库迁移是只加列的幂等操作,老代码仍能读新列)。
|
||
# 备份包来自 deploy.sh 每次部署前在主机上打的
|
||
# /opt/codex-app-server-backups/codex-app-server-<时间戳>.tar.gz,
|
||
# 本脚本恢复其中最新的一份;主机上没有备份包时直接报错退出,不编造。
|
||
set -eu
|
||
|
||
HOST=${1:-}
|
||
USER_ARG=${2:-root}
|
||
if [ -z "$HOST" ]; then
|
||
echo "用法:deploy/rollback.sh <host> [user]" >&2
|
||
exit 2
|
||
fi
|
||
|
||
ssh_cmd() {
|
||
if [ -n "${SSH_PROXY_CMD:-}" ]; then
|
||
ssh -o "ProxyCommand $SSH_PROXY_CMD" -o StrictHostKeyChecking=no \
|
||
-o UserKnownHostsFile=/dev/null "$@"
|
||
else
|
||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$@"
|
||
fi
|
||
}
|
||
|
||
ssh_cmd "$USER_ARG@$HOST" 'sh -s' <<'HOST_SCRIPT'
|
||
set -eu
|
||
APP_DIR=/opt/codex-app-server
|
||
BACKUP_DIR=/opt/codex-app-server-backups
|
||
|
||
check_health() {
|
||
OUT=$(curl -s --max-time 5 http://127.0.0.1:8765/health || true)
|
||
[ -n "$OUT" ] && printf '%s' "$OUT" | python3 -c '
|
||
import json, sys
|
||
try:
|
||
d = json.load(sys.stdin)
|
||
except Exception:
|
||
sys.exit(1)
|
||
sys.exit(0 if (d.get("ok") is True and d.get("backend") == "postgres"
|
||
and d.get("db_ok") is True) else 1)
|
||
'
|
||
}
|
||
|
||
wait_health() {
|
||
i=0
|
||
while [ "$i" -lt 12 ]; do
|
||
if check_health; then return 0; fi
|
||
sleep 5
|
||
i=$((i + 1))
|
||
done
|
||
return 1
|
||
}
|
||
|
||
BACKUP_FILE=$(ls -t "$BACKUP_DIR"/codex-app-server-*.tar.gz 2>/dev/null \
|
||
| head -n 1 || true)
|
||
if [ -z "$BACKUP_FILE" ]; then
|
||
echo "主机上没有代码备份包,无法回滚:$BACKUP_DIR" >&2
|
||
exit 1
|
||
fi
|
||
echo "将恢复备份包:$BACKUP_FILE"
|
||
systemctl stop codex-cloud-worker codex-cloud-server || true
|
||
find "$APP_DIR" -mindepth 1 -maxdepth 1 ! -name work -exec rm -rf {} +
|
||
tar -xzf "$BACKUP_FILE" -C /opt
|
||
chown -R codexsvc:codexsvc "$APP_DIR"
|
||
systemctl start codex-cloud-server codex-cloud-worker
|
||
if wait_health; then
|
||
echo "回滚成功,health 通过,当前代码为备份包:$BACKUP_FILE"
|
||
exit 0
|
||
fi
|
||
echo "回滚后 health 仍失败,需人工介入" >&2
|
||
exit 1
|
||
HOST_SCRIPT
|