160 lines
4.4 KiB
Bash
160 lines
4.4 KiB
Bash
#!/bin/bash
|
||
# ============================================================
|
||
# config-protector.sh — 配置保护器
|
||
# 作用:在每次修改配置前自动备份
|
||
# 修改后健康检查失败 → 自动回滚
|
||
# 成功 → 标记为新的稳定点
|
||
# 由 health-watchdog.sh 联动触发
|
||
# 也支持手动调用:config-protector.sh [snapshot|rollback|status]
|
||
# ============================================================
|
||
set -e
|
||
|
||
CONFIG_DIR="$HOME/.hermes"
|
||
LOG="$HOME/.hermes/watchdog/config-protector.log"
|
||
mkdir -p "$(dirname "$LOG")"
|
||
|
||
log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; }
|
||
|
||
# === 快照:记录当前配置状态 ===
|
||
snapshot() {
|
||
cd "$CONFIG_DIR"
|
||
|
||
# 检查是否有未提交的变更
|
||
if git diff --quiet && git diff --cached --quiet; then
|
||
log "✅ 配置无变更,无需快照"
|
||
return 0
|
||
fi
|
||
|
||
# 有变更 → 自动 commit
|
||
git add -A 2>/dev/null
|
||
local changed=$(git diff --cached --name-only | head -5)
|
||
git commit -m "auto-snapshot $(date '+%Y-%m-%d %H:%M:%S')" 2>&1 | tail -1 | log
|
||
|
||
log "📸 快照已保存(变更文件:${changed:-无描述})"
|
||
|
||
# 标记最近配置
|
||
git tag -f last-config 2>/dev/null
|
||
|
||
return 0
|
||
}
|
||
|
||
# === 回滚:恢复到上次稳定点 ===
|
||
rollback() {
|
||
cd "$CONFIG_DIR"
|
||
|
||
local target="${1:-stable}"
|
||
|
||
if ! git rev-parse --verify "$target" 2>/dev/null; then
|
||
log "❌ 回滚目标 '$target' 不存在"
|
||
return 1
|
||
fi
|
||
|
||
log "⚠️ 开始回滚到 $target..."
|
||
|
||
# 保存当前状态(回滚前的状态,用于诊断)
|
||
git stash 2>/dev/null || true
|
||
|
||
# 硬重置到目标
|
||
git checkout --force "$target" 2>&1 | log
|
||
|
||
log "✅ 已回滚到 $target"
|
||
log "📋 受影响文件:$(git diff --name-only HEAD~1..HEAD 2>/dev/null | head -10 || echo '首次回滚')"
|
||
|
||
# 创建回滚事件记录
|
||
echo "$(date '+%Y-%m-%dT%H:%M:%S')|rollback|$target" >> "$CONFIG_DIR/watchdog/rollback-history.txt"
|
||
|
||
return 0
|
||
}
|
||
|
||
# === 标记当前为稳定 ===
|
||
mark_stable() {
|
||
cd "$CONFIG_DIR"
|
||
local tag="stable-$(date '+%Y%m%d-%H%M%S')"
|
||
git tag -f "$tag" 2>/dev/null
|
||
git tag -f stable 2>/dev/null
|
||
log "⭐ 已标记 $tag 为稳定点"
|
||
return 0
|
||
}
|
||
|
||
# === 状态:显示配置保护和最近变更 ===
|
||
status() {
|
||
cd "$CONFIG_DIR"
|
||
echo "=== 配置保护状态 ==="
|
||
echo "仓库: $CONFIG_DIR/.git"
|
||
echo "最近提交:"
|
||
git log --oneline -5 2>/dev/null || echo " (无提交)"
|
||
echo ""
|
||
echo "未跟踪文件:"
|
||
git status --short 2>/dev/null | head -10 || echo " 全部已跟踪"
|
||
echo ""
|
||
echo "稳定标签:"
|
||
git tag -l 'stable-*' | sort -r | head -5 2>/dev/null || echo " (无)"
|
||
echo ""
|
||
if [ -f "$CONFIG_DIR/watchdog/rollback-history.txt" ]; then
|
||
echo "回滚历史:"
|
||
tail -3 "$CONFIG_DIR/watchdog/rollback-history.txt"
|
||
fi
|
||
}
|
||
|
||
# === 与看门狗联动:健康检测失败时自动回滚 ===
|
||
auto_rollback_if_unhealthy() {
|
||
# 由 watchdog 调用,检测上次变更后系统是否正常
|
||
cd "$CONFIG_DIR"
|
||
|
||
# 检查最近是否有配置变更(30分钟内)
|
||
local last_change=$(git log --oneline -1 --format="%ct" HEAD 2>/dev/null || echo 0)
|
||
local now=$(date +%s)
|
||
local age=$(( (now - last_change) / 60 ))
|
||
|
||
if [ "$age" -gt 30 ]; then
|
||
# 上次变更超过30分钟,不触发自动回滚
|
||
return 0
|
||
fi
|
||
|
||
# 检查关键进程
|
||
local dead=""
|
||
for p in zhiyid-new new-api hermes bge_embed_server; do
|
||
if ! pgrep -f "$p" > /dev/null 2>&1; then
|
||
dead="$dead $p"
|
||
fi
|
||
done
|
||
|
||
if [ -n "$dead" ]; then
|
||
log "🚨 检测到自动回滚条件:最近配置变更后进程挂了($dead)"
|
||
log "🔙 自动回滚中..."
|
||
rollback "stable"
|
||
log "🔄 回滚完成,重启服务..."
|
||
|
||
# 重启关键服务
|
||
systemctl --user restart zhiyid.service bge-embed.service new-api.service 2>/dev/null || true
|
||
sleep 5
|
||
|
||
log "✅ 回滚自愈完成"
|
||
return 0
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# === 主入口 ===
|
||
case "${1:-snapshot}" in
|
||
snapshot)
|
||
snapshot
|
||
;;
|
||
rollback)
|
||
rollback "$2"
|
||
;;
|
||
mark-stable)
|
||
mark_stable
|
||
;;
|
||
status)
|
||
status
|
||
;;
|
||
auto-heal)
|
||
auto_rollback_if_unhealthy
|
||
;;
|
||
*)
|
||
echo "用法: config-protector.sh [snapshot|rollback <tag>|mark-stable|status|auto-heal]"
|
||
;;
|
||
esac
|