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

feat(server-check): 添加Redis容器修复和Emqx容器检测功能

- 实现Redis容器异常时的日志导出、远端修复和复检流程
- 添加Emqx容器异常检测和日志导出功能
- 优化issue_handler.sh中Redis容器修复脚本的交互模式和参数处理
- 更新PRD文档中的Redis修复交互模式说明和Emqx容器检测需求
- 完善服务自检需求文档中的检测功能详细描述和执行要求
上级 04c07cb7
......@@ -668,3 +668,12 @@ cd /data/services/api/java-meeting/java-meeting-extapi/
路径:/var/www/redis/data,将此目录下数据删除后重启uredis容器
新统一平台:
路径:/data/middleware/redis/data,将此目录下数据删除后重启uredis容器
交互模式与非交互模式说明:
- 默认执行(不带额外参数)时,脚本以交互模式运行:
1)在删除 data 目录之前,提示用户“是否确认删除 redis data 下所有数据”,必须输入 yes 才会继续执行;
2)适合现场运维人员手动执行,避免误删数据。
- 当通过服务自检脚本自动调用时,使用非交互模式:
1)调用示例:./issue_handler.sh --action redis_container_exception --non-interactive --yes
2)非交互模式下,如果未同时指定 --yes,脚本应出于安全考虑直接退出,不删除任何数据;
3)只有在同时传入 --non-interactive 和 --yes 时,才会自动执行删除 data 并重启 uredis 的操作。
\ No newline at end of file
......@@ -1987,115 +1987,94 @@ show_disk_partition_info() {
# 补充redis服务异常时修复操作
redis_container_exception() {
log_info "开始修复 redis 容器启动异常问题"
local non_interactive=0
local auto_yes=0
# 1. 检测平台类型(new / standard / unknown)
local platform
platform=$(detect_platform)
log_info "检测到平台类型: $platform"
# 解析参数
while [[ $# -gt 0 ]]; do
case "$1" in
--non-interactive)
non_interactive=1
shift
;;
--yes|-y)
auto_yes=1
shift
;;
*)
break
;;
esac
done
# 2. 检查 docker 与 uredis 容器
if ! command -v docker >/dev/null 2>&1; then
log_error "系统中未安装 docker,无法处理 redis 容器异常"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (未安装 docker)"
return 1
fi
echo "=== 修复 Redis 容器文件损坏问题 (redis_container_exception) ==="
if ! docker ps -a --format '{{.Names}}' | grep -q '^uredis$'; then
log_error "未找到 uredis 容器,请确认 redis 容器已创建"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (未找到 uredis 容器)"
# 1. 检测新旧平台
local redis_data_path="/var/www/redis/data"
if [[ -d "/data/middleware/redis/data" ]]; then
redis_data_path="/data/middleware/redis/data"
echo "检测到新统一平台,Redis 数据目录:$redis_data_path"
elif [[ -d "/var/www/redis/data" ]]; then
echo "检测到标准版平台,Redis 数据目录:$redis_data_path"
else
echo "未找到 Redis 数据目录,请手动确认 /var/www/redis 或 /data/middleware/redis 是否存在"
return 1
fi
# 3. 先尝试正常重启 uredis 容器
log_info "尝试重启 uredis 容器..."
if docker restart uredis >/dev/null 2>&1; then
sleep 5
if docker ps --format '{{.Names}}' | grep -q '^uredis$'; then
log_info "uredis 容器重启成功,无需清理数据"
show_operation_summary "修复 redis 容器异常" "${GREEN}完成${NC} (容器重启成功)"
# 2. 先尝试简单重启 uredis 容器
echo "尝试重启 uredis 容器..."
if docker ps -a --format '{{.Names}}' | grep -qw uredis; then
docker restart uredis
sleep 3
if docker ps --format '{{.Names}}' | grep -qw uredis; then
echo "uredis 容器重启成功,无需清空数据目录。"
return 0
else
log_warn "uredis 容器重启后未处于运行状态,将按 PRD 执行数据清理流程"
echo "uredis 容器重启失败,将按步骤 3 清空数据目录后再尝试重启。"
fi
else
log_warn "直接重启 uredis 容器失败,将按 PRD 执行数据清理流程"
echo "未找到 uredis 容器,后续清数据并尝试重新创建/启动时可能失败,请手动排查。"
fi
# 4. 确定 redis data 目录(按平台分支)
local redis_data_dir=""
if [ "$platform" = "new" ]; then
redis_data_dir="/data/middleware/redis/data"
elif [ "$platform" = "standard" ]; then
redis_data_dir="/var/www/redis/data"
else
# 未识别平台时,根据目录存在性猜测
if [ -d "/data/middleware/redis/data" ]; then
redis_data_dir="/data/middleware/redis/data"
log_warn "平台类型 unknown,使用新平台 redis data 目录: $redis_data_dir"
elif [ -d "/var/www/redis/data" ]; then
redis_data_dir="/var/www/redis/data"
log_warn "平台类型 unknown,使用旧平台 redis data 目录: $redis_data_dir"
else
log_error "无法确定 redis data 目录,请确认平台及目录结构"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (未找到 redis data 目录)"
# 3. 删除 redis data 下所有数据(高风险操作,需要确认)
if [[ $non_interactive -eq 0 ]]; then
# 交互模式:要求用户手动确认
echo "警告:将要删除 Redis 数据目录下的所有数据:$redis_data_path"
read -r -p "确认执行此操作吗?(yes/NO): " answer
if [[ "$answer" != "yes" ]]; then
echo "用户取消操作,不执行数据删除。"
return 1
fi
fi
log_info "将使用 redis data 目录: $redis_data_dir"
if [ ! -d "$redis_data_dir" ]; then
log_error "redis data 目录不存在: $redis_data_dir"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (redis data 目录不存在)"
else
# 非交互模式:必须带 --yes 才继续
if [[ $auto_yes -ne 1 ]]; then
echo "非交互模式下未提供 --yes,出于安全考虑,取消操作。"
return 1
fi
echo "非交互模式 + --yes:将删除 Redis 数据目录:$redis_data_path"
fi
# 5. 确认是否清空 redis data 目录(支持非交互)
local do_clear_data=false
log_warn "准备删除 redis data 目录下所有数据,这将清空当前 redis 数据。"
log_info "目录: $redis_data_dir"
echo "清空 Redis 数据目录:$redis_data_path"
rm -rf "${redis_data_path:?}/"* || {
echo "删除 $redis_data_path 下数据失败,请检查权限。"
return 1
}
if [ "$NON_INTERACTIVE" = "1" ] && [ "$ASSUME_YES" = "1" ]; then
log_info "非交互模式,自动确认清空 redis data 目录"
do_clear_data=true
# 再次尝试启动/重启 uredis 容器
if docker ps -a --format '{{.Names}}' | grep -qw uredis; then
echo "尝试重启 uredis 容器..."
docker restart uredis
else
if confirm_action "是否确认删除该目录下所有数据并重新启动 uredis 容器?"; then
do_clear_data=true
else
log_info "用户取消删除 redis data 数据"
fi
echo "未找到 uredis 容器,尝试 docker start uredis..."
docker start uredis || true
fi
if [ "$do_clear_data" != true ]; then
show_operation_summary "修复 redis 容器异常" "${YELLOW}取消${NC} (用户取消删除数据)"
sleep 3
if docker ps --format '{{.Names}}' | grep -qw uredis; then
echo "uredis 容器启动成功,Redis 文件损坏修复完成。"
return 0
fi
# 6. 停止容器并清空数据目录
log_info "停止 uredis 容器..."
docker stop uredis >/dev/null 2>&1 || log_warn "停止 uredis 容器失败,可能已停止"
log_info "清空 redis data 目录内容: $redis_data_dir"
# 防止变量为空导致 rm -rf / 等危险:加 :? 保护
rm -rf "${redis_data_dir:?}/"* "${redis_data_dir:?}"/.[!.]* "${redis_data_dir:?}"/..?* 2>/dev/null || true
# 7. 重启 uredis 容器
log_info "重新启动 uredis 容器..."
if docker start uredis >/dev/null 2>&1; then
sleep 5
if docker ps --format '{{.Names}}' | grep -q '^uredis$'; then
log_info "uredis 容器已在清空数据后成功启动"
show_operation_summary "修复 redis 容器异常" "${GREEN}完成${NC} (已清空 data 并重启 uredis)"
return 0
else
log_error "清空数据后 uredis 容器仍未处于运行状态,请检查容器日志"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (清空 data 后容器仍未运行)"
return 1
fi
else
log_error "清空数据后启动 uredis 容器失败,请检查 docker / 容器配置"
show_operation_summary "修复 redis 容器异常" "${RED}失败${NC} (docker start uredis 失败)"
echo "uredis 容器仍未启动成功,请人工进一步排查。"
return 1
fi
}
......
......@@ -1645,34 +1645,27 @@ function Test-ContainerInformation {
}
# =====================================================================
# Redis 容器异常:日志导出 + 远端修复 + 复检 (需求文档第12点)
# Redis 容器异常:日志导出 + 远端修复 + 复检
# =====================================================================
# 1) Redis 日志路径根据平台判断
$platformType = $Global:PlatformType # 你前面平台识别时应已设置此全局变量:'new' 或 'old'
$redisLogPath = "/var/www/redis/data/redis.log" # 传统平台默认路径
$platformType = $Global:PlatformType
$redisLogPath = "/var/www/redis/data/redis.log"
if ($platformType -eq "new") {
# 新统一平台路径(根据文档):/data/middleware/redis/data/redis.log
$redisLogPath = "/data/middleware/redis/data/redis.log"
}
# 本地自检结果目录:形如 output\<IP>\logs\redis\
# 本地目录
$baseOutputDir = Join-Path -Path $PSScriptRoot -ChildPath "output"
$serverDir = Join-Path -Path $baseOutputDir -ChildPath $Server.IP
$redisOutDir = Join-Path -Path $serverDir -ChildPath "logs\redis"
if (-not (Test-Path $redisOutDir)) {
New-Item -Path $redisOutDir -ItemType Directory -Force | Out-Null
}
$localRedisLog = Join-Path -Path $redisOutDir -ChildPath "redis.log"
Write-Log -Level "INFO" -Message "[Redis] 准备导出 redis 日志: $redisLogPath -> $localRedisLog"
# 2) 从远端导出 redis.log 到本地
# 这里假定你已有一个封装的远程下载函数,例如 Download-RemoteFile
# 如果你实际用的是 Get-SFTPItem 或者其他名字,请替换为你的函数名和参数。
$exportOk = $false
try {
$downloadRes = Download-RemoteFile -Server $Server -RemotePath $redisLogPath -LocalPath $localRedisLog -ErrorAction Stop
......@@ -1694,28 +1687,22 @@ function Test-ContainerInformation {
}
# 3) Redis 容器异常判定
# 条件:uredis 容器未运行,且没有其他名字中包含 'redis' 的运行中容器
$redisRunning = $runningContainers | Where-Object { $_.Name -match '(?i)redis' }
$uredisRunning = $redisRunning | Where-Object { $_.Name -eq 'uredis' }
$uredisStopped = $stoppedContainers | Where-Object { $_.Name -eq 'uredis' }
$redisNeedRepair = $false
if (-not $uredisRunning -and $uredisStopped) {
if (-not $redisRunning) {
# uredis 存在但未运行,且没有其他 redis 命名的运行中容器
$redisNeedRepair = $true
}
}
if (-not $redisNeedRepair) {
Write-Log -Level "INFO" -Message "[Redis] 未检测到需要自动修复的 Redis 容器异常"
return $results
}
# 只有 Redis 需要修复时,才准备 repairItem
$repairItem = $null
if ($redisNeedRepair) {
Write-Log -Level "ERROR" -Message "[Redis] 检测到 Redis 容器异常:uredis 未运行,且无其他 redis 命名容器运行,开始执行远端修复"
# 4) 远端修复:上传 issue_handler.sh 并执行 redis_container_exception (非交互模式)
$repairItem = [ordered]@{
Check = "Redis容器修复"
Status = "未执行"
......@@ -1731,8 +1718,6 @@ function Test-ContainerInformation {
Port = $Server.Port
}
# Upload_the_repair_script 内部应拼出:
# ./issue_handler.sh --action redis_container_exception --non-interactive --yes
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "redis_container_exception" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes['Success']) {
......@@ -1741,7 +1726,7 @@ function Test-ContainerInformation {
$repairItem.Details = "远端脚本执行成功 (redis_container_exception)"
$repairItem.Success = $true
# 5) 修复完成后的复检
# 复检
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
......@@ -1775,9 +1760,78 @@ function Test-ContainerInformation {
$repairItem.Details = "调用修复脚本异常:$($_.Exception.Message)"
}
# 把 Redis 修复结果写入 $results
$results += $repairItem
}
else {
Write-Log -Level "INFO" -Message "[Redis] 未检测到需要自动修复的 Redis 容器异常"
}
# =====================================================================
# Emqx 容器异常:日志导出 + 异常判定(远端修复暂不实现)
# =====================================================================
# 1) emqx 日志路径根据平台判断
$emqxLogPath = "/var/www/emqx/log/emqx.log.1"
if ($platformType -eq "new") {
$emqxLogPath = "/data/middleware/emqx/log/emqx.log.1"
}
$emqxOutDir = Join-Path -Path $serverDir -ChildPath "logs\emqx"
if (-not (Test-Path $emqxOutDir)) {
New-Item -Path $emqxOutDir -ItemType Directory -Force | Out-Null
}
$localEmqxLog = Join-Path -Path $emqxOutDir -ChildPath "emqx.log.1"
Write-Log -Level "INFO" -Message "[Emqx] 准备导出 emqx 日志: $emqxLogPath -> $localEmqxLog"
$emqxExportOk = $false
try {
$emqxDl = Download-RemoteFile -Server $Server -RemotePath $emqxLogPath -LocalPath $localEmqxLog -ErrorAction Stop
if ($emqxDl -and $emqxDl.Success) {
Write-Log -Level "SUCCESS" -Message "[Emqx] emqx.log.1 导出成功,已保存到本地: $localEmqxLog"
$emqxExportOk = $true
} else {
Write-Log -Level "WARN" -Message "[Emqx] emqx.log.1 导出失败(返回结果不成功),请检查远端文件是否存在:$emqxLogPath"
}
} catch {
Write-Log -Level "WARN" -Message "[Emqx] emqx.log.1 导出异常:$($_.Exception.Message)"
}
$results += @{
Check = "Emqx日志导出"
Status = ($emqxExportOk ? "完成" : "失败")
Details = $emqxExportOk ? "emqx.log.1 导出成功 -> $localEmqxLog" : "emqx.log.1 导出失败或文件不存在 ($emqxLogPath)"
Success = $emqxExportOk
}
# 3) Emqx 容器异常判定
$emqxRunning = $runningContainers | Where-Object { $_.Name -match '(?i)emqx' }
$uemqxRunning = $emqxRunning | Where-Object { $_.Name -eq 'uemqx' }
$uemqxStopped = $stoppedContainers | Where-Object { $_.Name -eq 'uemqx' }
$emqxNeedRepair = $false
if (-not $uemqxRunning -and $uemqxStopped) {
if (-not $emqxRunning) {
$emqxNeedRepair = $true
}
}
if (-not $emqxNeedRepair) {
Write-Log -Level "INFO" -Message "[Emqx] 未检测到 Emqx 容器异常(或存在其他 emqx 容器运行中)"
}
else {
Write-Log -Level "ERROR" -Message "[Emqx] 检测到 Emqx 容器异常:uemqx 未运行,且无其他 emqx 命名容器运行"
$results += @{
Check = "Emqx容器状态"
Status = "异常"
Details = "检测到 Emqx 容器异常:uemqx 未运行,且无其他 emqx 容器;暂未自动修复,请人工排查"
Success = $false
}
}
return $results
}
# ================================
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论