提交 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 {
}
if ($extSvc -and -not $extSvc.Running) {
Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行,准备执行远程修复 (fix_external_service_disconnect)"
$global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server
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
} else {
Write-Log -Level "INFO" -Message "[EXT] 用户取消修复操作,跳过"
$global:ExternalServiceRepairResult = @{ Status = "SKIPPED"; Message = "用户取消修复" }
}
}
}
}
......@@ -571,8 +580,17 @@ function Main {
}
if ($extSvc -and -not $extSvc.Running) {
Write-Log -Level "WARN" -Message "[EXT] 检测到对外服务进程未运行,准备执行远程修复 (fix_external_service_disconnect)"
$global:ExternalServiceRepairResult = Repair-ExternalMeetingService -Server $server
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
} else {
Write-Log -Level "INFO" -Message "[EXT] 用户取消修复操作,跳过"
$global:ExternalServiceRepairResult = @{ Status = "SKIPPED"; Message = "用户取消修复" }
}
}
}
......
......@@ -373,63 +373,81 @@ function Test-ContainerInformation {
}
}
if ($redisNeedRepair) {
Write-Log -Level "ERROR" -Message "[Redis] 检测到 Redis 容器异常:uredis 未运行,且无其他 redis 命名容器运行,开始执行远端修复"
$repairItem = [ordered]@{
Check = "Redis容器修复"
Status = "未执行"
Details = ""
Success = $false
}
try {
$serverForRepair = @{
IP = $Server.IP
User = $Server.User
Pass = $Server.Pass
Port = $Server.Port
if ($redisNeedRepair) {
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]@{
Check = "Redis容器修复"
Status = "未执行"
Details = ""
Success = $false
}
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "redis_container_exception" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) {
Write-Log -Level "SUCCESS" -Message "[Redis] 远端 Redis 容器修复脚本执行成功 (redis_container_exception)"
$repairItem.Status = "已执行"
$repairItem.Details = "远端脚本执行成功 (redis_container_exception)"
$repairItem.Success = $true
# 复检
Write-Log -Level "INFO" -Message "[Redis] 修复后进行 uredis 容器复检..."
$checkCmd = "docker ps --format '{{.Names}}' | grep -w 'uredis' || echo 'NO_UREDIS'"
$recheck = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $checkCmd
try {
$serverForRepair = @{
IP = $Server.IP
User = $Server.User
Pass = $Server.Pass
Port = $Server.Port
}
if ($recheck.ExitCode -eq 0 -and -not ($recheck.Output -contains 'NO_UREDIS')) {
Write-Log -Level "SUCCESS" -Message "[Redis] Redis容器复检成功:uredis 已处于运行状态"
$repairItem.Details += " | 复检成功:uredis 已运行"
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "redis_container_exception" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) {
Write-Log -Level "SUCCESS" -Message "[Redis] 远端 Redis 容器修复脚本执行成功 (redis_container_exception)"
$repairItem.Status = "已执行"
$repairItem.Details = "远端脚本执行成功 (redis_container_exception)"
$repairItem.Success = $true
# 复检
Write-Log -Level "INFO" -Message "[Redis] 修复后进行 uredis 容器复检..."
$checkCmd = "docker ps --format '{{.Names}}' | grep -w 'uredis' || echo 'NO_UREDIS'"
$recheck = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $checkCmd
if ($recheck.ExitCode -eq 0 -and -not ($recheck.Output -contains 'NO_UREDIS')) {
Write-Log -Level "SUCCESS" -Message "[Redis] Redis容器复检成功:uredis 已处于运行状态"
$repairItem.Details += " | 复检成功:uredis 已运行"
} else {
Write-Log -Level "WARN" -Message "[Redis] Redis容器复检失败:仍未检测到运行中的 uredis 容器,需要人工排查"
$repairItem.Status = "部分成功"
$repairItem.Details += " | 复检失败:uredis 仍未运行,请人工排查"
}
} else {
Write-Log -Level "WARN" -Message "[Redis] Redis容器复检失败:仍未检测到运行中的 uredis 容器,需要人工排查"
$repairItem.Status = "部分成功"
$repairItem.Details += " | 复检失败:uredis 仍未运行,请人工排查"
}
} else {
$errMsg = "未知错误"
if ($repairRes -is [hashtable]) {
if ($repairRes.ContainsKey('Error') -and $repairRes['Error']) { $errMsg = [string]::Join(' ', $repairRes['Error']) }
elseif ($repairRes.ContainsKey('Output') -and $repairRes['Output']) { $errMsg = [string]::Join(' ', $repairRes['Output']) }
elseif ($repairRes.ContainsKey('Message') -and $repairRes['Message']) { $errMsg = $repairRes['Message'] }
} elseif ($repairRes) {
$errMsg = $repairRes.ToString()
$errMsg = "未知错误"
if ($repairRes -is [hashtable]) {
if ($repairRes.ContainsKey('Error') -and $repairRes['Error']) { $errMsg = [string]::Join(' ', $repairRes['Error']) }
elseif ($repairRes.ContainsKey('Output') -and $repairRes['Output']) { $errMsg = [string]::Join(' ', $repairRes['Output']) }
elseif ($repairRes.ContainsKey('Message') -and $repairRes['Message']) { $errMsg = $repairRes['Message'] }
} elseif ($repairRes) {
$errMsg = $repairRes.ToString()
}
Write-Log -Level "ERROR" -Message "[Redis] 远端 Redis 容器修复执行失败:$errMsg"
$repairItem.Status = "失败"
$repairItem.Details = "远程修复失败:$errMsg"
}
Write-Log -Level "ERROR" -Message "[Redis] 远端 Redis 容器修复执行失败:$errMsg"
$repairItem.Status = "失败"
$repairItem.Details = "远程修复失败:$errMsg"
} catch {
Write-Log -Level "ERROR" -Message "[Redis] 调用 Upload_the_repair_script 异常:$($_.Exception.Message)"
$repairItem.Status = "异常"
$repairItem.Details = "调用修复脚本异常:$($_.Exception.Message)"
}
} else {
Write-Log -Level "INFO" -Message "[Redis] 用户取消修复操作,跳过 Redis 容器修复"
$repairItem = [ordered]@{
Check = "Redis容器修复"
Status = "已跳过"
Details = "用户取消修复"
Success = $false
}
}
catch {
Write-Log -Level "ERROR" -Message "[Redis] 调用 Upload_the_repair_script 异常:$($_.Exception.Message)"
$repairItem.Status = "异常"
$repairItem.Details = "调用修复脚本异常:$($_.Exception.Message)"
}
$results += $repairItem
......
......@@ -205,62 +205,72 @@ function Test-NTPService {
# 检测到异常/未安装/偏移,上传并执行修复脚本
# ==============================================================================
if ($needRepair) {
Write-Log -Level "INFO" -Message "[NTP] 准备自动修复: ./issue_handler.sh --action fix_ntp_config --ntp-auto"
try {
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "fix_ntp_config" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) {
Write-Log -Level "SUCCESS" -Message "[NTP] 自动修复命令执行成功 (fix_ntp_config)"
# 修复后验证 NTP 状态和时间
Write-Log -Level "INFO" -Message "[NTP] 修复后验证..."
$postStatus = Invoke-SSHCommand -HostName $ServerIP -User $Username -Pass $Password -Port $Server.Port -Command "timedatectl status"
$postTime = Invoke-SSHCommand -HostName $ServerIP -User $Username -Pass $Password -Port $Server.Port -Command "date +%s"
if ($postStatus.ExitCode -eq 0 -and $postTime.ExitCode -eq 0) {
$srvTs = [int]($postTime.Output | Select-Object -First 1).Trim()
# 比较本地 UTC 时间
$locTs = [int][DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
$diff = [math]::Abs($srvTs - $locTs)
Write-Log -Level "INFO" -Message "[NTP] 服务器时间戳: ${diff}s"
if ($diff -le 5) {
$summary.Status = '正常'
$summary.Detail = "已修复 | 时间差 ${diff}s"
Write-Log -Level "SUCCESS" -Message "[NTP] 修复成功时间已基本同步"
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 {
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "fix_ntp_config" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) {
Write-Log -Level "SUCCESS" -Message "[NTP] 远程修复命令执行成功 (fix_ntp_config)"
# 修复后验证 NTP 状态和时间
Write-Log -Level "INFO" -Message "[NTP] 修复后验证..."
$postStatus = Invoke-SSHCommand -HostName $ServerIP -User $Username -Pass $Password -Port $Server.Port -Command "timedatectl status"
$postTime = Invoke-SSHCommand -HostName $ServerIP -User $Username -Pass $Password -Port $Server.Port -Command "date +%s"
if ($postStatus.ExitCode -eq 0 -and $postTime.ExitCode -eq 0) {
$srvTs = [int]($postTime.Output | Select-Object -First 1).Trim()
# 比较本地 UTC 时间
$locTs = [int][DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
$diff = [math]::Abs($srvTs - $locTs)
Write-Log -Level "INFO" -Message "[NTP] 服务器时间戳: ${diff}s"
if ($diff -le 5) {
$summary.Status = '正常'
$summary.Detail = "已修复 | 时间差 ${diff}s"
Write-Log -Level "SUCCESS" -Message "[NTP] 修复成功时间已基本同步"
} else {
# 未完全同步,认为偏移较大但已执行修复
$summary.Status = '偏移'
$summary.Detail = "已执行修复 | 当前时间偏移 ${diff}s"
Write-Log -Level "WARN" -Message "[NTP] 修复后时间仍偏移 ${diff}s"
}
} else {
# 未完全同步,认为偏移较大但已执行修复
$summary.Status = '偏移'
$summary.Detail = "已执行修复 | 当前时间偏移 ${diff}s"
Write-Log -Level "WARN" -Message "[NTP] 修复后时间仍偏移 ${diff}s"
# 修复失败导致的验证失败
if ([string]::IsNullOrWhiteSpace($summary.Detail)) {
$summary.Detail = "已执行修复(验证失败)"
} else {
$summary.Detail = "$($summary.Detail) | 已执行修复(验证失败)"
}
Write-Log -Level "WARN" -Message "[NTP] 修复后验证失败"
}
} else {
# 修复失败导致的验证失败
if ([string]::IsNullOrWhiteSpace($summary.Detail)) {
$summary.Detail = "已执行修复(验证失败)"
} else {
$summary.Detail = "$($summary.Detail) | 已执行修复(验证失败)"
# 尝试获取返回的错误信息
$errMsg = "未知错误"
if ($repairRes -is [hashtable]) {
if ($repairRes.ContainsKey('Error') -and $repairRes['Error']) {
$errMsg = [string]::Join(' ', $repairRes['Error'])
} elseif ($repairRes.ContainsKey('Output') -and $repairRes['Output']) {
$errMsg = [string]::Join(' ', $repairRes['Output'])
} elseif ($repairRes.ContainsKey('Message') -and $repairRes['Message']) {
$errMsg = $repairRes['Message']
}
} elseif ($repairRes) {
$errMsg = $repairRes.ToString()
}
Write-Log -Level "WARN" -Message "[NTP] 修复后验证失败"
Write-Log -Level "ERROR" -Message "[NTP] 远程修复执行失败: $errMsg"
}
} else {
# 尝试获取返回的错误信息
$errMsg = "未知错误"
if ($repairRes -is [hashtable]) {
if ($repairRes.ContainsKey('Error') -and $repairRes['Error']) {
$errMsg = [string]::Join(' ', $repairRes['Error'])
} elseif ($repairRes.ContainsKey('Output') -and $repairRes['Output']) {
$errMsg = [string]::Join(' ', $repairRes['Output'])
} elseif ($repairRes.ContainsKey('Message') -and $repairRes['Message']) {
$errMsg = $repairRes['Message']
}
} elseif ($repairRes) {
$errMsg = $repairRes.ToString()
}
Write-Log -Level "ERROR" -Message "[NTP] 自动修复执行失败: $errMsg"
} catch {
# 捕获 Upload_the_repair_script 调用异常,避免泄漏 .Error 信息
Write-Log -Level "ERROR" -Message "[NTP] 调用 Upload_the_repair_script 异常: $($_.Exception.Message)"
}
} catch {
# 捕获 Upload_the_repair_script 调用异常,避免泄漏 .Error 信息
Write-Log -Level "ERROR" -Message "[NTP] 调用 Upload_the_repair_script 异常: $($_.Exception.Message)"
} else {
Write-Log -Level "INFO" -Message "[NTP] 用户取消修复,跳过"
$summary.Status = '异常(未修复)'
$summary.Detail = '用户取消修复'
}
}
......
......@@ -559,6 +559,20 @@ function Repair-ExternalMeetingService {
[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"
$serverForRepair = $Server
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论