提交 420f5c98 authored 作者: 陈泽健's avatar 陈泽健

feat(service-health): 所有修复项执行前增加用户确认交互,默认不自动修复

- check_server_health.ps1: 对外服务修复(新/传统平台)增加 Read-Host 确认
- check_server_health.sh: 新增 confirm_repair 函数,DNS/NTP/Redis/Emqx/Console 修复项增加确认
- DNSCheck.psm1: DNS修复增加确认交互
- NTPCheck.psm1: NTP修复增加确认交互
- ServerResourceAnalysis.psm1: 防火墙修复增加确认交互
- ContainerCheck.psm1: Redis修复增加高风险确认(需输入 yes)
- ServiceCheck.psm1: 对外服务修复增加确认交互

支持 AUTO_REPAIR=yes 环境变量跳过确认用于无人值守场景
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 0da15710
...@@ -523,8 +523,17 @@ function Main { ...@@ -523,8 +523,17 @@ function Main {
} }
if ($extSvc -and -not $extSvc.Running) { if ($extSvc -and -not $extSvc.Running) {
Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行,准备执行远程修复 (fix_external_service_disconnect)" Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行"
Write-Host " 检测到对外服务进程未运行,是否执行远程修复?" -ForegroundColor Yellow
$repairChoice = Read-Host " 执行修复? (y/n) [默认: n]"
if ($repairChoice -eq "y" -or $repairChoice -eq "Y") {
Write-Log -Level "INFO" -Message "[EXT] 用户确认执行远程修复 (fix_external_service_disconnect)"
$global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server $global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server
} else {
Write-Log -Level "INFO" -Message "[EXT] 用户取消修复操作,跳过"
$global:ExternalServiceRepairResult = @{ Status = "SKIPPED"; Message = "用户取消修复" }
}
} }
} }
} }
...@@ -571,8 +580,17 @@ function Main { ...@@ -571,8 +580,17 @@ function Main {
} }
if ($extSvc -and -not $extSvc.Running) { if ($extSvc -and -not $extSvc.Running) {
Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行,准备执行远程修复 (fix_external_service_disconnect)" Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行"
Write-Host " 检测到对外服务进程未运行,是否执行远程修复?" -ForegroundColor Yellow
$repairChoice = Read-Host " 执行修复? (y/n) [默认: n]"
if ($repairChoice -eq "y" -or $repairChoice -eq "Y") {
Write-Log -Level "INFO" -Message "[EXT] 用户确认执行远程修复 (fix_external_service_disconnect)"
$global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server $global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server
} else {
Write-Log -Level "INFO" -Message "[EXT] 用户取消修复操作,跳过"
$global:ExternalServiceRepairResult = @{ Status = "SKIPPED"; Message = "用户取消修复" }
}
} }
} }
......
...@@ -133,37 +133,85 @@ get_primary_ip() { ...@@ -133,37 +133,85 @@ get_primary_ip() {
# 执行修复脚本:同目录 issue_handler.sh # 执行修复脚本:同目录 issue_handler.sh
run_issue_handler() { run_issue_handler() {
local action="$1" local action=$1
local platform="${2:-auto}" local platform=${2:-auto}
local extra="${3:-}" local extra=${3:-}
local issue="$SCRIPT_DIR/issue_handler.sh" local issue=$SCRIPT_DIR/issue_handler.sh”
if [[ ! -f "$issue" ]]; then if [[ ! -f $issue ]]; then
log ERROR "[修复] 未找到 issue_handler.sh:$issue" log ERROR “[修复] 未找到 issue_handler.sh:$issue
return 1 return 1
fi fi
chmod +x "$issue" 2>/dev/null || true chmod +x $issue 2>/dev/null || true
# dos2unix 可选 # dos2unix 可选
if command_exists dos2unix; then if command_exists dos2unix; then
dos2unix "$issue" >/dev/null 2>&1 || true dos2unix $issue >/dev/null 2>&1 || true
fi fi
local cmd="$issue --action $action --platform $platform $extra" local cmd=$issue --action $action --platform $platform $extra
log WARN "[修复] 执行:$cmd" log WARN “[修复] 执行:$cmd
# ❌ 不要再把输出单独重定向到 $LOG_FILE # ❌ 不要再把输出单独重定向到 $LOG_FILE
# ✅ 由脚本开头的 exec+tee 统一实现实时打印 + 写日志” # ✅ 由脚本开头的 exec+tee 统一实现实时打印 + 写日志”
if bash -c "$cmd"; then if bash -c $cmd; then
log SUCCESS "[修复] 执行成功:$action" log SUCCESS “[修复] 执行成功:$action
return 0 return 0
else else
log ERROR "[修复] 执行失败:$action(详见日志:$LOG_FILE)" log ERROR “[修复] 执行失败:$action(详见日志:$LOG_FILE)”
return 1 return 1
fi fi
} }
# ------------------------------
# 用户确认修复操作
# 用途:在所有修复项执行前要求用户明确确认
# 参数:
# $1 - 修复项名称(如 “DNS配置修复”)
# $2 - 修复详情描述(可选)
# 返回:
# 0 - 用户确认执行修复
# 1 - 用户取消修复
# 说明:
# - 支持环境变量 AUTO_REPAIR=yes 跳过确认(用于无人值守场景)
# - 确认结果会记录到日志中
# ------------------------------
confirm_repair() {
local repair_name=$1
local detail_msg=${2:-}
# 自动模式:通过环境变量 AUTO_REPAIR=yes 跳过确认
if [[${AUTO_REPAIR:-no}== “yes” ]]; then
log WARN “[确认] 自动修复模式已启用,自动执行: $repair_name
return 0
fi
# 显示确认提示
log WARN “┌──────────────────────────────────────────────────────────────”
log WARN “│ [修复确认] $repair_name
if [[ -n$detail_msg]]; then
log WARN “│ 详情: $detail_msg
fi
log WARN “│ ⚠ 注意: 修复操作可能修改系统配置,请确认后执行”
log WARN “└──────────────────────────────────────────────────────────────”
echo -n “ 是否执行以上修复? (y/N): “
local response
read response
case$responsein
[yY][eE][sS]|[yY])
log INFO “[确认] 用户确认执行修复: $repair_name
return 0
;;
*)
log INFO “[确认] 用户取消修复: $repair_name
return 1
;;
esac
}
# ------------------------------ # ------------------------------
# 1) 平台识别 # 1) 平台识别
# ------------------------------ # ------------------------------
...@@ -562,7 +610,11 @@ repair_dns_if_needed() { ...@@ -562,7 +610,11 @@ repair_dns_if_needed() {
if [[ "$status" == "OK" ]]; then if [[ "$status" == "OK" ]]; then
return 0 return 0
fi fi
log WARN "[DNS] 检测到 DNS 异常($status),触发修复:fix_dns_config"
log WARN "[DNS] 检测到 DNS 异常($status)"
# ✅ 增加用户确认交互
if confirm_repair "DNS配置修复" "将执行 fix_dns_config 修复DNS配置(可能修改 /etc/resolv.conf)"; then
run_issue_handler "fix_dns_config" "auto" "--non-interactive --yes" || true run_issue_handler "fix_dns_config" "auto" "--non-interactive --yes" || true
log INFO "[DNS] 修复后复检..." log INFO "[DNS] 修复后复检..."
...@@ -575,6 +627,10 @@ repair_dns_if_needed() { ...@@ -575,6 +627,10 @@ repair_dns_if_needed() {
else else
log WARN "[DNS] 复检仍异常:$post(需人工排查)" log WARN "[DNS] 复检仍异常:$post(需人工排查)"
fi fi
else
log INFO "[DNS] 用户取消修复,跳过"
report_kv_set "dns.repair" "SKIPPED"
fi
} }
# ------------------------------ # ------------------------------
...@@ -884,7 +940,11 @@ repair_ntp_if_needed() { ...@@ -884,7 +940,11 @@ repair_ntp_if_needed() {
if [[ "$status" == "OK" ]]; then if [[ "$status" == "OK" ]]; then
return 0 return 0
fi fi
log WARN "[NTP] 状态=$status,触发修复:fix_ntp_config"
log WARN "[NTP] 状态=$status"
# ✅ 增加用户确认交互
if confirm_repair "NTP配置修复" "将执行 fix_ntp_config 修复NTP服务配置(可能修改 chrony/ntp 配置文件并重启服务)"; then
run_issue_handler "fix_ntp_config" "auto" "--ntp-auto" || true run_issue_handler "fix_ntp_config" "auto" "--ntp-auto" || true
log INFO "[NTP] 修复后复检..." log INFO "[NTP] 修复后复检..."
...@@ -895,7 +955,13 @@ repair_ntp_if_needed() { ...@@ -895,7 +955,13 @@ repair_ntp_if_needed() {
if [[ "$post" == "OK" ]]; then if [[ "$post" == "OK" ]]; then
log SUCCESS "[NTP] 复检成功:已恢复正常" log SUCCESS "[NTP] 复检成功:已恢复正常"
else else
log WARN "[NTP] 复检仍异常:$post" log WARN "[NTP] 复检仍异常:$post(需人工排查)"
fi
else
log INFO "[NTP] 用户取消修复,跳过"
report_kv_set "ntp.repair" "SKIPPED"
fi
}
fi fi
} }
...@@ -1079,9 +1145,13 @@ collect_container_info() { ...@@ -1079,9 +1145,13 @@ collect_container_info() {
report_kv_set "redis.uredis_stopped" "$uredis_stopped" report_kv_set "redis.uredis_stopped" "$uredis_stopped"
if [[ "$uredis_running" -eq 0 && "$uredis_stopped" -eq 1 && "$redis_running" -eq 0 ]]; then if [[ "$uredis_running" -eq 0 && "$uredis_stopped" -eq 1 && "$redis_running" -eq 0 ]]; then
log ERROR "[Redis] 判定 Redis 容器异常:uredis 未运行且无其他 redis 容器运行,触发修复" log ERROR "[Redis] 判定 Redis 容器异常:uredis 未运行且无其他 redis 容器运行"
report_kv_set "redis.exception" "true" report_kv_set "redis.exception" "true"
# ✅ 增加用户确认交互(Redis修复涉及清空数据,必须明确确认)
if confirm_repair "Redis容器修复" "⚠ 高风险操作:将执行 redis_container_exception 修复Redis容器(可能清空数据目录)"; then
run_issue_handler "redis_container_exception" "auto" "--non-interactive --yes" || true run_issue_handler "redis_container_exception" "auto" "--non-interactive --yes" || true
if docker ps --format '{{.Names}}' | grep -w uredis >/dev/null 2>&1; then if docker ps --format '{{.Names}}' | grep -w uredis >/dev/null 2>&1; then
log SUCCESS "[Redis] 复检成功:uredis 已运行" log SUCCESS "[Redis] 复检成功:uredis 已运行"
report_kv_set "redis.recheck" "OK" report_kv_set "redis.recheck" "OK"
...@@ -1089,6 +1159,10 @@ collect_container_info() { ...@@ -1089,6 +1159,10 @@ collect_container_info() {
log WARN "[Redis] 复检失败:uredis 仍未运行(需人工排查)" log WARN "[Redis] 复检失败:uredis 仍未运行(需人工排查)"
report_kv_set "redis.recheck" "FAIL" report_kv_set "redis.recheck" "FAIL"
fi fi
else
log INFO "[Redis] 用户取消修复,跳过(Redis容器异常未处理)"
report_kv_set "redis.repair" "SKIPPED"
fi
else else
log INFO "[Redis] 未检测到需要自动修复的 Redis 容器异常" log INFO "[Redis] 未检测到需要自动修复的 Redis 容器异常"
report_kv_set "redis.exception" "false" report_kv_set "redis.exception" "false"
...@@ -1521,6 +1595,9 @@ test_config_console() { ...@@ -1521,6 +1595,9 @@ test_config_console() {
local fixed_files=() local fixed_files=()
local error_files=() local error_files=()
# ✅ 新增:用户确认标志(首次发现时询问,后续使用同一决策)
local CONSOLE_REPAIR_CONFIRMED="pending"
# console配置的正则表达式(匹配console后跟:或=,然后是true) # console配置的正则表达式(匹配console后跟:或=,然后是true)
local console_re='console[[:space:]]*[:=][[:space:]]*true' local console_re='console[[:space:]]*[:=][[:space:]]*true'
...@@ -1563,6 +1640,19 @@ test_config_console() { ...@@ -1563,6 +1640,19 @@ test_config_console() {
if [[ "$has_console_true" -eq 1 ]]; then if [[ "$has_console_true" -eq 1 ]]; then
log INFO "[CONSOLE] 发现console=true: $f" log INFO "[CONSOLE] 发现console=true: $f"
# ✅ 首次发现console=true时,询问用户是否修复
if [[ "$CONSOLE_REPAIR_CONFIRMED" == "pending" ]]; then
if confirm_repair "Console配置修复" "将把所有配置文件中的 console=true 改为 console=false(会自动备份原文件为 .bak)"; then
CONSOLE_REPAIR_CONFIRMED="yes"
else
CONSOLE_REPAIR_CONFIRMED="no"
log INFO "[CONSOLE] 用户取消修复,跳过所有console配置修复"
break
fi
fi
# ✅ 用户确认后才执行修复
if [[ "$CONSOLE_REPAIR_CONFIRMED" == "yes" ]]; then
# 备份文件 # 备份文件
local backup_file="${f}.bak" local backup_file="${f}.bak"
if cp "$f" "$backup_file" 2>/dev/null; then if cp "$f" "$backup_file" 2>/dev/null; then
...@@ -1582,6 +1672,7 @@ test_config_console() { ...@@ -1582,6 +1672,7 @@ test_config_console() {
error_files+=("$f") error_files+=("$f")
fi fi
fi fi
fi
done < <($list_cmd) done < <($list_cmd)
report_kv_set "console.total_files" "$total_files" report_kv_set "console.total_files" "$total_files"
...@@ -1721,8 +1812,11 @@ check_emqx_container_exception() { ...@@ -1721,8 +1812,11 @@ check_emqx_container_exception() {
done <<<"$stopped_txt" done <<<"$stopped_txt"
if [[ "$uemqx_running" -eq 0 && "$uemqx_stopped" -eq 1 && "$has_emqx_running" -eq 0 ]]; then if [[ "$uemqx_running" -eq 0 && "$uemqx_stopped" -eq 1 && "$has_emqx_running" -eq 0 ]]; then
log ERROR "[Emqx] 判定 Emqx 容器异常:uemqx 未运行且无其他 emqx 容器运行,触发修复" log ERROR "[Emqx] 判定 Emqx 容器异常:uemqx 未运行且无其他 emqx 容器运行"
report_kv_set "emqx.exception" "true" report_kv_set "emqx.exception" "true"
# ✅ 增加用户确认交互
if confirm_repair "Emqx容器修复" "将执行 emqx_container_exception 修复Emqx容器"; then
run_issue_handler "emqx_container_exception" "auto" "--non-interactive --yes" || true run_issue_handler "emqx_container_exception" "auto" "--non-interactive --yes" || true
if docker ps --format '{{.Names}}' | grep -w uemqx >/dev/null 2>&1; then if docker ps --format '{{.Names}}' | grep -w uemqx >/dev/null 2>&1; then
...@@ -1732,6 +1826,14 @@ check_emqx_container_exception() { ...@@ -1732,6 +1826,14 @@ check_emqx_container_exception() {
log WARN "[Emqx] 复检失败:uemqx 仍未运行(需人工排查)" log WARN "[Emqx] 复检失败:uemqx 仍未运行(需人工排查)"
report_kv_set "emqx.recheck" "FAIL" report_kv_set "emqx.recheck" "FAIL"
fi fi
else
log INFO "[Emqx] 用户取消修复,跳过(Emqx容器异常未处理)"
report_kv_set "emqx.repair" "SKIPPED"
fi
else
log WARN "[Emqx] 复检失败:uemqx 仍未运行(需人工排查)"
report_kv_set "emqx.recheck" "FAIL"
fi
else else
log INFO "[Emqx] 未检测到需要自动修复的 Emqx 容器异常" log INFO "[Emqx] 未检测到需要自动修复的 Emqx 容器异常"
report_kv_set "emqx.exception" "false" report_kv_set "emqx.exception" "false"
......
...@@ -373,8 +373,18 @@ function Test-ContainerInformation { ...@@ -373,8 +373,18 @@ function Test-ContainerInformation {
} }
} }
if ($redisNeedRepair) { if ($redisNeedRepair) {
Write-Log -Level "ERROR" -Message "[Redis] 检测到 Redis 容器异常:uredis 未运行,且无其他 redis 命名容器运行,开始执行远端修复" Write-Log -Level "ERROR" -Message "[Redis] 检测到 Redis 容器异常:uredis 未运行,且无其他 redis 命名容器运行"
Write-Host "===========================================" -ForegroundColor Red
Write-Host " ** 高风险操作警告 **" -ForegroundColor Red -BackgroundColor Black
Write-Host " 即将清空 Redis 数据目录 (/usr/local/uredis/data) 并重启 uredis 容器" -ForegroundColor Yellow
Write-Host " 此操作不可逆,请谨慎确认!" -ForegroundColor Red
Write-Host "===========================================" -ForegroundColor Red
Write-Host "检测到 Redis 容器异常,是否执行远程修复?" -ForegroundColor Yellow
$repairChoice = Read-Host "执行修复? 请输入 yes 确认 (yes/n) [默认: n]"
if ($repairChoice -eq "yes") {
Write-Log -Level "INFO" -Message "[Redis] 用户输入 'yes' 确认执行 Redis 容器修复 (redis_container_exception)"
$repairItem = [ordered]@{ $repairItem = [ordered]@{
Check = "Redis容器修复" Check = "Redis容器修复"
...@@ -425,12 +435,20 @@ function Test-ContainerInformation { ...@@ -425,12 +435,20 @@ function Test-ContainerInformation {
$repairItem.Status = "失败" $repairItem.Status = "失败"
$repairItem.Details = "远程修复失败:$errMsg" $repairItem.Details = "远程修复失败:$errMsg"
} }
} } catch {
catch {
Write-Log -Level "ERROR" -Message "[Redis] 调用 Upload_the_repair_script 异常:$($_.Exception.Message)" Write-Log -Level "ERROR" -Message "[Redis] 调用 Upload_the_repair_script 异常:$($_.Exception.Message)"
$repairItem.Status = "异常" $repairItem.Status = "异常"
$repairItem.Details = "调用修复脚本异常:$($_.Exception.Message)" $repairItem.Details = "调用修复脚本异常:$($_.Exception.Message)"
} }
} else {
Write-Log -Level "INFO" -Message "[Redis] 用户取消修复操作,跳过 Redis 容器修复"
$repairItem = [ordered]@{
Check = "Redis容器修复"
Status = "已跳过"
Details = "用户取消修复"
Success = $false
}
}
$results += $repairItem $results += $repairItem
} }
......
...@@ -205,11 +205,16 @@ function Test-NTPService { ...@@ -205,11 +205,16 @@ function Test-NTPService {
# 检测到异常/未安装/偏移,上传并执行修复脚本 # 检测到异常/未安装/偏移,上传并执行修复脚本
# ============================================================================== # ==============================================================================
if ($needRepair) { if ($needRepair) {
Write-Log -Level "INFO" -Message "[NTP] 准备自动修复: ./issue_handler.sh --action fix_ntp_config --ntp-auto" Write-Log -Level "WARN" -Message "[NTP] 检测到NTP服务异常"
Write-Host " 检测到NTP服务异常,是否执行远程修复 (fix_ntp_config)?" -ForegroundColor Yellow
$repairNtpChoice = Read-Host " 执行修复? (y/n) [默认: n]"
if ($repairNtpChoice -eq "y" -or $repairNtpChoice -eq "Y") {
Write-Log -Level "INFO" -Message "[NTP] 用户确认执行修复 (fix_ntp_config)"
try { try {
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "fix_ntp_config" -Platform "auto" -RemoteDir "/home/repair_scripts" $repairRes = Upload_the_repair_script -Server $serverForRepair -Action "fix_ntp_config" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) { if ($repairRes -and $repairRes['Success']) {
Write-Log -Level "SUCCESS" -Message "[NTP] 自动修复命令执行成功 (fix_ntp_config)" Write-Log -Level "SUCCESS" -Message "[NTP] 远程修复命令执行成功 (fix_ntp_config)"
# 修复后验证 NTP 状态和时间 # 修复后验证 NTP 状态和时间
Write-Log -Level "INFO" -Message "[NTP] 修复后验证..." Write-Log -Level "INFO" -Message "[NTP] 修复后验证..."
...@@ -256,12 +261,17 @@ function Test-NTPService { ...@@ -256,12 +261,17 @@ function Test-NTPService {
} elseif ($repairRes) { } elseif ($repairRes) {
$errMsg = $repairRes.ToString() $errMsg = $repairRes.ToString()
} }
Write-Log -Level "ERROR" -Message "[NTP] 自动修复执行失败: $errMsg" Write-Log -Level "ERROR" -Message "[NTP] 远程修复执行失败: $errMsg"
} }
} catch { } catch {
# 捕获 Upload_the_repair_script 调用异常,避免泄漏 .Error 信息 # 捕获 Upload_the_repair_script 调用异常,避免泄漏 .Error 信息
Write-Log -Level "ERROR" -Message "[NTP] 调用 Upload_the_repair_script 异常: $($_.Exception.Message)" Write-Log -Level "ERROR" -Message "[NTP] 调用 Upload_the_repair_script 异常: $($_.Exception.Message)"
} }
} else {
Write-Log -Level "INFO" -Message "[NTP] 用户取消修复,跳过"
$summary.Status = '异常(未修复)'
$summary.Detail = '用户取消修复'
}
} }
return $summary return $summary
......
...@@ -559,6 +559,20 @@ function Repair-ExternalMeetingService { ...@@ -559,6 +559,20 @@ function Repair-ExternalMeetingService {
[hashtable]$Server [hashtable]$Server
) )
Write-Host "检测到对外服务未运行,是否执行远程修复?" -ForegroundColor Yellow
$repairChoice = Read-Host "执行修复? (y/n) [默认: n]"
if ($repairChoice -ne "y" -and $repairChoice -ne "Y") {
Write-Log -Level "INFO" -Message "[EXT] 用户取消修复操作,跳过对外服务修复"
return [pscustomobject]@{
Target = "external-meeting-api"
Attempted = $false
Success = $false
Detail = "用户取消修复"
}
}
Write-Log -Level "INFO" -Message "[EXT] 用户确认执行远程修复 (fix_external_service_disconnect)"
Write-Log -Level "INFO" -Message "[EXT] 准备自动修复: ./issue_handler.sh --action fix_external_service_disconnect" Write-Log -Level "INFO" -Message "[EXT] 准备自动修复: ./issue_handler.sh --action fix_external_service_disconnect"
$serverForRepair = $Server $serverForRepair = $Server
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论