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

docs(服务自检): 更新服务自检与远程程序更新脚本执行遇到的相关问题处理文档及计划执行

- 添加 EMQX 容器匹配不到问题的解决方案
- 修复中间件检测乱码异常的处理记录
- 更新中间件检测脚本上传失败问题的分析
- 添加远程更新程序参数转换错误的修复方案
- 完善检测信息打印乱码问题的处理文档
上级 8d3fd1a1
...@@ -95,7 +95,12 @@ ...@@ -95,7 +95,12 @@
"Bash(powershell -ExecutionPolicy Bypass -File \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\debug_modules.ps1\")", "Bash(powershell -ExecutionPolicy Bypass -File \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\debug_modules.ps1\")",
"Bash(powershell -ExecutionPolicy Bypass -File \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\debug_modules2.ps1\")", "Bash(powershell -ExecutionPolicy Bypass -File \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\debug_modules2.ps1\")",
"Bash(powershell:*)", "Bash(powershell:*)",
"Bash(dir /b \"C:\\\\PycharmData\\\\ubains-module-test\\\\Docs\\\\PRD\\\\服务自检\\\\问题修复\"\" | findstr \"java服务 \")" "Bash(dir /b \"C:\\\\PycharmData\\\\ubains-module-test\\\\Docs\\\\PRD\\\\服务自检\\\\问题修复\"\" | findstr \"java服务 \")",
"Bash(python fix_encoding.py)",
"Bash(python fix_middleware.py)",
"Bash(del \"C:\\\\Users\\\\EDY\\\\Desktop\\\\fix_encoding.ps1\")",
"Bash(copy /Y \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\modules\\\\MiddlewareCheck.psm1.backup3\" \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\ServiceSelfInspection\\\\modules\\\\MiddlewareCheck.psm1\")",
"Bash(xxd -l 10 \"C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\RemoteUpdate\\\\remote_update.ps1\")"
] ]
} }
} }
{
"permissions": {
"allow": [
"Bash(dir \"C:\\\\PycharmData\\\\ubains-module-test\\\\Docs\\\\PRD\\\\服务自检\\\\问题修复\" /b)",
"Bash(for f in *配置IP*)",
"Bash(do cat \"$f\")",
"Bash(done)"
]
}
}
{
"projects": {
"1": {
"name": "中广核大亚湾项目",
"platforms": {
"新统一平台": {
"预定系统": {
"frontend_path": "/data/cgnyd-meeting/frontend",
"inner_backend_path": "/data/api/java-meeting/java-meeting2.0",
"outer_backend_path": "/data/api/java-meeting/java-meeting-extapi",
"upload_path": "/home/appadmin/"
},
"运维集控系统": {
"frontend_path": "/data/",
"inner_backend_path": "/data/",
"outer_backend_path": "/data/",
"upload_path": "/home/appadmin/"
},
"语音转录系统": {
"frontend_path": "/data/",
"inner_backend_path": "/data/",
"outer_backend_path": "/data/",
"upload_path": "/home/appadmin/"
}
},
"标准版平台": {
"预定系统": {
"frontend_path": "/var/www/cims-web/",
"inner_backend_path": "/var/www/cims-java/",
"outer_backend_path": "/var/www/cims-exapi/",
"upload_path": "/home/appadmin/"
},
"运维集控系统": {
"frontend_path": "/data/",
"inner_backend_path": "/data/",
"outer_backend_path": "/data/",
"upload_path": "/home/appadmin/"
},
"语音转录系统": {
"frontend_path": "/data/",
"inner_backend_path": "/data/",
"outer_backend_path": "/data/",
"upload_path": "/home/appadmin/"
}
}
},
"database": {
"type": "MySQL",
"is_containerized": true,
"container_pattern": "umysql",
"username": "root",
"password": "dNrprU&2S",
"databases": ["ubains", "devops"]
}
}
}
}
{
"servers": {
"1": {
"name": "中广核大亚湾-前端测试环境",
"ip": "10.126.4.79",
"port": 1122,
"ssh_username": "root",
"ssh_password": "Admin@123Admin@123"
},
"2": {
"name": "中广核大亚湾-后端测试环境",
"ip": "10.126.4.81",
"port": 1122,
"ssh_username": "appadmin",
"ssh_password": "CGNadm!@345CGNadm!@345",
"su_username": "root",
"su_password": "Admin@123Admin@123"
}
}
}
此差异已折叠。
# ==============================================================================
# database.ps1
# ------------------------------------------------------------------------------
# 数据库模块(预留功能)
#
# .SYNOPSIS
# 提供数据库备份和恢复功能(预留)
#
# .DESCRIPTION
# 本模块提供数据库的备份和恢复功能
# 由于不同项目使用的数据库类型可能不同(MySQL/达梦等),
# 部署方式也存在差异(容器化/非容器化),此功能暂时不执行,
# 仅预留函数接口供后续扩展。
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
# 状态:预留功能,暂不执行
#
# 依赖:
# - ssh.ps1 (SSH 连接模块)
# - log.ps1 (日志模块)
# ==============================================================================
# 获取脚本目录
if ($PSScriptRoot) {
$LIB_SCRIPT_DIR = $PSScriptRoot
} else {
$LIB_SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
}
# 导入依赖模块
Import-Module (Join-Path $LIB_SCRIPT_DIR "ssh.ps1") -Force
Import-Module (Join-Path $LIB_SCRIPT_DIR "log.ps1") -Force
# ==============================================================================
# 数据库备份(预留功能)
# ==============================================================================
function Backup-Database {
<#
.SYNOPSIS
数据库备份函数(预留)
.DESCRIPTION
根据数据库类型执行不同的备份逻辑:
- MySQL: 容器化部署,通过 docker exec 执行 mysqldump
- 达梦: 非容器化部署,通过 SSH 执行 dexp 命令
.PARAMETER ServerInfo
服务器连接信息哈希表
.PARAMETER DatabaseConfig
数据库配置信息
.PARAMETER DatabaseType
数据库类型(MySQL/DM)
.EXAMPLE
$dbConfig = @{
Type = "MySQL"
IsContainerized = $true
ContainerPattern = "umysql"
Username = "root"
Password = "password"
Databases = @("ubains", "devops")
}
Backup-Database -ServerInfo $server -DatabaseConfig $dbConfig -DatabaseType "MySQL"
.OUTPUTS
Boolean,备份成功返回 $true,否则返回 $false
#>
param(
[Parameter(Mandatory=$true)]
[hashtable]$ServerInfo,
[Parameter(Mandatory=$true)]
[hashtable]$DatabaseConfig,
[Parameter(Mandatory=$true)]
[string]$DatabaseType
)
# 预留功能,暂不执行
Write-Log -Level "WARN" -Message "数据库备份功能为预留功能,暂不执行"
Write-Log -Level "INFO" -Message "数据库类型: $DatabaseType"
<#
TODO: 根据数据库类型执行不同的备份逻辑
# MySQL 容器化部署示例
if ($DatabaseType -eq "MySQL" -and $DatabaseConfig.IsContainerized) {
# 模糊匹配容器
$containerPattern = $DatabaseConfig.ContainerPattern
$findCmd = "docker ps --format '{{.Names}}' | grep -E '$containerPattern'"
$result = Invoke-SSHCommand @ServerInfo -Command $findCmd
$containerName = ($result.Output | Where-Object { $_ -ne "" } | Select-Object -First 1).Trim()
foreach ($dbName in $DatabaseConfig.Databases) {
$backupFile = "$BackendPath/backup/${dbName}_backup_$(Get-Date -Format 'yyyyMMddHHmmss').sql"
$backupCmd = "docker exec $containerName mysqldump -u$($DatabaseConfig.Username) -p$($DatabaseConfig.Password) --skip-triggers --compact --no-create-info $dbName > $backupFile"
Invoke-SSHCommand @ServerInfo -Command $backupCmd
}
}
# 达梦数据库示例
if ($DatabaseType -eq "DM") {
$dexpCmd = "dexp USERID=$($DatabaseConfig.Username)/$($DatabaseConfig.Password) FILE=$backupFile LOG=$logFile FULL=N OWNER=$($DatabaseConfig.Username)"
Invoke-SSHCommand @ServerInfo -Command $dexpCmd
}
#>
return $true
}
# ==============================================================================
# 数据库恢复(预留功能)
# ==============================================================================
function Restore-Database {
<#
.SYNOPSIS
数据库恢复函数(预留)
.DESCRIPTION
根据数据库类型执行不同的恢复逻辑
.PARAMETER ServerInfo
服务器连接信息哈希表
.PARAMETER DatabaseConfig
数据库配置信息
.PARAMETER BackupFile
备份文件路径
.EXAMPLE
Restore-Database -ServerInfo $server -DatabaseConfig $dbConfig -BackupFile "/data/backup/ubains_backup.sql"
.OUTPUTS
Boolean,恢复成功返回 $true,否则返回 $false
#>
param(
[Parameter(Mandatory=$true)]
[hashtable]$ServerInfo,
[Parameter(Mandatory=$true)]
[hashtable]$DatabaseConfig,
[Parameter(Mandatory=$true)]
[string]$BackupFile
)
# 预留功能,暂不执行
Write-Log -Level "WARN" -Message "数据库恢复功能为预留功能,暂不执行"
Write-Log -Level "INFO" -Message "备份文件: $BackupFile"
<#
TODO: 根据数据库类型执行不同的恢复逻辑
# MySQL 容器化部署示例
if ($DatabaseConfig.Type -eq "MySQL" -and $DatabaseConfig.IsContainerized) {
$containerName = $DatabaseConfig.ContainerName
$restoreCmd = "docker exec -i $containerName mysql -u$($DatabaseConfig.Username) -p$($DatabaseConfig.Password) $dbName < $BackupFile"
Invoke-SSHCommand @ServerInfo -Command $restoreCmd
}
# 达梦数据库示例
if ($DatabaseConfig.Type -eq "DM") {
$dimpCmd = "dimp USERID=$($DatabaseConfig.Username)/$($DatabaseConfig.Password) FILE=$BackupFile LOG=$logFile"
Invoke-SSHCommand @ServerInfo -Command $dimpCmd
}
#>
return $true
}
# ==============================================================================
# file.ps1
# ------------------------------------------------------------------------------
# 文件操作模块
#
# .SYNOPSIS
# 提供文件上传和下载功能
#
# .DESCRIPTION
# 本模块通过 pscp.exe 实现文件的上传和下载
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
#
# 依赖:
# - pscp.exe (PuTTY 套件)
# - ssh.ps1 (SSH 连接模块)
# ==============================================================================
# 获取脚本目录
if ($PSScriptRoot) {
$LIB_SCRIPT_DIR = $PSScriptRoot
} else {
$LIB_SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
}
# 导入依赖模块
Import-Module (Join-Path $LIB_SCRIPT_DIR "ssh.ps1") -Force
# ==============================================================================
# 文件上传
# ==============================================================================
function Upload-File {
<#
.SYNOPSIS
上传本地文件到远程服务器
.DESCRIPTION
使用 pscp.exe 将本地文件上传到远程服务器指定目录
.PARAMETER LocalPath
本地文件完整路径
.PARAMETER ServerInfo
服务器连接信息哈希表
.PARAMETER RemotePath
远程目标目录
.EXAMPLE
$server = @{
IP = "192.168.1.1"
Port = 22
SshUsername = "root"
SshPassword = "password"
}
Upload-File -LocalPath "C:\test.zip" -ServerInfo $server -RemotePath "/home/appadmin/"
.OUTPUTS
Boolean,上传成功返回 $true,否则返回 $false
#>
param(
[Parameter(Mandatory=$true)]
[string]$LocalPath,
[Parameter(Mandatory=$true)]
[hashtable]$ServerInfo,
[Parameter(Mandatory=$true)]
[string]$RemotePath
)
if (-not (Test-Path -LiteralPath $LocalPath)) {
Write-Log -Level "ERROR" -Message "本地文件不存在: $LocalPath"
return $false
}
# 确保 pscp 可用
if (-not $global:PSCP_PATH) {
Initialize-SSHTools | Out-Null
}
if (-not $global:PSCP_PATH) {
Write-Log -Level "ERROR" -Message "pscp.exe 未找到,无法上传文件"
return $false
}
Write-Log -Level "INFO" -Message "上传文件: $LocalPath -> $($ServerInfo.IP):$RemotePath"
# 构建 pscp 参数
$pscpArgs = @(
"-P", $ServerInfo.Port,
"-l", $ServerInfo.SshUsername,
"-pw", $ServerInfo.SshPassword,
"-batch",
"-no-antispoof",
$LocalPath,
"$($ServerInfo.SshUsername)@$($ServerInfo.IP):$RemotePath/"
)
try {
$result = & $global:PSCP_PATH @pscpArgs 2>&1
$exitCode = $LASTEXITCODE
# 处理首次连接主机密钥问题
if ($exitCode -ne 0 -and ($result -match "host key" -or $result -match "Store key in cache")) {
$cmdLine = "echo y | `"$($global:PSCP_PATH)`" -P $($ServerInfo.Port) -l $($ServerInfo.SshUsername) -pw `"$($ServerInfo.SshPassword)`" `"$LocalPath`" `"$($ServerInfo.SshUsername)@$($ServerInfo.IP):$RemotePath/`""
$result = cmd /c $cmdLine 2>&1
$exitCode = $LASTEXITCODE
}
if ($exitCode -eq 0) {
Write-Log -Level "SUCCESS" -Message "文件上传成功"
return $true
} else {
Write-Log -Level "ERROR" -Message "文件上传失败: $result"
return $false
}
}
catch {
Write-Log -Level "ERROR" -Message "文件上传异常: $($_.Exception.Message)"
return $false
}
}
# ==============================================================================
# 文件下载
# ==============================================================================
function Download-File {
<#
.SYNOPSIS
从远程服务器下载文件到本地
.DESCRIPTION
使用 pscp.exe 从远程服务器下载文件到本地指定目录
.PARAMETER ServerInfo
服务器连接信息哈希表
.PARAMETER RemotePath
远程文件完整路径
.PARAMETER LocalPath
本地目标文件路径
.EXAMPLE
$server = @{
IP = "192.168.1.1"
Port = 22
SshUsername = "root"
SshPassword = "password"
}
Download-File -ServerInfo $server -RemotePath "/home/appadmin/test.zip" -LocalPath "C:\test.zip"
.OUTPUTS
Boolean,下载成功返回 $true,否则返回 $false
#>
param(
[Parameter(Mandatory=$true)]
[hashtable]$ServerInfo,
[Parameter(Mandatory=$true)]
[string]$RemotePath,
[Parameter(Mandatory=$true)]
[string]$LocalPath
)
# 确保 pscp 可用
if (-not $global:PSCP_PATH) {
Initialize-SSHTools | Out-Null
}
if (-not $global:PSCP_PATH) {
Write-Log -Level "WARN" -Message "pscp.exe 未找到,无法下载文件"
return $false
}
Write-Log -Level "INFO" -Message "下载文件: $($ServerInfo.IP):$RemotePath -> $LocalPath"
# 确保本地目录存在
$localDir = Split-Path -Parent $LocalPath
if (-not (Test-Path $localDir)) {
New-Item -ItemType Directory -Path $localDir -Force | Out-Null
}
# 构建 pscp 参数
$pscpArgs = @(
"-P", $ServerInfo.Port,
"-l", $ServerInfo.SshUsername,
"-pw", $ServerInfo.SshPassword,
"-batch",
"-no-antispoof",
"$($ServerInfo.SshUsername)@$($ServerInfo.IP):$RemotePath",
$LocalPath
)
try {
$result = & $global:PSCP_PATH @pscpArgs 2>&1
$exitCode = $LASTEXITCODE
# 处理首次连接主机密钥问题
if ($exitCode -ne 0 -and ($result -match "host key" -or $result -match "Store key in cache")) {
$cmdLine = "echo y | `"$($global:PSCP_PATH)`" -P $($ServerInfo.Port) -l $($ServerInfo.SshUsername) -pw `"$($ServerInfo.SshPassword)`" `"$($ServerInfo.SshUsername)@$($ServerInfo.IP):$RemotePath`" `"$LocalPath`""
$result = cmd /c $cmdLine 2>&1
$exitCode = $LASTEXITCODE
}
if ($exitCode -eq 0 -and (Test-Path $LocalPath)) {
Write-Log -Level "SUCCESS" -Message "文件下载成功"
return $true
} else {
Write-Log -Level "WARN" -Message "文件下载失败: $result"
return $false
}
}
catch {
Write-Log -Level "WARN" -Message "文件下载异常: $($_.Exception.Message)"
return $false
}
}
# ==============================================================================
# log.ps1
# ------------------------------------------------------------------------------
# 日志模块
#
# .SYNOPSIS
# 提供日志输出功能
#
# .DESCRIPTION
# 本模块提供日志输出到控制台和日志文件的功能
# 支持多个日志级别:INFO、WARN、ERROR、SUCCESS
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
# ==============================================================================
# ==============================================================================
# 全局变量
# ==============================================================================
$global:LOG_FILE = $null
$global:LOG_DIR = Join-Path $PSScriptRoot "..\logs"
# 确保日志目录存在
if (-not (Test-Path $global:LOG_DIR)) {
New-Item -ItemType Directory -Path $global:LOG_DIR -Force | Out-Null
}
# 初始化日志文件
function Initialize-Log {
$LOG_TIMESTAMP = Get-Date -Format "yyyyMMdd_HHmmss"
$global:LOG_FILE = Join-Path $global:LOG_DIR "remote_update_$LOG_TIMESTAMP.log"
}
# ==============================================================================
# 日志函数
# ==============================================================================
function Write-Log {
<#
.SYNOPSIS
输出日志信息到控制台和日志文件
.DESCRIPTION
该函数将日志信息输出到控制台(带颜色)并写入到日志文件。
支持多个日志级别:INFO、WARN、ERROR、SUCCESS
.PARAMETER Level
日志级别:INFO、WARN、ERROR、SUCCESS
.PARAMETER Message
日志消息内容(可为空字符串,此时只输出空行)
.EXAMPLE
Write-Log -Level "INFO" -Message "开始检测服务"
Write-Log -Level "ERROR" -Message "检测失败"
#>
param(
[Parameter(Mandatory=$false)]
[ValidateSet("INFO", "WARN", "ERROR", "SUCCESS")]
[string]$Level = "INFO",
[Parameter(Mandatory=$false)]
[AllowEmptyString()]
[string]$Message = ""
)
# 如果日志文件未初始化,先初始化
if (-not $global:LOG_FILE) {
Initialize-Log
}
# 如果消息为空,直接输出空行到控制台,不记录到日志文件
if ([string]::IsNullOrEmpty($Message)) {
Write-Host ""
return
}
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logLine = "[$timestamp] [$Level] $Message"
$colorMap = @{
"INFO" = "Cyan"
"WARN" = "Yellow"
"ERROR" = "Red"
"SUCCESS" = "Green"
}
$color = $colorMap[$Level]
Write-Host $logLine -ForegroundColor $color
try {
# 使用全局日志文件路径
if ($global:LOG_FILE) {
$logLine | Out-File -FilePath $global:LOG_FILE -Append -Encoding utf8
}
}
catch {
# 日志文件写入失败不影响主流程
}
}
# ==============================================================================
# ssh.ps1
# ------------------------------------------------------------------------------
# SSH 连接模块
#
# .SYNOPSIS
# 提供远程 SSH 连接和命令执行功能
#
# .DESCRIPTION
# 本模块通过 plink.exe 实现 SSH 连接和远程命令执行
# 支持直接 root 连接和普通用户 + su 切换两种方式
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
#
# 依赖:
# - plink.exe (PuTTY 套件)
# - pscp.exe (PuTTY 套件)
# ==============================================================================
# ==============================================================================
# 全局变量
# ==============================================================================
if ($PSScriptRoot) {
$LIB_SCRIPT_DIR = $PSScriptRoot
} else {
$LIB_SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
}
$global:PLINK_PATH = $null
$global:PSCP_PATH = $null
# ==============================================================================
# 查找 plink 和 pscp 工具
# ==============================================================================
function Initialize-SSHTools {
# 1. 检查 lib 目录的父目录下的 plink.exe(RemoteUpdate 目录)
$parentDir = Split-Path -Parent $LIB_SCRIPT_DIR
$localPlinkPath = Join-Path $parentDir "plink.exe"
if (Test-Path $localPlinkPath) {
$global:PLINK_PATH = $localPlinkPath
$localPscpPath = Join-Path $parentDir "pscp.exe"
if (Test-Path $localPscpPath) {
$global:PSCP_PATH = $localPscpPath
}
return $true
}
# 2. 检查系统 PATH 中的 plink
try {
$systemPlink = Get-Command plink -ErrorAction Stop
$global:PLINK_PATH = $systemPlink.Source
try {
$systemPscp = Get-Command pscp -ErrorAction Stop
$global:PSCP_PATH = $systemPscp.Source
}
catch {
# pscp 未找到,但 plink 存在
}
return $true
}
catch {
return $false
}
}
# ==============================================================================
# SSH 命令执行
# ==============================================================================
function Invoke-SSHCommand {
<#
.SYNOPSIS
通过 SSH 执行远程命令
.DESCRIPTION
使用 plink.exe 通过 SSH 连接到远程服务器并执行命令。
支持直接 root 连接和普通用户 + su 切换两种方式。
.PARAMETER HostName
目标主机 IP 地址或主机名
.PARAMETER User
SSH 登录用户名
.PARAMETER Pass
SSH 登录密码
.PARAMETER Port
SSH 端口号,默认为 22
.PARAMETER Command
要执行的远程命令
.PARAMETER SuUser
切换用户名称(可选),如果提供则先 su 切换再执行命令
.PARAMETER SuPass
切换用户密码(可选)
.EXAMPLE
# 直接 root 连接执行命令
$result = Invoke-SSHCommand -HostName "192.168.1.1" -User "root" -Pass "password" -Command "ls -la"
.EXAMPLE
# 普通用户连接后切换 root 执行命令
$result = Invoke-SSHCommand -HostName "192.168.1.1" -User "appadmin" -Pass "pass" -SuUser "root" -SuPass "rootpass" -Command "docker ps"
.OUTPUTS
System.Collections.Hashtable
包含 Output(命令输出)和 ExitCode(退出码)的哈希表
#>
param(
[Parameter(Mandatory=$true)]
[string]$HostName,
[Parameter(Mandatory=$true)]
[string]$User,
[Parameter(Mandatory=$true)]
[string]$Pass,
[Parameter(Mandatory=$false)]
[int]$Port = 22,
[Parameter(Mandatory=$true)]
[string]$Command,
[Parameter(Mandatory=$false)]
[string]$SuUser = $null,
[Parameter(Mandatory=$false)]
[string]$SuPass = $null
)
# 确保 plink 可用
if (-not $global:PLINK_PATH) {
if (-not (Initialize-SSHTools)) {
throw "plink.exe 未找到,请将 plink.exe 放在脚本同目录下或安装 PuTTY 到系统 PATH"
}
}
# 构建完整的命令
if ($SuUser) {
# 需要先 su 切换用户再执行命令
$fullCommand = "echo '$SuPass' | su - $SuUser -c '$Command'"
} else {
# 直接执行命令
$fullCommand = $Command
}
# 构建 plink 参数
$plinkArgs = @(
"-ssh",
"-P", $Port,
"-l", $User,
"-pw", $Pass,
"-batch",
"-no-antispoof", # 禁用反欺骗检测
$HostName,
$fullCommand
)
# 执行命令
try {
$result = & $global:PLINK_PATH @plinkArgs 2>&1
$exitCode = $LASTEXITCODE
# 处理首次连接主机密钥问题
if ($exitCode -ne 0 -and ($result -match "host key" -or $result -match "Store key in cache")) {
# 尝试接受主机密钥并重试
$plinkArgs = @(
"-ssh",
"-P", $Port,
"-l", $User,
"-pw", $Pass,
"-batch",
"-no-antispoof",
$HostName,
$fullCommand
)
# 通过管道输入 y 来接受主机密钥
$cmdInput = "y`n"
$result = $cmdInput | & $global:PLINK_PATH @plinkArgs 2>&1
$exitCode = $LASTEXITCODE
}
}
catch {
$result = $_.Exception.Message
$exitCode = -1
}
return @{
Output = $result
ExitCode = $exitCode
}
}
# ==============================================================================
# 测试 SSH 连接
# ==============================================================================
function Test-SSHConnection {
<#
.SYNOPSIS
测试 SSH 连接是否可用
.PARAMETER ServerInfo
服务器连接信息哈希表
.EXAMPLE
$server = @{
IP = "192.168.1.1"
Port = 22
SshUsername = "root"
SshPassword = "password"
}
Test-SSHConnection -ServerInfo $server
.OUTPUTS
Boolean,连接成功返回 $true,否则返回 $false
#>
param(
[Parameter(Mandatory=$true)]
[hashtable]$ServerInfo
)
$ipPort = "$($ServerInfo.IP):$($ServerInfo.Port)"
Write-Log -Level "INFO" -Message "测试 SSH 连接: $ipPort"
$testCmd = "echo 'CONNECTION_OK'"
$result = Invoke-SSHCommand `
-HostName $ServerInfo.IP `
-User $ServerInfo.SshUsername `
-Pass $ServerInfo.SshPassword `
-Port $ServerInfo.Port `
-Command $testCmd `
-SuUser $ServerInfo.SuUsername `
-SuPass $ServerInfo.SuPassword
if ($result.ExitCode -eq 0 -and $result.Output -match "CONNECTION_OK") {
Write-Log -Level "SUCCESS" -Message "SSH 连接测试通过"
return $true
} else {
Write-Log -Level "ERROR" -Message "SSH 连接测试失败"
Write-Log -Level "ERROR" -Message "输出信息: $($result.Output -join ' ')"
return $false
}
}
此差异已折叠。
...@@ -345,9 +345,9 @@ $ExpectedFunctions = @( ...@@ -345,9 +345,9 @@ $ExpectedFunctions = @(
"Test-RedisConnection", "Test-RedisConnection",
"Test-MySQLConnection", "Test-MySQLConnection",
"Test-FastDFSConnection", "Test-FastDFSConnection",
"Check-NewPlatformIPs", "Test-NewPlatformIPs",
"Check-TraditionalPlatformIPs", "Test-TraditionalPlatformIPs",
"Check-NTPService", "Test-NTPService",
"Test-AndroidDeviceHealth", "Test-AndroidDeviceHealth",
"Show-HealthReport" "Show-HealthReport"
) )
...@@ -1370,16 +1370,16 @@ function Main { ...@@ -1370,16 +1370,16 @@ function Main {
Write-Host "" Write-Host ""
Write-Log -Level "INFO" -Message "========== 开始检测配置文件 IP ==========" Write-Log -Level "INFO" -Message "========== 开始检测配置文件 IP =========="
if ($platformType -eq "new") { if ($platformType -eq "new") {
Check-NewPlatformIPs -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port Test-NewPlatformIPs -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port
} elseif ($platformType -eq "old") { } elseif ($platformType -eq "old") {
# ✅ 关键:把 systemInfo 传进去,才能按 meeting/unified 选路径 # ✅ 关键:把 systemInfo 传进去,才能按 meeting/unified 选路径
Check-TraditionalPlatformIPs -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port -SystemInfo $systemInfo Test-TraditionalPlatformIPs -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port -SystemInfo $systemInfo
} }
Write-Log -Level "INFO" -Message "========== 结束检测配置文件 IP ==========" Write-Log -Level "INFO" -Message "========== 结束检测配置文件 IP =========="
# 检测 NTP 服务 # 检测 NTP 服务
Write-Log -Level "INFO" -Message "========== 开始检测NTP服务 ==========" Write-Log -Level "INFO" -Message "========== 开始检测NTP服务 =========="
$ntpResults = Check-NTPService -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port $ntpResults = Test-NTPService -ServerIP $server.IP -Username $server.User -Password $server.Pass -Port $server.Port
Write-Log -Level "INFO" -Message "NTP 服务检测完成." Write-Log -Level "INFO" -Message "NTP 服务检测完成."
# 输出 NTP 摘要 # 输出 NTP 摘要
if ($ntpResults) { if ($ntpResults) {
......
# Direct fix script
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
Write-Host "Reading file..."
# Read file
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open($ModulePath, [System.IO.FileMode]::Open),
[System.Text.Encoding]::UTF8
)
$content = $reader.ReadToEnd()
$reader.Close()
# Apply fixes
$originalContent = $content
# Fix 1: MQTT
$content = $content -replace "grep -E '$containerName\|emqx'", "grep -wE '$containerName|emqx'"
Write-Host "Applied fix 1: MQTT container detection"
# Fix 2: echo command
$content = $content -replace "|| echo '''", "| echo ""`""
Write-Host "Applied fix 2: echo command"
# Fix 3: bash command (multiple patterns)
$content = $content -replace 'bash ''\$actualScriptPath'' 2>&1', 'bash "$actualScriptPath" 2>&1'
Write-Host "Applied fix 3: script execution command"
# Save if changed
if ($content -ne $originalContent) {
# Backup
$backupPath = $ModulePath + ".backup3"
[System.IO.File]::WriteAllText($backupPath, $originalContent, [System.Text.Encoding]::UTF8)
# Save fixed
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host "File updated successfully" -ForegroundColor Green
} else {
Write-Host "No changes needed" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "Please verify the fixes:" -ForegroundColor Cyan
Write-Host "1. MQTT: grep -wE should be present" -ForegroundColor Cyan
Write-Host "2. echo "" should be used instead of echo '''" -ForegroundColor Cyan
Write-Host "3. bash `"$actualScriptPath`" should be used for script execution" -ForegroundColor Cyan
# Middleware check module fix script
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
Write-Host "Reading file..." -ForegroundColor Cyan
# Read file as bytes and handle BOM
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
$offset = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$offset = 3
}
$content = [System.Text.Encoding]::UTF8.GetString($bytes, $offset, $bytes.Length - $offset)
# Apply fixes
$content = $content -replace "grep -E '\$containerName\|emqx'", "grep -wE '$containerName|emqx'"
Write-Host "Fixed MQTT container detection" -ForegroundColor Green
$content = $content -replace '\| echo '''', '| echo ""'
Write-Host "Fixed echo command" -ForegroundColor Green
$content = $content -replace "bash '\$actualScriptPath' 2>&1", 'bash "$actualScriptPath" 2>&1'
Write-Host "Fixed script execution command" -ForegroundColor Green
# Save backup and fixed file
[System.IO.File]::WriteAllBytes($ModulePath + ".backup", $bytes)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host ""
Write-Host "Fix completed!" -ForegroundColor Green
# ==============================================================================
# fix_middleware_check.ps1
# ------------------------------------------------------------------------------
# 中间件检测模块修复脚本
#
# .SYNOPSIS
# 修复 MiddlewareCheck.psm1 模块中的脚本路径和执行命令问题
#
# .DESCRIPTION
# 本脚本修复以下问题:
# 1. MQTT 容器检测:添加 -w 参数进行精确单词匹配
# 2. Redis/MySQL/FastDFS 检测:修复远程目录检测和脚本执行命令
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
# ==============================================================================
param(
[Parameter(Mandatory=$false)]
[string]$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
)
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host " 中间件检测模块修复脚本" -ForegroundColor Cyan
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host ""
# 检查文件是否存在
if (-not (Test-Path $ModulePath)) {
Write-Host "[错误] 模块文件不存在: $ModulePath" -ForegroundColor Red
exit 1
}
Write-Host "[信息] 正在读取模块文件..." -ForegroundColor Cyan
# 读取文件内容(处理 BOM 编码)
$content = Get-Content -Path $ModulePath -Raw -Encoding UTF8
$lines = $content -split "`r`n"
$originalLines = $lines.Clone()
Write-Host "[信息] 文件行数: $($lines.Count)" -ForegroundColor Cyan
# 记录修改
$changes = @()
# ==============================================================================
# 修复 1: MQTT 容器检测(第 125 行)
# ==============================================================================
Write-Host ""
Write-Host "[修复 1/4] MQTT 容器检测..." -ForegroundColor Yellow
$mqttLineIdx = 124 # 数组索引从 0 开始
if ($mqttLineIdx -lt $lines.Count -and $lines[$mqttLineIdx] -match "grep -E '\$containerName\|emqx'") {
$lines[$mqttLineIdx] = $lines[$mqttLineIdx] -replace "grep -E", "grep -wE"
$changes += "MQTT 容器检测:添加 -w 参数进行精确单词匹配"
Write-Host " ✓ 已修复 MQTT 容器检测命令" -ForegroundColor Green
}
# ==============================================================================
# 修复 2: Redis 检测模块
# ==============================================================================
Write-Host "[修复 2/4] Redis 检测模块..." -ForegroundColor Yellow
# 修复第 284 行的 echo 命令
$redisDirLineIdx = 283
if ($redisDirLineIdx -lt $lines.Count -and $lines[$redisDirLineIdx] -match "echo '''$") {
$lines[$redisDirLineIdx] = $lines[$redisDirLineIdx] -replace "echo '''$", 'echo ""'
$changes += "Redis:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 Redis 远程目录检测" -ForegroundColor Green
}
# 在第 293 行后添加空值检查
$insertIdx = 293
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$insertIdx..($insertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $insertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
# 修复第 367 行的脚本执行命令
$redisCmdLineIdx = 366
if ($redisCmdLineIdx -lt $lines.Count -and $lines[$redisCmdLineIdx] -match "bash '\$actualScriptPath'") {
$lines[$redisCmdLineIdx] = $lines[$redisCmdLineIdx] -replace "bash '\$actualScriptPath'", 'bash "`$actualScriptPath`"'
$changes += "Redis:修复脚本执行命令"
Write-Host " ✓ 已修复 Redis 脚本执行命令" -ForegroundColor Green
}
# ==============================================================================
# 修复 3: MySQL 检测模块
# ==============================================================================
Write-Host "[修复 3/4] MySQL 检测模块..." -ForegroundColor Yellow
# 由于插入行导致索引变化,需要重新搜索
$mysqlDirLineIdx = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "which check_server_health\.sh.*xargs dirname.*echo '''") {
$mysqlDirLineIdx = $i
break
}
}
if ($mysqlDirLineIdx -ge 0) {
$lines[$mysqlDirLineIdx] = $lines[$mysqlDirLineIdx] -replace "echo '''$", 'echo ""'
$changes += "MySQL:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 MySQL 远程目录检测" -ForegroundColor Green
}
# 查找 MySQL 的远程目录检测结束位置并添加空值检查
$mysqlInsertIdx = -1
for ($i = $mysqlDirLineIdx + 1; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "Write-Log.*检测到远程脚本目录") {
$mysqlInsertIdx = $i
break
}
}
if ($mysqlInsertIdx -gt 0) {
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$mysqlInsertIdx..($mysqlInsertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $mysqlInsertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
$changes += "MySQL:添加空值检查和默认目录"
Write-Host " ✓ 已添加 MySQL 空值检查" -ForegroundColor Green
}
# 修复 MySQL 脚本执行命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match 'mysqlCmd.*= "bash.*"\$actualScriptPath'') {
$lines[$i] = $lines[$i] -replace 'bash "\$actualScriptPath"', 'bash "`$actualScriptPath`"'
$changes += "MySQL:修复脚本执行命令"
Write-Host " ✓ 已修复 MySQL 脚本执行命令" -ForegroundColor Green
break
}
}
# ==============================================================================
# 修复 4: FastDFS 检测模块
# ==============================================================================
Write-Host "[修复 4/4] FastDFS 检测模块..." -ForegroundColor Yellow
# 修复 FastDFS 的 echo 命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "which check_server_health\.sh.*xargs dirname.*echo '''") {
$lines[$i] = $lines[$i] -replace "echo '''$", 'echo ""'
$changes += "FastDFS:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 FastDFS 远程目录检测" -ForegroundColor Green
break
}
}
# 添加 FastDFS 空值检查(类似 MySQL)
$fdfsInsertIdx = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "Write-Log.*检测到远程脚本目录.*FastDFS") {
$fdfsInsertIdx = $i
break
}
}
if ($fdfsInsertIdx -gt 0) {
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$fdfsInsertIdx..($fdfsInsertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $fdfsInsertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
$changes += "FastDFS:添加空值检查和默认目录"
Write-Host " ✓ 已添加 FastDFS 空值检查" -ForegroundColor Green
}
# 修复 FastDFS 脚本执行命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match 'fdfsCmd.*=.*bash.*"\$actualScriptPath'') {
$lines[$i] = $lines[$i] -replace 'bash "\$actualScriptPath"', 'bash "`$actualScriptPath`"'
$changes += "FastDFS:修复脚本执行命令"
Write-Host " ✓ 已修复 FastDFS 脚本执行命令" -ForegroundColor Green
break
}
}
# ==============================================================================
# 保存修复后的文件
# ==============================================================================
Write-Host ""
Write-Host "[信息] 正在保存修复后的文件..." -ForegroundColor Cyan
# 创建备份
$backupPath = $ModulePath + ".backup"
Copy-Item -Path $ModulePath -Destination $backupPath -Force
Write-Host " ✓ 已创建备份: $backupPath" -ForegroundColor Green
# 保存修复后的内容(使用 UTF8 编码,无 BOM)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
$fixedContent = $lines -join "`n"
[System.IO.File]::WriteAllText($ModulePath, $fixedContent, $utf8NoBom)
Write-Host " ✓ 已保存修复后的文件" -ForegroundColor Green
# ==============================================================================
# 显示修复摘要
# ==============================================================================
Write-Host ""
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host " 修复完成" -ForegroundColor Green
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "修复项数量: $($changes.Count)" -ForegroundColor Cyan
Write-Host ""
foreach ($change in $changes) {
Write-Host "$change" -ForegroundColor Green
}
Write-Host ""
Write-Host "原文件已备份到: $backupPath" -ForegroundColor Yellow
Write-Host ""
# ==============================================================================
# 中间件检测模块快速修复脚本
# ==============================================================================
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
$BackupPath = $ModulePath + ".backup"
Write-Host "正在读取文件..." -ForegroundColor Cyan
# 使用 .NET 读取文件,避免编码问题
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
# 检测 BOM 并移除
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$bytes = $bytes[3..($bytes.Length-1)]
}
# 转换为字符串
$content = [System.Text.Encoding]::UTF8.GetString($bytes)
# 修复 1: MQTT 容器检测
$content = $content -replace "grep -E '\$containerName\|emqx'", "grep -wE '`$containerName'|emqx'"
Write-Host " ✓ 修复 MQTT 容器检测" -ForegroundColor Green
# 修复 2: 修复所有 || echo ''' 的问题
$content = $content -replace '\|\s+echo\s*'''', "| echo `"`"`""
Write-Host " ✓ 修复远程目录检测" -ForegroundColor Green
# 修复 3: 修复脚本执行命令
$content = $content -replace 'bash ''\$actualScriptPath'' 2>&1', 'bash "`$actualScriptPath`" 2>&1'
Write-Host " ✓ 修复脚本执行命令" -ForegroundColor Green
# 修复 4: 在检测到远程脚本目录后添加空值检查
$content = $content -replace "(Write-Log -Level \"INFO\" -Message \"\[(Redis|MySQL|FastDFS)\] 检测到远程脚本目录: `\$remoteScriptDir\")", "`$1`n`n # 如果仍然为空,使用默认目录`n if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {`n `$remoteScriptDir = `"/root`"`n }"
Write-Host " ✓ 添加空值检查" -ForegroundColor Green
# 创建备份
[System.IO.File]::WriteAllBytes($BackupPath, [System.IO.File]::ReadAllBytes($ModulePath))
Write-Host " ✓ 已创建备份: $BackupPath" -ForegroundColor Green
# 保存修复后的文件(UTF-8 无 BOM)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host ""
Write-Host "修复完成!" -ForegroundColor Green
Write-Host ""
# Fix script for middleware module
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
# Read file
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
$offset = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$offset = 3
}
$content = [System.Text.Encoding]::UTF8.GetString($bytes, $offset, $bytes.Length - $offset)
# Fix MQTT: grep -E -> grep -wE
$content = $content -replace "grep -E", "grep -wE"
# Fix echo command: echo ''' -> echo ""
$content = $content -replace [char]0x27 + [char]0x27 + [char]0x27, [char]0x22 + [char]0x22 + [char]0x22
# Fix script exec: bash '$actualScriptPath' -> bash "$actualScriptPath"
$pattern1 = [char]0x62 + [char]0x61 + [char]0x73 + [char]0x68 + [char]0x20 + [char]0x27 + [char]0x24 + [char]0x61 + [char]0x63 + [char]0x74 + [char]0x75 + [char]0x61 + [char]0x6C + [char]0x53 + [char]0x63 + [char]0x72 + [char]0x69 + [char]0x70 + [char]0x74 + [char]0x50 + [char]0x61 + [char]0x74 + [char]0x68 + [char]0x20 + [char]0x27 + [char]0x32 + [char]0x3E + [char]0x31
$replace1 = [char]0x62 + [char]0x61 + [char]0x73 + [char]0x68 + [char]0x20 + [char]0x22 + [char]0x24 + [char]0x61 + [char]0x63 + [char]0x74 + [char]0x75 + [char]0x61 + [char]0x6C + [char]0x53 + [char]0x63 + [char]0x72 + [char]0x69 + [char]0x70 + [char]0x74 + [char]0x50 + [char]0x61 + [char]0x74 + [char]0x68 + [char]0x20 + [char]0x22 + [char]0x32 + [char]0x3E + [char]0x31
$content = $content -replace $pattern1, $replace1
# Save backup
[System.IO.File]::WriteAllBytes($ModulePath + ".backup2", $bytes)
# Save fixed file
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host "Fix completed" -ForegroundColor Green
# _PRD_中间件emqx匹配不到容器_问题处理
> 脚本来源:
- `AuxiliaryTool/ScriptTool/ServiceSelfInspection/check_server_health.ps1`
- `AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules`
## 1. 背景与目标
### 1.1 背景
执行主运行脚本后中间件检测时emqx容器没能匹配到容器,导致无法检测,但实际服务器上是有运行uemqx2容器的。
### 1.2 目标
确保服务检测正确、日志和报告正确打印信息。
---
## 2. 问题报错信息
### 2.1问题一
```
[2026-02-10 13:19:29] [INFO] ========== 开始中间件连接检测 ==========
[2026-02-10 13:19:32] [INFO] [中间件] 检测到平台类型: old
[2026-02-10 13:19:34] [INFO] [中间件] 日志导出目录: ./middleware_logs
[2026-02-10 13:19:34] [INFO] ========== MQTT服务连接检测 ==========
[2026-02-10 13:19:37] [WARN] [MQTT] 未检测到EMQX容器(),跳过MQTT连接检测
[2026-02-10 13:19:38] [INFO] ========== Redis连接检测 ==========
[2026-02-10 13:19:38] [INFO] [Redis] 开始上传/更新 check_redis.sh 脚本...
```
### 2.2问题二
```
```
## 3. 问题解决分析
### 3.1 问题根因
**容器名称不匹配**
- 配置中 `ContainerName = "uemqx"`
- 实际服务器运行的容器为 `uemqx2`
- grep 命令使用 `-w` 参数要求**全词匹配**
- `uemqx2` 作为整体单词不等于 `uemqx`,导致匹配失败
**代码位置**`MiddlewareCheck.psm1:125`
```powershell
$checkContainerCmd = "docker ps --format '{{.Names}}' | grep -wE '$containerName|emqx' | head -n 1"
```
**匹配分析**
| 模式 | 匹配 uemqx | 匹配 uemqx2 | 说明 |
|------|-----------|------------|------|
| `grep -wE 'uemqx|emqx'` | ✅ | ❌ | 全词匹配,uemqx2 ≠ uemqx |
### 3.2 涉及文件
| 文件 | 位置 | 状态 |
|------|------|------|
| MiddlewareCheck.psm1 | AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules/ | ✅ 已修复 |
### 3.3 代码验证
**修复前**
```powershell
$checkContainerCmd = "docker ps --format '{{.Names}}' | grep -wE '$containerName|emqx' | head -n 1"
```
**修复后**
```powershell
# 使用更灵活的匹配模式:匹配配置的容器名、容器名加数字后缀、或包含emqx的容器名
$checkContainerCmd = "docker ps --format '{{.Names}}' | grep -E '^${containerName}$|^${containerName}[0-9]+$|emqx' | head -n 1"
```
**新正则说明**
- `^${containerName}$` - 精确匹配配置的容器名(如 `uemqx`
- `^${containerName}[0-9]+$` - 匹配容器名加数字后缀(如 `uemqx2`, `uemqx3`
- `emqx` - 兜底匹配任何包含 `emqx` 的容器名
### 3.4 解决方案
修改 `MiddlewareCheck.psm1` 第 125 行的容器检测命令:
1. 移除 `-w` 全词匹配参数
2. 添加对容器名加数字后缀的支持
### 3.5 预防措施
1. 定期检查各环境的容器命名规范
2. 考虑在配置中支持多个容器名模式
3. 增加容器检测的日志输出,便于排查
### 3.6 问题状态
| 状态项 | 值 |
|--------|-----|
| 问题状态 | ✅ 已修复 |
| 修复日期 | 2026-02-10 |
| 执行计划 | 已创建:`_PRD_中间件emqx匹配不到容器_执行计划.md` |
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
\ No newline at end of file
...@@ -176,7 +176,27 @@ switch 语句的子句中缺少语句块。 ...@@ -176,7 +176,27 @@ switch 语句的子句中缺少语句块。
### 2.2问题二 ### 2.2问题二
``` ```
PS C:\Users\EDY\Desktop\Sever_health_check> .\check_server_health.ps1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: Common.psm1 (公共函数)
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: ServiceCheck.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: DNSCheck.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: ServerResourceAnalysis.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: NTPCheck.psm1
[模块加载] 成功加载: ContainerCheck.psm1
[模块加载] 加载失败: ConfigIPCheck.psm1 - 已停止该运行的命令,因为首选项变量“ErrorActionPreference”或通用参数设置为 Stop: 所在位置 C:\Users\EDY\Desktop\Sever_health_check\modules\ConfigIPCheck.psm1:280 字符: 38
+ Write-Log -Level "INFO" -Message "[CFG] 浼犵粺骞冲彴閰嶇疆鏂囦欢 IP 妫€鏌ュ畬鎴?
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
字符串缺少终止符: "。
所在位置 C:\Users\EDY\Desktop\Sever_health_check\modules\ConfigIPCheck.psm1:226 字符: 38
+ function Test-TraditionalPlatformIPs {
+ ~
语句块或类型定义中缺少右“}”
``` ```
## 3. 问题解决分析 ## 3. 问题解决分析
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论