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

feat(service-monitor): P2级检测模块移植-系统类型识别/平台服务检测/配置IP检测/Console配置检测

新增 4 个检测模块(阶段三):
- 50_system_profile.sh:系统类型识别(平台/容器/ujava变体)
- 51_service_check.sh:平台服务检测(服务进程+端口监听)
- 52_config_ip_check.sh:配置IP检测(未授权IP扫描)
- 53_config_console_check.sh:Console配置检测(只检测不修复)

配套更新:
- check_modules.py 追加 4 个模块注册
- display_names.py 追加 35 个 KEY 映射
- parser.py 追加 2 个状态词映射
- config.sh.template 追加服务匹配模式+端口列表配置

文档:PRD_需求文档_P2级移植.md + PRD_计划执行_P2级移植.md + HANDOFF更新
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 5400a91f
# 计划执行:P2 级检测模块移植
## 文档信息
- 创建时间:2026-07-22
- 关联需求文档:`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
- 预计改动文件:4 个
- 预计新增文件:4 个
---
## 执行步骤
### Step 1:系统类型识别模块 — 50_system_profile.sh
**文件**`skill/code/web/service_monitor/assets/system/50_system_profile.sh`(新增)
**检测项**
| KEY | 输出 |
|-----|------|
| `SYS_PROFILE_PLATFORM_TYPE` | new/old |
| `SYS_PROFILE_PLATFORM_TYPE_LEVEL` | 正常/跳过 |
| `SYS_PROFILE_CONTAINER_TYPE` | ujava/upython/upython_voice/unknown |
| `SYS_PROFILE_CONTAINER_TYPE_LEVEL` | 正常/跳过 |
| `SYS_PROFILE_UJAVA_VARIANT` | unified/meeting/none |
| `SYS_PROFILE_UJAVA_VARIANT_LEVEL` | 正常/跳过 |
**实现要点**
```bash
#!/bin/bash
################################################################################
# 50_system_profile.sh — 系统类型识别
# 功能: 检测平台类型、容器类型、ujava 变体
# 参考: ServerProfile.psm1
# 日期: 2026-07-22
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"
# ==================== 平台类型检测 ====================
detect_platform_type() {
if [ -d "/data/services" ]; then
output_result "SYS_PROFILE_PLATFORM_TYPE" "new"
else
output_result "SYS_PROFILE_PLATFORM_TYPE" "old"
fi
output_result "SYS_PROFILE_PLATFORM_TYPE_LEVEL" "正常"
}
# ==================== 容器类型检测 ====================
detect_container_type() {
local containers
containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "ujava"
elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "upython_voice"
elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "upython"
else
output_result "SYS_PROFILE_CONTAINER_TYPE" "unknown"
fi
output_result "SYS_PROFILE_CONTAINER_TYPE_LEVEL" "正常"
}
# ==================== ujava 变体检测 ====================
detect_ujava_variant() {
local container_type
container_type=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
if [ -n "$container_type" ]; then
if [ -d "/var/www/java/unifiedPlatform" ]; then
output_result "SYS_PROFILE_UJAVA_VARIANT" "unified"
else
output_result "SYS_PROFILE_UJAVA_VARIANT" "meeting"
fi
else
output_result "SYS_PROFILE_UJAVA_VARIANT" "none"
fi
output_result "SYS_PROFILE_UJAVA_VARIANT_LEVEL" "正常"
}
# 主函数
main() {
detect_platform_type
detect_container_type
detect_ujava_variant
}
main "$@"
```
**依赖**`docker` 命令
---
### Step 2:平台服务检测模块 — 51_service_check.sh
**文件**`skill/code/web/service_monitor/assets/service/51_service_check.sh`(新增)
**检测项**:约 20 个(服务状态 + 端口状态)
**实现要点**
```bash
#!/bin/bash
################################################################################
# 51_service_check.sh — 平台服务检测
# 功能: 检测核心业务服务进程状态 + 容器端口监听
# 参考: ServiceCheck.psm1, check_server_health.sh
# 日期: 2026-07-22
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"
# 服务匹配模式(从 config.sh 读取或使用默认值)
UJAVA_SERVICES="${UJAVA_SERVICES:-auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar}"
UJAVA_HOST_SERVICES="${UJAVA_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_CONTAINER_SERVICES="${UJAVA_OLD_CONTAINER_SERVICES:-nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_HOST_SERVICES="${UJAVA_OLD_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
# 端口列表
UPYTHON_PORTS_NEW="${UPYTHON_PORTS_NEW:-8000:uwsgi,11211:memcached}"
UPYTHON_VOICE_PORTS_NEW="${UPYTHON_VOICE_PORTS_NEW:-8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto}"
UPYTHON_PORTS_OLD="${UPYTHON_PORTS_OLD:-8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd}"
# 先检测平台类型和容器类型(内部实现,不依赖 50 模块)
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
detect_container_type() {
local containers
containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
echo "ujava"
elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
echo "upython_voice"
elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
echo "upython"
else
echo "unknown"
fi
}
# 检测服务进程(容器内)
check_service_in_container() {
local container="$1"
local pattern="$2"
local key="$3"
local display_name="$4"
local count
count=$(docker exec "$container" ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
if [ "$count" -gt 0 ]; then
output_result "${key}_STATUS" "运行中"
output_result "${key}_STATUS_LEVEL" "正常"
else
output_result "${key}_STATUS" "未运行"
output_result "${key}_STATUS_LEVEL" "严重"
fi
}
# 检测服务进程(宿主机)
check_service_on_host() {
local pattern="$1"
local key="$2"
local path_hint="$3" # 可选路径匹配
local count
if [ -n "$path_hint" ]; then
count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -F "$path_hint" | grep -v grep | wc -l)
else
count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
fi
if [ "$count" -gt 0 ]; then
output_result "${key}_STATUS" "运行中"
output_result "${key}_STATUS_LEVEL" "正常"
else
output_result "${key}_STATUS" "未运行"
output_result "${key}_STATUS_LEVEL" "严重"
fi
}
# 检测端口监听(容器内,用进程检查代替 ss)
check_port_in_container() {
local container="$1"
local port="$2"
local process="$3"
local key="$4"
local count
count=$(docker exec "$container" ps aux 2>/dev/null | grep "$process" | grep -v grep | wc -l)
if [ "$count" -gt 0 ]; then
output_result "SVC_CHECK_PORT_${port}_STATUS" "监听"
output_result "SVC_CHECK_PORT_${port}_STATUS_LEVEL" "正常"
else
output_result "SVC_CHECK_PORT_${port}_STATUS" "未监听"
output_result "SVC_CHECK_PORT_${port}_STATUS_LEVEL" "严重"
fi
}
# 主函数
main() {
local platform_type container_type ujava_container upython_container
platform_type=$(detect_platform_type)
container_type=$(detect_container_type)
# 获取容器名
ujava_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
upython_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^upython' | head -1)
if [ "$platform_type" = "new" ]; then
# 新平台服务检测
if [ "$container_type" = "ujava" ]; then
# 容器内服务
IFS=',' read -ra services <<< "$UJAVA_SERVICES"
for svc in "${services[@]}"; do
IFS=':' read -r key pattern <<< "$svc"
check_service_in_container "$ujava_container" "$pattern" "SVC_CHECK_${key^^}" "$key"
done
fi
# 宿主机 extapi
IFS=',' read -ra host_services <<< "$UJAVA_HOST_SERVICES"
for svc in "${host_services[@]}"; do
IFS=':' read -r key pattern <<< "$svc"
check_service_on_host "$pattern" "SVC_CHECK_${key^^}"
done
# upython/upython_voice 端口
if [ "$container_type" = "upython" ]; then
IFS=',' read -ra ports <<< "$UPYTHON_PORTS_NEW"
elif [ "$container_type" = "upython_voice" ]; then
IFS=',' read -ra ports <<< "$UPYTHON_VOICE_PORTS_NEW"
fi
for port_proc in "${ports[@]}"; do
IFS=':' read -r port process <<< "$port_proc"
check_port_in_container "$upython_container" "$port" "$process"
done
else
# 传统平台服务检测
if [ "$container_type" = "ujava" ]; then
IFS=',' read -ra services <<< "$UJAVA_OLD_CONTAINER_SERVICES"
for svc in "${services[@]}"; do
IFS=':' read -r key pattern <<< "$svc"
check_service_in_container "$ujava_container" "$pattern" "SVC_CHECK_${key^^}_OLD" "$key"
done
fi
# 传统平台 extapi(宿主机)
check_service_on_host "ubains-meeting-api-1.0-SNAPSHOT.jar" "SVC_CHECK_EXTAPI_OLD" "/var/www/java/external-meeting-api"
# 传统平台 upython 端口
IFS=',' read -ra ports <<< "$UPYTHON_PORTS_OLD"
for port_proc in "${ports[@]}"; do
IFS=':' read -r port process <<< "$port_proc"
check_port_in_container "$upython_container" "$port" "$process"
done
fi
}
main "$@"
```
**依赖**`docker``ps` 命令
---
### Step 3:配置IP检测模块 — 52_config_ip_check.sh
**文件**`skill/code/web/service_monitor/assets/system/52_config_ip_check.sh`(新增)
**检测项**
| KEY | 输出 |
|-----|------|
| `CFG_IP_STATUS` | OK/WARN |
| `CFG_IP_STATUS_LEVEL` | 正常/警告 |
| `CFG_IP_TOTAL_FILES` | 整数 |
| `CFG_IP_UNAUTHORIZED_COUNT` | 整数 |
| `CFG_IP_UNAUTHORIZED_LINES` | JSON 数组字符串 |
**实现要点**
```bash
#!/bin/bash
################################################################################
# 52_config_ip_check.sh — 配置IP检测
# 功能: 扫描配置文件中的未授权 IP 地址
# 参考: ConfigIPCheck.psm1, config_check.sh
# 日期: 2026-07-22
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"
# IP 正则
IP_REGEX='([0-9]{1,3}\.){3}[0-9]{1,3}'
# 允许列表(从 config.sh 读取或使用默认值)
SERVER_IP="${SERVER_IP:-}"
ALLOWED_IPS="${SERVER_IP} 127.0.0.1 172.17.0.1"
# 新平台配置目录
NEW_PLATFORM_CONFIG_DIRS=(
"/data/services/api/auth/auth-sso-auth/config"
"/data/services/api/auth/auth-sso-gateway/config"
"/data/services/api/auth/auth-sso-system/config"
"/data/services/api/java-meeting/java-meeting2.0/config"
"/data/services/api/java-meeting/java-meeting-extapi/config"
"/data/services/api/java-meeting/java-message-scheduling/config"
"/data/services/api/java-meeting/java-mqtt/config"
"/data/services/api/java-meeting/java-quartz/config"
"/data/services/api/python-cmdb"
"/data/services/web/pc/pc-vue2-ai/static"
"/data/services/web/mobile/mobile-vue2/static"
"/data/middleware/nginx/config"
)
# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
"/var/www/java/api-java-meeting2.0/config"
"/var/www/java/external-meeting-api/config"
"/var/www/java/ubains-web-2.0/static"
"/var/www/java/ubains-web-admin/static"
"/var/www/java/ubains-web-h5/static/h5"
"/var/www/java/nginx-conf.d"
)
# 检测平台类型
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
# 扫描 IP
scan_config_ips() {
local platform_type="$1"
local -a config_dirs
local total_files=0
local unauthorized_count=0
local unauthorized_lines=()
if [ "$platform_type" = "new" ]; then
config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
else
config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
fi
for dir in "${config_dirs[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
while IFS= read -r file; do
((total_files++))
local line_num=0
while IFS= read -r line; do
((line_num++))
local ips
ips=$(echo "$line" | grep -oE "$IP_REGEX" 2>/dev/null)
for ip in $ips; do
if ! echo "$ALLOWED_IPS" | grep -qF "$ip"; then
((unauthorized_count++))
unauthorized_lines+=("{\"file\":\"$file\",\"line\":$line_num,\"ip\":\"$ip\"}")
fi
done
done < "$file"
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" -o -name "*.conf" \) 2>/dev/null)
done
# 输出结果
if [ "$unauthorized_count" -eq 0 ]; then
output_result "CFG_IP_STATUS" "OK"
output_result "CFG_IP_STATUS_LEVEL" "正常"
else
output_result "CFG_IP_STATUS" "WARN"
output_result "CFG_IP_STATUS_LEVEL" "警告"
fi
output_result "CFG_IP_TOTAL_FILES" "$total_files"
output_result "CFG_IP_UNAUTHORIZED_COUNT" "$unauthorized_count"
# JSON 数组输出
if [ ${#unauthorized_lines[@]} -gt 0 ]; then
local json_array="["
json_array+=$(IFS=,; echo "${unauthorized_lines[*]}")
json_array+="]"
output_result "CFG_IP_UNAUTHORIZED_LINES" "$json_array"
else
output_result "CFG_IP_UNAUTHORIZED_LINES" "[]"
fi
}
main() {
local platform_type
platform_type=$(detect_platform_type)
scan_config_ips "$platform_type"
}
main "$@"
```
**依赖**`find``grep``SERVER_IP` 配置
---
### Step 4:Console配置检测模块 — 53_config_console_check.sh
**文件**`skill/code/web/service_monitor/assets/system/53_config_console_check.sh`(新增)
**检测项**
| KEY | 输出 |
|-----|------|
| `CFG_CONSOLE_STATUS` | OK/WARN |
| `CFG_CONSOLE_STATUS_LEVEL` | 正常/警告 |
| `CFG_CONSOLE_TOTAL_FILES` | 整数 |
| `CFG_CONSOLE_FOUND_COUNT` | 整数 |
| `CFG_CONSOLE_FOUND_FILES` | JSON 数组字符串 |
**实现要点**
```bash
#!/bin/bash
################################################################################
# 53_config_console_check.sh — Console配置检测
# 功能: 检测 console=true 配置项未关闭问题(只检测不修复)
# 参考: check_server_health.sh (第1582-1708行)
# 日期: 2026-07-22
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
source "$LIB_DIR/lib/config.sh"
source "$LIB_DIR/lib/common.sh"
# console 正则(不区分大小写)
CONSOLE_REGEX='console[[:space:]]*[:=][[:space:]]*true'
# 新平台配置目录(复用 IP 检测的目录列表)
NEW_PLATFORM_CONFIG_DIRS=(
"/data/services/api/auth/auth-sso-auth/config"
"/data/services/api/auth/auth-sso-gateway/config"
"/data/services/api/auth/auth-sso-system/config"
"/data/services/api/java-meeting/java-meeting2.0/config"
"/data/services/api/java-meeting/java-meeting-extapi/config"
"/data/services/api/java-meeting/java-message-scheduling/config"
"/data/services/api/java-meeting/java-mqtt/config"
"/data/services/api/java-meeting/java-quartz/config"
"/data/services/api/python-cmdb"
"/data/services/web/pc/pc-vue2-ai/static"
"/data/services/web/mobile/mobile-vue2/static"
"/data/middleware/nginx/config"
)
# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
"/var/www/java/api-java-meeting2.0/config"
"/var/www/java/external-meeting-api/config"
"/var/www/java/ubains-web-2.0/static"
"/var/www/java/ubains-web-admin/static"
"/var/www/java/ubains-web-h5/static/h5"
"/var/www/java/nginx-conf.d"
)
# 检测平台类型
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
# 扫描 console=true
scan_console_config() {
local platform_type="$1"
local -a config_dirs
local total_files=0
local found_count=0
local found_files=()
if [ "$platform_type" = "new" ]; then
config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
else
config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
fi
for dir in "${config_dirs[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
while IFS= read -r file; do
((total_files++))
if grep -qiE "$CONSOLE_REGEX" "$file" 2>/dev/null; then
((found_count++))
found_files+=("\"$file\"")
fi
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" \) 2>/dev/null)
done
# 输出结果
if [ "$found_count" -eq 0 ]; then
output_result "CFG_CONSOLE_STATUS" "OK"
output_result "CFG_CONSOLE_STATUS_LEVEL" "正常"
else
output_result "CFG_CONSOLE_STATUS" "WARN"
output_result "CFG_CONSOLE_STATUS_LEVEL" "警告"
fi
output_result "CFG_CONSOLE_TOTAL_FILES" "$total_files"
output_result "CFG_CONSOLE_FOUND_COUNT" "$found_count"
# JSON 数组输出
if [ ${#found_files[@]} -gt 0 ]; then
local json_array="["
json_array+=$(IFS=,; echo "${found_files[*]}")
json_array+="]"
output_result "CFG_CONSOLE_FOUND_FILES" "$json_array"
else
output_result "CFG_CONSOLE_FOUND_FILES" "[]"
fi
}
main() {
local platform_type
platform_type=$(detect_platform_type)
scan_console_config "$platform_type"
}
main "$@"
```
**依赖**`find``grep`
---
### Step 5:模块注册 — check_modules.py
**文件**`skill/code/web/service_monitor/utils/check_modules.py`
**改动位置**`ALL_MODULES` 列表
**新增内容**
```python
# 在 system 类区块(46_security_deep 之后)
CheckModule("50_system_profile", "系统类型识别", "system",
{SUITE_FULL}, "50_system_profile.sh"),
CheckModule("52_config_ip_check", "配置IP检测", "system",
{SUITE_FULL}, "52_config_ip_check.sh"),
CheckModule("53_config_console_check", "Console配置检测", "system",
{SUITE_FULL}, "53_config_console_check.sh"),
# 在 service 类区块(39_middleware_conn 之后)
CheckModule("51_service_check", "平台服务检测", "service",
{SUITE_FULL}, "51_service_check.sh"),
```
**注意顺序**`50_system_profile` 应在 `51_service_check` 之前,确保平台类型先被识别。
---
### Step 6:显示名映射 — display_names.py
**文件**`skill/code/web/service_monitor/utils/display_names.py`
**新增内容**(约 35 个 KEY):
```python
# ==================== 系统类型识别 (50_system_profile) ====================
"SYS_PROFILE_PLATFORM_TYPE": "平台类型",
"SYS_PROFILE_PLATFORM_TYPE_LEVEL": "平台类型状态等级",
"SYS_PROFILE_CONTAINER_TYPE": "容器类型",
"SYS_PROFILE_CONTAINER_TYPE_LEVEL": "容器类型状态等级",
"SYS_PROFILE_UJAVA_VARIANT": "ujava变体",
"SYS_PROFILE_UJAVA_VARIANT_LEVEL": "ujava变体状态等级",
# ==================== 平台服务检测 (51_service_check) ====================
"SVC_CHECK_AUTH_STATUS": "认证服务状态",
"SVC_CHECK_AUTH_STATUS_LEVEL": "认证服务状态等级",
"SVC_CHECK_GATEWAY_STATUS": "网关服务状态",
"SVC_CHECK_GATEWAY_STATUS_LEVEL": "网关服务状态等级",
"SVC_CHECK_SYSTEM_STATUS": "系统服务状态",
"SVC_CHECK_SYSTEM_STATUS_LEVEL": "系统服务状态等级",
"SVC_CHECK_MEETING_STATUS": "会议服务状态",
"SVC_CHECK_MEETING_STATUS_LEVEL": "会议服务状态等级",
"SVC_CHECK_MQTT_STATUS": "MQTT服务状态",
"SVC_CHECK_MQTT_STATUS_LEVEL": "MQTT服务状态等级",
"SVC_CHECK_QUARTZ_STATUS": "定时任务服务状态",
"SVC_CHECK_QUARTZ_STATUS_LEVEL": "定时任务服务状态等级",
"SVC_CHECK_MESSAGE_STATUS": "消息调度服务状态",
"SVC_CHECK_MESSAGE_STATUS_LEVEL": "消息调度服务状态等级",
"SVC_CHECK_EXTAPI_STATUS": "对外API服务状态",
"SVC_CHECK_EXTAPI_STATUS_LEVEL": "对外API服务状态等级",
# 传统平台服务
"SVC_CHECK_NGINX_OLD_STATUS": "Nginx服务状态(传统)",
"SVC_CHECK_NGINX_OLD_STATUS_LEVEL": "Nginx服务状态等级(传统)",
"SVC_CHECK_MEETING_OLD_STATUS": "会议服务状态(传统)",
"SVC_CHECK_MEETING_OLD_STATUS_LEVEL": "会议服务状态等级(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS": "对外API服务状态(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS_LEVEL": "对外API服务状态等级(传统)",
# 端口检测
"SVC_CHECK_PORT_8000_STATUS": "uWSGI端口8000状态",
"SVC_CHECK_PORT_8000_STATUS_LEVEL": "uWSGI端口8000状态等级",
"SVC_CHECK_PORT_11211_STATUS": "Memcached端口11211状态",
"SVC_CHECK_PORT_11211_STATUS_LEVEL": "Memcached端口11211状态等级",
"SVC_CHECK_PORT_8080_STATUS": "Nginx端口8080状态",
"SVC_CHECK_PORT_8080_STATUS_LEVEL": "Nginx端口8080状态等级",
"SVC_CHECK_PORT_1883_STATUS": "MQTT端口1883状态",
"SVC_CHECK_PORT_1883_STATUS_LEVEL": "MQTT端口1883状态等级",
# ==================== 配置IP检测 (52_config_ip_check) ====================
"CFG_IP_STATUS": "配置IP检测状态",
"CFG_IP_STATUS_LEVEL": "配置IP检测状态等级",
"CFG_IP_TOTAL_FILES": "扫描文件数",
"CFG_IP_UNAUTHORIZED_COUNT": "未授权IP数",
"CFG_IP_UNAUTHORIZED_LINES": "未授权IP明细",
# ==================== Console配置检测 (53_config_console_check) ====================
"CFG_CONSOLE_STATUS": "Console配置检测状态",
"CFG_CONSOLE_STATUS_LEVEL": "Console配置检测状态等级",
"CFG_CONSOLE_TOTAL_FILES": "扫描文件数",
"CFG_CONSOLE_FOUND_COUNT": "发现问题数",
"CFG_CONSOLE_FOUND_FILES": "问题文件列表",
```
---
### Step 7:阈值配置 — thresholds.py
**文件**`skill/code/web/service_monitor/utils/thresholds.py`
**新增内容**(可选,状态检测通常用 LEVEL 字段):
```python
# 如果需要数值型阈值,可添加:
# "CFG_IP_UNAUTHORIZED_COUNT": {"warning": 1, "critical": 10},
# "CFG_CONSOLE_FOUND_COUNT": {"warning": 1, "critical": 5},
```
**状态词映射**(在 `_VALUE_STATUS_MAP` 中添加):
```python
# 状态词 → 状态等级映射
"运行中": "正常",
"未运行": "严重",
"监听": "正常",
"未监听": "严重",
```
---
### Step 8:配置模板 — config.sh.template
**文件**`skill/code/web/service_monitor/assets/config.sh.template`
**新增内容**
```bash
# ==================== 平台服务检测配置 ====================
# ujava 服务匹配模式(新平台)
export UJAVA_SERVICES="auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar"
# ujava 宿主机服务
export UJAVA_HOST_SERVICES="extapi:ubains-meeting-api-1.0-SNAPSHOT.jar"
# 传统平台 ujava 容器服务
export UJAVA_OLD_CONTAINER_SERVICES="nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar"
# 传统平台 ujava 宿主机服务
export UJAVA_OLD_HOST_SERVICES="extapi:ubains-meeting-api-1.0-SNAPSHOT.jar"
# upython 端口列表(新平台)
export UPYTHON_PORTS_NEW="8000:uwsgi,11211:memcached"
# upython_voice 端口列表(新平台)
export UPYTHON_VOICE_PORTS_NEW="8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto"
# upython 端口列表(传统平台)
export UPYTHON_PORTS_OLD="8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd"
# ==================== 配置IP检测配置 ====================
# 允许的 IP 列表(服务器IP 在运行时注入)
# 格式:空格分隔的 IP 列表
# export ALLOWED_IPS="__SERVER_IP__ 127.0.0.1 172.17.0.1"
```
---
## 验收标准
| 验收项 | 验证方法 |
|--------|---------|
| 4 个脚本语法正确 | `bash -n script.sh` 无报错 |
| 模块已注册 | `get_suite('full')` 返回 34 个模块 |
| 显示名已添加 | 新 KEY 在 `DISPLAY_NAMES` 中存在 |
| 单元测试通过 | `pytest` 全绿(218 个 + 新增测试) |
| 服务检测正确 | 在 5.44 目标运行,结果与 `docker ps` 一致 |
| 配置 IP 检测正确 | 人工抽查配置文件验证 |
| Console 检测正确 | 人工抽查配置文件验证 |
---
## 测试计划
### 单元测试
1. **check_modules.test_get_suite**:验证 `get_suite('full')` 包含新模块
2. **check_modules.test_render_config**:验证新配置项渲染正确
### 集成测试
1. 在 5.44 目标运行 `full` 套件
2. 检查报告中新检测项输出
3. 对比 `docker ps` 验证服务检测准确性
4. 抽查配置文件验证 IP/Console 检测准确性
---
## 风险与缓解
| 风险 | 缓解措施 |
|------|---------|
| 配置目录不存在 | 脚本内做存在性检查,graceful 跳过 |
| 容器名匹配失败 | 使用 `grep -iE` 模糊匹配 + 默认值 |
| 新旧平台混合 | 先检测平台类型,分支执行 |
| 端口检测容器内无 ss | 用进程检查代替端口检测 |
---
## 实施记录
| 步骤 | 状态 | 说明 |
|------|------|------|
| Step 1: 50_system_profile.sh | ⬜ 待实施 | |
| Step 2: 51_service_check.sh | ⬜ 待实施 | |
| Step 3: 52_config_ip_check.sh | ⬜ 待实施 | |
| Step 4: 53_config_console_check.sh | ⬜ 待实施 | |
| Step 5: check_modules.py | ⬜ 待实施 | |
| Step 6: display_names.py | ⬜ 待实施 | |
| Step 7: thresholds.py | ⬜ 待实施 | |
| Step 8: config.sh.template | ⬜ 待实施 | |
| 集成测试 | ⬜ 待实施 | |
| 部署验证 | ⬜ 待实施 | |
---
## 后续工作
- P3 级模块移植:文件权限、定时任务预期、FastDFS 等
- 服务检测扩展:支持自定义服务匹配模式
- 配置 IP 检测增强:IP 白名单可配置化
# 需求文档:P2 级检测模块移植(系统类型识别 + 平台服务检测 + 配置IP检测 + Console配置检测)
## 文档信息
- 创建时间:2026-07-22
- 需求来源:用户需求
- 关联模块:service_monitor
- 父需求:`PRD_需求文档_检测项丰富化移植.md`(阶段三)
---
## 1. 背景与目标
### 1.1 背景
服务监测模块已完成阶段一(补全缺失项 + 重构 depth 脚本)和阶段二(安全合规深度检测 + 中间件连接检测)。本次为阶段三,移植 P2 优先级的 4 个检测模块。
### 1.2 目标
移植参考目录(老版 PowerShell + Shell 巡检工具集)中的 4 个检测模块到本项目,适配现有架构:
1. **系统类型识别**:检测平台类型(新/旧)、容器类型(ujava/upython/upython_voice)、ujava 变体(unified/meeting)
2. **平台服务检测**:检测核心业务服务进程状态(auth/gateway/system/meeting/mqtt/quartz/message/extapi)+ 容器端口监听
3. **配置IP检测**:扫描配置文件中的未授权 IP 地址
4. **Console配置检测**:检测 `console=true` 配置项未关闭问题
---
## 2. 参考源文件分析
| 模块 | 参考源 | 行数 | 核心功能 |
|------|--------|------|---------|
| 系统类型识别 | `ServerProfile.psm1` | 422 | 平台类型、容器类型、ujava 变体识别 |
| 平台服务检测 | `ServiceCheck.psm1` + `check_server_health.sh` | 644 + 5013 | 服务进程检测、端口监听检测 |
| 配置IP检测 | `ConfigIPCheck.psm1` + `config_check.sh` | 613 + 304 | 配置文件 IP 扫描 |
| Console配置检测 | `check_server_health.sh` (第1582-1708行) | ~130 | console=true 检测 |
---
## 3. 模块一:系统类型识别(50_system_profile.sh)
### 3.1 检测项列表
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SYS_PROFILE_PLATFORM_TYPE` | 平台类型 | "new"(新统一平台) / "old"(传统平台) |
| `SYS_PROFILE_PLATFORM_TYPE_LEVEL` | 平台类型状态等级 | 正常/跳过 |
| `SYS_PROFILE_CONTAINER_TYPE` | 容器类型 | "ujava" / "upython" / "upython_voice" / "unknown" |
| `SYS_PROFILE_CONTAINER_TYPE_LEVEL` | 容器类型状态等级 | 正常/跳过 |
| `SYS_PROFILE_UJAVA_VARIANT` | ujava 变体 | "unified" / "meeting" / "none"(仅 ujava 容器有效) |
| `SYS_PROFILE_UJAVA_VARIANT_LEVEL` | ujava 变体状态等级 | 正常/跳过 |
### 3.2 检测逻辑
#### 3.2.1 平台类型检测
```bash
# 新平台:存在 /data/services 目录
if [ -d "/data/services" ]; then
PLATFORM_TYPE="new"
else
PLATFORM_TYPE="old"
fi
```
#### 3.2.2 容器类型检测
```bash
# 获取运行中的容器名称列表
containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
# 正则匹配容器名
if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
CONTAINER_TYPE="ujava"
elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
CONTAINER_TYPE="upython_voice"
elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
CONTAINER_TYPE="upython"
else
CONTAINER_TYPE="unknown"
fi
```
#### 3.2.3 ujava 变体检测
```bash
# 仅 ujava 容器有效
if [ "$CONTAINER_TYPE" = "ujava" ]; then
if [ -d "/var/www/java/unifiedPlatform" ]; then
UJAVA_VARIANT="unified"
else
UJAVA_VARIANT="meeting"
fi
else
UJAVA_VARIANT="none"
fi
```
### 3.3 依赖
- 命令:`docker``ls`/`test`
- 无需凭据
---
## 4. 模块二:平台服务检测(51_service_check.sh)
### 4.1 检测项列表
#### 4.1.1 新平台 ujava 服务(容器内)
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SVC_CHECK_AUTH_STATUS` | 认证服务状态 | 运行中/未运行 |
| `SVC_CHECK_AUTH_STATUS_LEVEL` | 认证服务状态等级 | 正常/严重 |
| `SVC_CHECK_GATEWAY_STATUS` | 网关服务状态 | 运行中/未运行 |
| `SVC_CHECK_GATEWAY_STATUS_LEVEL` | 网关服务状态等级 | 正常/严重 |
| `SVC_CHECK_SYSTEM_STATUS` | 系统服务状态 | 运行中/未运行 |
| `SVC_CHECK_SYSTEM_STATUS_LEVEL` | 系统服务状态等级 | 正常/严重 |
| `SVC_CHECK_MEETING_STATUS` | 会议服务状态 | 运行中/未运行 |
| `SVC_CHECK_MEETING_STATUS_LEVEL` | 会议服务状态等级 | 正常/严重 |
| `SVC_CHECK_MQTT_STATUS` | MQTT 服务状态 | 运行中/未运行 |
| `SVC_CHECK_MQTT_STATUS_LEVEL` | MQTT 服务状态等级 | 正常/严重 |
| `SVC_CHECK_QUARTZ_STATUS` | 定时任务服务状态 | 运行中/未运行 |
| `SVC_CHECK_QUARTZ_STATUS_LEVEL` | 定时任务服务状态等级 | 正常/严重 |
| `SVC_CHECK_MESSAGE_STATUS` | 消息调度服务状态 | 运行中/未运行 |
| `SVC_CHECK_MESSAGE_STATUS_LEVEL` | 消息调度服务状态等级 | 正常/严重 |
#### 4.1.2 新平台 ujava 宿主机服务
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SVC_CHECK_EXTAPI_STATUS` | 对外API服务状态 | 运行中/未运行 |
| `SVC_CHECK_EXTAPI_STATUS_LEVEL` | 对外API服务状态等级 | 正常/严重 |
#### 4.1.3 传统平台 ujava 容器服务
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SVC_CHECK_NGINX_OLD_STATUS` | Nginx 服务状态(传统) | 运行中/未运行 |
| `SVC_CHECK_NGINX_OLD_STATUS_LEVEL` | Nginx 服务状态等级(传统) | 正常/严重 |
| `SVC_CHECK_MEETING_OLD_STATUS` | 会议服务状态(传统) | 运行中/未运行 |
| `SVC_CHECK_MEETING_OLD_STATUS_LEVEL` | 会议服务状态等级(传统) | 正常/严重 |
#### 4.1.4 传统平台 extapi 宿主机服务
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SVC_CHECK_EXTAPI_OLD_STATUS` | 对外API服务状态(传统) | 运行中/未运行 |
| `SVC_CHECK_EXTAPI_OLD_STATUS_LEVEL` | 对外API服务状态等级(传统) | 正常/严重 |
#### 4.1.5 upython/upython_voice 端口监听
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `SVC_CHECK_PORT_8000_STATUS` | uWSGI 端口 8000 状态 | 监听/未监听 |
| `SVC_CHECK_PORT_8000_STATUS_LEVEL` | uWSGI 端口 8000 状态等级 | 正常/严重 |
| `SVC_CHECK_PORT_11211_STATUS` | Memcached 端口 11211 状态 | 监听/未监听 |
| `SVC_CHECK_PORT_11211_STATUS_LEVEL` | Memcached 端口 11211 状态等级 | 正常/严重 |
| `SVC_CHECK_PORT_8080_STATUS` | Nginx 端口 8080 状态 | 监听/未监听 |
| `SVC_CHECK_PORT_8080_STATUS_LEVEL` | Nginx 端口 8080 状态等级 | 正常/严重 |
| `SVC_CHECK_PORT_1883_STATUS` | MQTT 端口 1883 状态 | 监听/未监听 |
| `SVC_CHECK_PORT_1883_STATUS_LEVEL` | MQTT 端口 1883 状态等级 | 正常/严重 |
### 4.2 服务匹配模式配置
**新平台 ujava 服务**(在 `config.sh.template` 配置):
| 服务 | 匹配模式 | 说明 |
|------|---------|------|
| auth | `ubains-auth.jar` | 认证服务 |
| gateway | `ubains-gateway.jar` | 网关服务 |
| system | `ubains-modules-system.jar` | 系统服务 |
| meeting | `ubains-meeting-inner-api-1.0-SNAPSHOT.jar` | 会议对内服务 |
| mqtt | `ubains-meeting-mqtt-1.0-SNAPSHOT.jar` | MQTT 服务 |
| quartz | `ubains-meeting-quartz-1.0-SNAPSHOT.jar` | 定时任务服务 |
| message | `ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar` | 消息调度服务 |
| extapi | `ubains-meeting-api-1.0-SNAPSHOT.jar` | 对外 API 服务(宿主机) |
**传统平台服务**(匹配模式相同,路径不同):
- 容器内服务:nginx + meeting
- 宿主机服务:extapi(路径 `/var/www/java/external-meeting-api`
**端口列表**(按容器类型):
| 容器类型 | 端口 | 进程 |
|---------|------|------|
| upython (新平台) | 8000, 11211 | uwsgi, memcached |
| upython_voice (新平台) | 8000, 11211, 8080, 1883, 9001 | uwsgi, memcached, nginx, mosquitto |
| upython (传统平台) | 8000, 11211, 8081, 8443, 8002 | uwsgi, memcached, nginx, httpd |
### 4.3 检测逻辑
#### 4.3.1 服务进程检测
```bash
# 容器内检测
count=$(docker exec "$container" ps aux 2>/dev/null | grep -F "$jar_pattern" | grep -v grep | wc -l)
if [ "$count" -gt 0 ]; then
status="运行中"
else
status="未运行"
fi
# 宿主机检测
count=$(ps aux 2>/dev/null | grep -F "$jar_pattern" | grep -v grep | wc -l)
```
#### 4.3.2 端口监听检测
```bash
# 容器内端口检测(优先用进程检查,避免容器内无 ss/netstat)
count=$(docker exec "$container" ps aux 2>/dev/null | grep "$process_name" | grep -v grep | wc -l)
# 或宿主机端口检测
ss -tlnp 2>/dev/null | grep -q ":$port "
```
### 4.4 依赖
- 命令:`docker``ps``ss`/`netstat``grep`
- 无需凭据(服务进程检测无需密码)
- 需要先运行 `50_system_profile.sh` 获取平台/容器类型(或脚本内部自行检测)
---
## 5. 模块三:配置IP检测(52_config_ip_check.sh)
### 5.1 检测项列表
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `CFG_IP_STATUS` | 配置IP检测状态 | OK/WARN |
| `CFG_IP_STATUS_LEVEL` | 配置IP检测状态等级 | 正常/警告 |
| `CFG_IP_TOTAL_FILES` | 扫描文件数 | 整数 |
| `CFG_IP_UNAUTHORIZED_COUNT` | 未授权IP数 | 整数 |
| `CFG_IP_UNAUTHORIZED_LINES` | 未授权IP明细 | JSON 数组字符串 |
### 5.2 配置文件扫描路径
#### 5.2.1 新平台路径
| 目录 | 配置文件模式 |
|------|-------------|
| `/data/services/api/auth/auth-sso-auth/config` | *.yml, *.properties |
| `/data/services/api/auth/auth-sso-gateway/config` | *.yml, *.properties |
| `/data/services/api/auth/auth-sso-system/config` | *.yml, *.properties |
| `/data/services/api/java-meeting/java-meeting2.0/config` | *.yml, *.properties |
| `/data/services/api/java-meeting/java-meeting-extapi/config` | *.yml, *.properties |
| `/data/services/api/java-meeting/java-message-scheduling/config` | *.yml, *.properties |
| `/data/services/api/java-meeting/java-mqtt/config` | *.yml, *.properties |
| `/data/services/api/java-meeting/java-quartz/config` | *.yml, *.properties |
| `/data/services/api/python-cmdb` | *.yml, *.properties, config.py |
| `/data/services/web/pc/pc-vue2-ai/static` | config.js, config.json |
| `/data/services/web/mobile/mobile-vue2/static` | config.js, config.json |
| `/data/middleware/nginx/config` | *.conf |
#### 5.2.2 传统平台路径
| 目录 | 配置文件模式 |
|------|-------------|
| `/var/www/java/api-java-meeting2.0/config` | *.yml, *.properties |
| `/var/www/java/external-meeting-api/config` | *.yml, *.properties |
| `/var/www/java/ubains-web-2.0/static` | config.json |
| `/var/www/java/ubains-web-admin/static` | config.json |
| `/var/www/java/ubains-web-h5/static/h5` | config.js, config.json |
| `/var/www/java/nginx-conf.d` | *.conf |
### 5.3 检测逻辑
```bash
# IP 正则
IP_REGEX='([0-9]{1,3}\.){3}[0-9]{1,3}'
# 允许列表(服务器IP + 127.0.0.1 + 172.17.0.1)
ALLOWED_IPS="$SERVER_IP 127.0.0.1 172.17.0.1"
# 扫描配置文件
for dir in "${CONFIG_DIRS[@]}"; do
while IFS= read -r file; do
# 提取 IP
ips=$(grep -oE "$IP_REGEX" "$file" 2>/dev/null | sort -u)
for ip in $ips; do
# 检查是否在允许列表
if ! echo "$ALLOWED_IPS" | grep -qF "$ip"; then
echo "未授权IP: $ip (文件: $file)"
fi
done
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" -o -name "*.conf" \) 2>/dev/null)
done
```
### 5.4 依赖
- 命令:`find``grep``sort`
- 需要服务器 IP(从 config.sh 获取 `SERVER_IP`
- 需要先运行 `50_system_profile.sh` 获取平台类型
---
## 6. 模块四:Console配置检测(53_config_console_check.sh)
### 6.1 检测项列表
| KEY | 中文名 | 说明 |
|-----|--------|------|
| `CFG_CONSOLE_STATUS` | Console配置检测状态 | OK/WARN |
| `CFG_CONSOLE_STATUS_LEVEL` | Console配置检测状态等级 | 正常/警告 |
| `CFG_CONSOLE_TOTAL_FILES` | 扫描文件数 | 整数 |
| `CFG_CONSOLE_FOUND_COUNT` | 发现问题数 | 整数 |
| `CFG_CONSOLE_FOUND_FILES` | 问题文件列表 | JSON 数组字符串 |
### 6.2 配置文件扫描路径
复用配置 IP 检测的扫描路径(第 5.2 节)。
### 6.3 检测逻辑
```bash
# console=true 正则(不区分大小写)
CONSOLE_REGEX='console[[:space:]]*[:=][[:space:]]*true'
# 扫描配置文件
for dir in "${CONFIG_DIRS[@]}"; do
while IFS= read -r file; do
if grep -qiE "$CONSOLE_REGEX" "$file" 2>/dev/null; then
echo "发现 console=true: $file"
fi
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" \) 2>/dev/null)
done
```
### 6.4 行为约束
**只检测,不自动修复**(与用户确认的方案):
- 发现 `console=true` 时标记为异常
- 不执行备份和 sed 替换
- 由人工确认后修复
### 6.5 依赖
- 命令:`find``grep`
- 需要先运行 `50_system_profile.sh` 获取平台类型
---
## 7. 技术方案
### 7.1 模块注册
`check_modules.py``ALL_MODULES` 列表新增 4 个 `CheckModule` 条目:
```python
CheckModule("50_system_profile", "系统类型识别", "system", {SUITE_FULL}, "50_system_profile.sh"),
CheckModule("51_service_check", "平台服务检测", "service", {SUITE_FULL}, "51_service_check.sh"),
CheckModule("52_config_ip_check", "配置IP检测", "system", {SUITE_FULL}, "52_config_ip_check.sh"),
CheckModule("53_config_console_check", "Console配置检测", "system", {SUITE_FULL}, "53_config_console_check.sh"),
```
### 7.2 显示名映射
`display_names.py` 新增 KEY 映射(共约 35 个):
- 系统类型识别:6 个
- 平台服务检测:20+ 个
- 配置IP检测:5 个
- Console配置检测:5 个
### 7.3 阈值配置
`thresholds.py` 新增阈值(如有需要):
- 服务状态:未运行 = 严重
- 端口状态:未监听 = 严重
- 未授权 IP 数:> 0 = 警告
- console=true 数:> 0 = 警告
### 7.4 配置模板
`config.sh.template` 新增:
- 服务匹配模式(`SVC_PATTERNS` 关联数组)
- 端口列表(`UPYTHON_PORTS``UPYTHON_VOICE_PORTS`
### 7.5 模块依赖关系
```
50_system_profile.sh (平台/容器类型识别)
51_service_check.sh (依赖容器类型选择检测项)
52_config_ip_check.sh (依赖平台类型选择扫描路径)
53_config_console_check.sh (依赖平台类型选择扫描路径)
```
**建议**:在 `check_modules.py``get_suite` 返回列表中,将 `50_system_profile` 排在最前,确保先执行。
---
## 8. 验收标准
| 标准 | 验证方法 |
|------|---------|
| 4 个检测脚本创建 | 语法检查 `bash -n` 通过 |
| check_modules.py 注册 | `get_suite('full')` 包含新模块 |
| display_names.py 映射 | 新 KEY 有中文名 |
| 服务检测逻辑正确 | 在 5.44 目标实际运行,服务状态与 `docker ps` 一致 |
| 配置 IP 检测正确 | 人工检查配置文件,对比检测结果 |
| Console 检测正确 | 人工检查配置文件,对比检测结果 |
| 单元测试通过 | pytest 全绿 |
| 已有测试不受影响 | 218 个测试全绿 |
---
## 9. 风险评估
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 配置文件路径不存在 | 扫描结果为空 | 目录存在性检查,graceful 降级 |
| 容器名匹配失败 | 服务检测误判 | 使用 `grep -iE` 模糊匹配 + 默认值 |
| 新旧平台混合 | 检测项不适用 | 先识别平台类型,分支执行 |
| upython_voice 端口变化 | 端口检测误判 | 端口列表可配置化 |
---
## 10. 后续工作
- P3 级模块移植:文件权限、定时任务预期、FastDFS、Android 等
- 服务检测扩展:支持自定义服务匹配模式
- 配置 IP 检测增强:IP 白名单可配置化
# HANDOFF_服务监测 — 服务监测模块:检测项丰富化移植(阶段
# HANDOFF_服务监测 — 服务监测模块:检测项丰富化移植(阶段
> 最后更新:2026-07-22(状态等级误判 + 端口检测逻辑修复,5.44 实际运行验证通过)| 分支:troubleshoot-ai-assistant | 负责人:czj
> 最后更新:2026-07-22(P2 级移植完成:系统类型识别 + 平台服务检测 + 配置IP检测 + Console配置检测)| 分支:troubleshoot-ai-assistant | 负责人:czj
> 专属交接文档:聚焦服务监测模块(service_monitor)的全部历史与当前状态
---
......@@ -11,25 +11,28 @@
**已完成轮次**
- **阶段一**:补全缺失项 + 重构 MySQL/Redis 深度检测脚本(见 2.5 节)
- **阶段二(本次)**:移植安全合规深度检测 + 中间件连接检测模块
本轮会话完成了两个新检测模块的移植:
1. **安全合规深度检测**(46_security_deep.sh):检测弱密码、安全基线违规、可疑文件、异常配置。包含 9 类安全检测:
- MySQL Root 访问范围、空密码用户
- Redis 密码状态
- EMQX 默认密码检测
- Linux 空密码账户
- SUID 文件安全检查
- Crontab 异常任务
- SSH 暴力破解检测
- 异常端口监听
2. **中间件连接检测**(39_middleware_conn.sh):验证 Redis/MySQL/EMQX/FastDFS 连接状态和运行健康度。包含 4 类连接检测:
- Redis 连接(容器存在 + 端口监听 + ping 测试 + 版本/内存/连接数)
- MySQL 连接(容器存在 + 端口监听 + mysqladmin ping + 版本)
- EMQX 连接(MQTT 端口 + Dashboard 端口 + API 状态)
- FastDFS 连接(容器存在 + 进程检查)
- **阶段二**:移植安全合规深度检测 + 中间件连接检测模块(见 2.7-2.11 节)
- **阶段三(本次)**:移植 P2 级检测模块:系统类型识别 + 平台服务检测 + 配置IP检测 + Console配置检测
本轮会话完成了四个新检测模块的移植:
1. **系统类型识别**(50_system_profile.sh):识别目标服务器的平台类型、容器类型、ujava 变体
- 平台类型:new(新统一平台)/ old(传统平台)
- 容器类型:ujava / upython / upython_voice / unknown
- ujava 变体:unified / meeting / none
2. **平台服务检测**(51_service_check.sh):检测核心业务服务进程状态 + 容器端口监听
- 新平台服务:auth/gateway/system/meeting/mqtt/quartz/message/extapi
- 传统平台服务:nginx/meeting/extapi
- upython/upython_voice 端口:8000/11211/8080/1883 等
3. **配置IP检测**(52_config_ip_check.sh):扫描配置文件中的未授权 IP 地址
- 扫描路径:服务配置目录 + 前端配置目录 + 中间件配置
- 允许列表:服务器IP + 127.0.0.1 + 172.17.0.1
4. **Console配置检测**(53_config_console_check.sh):检测 console=true 配置项未关闭问题
- 只检测不修复(避免巡检工具自动改生产配置)
- 发现问题标记为警告
---
......@@ -255,24 +258,104 @@
- EMQX 默认密码:使用默认密码 → **严重**(admin:public)
- 异常端口数:57 个 → **严重**(大量非白名单端口)
### 2.12 系统类型识别模块 ✅
**需求文档**`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
**参考来源**`platform-auto-test/临时目录/服务监测/modules/ServerProfile.psm1`
**核心实现**
- `50_system_profile.sh`(新增):系统类型识别脚本,3 类识别
- 平台类型:检测 `/data/services` 目录存在 → new,否则 → old
- 容器类型:`docker ps` 容器名正则匹配(ujava/upython/upython_voice/unknown)
- ujava 变体:检测 `/var/www/java/unifiedPlatform` 目录 → unified,否则 → meeting
- `display_names.py`:新增 6 个 `SYS_PROFILE_*` KEY 映射
- `check_modules.py`:注册 `50_system_profile` 模块
**验证结果**:218 个测试全绿 ✅ 语法检查通过 ✅
### 2.13 平台服务检测模块 ✅
**需求文档**`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
**参考来源**`platform-auto-test/临时目录/服务监测/modules/ServiceCheck.psm1` + `check_server_health.sh`
**核心实现**
- `51_service_check.sh`(新增):平台服务检测脚本
- 新平台 ujava 容器内服务:auth/gateway/system/meeting/mqtt/quartz/message(7 个 jar 进程匹配)
- 新平台宿主机服务:extapi(jar 进程匹配)
- 传统平台 ujava 容器服务:nginx + meeting
- 传统平台宿主机服务:extapi(路径匹配 `/var/www/java/external-meeting-api`
- upython/upython_voice 端口监听:用进程检查代替 ss(避免容器内无 ss/netstat 误判)
- `display_names.py`:新增 20+ 个 `SVC_CHECK_*` KEY 映射
- `config.sh.template`:新增服务匹配模式 + 端口列表配置
- `check_modules.py`:注册 `51_service_check` 模块
**设计要点**
- 服务匹配模式可配置化(`UJAVA_SERVICES` 等环境变量)
- 端口检测用进程检查代替 ss(吸取坑 9 教训)
- 内部自行检测平台/容器类型,不依赖 50 模块执行顺序
**验证结果**:218 个测试全绿 ✅ 语法检查通过 ✅
### 2.14 配置IP检测模块 ✅
**需求文档**`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
**参考来源**`platform-auto-test/临时目录/服务监测/modules/ConfigIPCheck.psm1` + `lib/shell/config_check.sh`
**核心实现**
- `52_config_ip_check.sh`(新增):配置IP检测脚本
- 新平台扫描 12 个配置目录(API 服务 + 前端 + 中间件)
- 传统平台扫描 6 个配置目录
- IP 提取:`grep -oE` 匹配 IP 正则
- 允许列表:SERVER_IP + 127.0.0.1 + 172.17.0.1
- 输出未授权 IP 明细(JSON 数组:文件路径 + 行号 + IP)
- `display_names.py`:新增 5 个 `CFG_IP_*` KEY 映射
- `config.sh.template`:新增 `SERVER_IP` 配置
- `check_modules.py`:注册 `52_config_ip_check` 模块
**验证结果**:218 个测试全绿 ✅ 语法检查通过 ✅
### 2.15 Console配置检测模块 ✅
**需求文档**`Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
**参考来源**`platform-auto-test/临时目录/服务监测/check_server_health.sh`(第1582-1708行)
**核心实现**
- `53_config_console_check.sh`(新增):Console配置检测脚本
- 扫描配置文件中 `console[:=]true` 的行(不区分大小写)
- **只检测不修复**(避免巡检工具自动改生产配置的风险)
- 复用配置 IP 检测的扫描路径
- 输出问题文件列表(JSON 数组)
- `display_names.py`:新增 5 个 `CFG_CONSOLE_*` KEY 映射
- `check_modules.py`:注册 `53_config_console_check` 模块
**验证结果**:218 个测试全绿 ✅ 语法检查通过 ✅
---
## 3. 当前卡在哪
**无卡点**。阶段一(补全缺失项 + 重构 depth 脚本)和阶段二(安全合规深度 + 中间件连接)已完成,状态等级误判和端口检测逻辑已修复,5.44 实际运行验证通过
**无卡点**。阶段一(补全缺失项 + 重构 depth 脚本)、阶段二(安全合规深度 + 中间件连接)、阶段三(P2 级移植)已完成
**当前状态**
- 服务健康检查:status: ok, scheduler: running ✅
- 报告免登访问正常工作 ✅
- 统计模块正常工作 ✅
- 检测项趋势图表友好提示正常 ✅
- display_names.py 已补全缺失 KEY(539+52+36=627 条)✅
- display_names.py 已补全缺失 KEY(539+52+36+35=662 条)✅
- 23_mysql_depth.sh / 25_redis_depth.sh 已重构为 output_result 格式 ✅
- 46_security_deep.sh 安全合规深度检测模块 ✅
- 39_middleware_conn.sh 中间件连接检测模块 ✅
- full 套件 32 个模块(原 30 + 新 2)✅
- 50_system_profile.sh 系统类型识别模块 ✅
- 51_service_check.sh 平台服务检测模块 ✅
- 52_config_ip_check.sh 配置IP检测模块 ✅
- 53_config_console_check.sh Console配置检测模块 ✅
- full 套件 34 个模块(原 30 + 新 4)✅
- 218 个单元测试全绿 ✅
- **已部署到 5.60** ✅(服务器端语法检查通过,文件完整
- **已部署到 5.60** ✅(阶段一+二,阶段三待部署
- **5.44 实际运行验证通过**(full 套件,中间件全部"运行中",安全模块发现真实问题)✅
- 状态等级误判已修复(LEVEL KEY 对齐 + 状态词映射兜底)✅
- 中间件端口检测逻辑已修复(服务 ping 优先,不依赖容器内 ss)✅
......@@ -286,7 +369,8 @@
|--------|------|------|
| ~~P1~~ | ~~Web 界面验证实际运行~~ | ✅ 已完成(5.44 full 套件检测通过,发现问题项正确标记严重) |
| ~~P1~~ | ~~统计页面验证~~ | ✅ 已完成(新检测项出现在统计页面选择器中) |
| P2 | 继续移植 P2 优先级模块 | 系统类型识别、平台服务检测、配置IP检测、Console配置 |
| ~~P2~~ | ~~继续移植 P2 优先级模块~~ | ✅ 已完成(系统类型识别/平台服务检测/配置IP检测/Console配置检测) |
| P2 | 部署阶段三到 5.60 + 5.44 实际运行验证 | 验证新模块在真实环境运行正确 |
| P3 | 继续移植 P3 优先级模块 | 文件权限、定时任务预期、FastDFS功能验证等 |
| 持续 | 更新 HANDOFF_服务监测文档 | 每次会话结束前更新进度 |
......@@ -400,6 +484,7 @@
| 日期 | Commit | 说明 |
|------|--------|------|
| 2026-07-22 | 待提交 | feat(service-monitor): P2级移植-系统类型识别/平台服务检测/配置IP检测/Console配置检测 |
| 2026-07-22 | `c0200115` | feat(service-monitor): 新增安全合规/中间件检测模块并修复状态等级误判 |
| 2026-07-14 | `3f48af4c` | feat(service-monitor): 报告免登访问 + 监测统计模块 + 多项修复 |
......@@ -459,6 +544,19 @@ feat(service-monitor): 新增安全合规/中间件检测模块并修复状态
| `service_monitor/utils/thresholds.py` | 追加 6 个安全检测阈值 |
| `service_monitor/utils/parser.py` | 追加 11 个异常状态词映射(`_VALUE_STATUS_MAP`) |
### 本次修改文件(阶段三:P2 级移植)
| 文件 | 改动 |
|------|------|
| `service_monitor/assets/system/50_system_profile.sh` | 新建 - 系统类型识别脚本(6 个检测项) |
| `service_monitor/assets/service/51_service_check.sh` | 新建 - 平台服务检测脚本(~20 个检测项) |
| `service_monitor/assets/system/52_config_ip_check.sh` | 新建 - 配置IP检测脚本(5 个检测项) |
| `service_monitor/assets/system/53_config_console_check.sh` | 新建 - Console配置检测脚本(5 个检测项) |
| `service_monitor/utils/check_modules.py` | 追加 4 个 CheckModule 条目(50/51/52/53) |
| `service_monitor/utils/display_names.py` | 追加 35 个 KEY 映射(`SYS_PROFILE_*` 6 个 + `SVC_CHECK_*` 20+ 个 + `CFG_IP_*` 5 个 + `CFG_CONSOLE_*` 5 个) |
| `service_monitor/utils/parser.py` | 追加 2 个状态词映射(监听/未监听) |
| `service_monitor/assets/config.sh.template` | 追加服务匹配模式 + 端口列表 + SERVER_IP 配置 |
### 新增文档
| 文件 | 说明 |
......@@ -512,16 +610,23 @@ curl -s "http://192.168.5.60:8088/service-monitor/report/<id>?token=rpt_xxx"
### 未提交文件
- 多个 PRD 文档(需求/计划执行/问题处理)
- `skill/code/web/users.json`(仅登录统计更新)
- `skill/code/web/service_monitor/assets/system/46_security_deep.sh`(新模块 + LEVEL KEY 对齐)
- `skill/code/web/service_monitor/assets/service/39_middleware_conn.sh`(新模块 + 端口检测逻辑重构)
- `skill/code/web/service_monitor/assets/config.sh.template`(追加白名单+EMQX配置)
- `skill/code/web/service_monitor/utils/check_modules.py`(追加2个模块)
- `skill/code/web/service_monitor/utils/display_names.py`(追加36个KEY + 11个LEVEL KEY改名)
- `skill/code/web/service_monitor/utils/thresholds.py`(追加6个阈值)
- `skill/code/web/service_monitor/utils/parser.py`(追加11个异常状态词映射)
- `skill/code/web/routes/service_manage.py`(见 git status)
- `HANDOFF_服务监测.md`(本轮待提交)
- **阶段三新增文件**
- `skill/code/web/service_monitor/assets/system/50_system_profile.sh`
- `skill/code/web/service_monitor/assets/service/51_service_check.sh`
- `skill/code/web/service_monitor/assets/system/52_config_ip_check.sh`
- `skill/code/web/service_monitor/assets/system/53_config_console_check.sh`
- **阶段三修改文件**
- `skill/code/web/service_monitor/utils/check_modules.py`
- `skill/code/web/service_monitor/utils/display_names.py`
- `skill/code/web/service_monitor/utils/parser.py`
- `skill/code/web/service_monitor/assets/config.sh.template`
- **文档**
- `Docs/需求文档/服务监测/PRD_需求文档_P2级移植.md`
- `Docs/需求文档/服务监测/PRD_计划执行_P2级移植.md`
- `HANDOFF_服务监测.md`
- **其他**
- `skill/code/web/users.json`(仅登录统计更新)
- `skill/code/web/routes/service_manage.py`(服务管理模块,见 git status)
- `skill/code/web/templates/service_manage/`(服务管理模块模板)
> 注:5.44 目标的 `credential_overrides`(MySQL/Redis 密码)已通过 API 写入 5.60 服务器的 `targets.json`(加密),不在代码仓库内。
\ No newline at end of file
......@@ -117,3 +117,30 @@ resolve_container() {
[ -z "$pattern" ] && return 1
docker ps --format '{{.Names}}' 2>/dev/null | grep -iE "$pattern" | head -1
}
# ==================== 平台服务检测配置 ====================
# 格式: key:pattern,key:pattern(51_service_check.sh 使用)
# ujava 服务匹配模式(新平台容器内)
UJAVA_SERVICES="${UJAVA_SERVICES:-auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar}"
# ujava 宿主机服务(新平台)
UJAVA_HOST_SERVICES="${UJAVA_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
# 传统平台 ujava 容器服务
UJAVA_OLD_CONTAINER_SERVICES="${UJAVA_OLD_CONTAINER_SERVICES:-nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar}"
# 传统平台 ujava 宿主机服务
UJAVA_OLD_HOST_SERVICES="${UJAVA_OLD_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
# upython 端口列表(新平台,格式: port:process,port:process)
UPYTHON_PORTS_NEW="${UPYTHON_PORTS_NEW:-8000:uwsgi,11211:memcached}"
# upython_voice 端口列表(新平台)
UPYTHON_VOICE_PORTS_NEW="${UPYTHON_VOICE_PORTS_NEW:-8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto}"
# upython 端口列表(传统平台)
UPYTHON_PORTS_OLD="${UPYTHON_PORTS_OLD:-8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd}"
# ==================== 配置IP检测配置 ====================
# 服务器IP(运行时注入,用于IP允许列表)
SERVER_IP="${SERVER_IP:-}"
#!/bin/bash
################################################################################
# 51_service_check.sh — 平台服务检测
# 功能: 检测核心业务服务进程状态(auth/gateway/system/meeting/mqtt/quartz/message/extapi)
# + upython/upython_voice 容器端口监听
# 参考: ServiceCheck.psm1, check_server_health.sh
# 日期: 2026-07-22
# 说明: 服务进程检测优先用 ps grep 匹配 jar 文件名;端口检测用进程检查代替 ss
# (避免容器内无 ss/netstat 导致误判,详见 HANDOFF 坑 9)
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# 服务匹配模式(从 config.sh 读取或使用默认值,格式: key:pattern,key:pattern)
UJAVA_SERVICES="${UJAVA_SERVICES:-auth:ubains-auth.jar,gateway:ubains-gateway.jar,system:ubains-modules-system.jar,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar,mqtt:ubains-meeting-mqtt-1.0-SNAPSHOT.jar,quartz:ubains-meeting-quartz-1.0-SNAPSHOT.jar,message:ubains-meeting-message-scheduling-1.0-SNAPSHOT.jar}"
UJAVA_HOST_SERVICES="${UJAVA_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_CONTAINER_SERVICES="${UJAVA_OLD_CONTAINER_SERVICES:-nginx:nginx: master process,meeting:ubains-meeting-inner-api-1.0-SNAPSHOT.jar}"
UJAVA_OLD_HOST_SERVICES="${UJAVA_OLD_HOST_SERVICES:-extapi:ubains-meeting-api-1.0-SNAPSHOT.jar}"
# 端口列表(格式: port:process,port:process)
UPYTHON_PORTS_NEW="${UPYTHON_PORTS_NEW:-8000:uwsgi,11211:memcached}"
UPYTHON_VOICE_PORTS_NEW="${UPYTHON_VOICE_PORTS_NEW:-8000:uwsgi,11211:memcached,8080:nginx,1883:mosquitto,9001:mosquitto}"
UPYTHON_PORTS_OLD="${UPYTHON_PORTS_OLD:-8000:uwsgi,11211:memcached,8081:nginx,8443:nginx,8002:httpd}"
# 将服务名转为大写用于 KEY(兼容 bash 3.x macOS / bash 4+ 都用 tr)
to_upper() {
echo "$1" | tr '[:lower:]' '[:upper:]'
}
# ==================== 平台/容器类型识别(内部实现,不依赖 50 模块) ====================
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
detect_container_type() {
local containers
containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
echo "ujava"
elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
echo "upython_voice"
elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
echo "upython"
else
echo "unknown"
fi
}
# ==================== 服务进程检测 ====================
# 检测容器内服务进程
# 参数: container pattern key_prefix
check_service_in_container() {
local container="$1"
local pattern="$2"
local key_prefix="$3"
if [ -z "$container" ]; then
output_result "${key_prefix}_STATUS" "未检测到容器"
output_result "${key_prefix}_STATUS_LEVEL" "跳过"
return
fi
local count
count=$(docker exec "$container" ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
if [ "$count" -gt 0 ]; then
output_result "${key_prefix}_STATUS" "运行中"
output_result "${key_prefix}_STATUS_LEVEL" "正常"
else
output_result "${key_prefix}_STATUS" "未运行"
output_result "${key_prefix}_STATUS_LEVEL" "严重"
fi
}
# 检测宿主机服务进程
# 参数: pattern key_prefix [path_hint]
check_service_on_host() {
local pattern="$1"
local key_prefix="$2"
local path_hint="$3"
local count
if [ -n "$path_hint" ]; then
count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -F "$path_hint" | grep -v grep | wc -l)
else
count=$(ps aux 2>/dev/null | grep -F "$pattern" | grep -v grep | wc -l)
fi
if [ "$count" -gt 0 ]; then
output_result "${key_prefix}_STATUS" "运行中"
output_result "${key_prefix}_STATUS_LEVEL" "正常"
else
output_result "${key_prefix}_STATUS" "未运行"
output_result "${key_prefix}_STATUS_LEVEL" "严重"
fi
}
# ==================== 端口监听检测(用进程检查代替 ss) ====================
# 检测容器内端口对应的进程
# 参数: container port process
check_port_in_container() {
local container="$1"
local port="$2"
local process="$3"
local key_prefix="SVC_CHECK_PORT_${port}"
if [ -z "$container" ]; then
output_result "${key_prefix}_STATUS" "未检测到容器"
output_result "${key_prefix}_STATUS_LEVEL" "跳过"
return
fi
local count
count=$(docker exec "$container" ps aux 2>/dev/null | grep "$process" | grep -v grep | wc -l)
if [ "$count" -gt 0 ]; then
output_result "${key_prefix}_STATUS" "监听"
output_result "${key_prefix}_STATUS_LEVEL" "正常"
else
output_result "${key_prefix}_STATUS" "未监听"
output_result "${key_prefix}_STATUS_LEVEL" "严重"
fi
}
# ==================== 服务列表遍历辅助 ====================
# 遍历 "key:pattern,key:pattern" 字符串,对每个服务在容器内检测
# 参数: services_str container key_suffix
check_services_in_container_list() {
local services_str="$1"
local container="$2"
local key_suffix="$3"
local IFS_save="$IFS"
IFS=','
local services=($services_str)
IFS="$IFS_save"
for svc in "${services[@]}"; do
[ -z "$svc" ] && continue
local key pattern
key="${svc%%:*}"
pattern="${svc#*:}"
[ -z "$key" ] || [ -z "$pattern" ] && continue
check_service_in_container "$container" "$pattern" "SVC_CHECK_$(to_upper "$key")${key_suffix}"
done
}
# 遍历 "key:pattern,..." 字符串,对每个服务在宿主机检测
# 参数: services_str key_suffix [path_hint]
check_services_on_host_list() {
local services_str="$1"
local key_suffix="$2"
local path_hint="$3"
local IFS_save="$IFS"
IFS=','
local services=($services_str)
IFS="$IFS_save"
for svc in "${services[@]}"; do
[ -z "$svc" ] && continue
local key pattern
key="${svc%%:*}"
pattern="${svc#*:}"
[ -z "$key" ] || [ -z "$pattern" ] && continue
if [ -n "$path_hint" ]; then
check_service_on_host "$pattern" "SVC_CHECK_$(to_upper "$key")${key_suffix}" "$path_hint"
else
check_service_on_host "$pattern" "SVC_CHECK_$(to_upper "$key")${key_suffix}"
fi
done
}
# 遍历 "port:process,..." 字符串,对每个端口在容器内检测
# 参数: ports_str container
check_ports_in_container_list() {
local ports_str="$1"
local container="$2"
local IFS_save="$IFS"
IFS=','
local ports=($ports_str)
IFS="$IFS_save"
for pp in "${ports[@]}"; do
[ -z "$pp" ] && continue
local port process
port="${pp%%:*}"
process="${pp#*:}"
[ -z "$port" ] || [ -z "$process" ] && continue
check_port_in_container "$container" "$port" "$process"
done
}
# ==================== 主检测流程 ====================
main() {
log_info "开始平台服务检测..."
set +e
local platform_type container_type
platform_type=$(detect_platform_type)
container_type=$(detect_container_type)
# 获取容器名
local ujava_container upython_container
ujava_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
upython_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^upython' | head -1)
if [ "$platform_type" = "new" ]; then
# 新平台:ujava 容器内服务
if [ "$container_type" = "ujava" ]; then
check_services_in_container_list "$UJAVA_SERVICES" "$ujava_container" ""
fi
# 新平台:宿主机 extapi
check_services_on_host_list "$UJAVA_HOST_SERVICES" ""
# 新平台:upython/upython_voice 端口
if [ "$container_type" = "upython" ]; then
check_ports_in_container_list "$UPYTHON_PORTS_NEW" "$upython_container"
elif [ "$container_type" = "upython_voice" ]; then
check_ports_in_container_list "$UPYTHON_VOICE_PORTS_NEW" "$upython_container"
fi
else
# 传统平台:ujava 容器内服务(nginx + meeting)
if [ "$container_type" = "ujava" ]; then
check_services_in_container_list "$UJAVA_OLD_CONTAINER_SERVICES" "$ujava_container" "_OLD"
fi
# 传统平台:宿主机 extapi(匹配路径)
check_services_on_host_list "$UJAVA_OLD_HOST_SERVICES" "_OLD" "/var/www/java/external-meeting-api"
# 传统平台:upython 端口
if [ "$container_type" = "upython" ] || [ "$container_type" = "upython_voice" ]; then
check_ports_in_container_list "$UPYTHON_PORTS_OLD" "$upython_container"
fi
fi
log_info "平台服务检测完成"
}
main
#!/bin/bash
################################################################################
# 50_system_profile.sh — 系统类型识别
# 功能: 检测平台类型(新/旧)、容器类型(ujava/upython/upython_voice)、ujava变体
# 参考: ServerProfile.psm1(PowerShell 移植)
# 日期: 2026-07-22
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# ==================== 平台类型检测 ====================
detect_platform_type() {
# 新统一平台:存在 /data/services 目录
if [ -d "/data/services" ]; then
output_result "SYS_PROFILE_PLATFORM_TYPE" "new"
else
output_result "SYS_PROFILE_PLATFORM_TYPE" "old"
fi
output_result "SYS_PROFILE_PLATFORM_TYPE_LEVEL" "正常"
}
# ==================== 容器类型检测 ====================
detect_container_type() {
local containers
containers=$(docker ps --format '{{.Names}}' 2>/dev/null)
# 注意匹配顺序:upython_voice 须在 upython 之前,否则 upython 会先匹配
if echo "$containers" | grep -qE '^ujava[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "ujava"
elif echo "$containers" | grep -qE '^upython_voice[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "upython_voice"
elif echo "$containers" | grep -qE '^upython[0-9]*$'; then
output_result "SYS_PROFILE_CONTAINER_TYPE" "upython"
else
output_result "SYS_PROFILE_CONTAINER_TYPE" "unknown"
fi
output_result "SYS_PROFILE_CONTAINER_TYPE_LEVEL" "正常"
}
# ==================== ujava 变体检测 ====================
detect_ujava_variant() {
# 仅 ujava 容器有效:通过目录区分 unified / meeting
local ujava_container
ujava_container=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^ujava[0-9]*$' | head -1)
if [ -n "$ujava_container" ]; then
if [ -d "/var/www/java/unifiedPlatform" ]; then
output_result "SYS_PROFILE_UJAVA_VARIANT" "unified"
else
output_result "SYS_PROFILE_UJAVA_VARIANT" "meeting"
fi
else
output_result "SYS_PROFILE_UJAVA_VARIANT" "none"
fi
output_result "SYS_PROFILE_UJAVA_VARIANT_LEVEL" "正常"
}
# ==================== 主检测流程 ====================
main() {
log_info "开始系统类型识别..."
set +e
detect_platform_type 2>/dev/null || true
detect_container_type 2>/dev/null || true
detect_ujava_variant 2>/dev/null || true
log_info "系统类型识别完成"
}
main
#!/bin/bash
################################################################################
# 52_config_ip_check.sh — 配置IP检测
# 功能: 扫描配置文件中的未授权 IP 地址
# 参考: ConfigIPCheck.psm1, config_check.sh
# 日期: 2026-07-22
# 说明: 遍历平台配置目录,提取 IP 与允许列表对比,输出未授权 IP 明细
# 允许列表 = 服务器IP + 127.0.0.1 + 172.17.0.1
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# IP 正则
IP_REGEX='([0-9]{1,3}\.){3}[0-9]{1,3}'
# 允许列表(SERVER_IP 从 config.sh 注入,默认为空)
ALLOWED_IPS="${SERVER_IP} 127.0.0.1 172.17.0.1"
# ==================== 配置目录定义 ====================
# 新平台配置目录
NEW_PLATFORM_CONFIG_DIRS=(
"/data/services/api/auth/auth-sso-auth/config"
"/data/services/api/auth/auth-sso-gateway/config"
"/data/services/api/auth/auth-sso-system/config"
"/data/services/api/java-meeting/java-meeting2.0/config"
"/data/services/api/java-meeting/java-meeting-extapi/config"
"/data/services/api/java-meeting/java-message-scheduling/config"
"/data/services/api/java-meeting/java-mqtt/config"
"/data/services/api/java-meeting/java-quartz/config"
"/data/services/api/python-cmdb"
"/data/services/web/pc/pc-vue2-ai/static"
"/data/services/web/mobile/mobile-vue2/static"
"/data/middleware/nginx/config"
)
# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
"/var/www/java/api-java-meeting2.0/config"
"/var/www/java/external-meeting-api/config"
"/var/www/java/ubains-web-2.0/static"
"/var/www/java/ubains-web-admin/static"
"/var/www/java/ubains-web-h5/static/h5"
"/var/www/java/nginx-conf.d"
)
# ==================== 平台类型识别 ====================
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
# ==================== IP 扫描 ====================
scan_config_ips() {
local platform_type="$1"
local -a config_dirs
if [ "$platform_type" = "new" ]; then
config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
else
config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
fi
local total_files=0
local unauthorized_count=0
local unauthorized_lines=""
for dir in "${config_dirs[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
while IFS= read -r file; do
[ -z "$file" ] && continue
[ ! -r "$file" ] && continue
total_files=$((total_files + 1))
local line_num=0
while IFS= read -r line; do
line_num=$((line_num + 1))
# 提取行中的 IP
local ips
ips=$(echo "$line" | grep -oE "$IP_REGEX" 2>/dev/null)
for ip in $ips; do
# 检查是否在允许列表
if ! echo " $ALLOWED_IPS " | grep -qF " $ip "; then
unauthorized_count=$((unauthorized_count + 1))
# 转义文件路径中的特殊字符
local escaped_file
escaped_file=$(echo "$file" | sed 's/"/\\"/g')
if [ -n "$unauthorized_lines" ]; then
unauthorized_lines="${unauthorized_lines},"
fi
unauthorized_lines="${unauthorized_lines}{\"file\":\"${escaped_file}\",\"line\":${line_num},\"ip\":\"${ip}\"}"
fi
done
done < "$file"
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" -o -name "*.conf" \) 2>/dev/null)
done
# 输出结果
if [ "$unauthorized_count" -eq 0 ]; then
output_result "CFG_IP_STATUS" "OK"
output_result "CFG_IP_STATUS_LEVEL" "正常"
else
output_result "CFG_IP_STATUS" "WARN"
output_result "CFG_IP_STATUS_LEVEL" "警告"
fi
output_result "CFG_IP_TOTAL_FILES" "$total_files"
output_result "CFG_IP_UNAUTHORIZED_COUNT" "$unauthorized_count"
# JSON 数组输出
if [ -n "$unauthorized_lines" ]; then
output_result "CFG_IP_UNAUTHORIZED_LINES" "[${unauthorized_lines}]"
else
output_result "CFG_IP_UNAUTHORIZED_LINES" "[]"
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始配置IP检测..."
set +e
local platform_type
platform_type=$(detect_platform_type)
scan_config_ips "$platform_type"
log_info "配置IP检测完成"
}
main
#!/bin/bash
################################################################################
# 53_config_console_check.sh — Console配置检测
# 功能: 检测 console=true 配置项未关闭问题(只检测不修复)
# 参考: check_server_health.sh (第1582-1708行)
# 日期: 2026-07-22
# 说明: 扫描配置文件中 console[:=]true 的行,发现则标记为异常
# 不执行备份和 sed 替换,由人工确认后修复
################################################################################
# 获取脚本所在目录并加载依赖
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LIB_DIR="${LIB_DIR:-/tmp/check_modules}"
# 加载配置文件和通用函数库
if [ -f "$LIB_DIR/lib/config.sh" ]; then
source "$LIB_DIR/lib/config.sh"
else
echo "ERROR: 配置文件不存在: $LIB_DIR/lib/config.sh"
exit 1
fi
if [ -f "$LIB_DIR/lib/common.sh" ]; then
source "$LIB_DIR/lib/common.sh"
else
echo "ERROR: 通用函数库不存在: $LIB_DIR/lib/common.sh"
exit 1
fi
# console 正则(不区分大小写,匹配 console=true 或 console: true)
CONSOLE_REGEX='console[[:space:]]*[:=][[:space:]]*true'
# ==================== 配置目录定义 ====================
# 新平台配置目录
NEW_PLATFORM_CONFIG_DIRS=(
"/data/services/api/auth/auth-sso-auth/config"
"/data/services/api/auth/auth-sso-gateway/config"
"/data/services/api/auth/auth-sso-system/config"
"/data/services/api/java-meeting/java-meeting2.0/config"
"/data/services/api/java-meeting/java-meeting-extapi/config"
"/data/services/api/java-meeting/java-message-scheduling/config"
"/data/services/api/java-meeting/java-mqtt/config"
"/data/services/api/java-meeting/java-quartz/config"
"/data/services/api/python-cmdb"
"/data/services/web/pc/pc-vue2-ai/static"
"/data/services/web/mobile/mobile-vue2/static"
"/data/middleware/nginx/config"
)
# 传统平台配置目录
OLD_PLATFORM_CONFIG_DIRS=(
"/var/www/java/api-java-meeting2.0/config"
"/var/www/java/external-meeting-api/config"
"/var/www/java/ubains-web-2.0/static"
"/var/www/java/ubains-web-admin/static"
"/var/www/java/ubains-web-h5/static/h5"
"/var/www/java/nginx-conf.d"
)
# ==================== 平台类型识别 ====================
detect_platform_type() {
[ -d "/data/services" ] && echo "new" || echo "old"
}
# ==================== Console 配置扫描 ====================
scan_console_config() {
local platform_type="$1"
local -a config_dirs
if [ "$platform_type" = "new" ]; then
config_dirs=("${NEW_PLATFORM_CONFIG_DIRS[@]}")
else
config_dirs=("${OLD_PLATFORM_CONFIG_DIRS[@]}")
fi
local total_files=0
local found_count=0
local found_files=""
for dir in "${config_dirs[@]}"; do
if [ ! -d "$dir" ]; then
continue
fi
while IFS= read -r file; do
[ -z "$file" ] && continue
[ ! -r "$file" ] && continue
total_files=$((total_files + 1))
if grep -qiE "$CONSOLE_REGEX" "$file" 2>/dev/null; then
found_count=$((found_count + 1))
# 转义文件路径中的特殊字符
local escaped_file
escaped_file=$(echo "$file" | sed 's/"/\\"/g')
if [ -n "$found_files" ]; then
found_files="${found_files},"
fi
found_files="${found_files}\"${escaped_file}\""
fi
done < <(find "$dir" -type f \( -name "*.yml" -o -name "*.properties" -o -name "config.js" -o -name "config.json" \) 2>/dev/null)
done
# 输出结果
if [ "$found_count" -eq 0 ]; then
output_result "CFG_CONSOLE_STATUS" "OK"
output_result "CFG_CONSOLE_STATUS_LEVEL" "正常"
else
output_result "CFG_CONSOLE_STATUS" "WARN"
output_result "CFG_CONSOLE_STATUS_LEVEL" "警告"
fi
output_result "CFG_CONSOLE_TOTAL_FILES" "$total_files"
output_result "CFG_CONSOLE_FOUND_COUNT" "$found_count"
# JSON 数组输出
if [ -n "$found_files" ]; then
output_result "CFG_CONSOLE_FOUND_FILES" "[${found_files}]"
else
output_result "CFG_CONSOLE_FOUND_FILES" "[]"
fi
}
# ==================== 主检测流程 ====================
main() {
log_info "开始Console配置检测..."
set +e
local platform_type
platform_type=$(detect_platform_type)
scan_console_config "$platform_type"
log_info "Console配置检测完成"
}
main
......@@ -81,6 +81,12 @@ ALL_MODULES: List[CheckModule] = [
{SUITE_FULL}, "45_time_sync.sh"),
CheckModule("46_security_deep", "安全合规深度检测", "system",
{SUITE_FULL}, "46_security_deep.sh"),
CheckModule("50_system_profile", "系统类型识别", "system",
{SUITE_FULL}, "50_system_profile.sh"),
CheckModule("52_config_ip_check", "配置IP检测", "system",
{SUITE_FULL}, "52_config_ip_check.sh"),
CheckModule("53_config_console_check", "Console配置检测", "system",
{SUITE_FULL}, "53_config_console_check.sh"),
# ---- service 类 ----
CheckModule("20_docker_basic", "Docker基础", "service",
{SUITE_QUICK, SUITE_FULL}, "20_docker_basic.sh"),
......@@ -118,6 +124,8 @@ ALL_MODULES: List[CheckModule] = [
{SUITE_FULL}, "38_utracker_check.sh"),
CheckModule("39_middleware_conn", "中间件连接检测", "service",
{SUITE_FULL}, "39_middleware_conn.sh"),
CheckModule("51_service_check", "平台服务检测", "service",
{SUITE_FULL}, "51_service_check.sh"),
]
_BY_ID: Dict[str, CheckModule] = {m.id: m for m in ALL_MODULES}
......
......@@ -701,4 +701,60 @@ DISPLAY_NAMES: Dict[str, str] = {
"PROCESSES_python": "Python进程数",
"PROCESSES_ustorage": "UStorage进程数",
"PROCESSES_utracker": "UTracker进程数",
# ---- 50 系统类型识别 ----
"SYS_PROFILE_PLATFORM_TYPE": "平台类型",
"SYS_PROFILE_PLATFORM_TYPE_LEVEL": "平台类型状态等级",
"SYS_PROFILE_CONTAINER_TYPE": "容器类型",
"SYS_PROFILE_CONTAINER_TYPE_LEVEL": "容器类型状态等级",
"SYS_PROFILE_UJAVA_VARIANT": "ujava变体",
"SYS_PROFILE_UJAVA_VARIANT_LEVEL": "ujava变体状态等级",
# ---- 51 平台服务检测 ----
"SVC_CHECK_AUTH_STATUS": "认证服务状态",
"SVC_CHECK_AUTH_STATUS_LEVEL": "认证服务状态等级",
"SVC_CHECK_GATEWAY_STATUS": "网关服务状态",
"SVC_CHECK_GATEWAY_STATUS_LEVEL": "网关服务状态等级",
"SVC_CHECK_SYSTEM_STATUS": "系统服务状态",
"SVC_CHECK_SYSTEM_STATUS_LEVEL": "系统服务状态等级",
"SVC_CHECK_MEETING_STATUS": "会议服务状态",
"SVC_CHECK_MEETING_STATUS_LEVEL": "会议服务状态等级",
"SVC_CHECK_MQTT_STATUS": "MQTT服务状态",
"SVC_CHECK_MQTT_STATUS_LEVEL": "MQTT服务状态等级",
"SVC_CHECK_QUARTZ_STATUS": "定时任务服务状态",
"SVC_CHECK_QUARTZ_STATUS_LEVEL": "定时任务服务状态等级",
"SVC_CHECK_MESSAGE_STATUS": "消息调度服务状态",
"SVC_CHECK_MESSAGE_STATUS_LEVEL": "消息调度服务状态等级",
"SVC_CHECK_EXTAPI_STATUS": "对外API服务状态",
"SVC_CHECK_EXTAPI_STATUS_LEVEL": "对外API服务状态等级",
# 传统平台服务
"SVC_CHECK_NGINX_OLD_STATUS": "Nginx服务状态(传统)",
"SVC_CHECK_NGINX_OLD_STATUS_LEVEL": "Nginx服务状态等级(传统)",
"SVC_CHECK_MEETING_OLD_STATUS": "会议服务状态(传统)",
"SVC_CHECK_MEETING_OLD_STATUS_LEVEL": "会议服务状态等级(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS": "对外API服务状态(传统)",
"SVC_CHECK_EXTAPI_OLD_STATUS_LEVEL": "对外API服务状态等级(传统)",
# 端口检测
"SVC_CHECK_PORT_8000_STATUS": "uWSGI端口8000状态",
"SVC_CHECK_PORT_8000_STATUS_LEVEL": "uWSGI端口8000状态等级",
"SVC_CHECK_PORT_11211_STATUS": "Memcached端口11211状态",
"SVC_CHECK_PORT_11211_STATUS_LEVEL": "Memcached端口11211状态等级",
"SVC_CHECK_PORT_8080_STATUS": "Nginx端口8080状态",
"SVC_CHECK_PORT_8080_STATUS_LEVEL": "Nginx端口8080状态等级",
"SVC_CHECK_PORT_1883_STATUS": "MQTT端口1883状态",
"SVC_CHECK_PORT_1883_STATUS_LEVEL": "MQTT端口1883状态等级",
# ---- 52 配置IP检测 ----
"CFG_IP_STATUS": "配置IP检测状态",
"CFG_IP_STATUS_LEVEL": "配置IP检测状态等级",
"CFG_IP_TOTAL_FILES": "扫描文件数",
"CFG_IP_UNAUTHORIZED_COUNT": "未授权IP数",
"CFG_IP_UNAUTHORIZED_LINES": "未授权IP明细",
# ---- 53 Console配置检测 ----
"CFG_CONSOLE_STATUS": "Console配置检测状态",
"CFG_CONSOLE_STATUS_LEVEL": "Console配置检测状态等级",
"CFG_CONSOLE_TOTAL_FILES": "扫描文件数",
"CFG_CONSOLE_FOUND_COUNT": "发现问题数",
"CFG_CONSOLE_FOUND_FILES": "问题文件列表",
}
......@@ -40,6 +40,8 @@ _VALUE_STATUS_MAP = {
"未检测到容器": CRITICAL, "容器未运行": CRITICAL,
"无密码": CRITICAL, "弱密码": CRITICAL, "使用默认密码": CRITICAL,
"查询失败": WARNING, "无法读取": WARNING,
# 平台服务检测 / 端口检测状态词
"监听": NORMAL, "未监听": CRITICAL,
}
# 无效值/未安装占位符(这些值表示服务未安装或检测失败,不作为正常检测项)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论