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

feat(server-check): 实现NTP服务自动修复与脚本上传功能

- 在NTP检测异常时自动触发远端修复流程
- 新增Upload_the_repair_script函数用于上传issue_handler.sh
- 支持检测并修复NTP服务配置偏差与时间同步问题
- 优化NTP时间比较逻辑,移除手动时区转换
- 修复issue_handler.sh中chrony服务名不一致问题
- 重构issue_handler.sh支持命令行动作调用模式
- 完善服务自检文档中的功能点编号与描述
- 统一代码风格,规范哈希表结尾分号使用
上级 323a46a8
...@@ -1160,7 +1160,7 @@ fix_ntp_config() { ...@@ -1160,7 +1160,7 @@ fix_ntp_config() {
if confirm_action "是否重启 chrony 服务?"; then if confirm_action "是否重启 chrony 服务?"; then
log_info "用户确认重启 chrony 服务" log_info "用户确认重启 chrony 服务"
restart_ntp_service "chrony" restart_ntp_service "chronyd"
else else
log_info "用户取消重启 chrony 服务" log_info "用户取消重启 chrony 服务"
fi fi
...@@ -1912,444 +1912,172 @@ show_disk_partition_info() { ...@@ -1912,444 +1912,172 @@ show_disk_partition_info() {
log_info "磁盘分区调整参考信息显示完成" log_info "磁盘分区调整参考信息显示完成"
} }
# 显示菜单 # 动作分发:根据动作名调用对应函数(必要时传入平台)
show_menu() { run_action_by_name() {
local platform=$(detect_platform) local action="$1"
local platform_name="" local platform="$2"
case "$platform" in case "$action" in
"new") # 日志相关
platform_name="新统一平台" export_and_compress_logs|export_logs)
export_and_compress_logs "$platform"
;; ;;
"standard") rotate_logs)
platform_name="标准版平台" rotate_logs "$platform"
;; ;;
*) clean_deleted_files)
platform_name="未知平台" clean_deleted_files
;; ;;
esac cleanup_system_log_table)
cleanup_system_log_table
# 清理屏幕并处理可能的字符显示问题
clear 2>/dev/null || printf '\033[2J\033[H'
echo -e "${BLUE}===========================================${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo "==========================================="
echo -e "${BLUE} 常见问题处理工具${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo " 常见问题处理工具"
echo -e "${BLUE}===========================================${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo "==========================================="
echo
echo -e "${YELLOW}当前平台类型: $platform_name${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo "当前平台类型: $platform_name"
echo
echo -e "${GREEN}主功能菜单:${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo "主功能菜单:"
echo " 1. 更新版本包"
echo " 1.1 更新预定系统对内后端包"
echo " 1.2 更新预定系统对外后端包"
echo " 1.3 更新预定系统前台包"
echo " 1.4 更新预定系统后台包"
echo " 1.5 更新运维后端包"
echo " 1.6 更新运维前端包"
echo
echo " 2. 修复文件权限问题"
echo " 2.1 修复普通文件权限"
echo " 2.2 修复数据库用户权限"
echo " 2.3 修复nginx用户权限"
echo
echo " 3. 修复配置文件IP不对问题"
echo
echo " 4. 修复系统磁盘问题"
echo " 4.1 清理已删除文件"
echo " 4.2 轮转日志文件"
echo " 4.3 清理数据库system_log表"
echo " 4.4 磁盘分区调整参考(手动处理)"
echo
echo " 5. 导出现场日志文件并压缩"
echo
echo " 6. 修复对外后端服务异常掉线"
echo
echo " 7. 修复ntp服务配置或启动问题"
echo
echo " 8. 修复端口开放问题"
echo
echo " 9. 修复服务器DNS异常问题"
echo
echo " 10. 打包备份现场环境数据"
echo
echo " 0. 退出"
echo
echo -e "${BLUE}===========================================${NC}" | iconv -f UTF-8 -t UTF-8//IGNORE 2>/dev/null || echo "==========================================="
echo
}
# 获取用户输入并验证
get_user_choice() {
local prompt="$1"
local valid_choices="$2"
local choice=""
# 仅当提示包含“按回车”时允许空输入(用于子菜单的“全选”场景)
local allow_empty=0
if [[ "$prompt" == *"按回车"* ]]; then
allow_empty=1
fi
while true; do
# 提示输出到 stderr,避免被命令替换捕获
printf "%s" "$prompt" >&2
IFS= read -r choice
if [ -z "$choice" ]; then
if [ $allow_empty -eq 1 ]; then
echo ""
return
else
echo -e "${RED}无效的选择,请重新输入${NC}" >&2
continue
fi
fi
# 检查输入是否为有效选项
if [[ ",$valid_choices," == *",$choice,"* ]]; then
echo "$choice"
return
else
echo -e "${RED}无效的选择,请重新输入${NC}" >&2
fi
done
}
show_submenu() {
local main_choice=$1
local platform=$2
case $main_choice in
1)
sub_choice=$(get_user_choice "请选择子操作 [1.1-1.6, 或按回车全选]: " "1.1,1.2,1.3,1.4,1.5,1.6")
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
1.1)
log_info "执行更新预定系统对内后端包"
update_inner_backend_jar "$platform"
;;
1.2)
log_info "执行更新预定系统对外后端包"
update_external_backend_jar "$platform"
;;
1.3)
log_info "执行更新预定系统前台包"
update_frontend "$platform"
;;
1.4)
log_info "执行更新预定系统后台包"
update_backend "$platform"
;;
1.5)
log_info "执行更新运维后端包"
update_ops_backend "$platform"
;;
1.6)
log_info "执行更新运维前端包"
update_ops_frontend "$platform"
;;
"")
log_info "执行更新所有包"
update_inner_backend_jar "$platform"
update_external_backend_jar "$platform"
update_frontend "$platform"
update_backend "$platform"
update_ops_backend "$platform"
update_ops_frontend "$platform"
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;; ;;
2) show_disk_partition_info)
sub_choice=$(get_user_choice "请选择子操作 [2.1-2.3, 或按回车全选]: " "2.1,2.2,2.3") show_disk_partition_info
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
2.1)
log_info "执行修复普通文件权限"
fix_permissions "$platform"
;;
2.2)
log_info "执行修复数据库用户权限"
fix_db_permissions
;;
2.3)
log_info "执行修复nginx用户权限"
fix_nginx_user
;;
"")
log_info "执行修复所有权限问题"
fix_permissions "$platform"
fix_db_permissions
fix_nginx_user
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;; ;;
3)
log_info "执行修复配置文件IP不对问题" # 配置修复
fix_ip_configurations)
fix_ip_configurations "$platform" fix_ip_configurations "$platform"
;; ;;
4) fix_permissions)
sub_choice=$(get_user_choice "请选择子操作 [4.1-4.4]: " "4.1,4.2,4.3,4.4") fix_permissions "$platform"
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
4.1)
log_info "执行清理已删除文件"
clean_deleted_files
;;
4.2)
log_info "执行轮转日志文件"
rotate_logs "$platform"
;;
4.3)
log_info "执行清理数据库system_log表"
cleanup_system_log_table
;;
4.4)
log_info "显示磁盘分区调整参考信息"
show_disk_partition_info
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;; ;;
5) fix_db_permissions)
log_info "执行导出现场日志文件并压缩" fix_db_permissions
export_and_compress_logs "$platform" ;;
fix_nginx_user)
fix_nginx_user
;; ;;
6) fix_external_service_disconnect)
log_info "执行修复对外后端服务异常掉线"
fix_external_service_disconnect "$platform" fix_external_service_disconnect "$platform"
;; ;;
7) fix_ntp_config)
log_info "执行修复ntp服务配置或启动问题" fix_ntp_config "$platform"
fix_ntp_config
;; ;;
8) fix_port_access)
log_info "执行修复端口开放问题"
fix_port_access "$platform" fix_port_access "$platform"
;; ;;
9) fix_dns_config)
log_info "执行修复服务器DNS异常问题"
fix_dns_config "$platform" fix_dns_config "$platform"
;; ;;
10)
log_info "执行打包备份现场环境数据" # 备份
backup_environment_data|backup_env)
backup_environment_data "$platform" backup_environment_data "$platform"
;; ;;
# 版本更新
update_inner_backend_jar)
update_inner_backend_jar "$platform"
;;
update_external_backend_jar)
update_external_backend_jar "$platform"
;;
update_frontend)
update_frontend "$platform"
;;
update_backend)
update_backend "$platform"
;;
update_ops_backend)
update_ops_backend "$platform"
;;
update_ops_frontend)
update_ops_frontend "$platform"
;;
*) *)
# 对于不需要子菜单的选项,直接执行 log_error "未知动作: $action"
case $main_choice in echo "可用动作: export_and_compress_logs, rotate_logs, clean_deleted_files, cleanup_system_log_table, show_disk_partition_info, fix_ip_configurations, fix_permissions, fix_db_permissions, fix_nginx_user, fix_external_service_disconnect, fix_ntp_config, fix_port_access, fix_dns_config, backup_environment_data, update_inner_backend_jar, update_external_backend_jar, update_frontend, update_backend, update_ops_backend, update_ops_frontend" >&2
*) return 1
log_error "无效的选择: $main_choice"
;;
esac
;; ;;
esac esac
} }
# 交互式模式函数 # ...existing code...
interactive_mode() { main() {
local platform=$(detect_platform) local ACTION=""
if [ "$platform" = "unknown" ]; then local PLATFORM_ARG=""
log_error "无法检测到有效的平台类型"
exit 1 if [ $# -gt 0 ]; then
fi # 解析命令行参数
while [ $# -gt 0 ]; do
log_info "检测到平台类型: $platform" case "$1" in
-h|--help)
# 显示主菜单 show_help
show_menu return 0
local main_choice=$(get_user_choice "请选择操作 [1-10]: " "1,2,3,4,5,6,7,8,9,10")
log_info "用户选择操作: $main_choice"
case $main_choice in
1)
sub_choice=$(get_user_choice "请选择子操作 [1.1-1.6, 或按回车全选]: " "1.1,1.2,1.3,1.4,1.5,1.6")
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
1.1)
log_info "执行更新预定系统对内后端包"
update_inner_backend_jar "$platform"
;;
1.2)
log_info "执行更新预定系统对外后端包"
update_external_backend_jar "$platform"
;;
1.3)
log_info "执行更新预定系统前台包"
update_frontend "$platform"
;;
1.4)
log_info "执行更新预定系统后台包"
update_backend "$platform"
;;
1.5)
log_info "执行更新运维后端包"
update_ops_backend "$platform"
;;
1.6)
log_info "执行更新运维前端包"
update_ops_frontend "$platform"
;;
"")
log_info "执行更新所有包"
update_inner_backend_jar "$platform"
update_external_backend_jar "$platform"
update_frontend "$platform"
update_backend "$platform"
update_ops_backend "$platform"
update_ops_frontend "$platform"
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;;
2)
sub_choice=$(get_user_choice "请选择子操作 [2.1-2.3, 或按回车全选]: " "2.1,2.2,2.3")
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
2.1)
log_info "执行修复普通文件权限"
fix_permissions "$platform"
;;
2.2)
log_info "执行修复数据库用户权限"
fix_db_permissions
;;
2.3)
log_info "执行修复nginx用户权限"
fix_nginx_user
;;
"")
log_info "执行修复所有权限问题"
fix_permissions "$platform"
fix_db_permissions
fix_nginx_user
;; ;;
*) -v|--version)
log_error "无效的选择: $sub_choice" show_version
return 0
;; ;;
esac --action|-a)
;; if [ -n "${2:-}" ]; then
3) ACTION="$2"; shift 2; continue
log_info "执行修复配置文件IP不对问题" else
fix_ip_configurations "$platform" log_error "--action 需要一个参数"
;; return 1
4) fi
sub_choice=$(get_user_choice "请选择子操作 [4.1-4.4]: " "4.1,4.2,4.3,4.4")
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
4.1)
log_info "执行清理已删除文件"
clean_deleted_files
;; ;;
4.2) # 新增:NTP 无交互模式
log_info "执行轮转日志文件" --ntp-auto|--ntp-non-interactive)
rotate_logs "$platform" NTP_AUTO_YES=1
shift
continue
;; ;;
4.3) --platform|-p)
log_info "执行清理数据库system_log表" if [ -n "${2:-}" ]; then
cleanup_system_log_table PLATFORM_ARG="$2"; shift 2; continue
else
log_error "--platform 需要一个参数(new|standard|auto)"
return 1
fi
;; ;;
4.4) repair|check|clean)
log_info "显示磁盘分区调整参考信息" log_info "执行命令: $1"
show_disk_partition_info case "$1" in
repair) perform_repair ;;
check) perform_check ;;
clean) perform_clean ;;
esac
return $?
;; ;;
*) *)
log_error "无效的选择: $sub_choice" # 未知参数,如果未指定 --action 则报错;若之后会走到 ACTION 分支则忽略
;; if [ -z "$ACTION" ]; then
esac log_error "未知参数: $1"
;; return 1
5) else
log_info "执行导出现场日志文件并压缩" # 忽略额外参数
export_and_compress_logs "$platform" shift
;; continue
6) fi
log_info "执行修复对外后端服务异常掉线"
fix_external_service_disconnect "$platform"
;;
7)
log_info "执行修复ntp服务配置或启动问题"
fix_ntp_config
;;
8)
log_info "执行修复端口开放问题"
fix_port_access "$platform"
;;
9)
log_info "执行修复服务器DNS异常问题"
fix_dns_config "$platform"
;;
10)
log_info "执行打包备份现场环境数据"
backup_environment_data "$platform"
;;
*)
# 对于不需要子菜单的选项,直接执行
case $main_choice in
*)
log_error "无效的选择: $main_choice"
;; ;;
esac esac
;; done
esac fi
}
# 脚本入口 # 有 --action 时,按动作直达
main() { if [ -n "$ACTION" ]; then
if [ $# -gt 0 ]; then local platform=""
case "$1" in if [ -n "$PLATFORM_ARG" ]; then
-h|--help) if [ "$PLATFORM_ARG" = "auto" ]; then
show_help platform=$(detect_platform)
exit 0 else
;; platform="$PLATFORM_ARG"
-v|--version) fi
show_version else
exit 0 platform=$(detect_platform)
;; fi
repair|check|clean) log_info "执行动作: $ACTION (平台: $platform)"
log_info "执行命令: $1" run_action_by_name "$ACTION" "$platform"
case "$1" in log_info "脚本执行完毕"
repair) return $?
perform_repair
;;
check)
perform_check
;;
clean)
perform_clean
;;
*)
log_error "未知操作: $1"
exit 1
;;
esac
;;
*)
log_error "未知参数: $1"
exit 1
;;
esac
else
# 否则进入交互式模式
log_info "进入交互式模式"
interactive_mode
fi fi
# 无参数与动作时进入交互式模式
log_info "进入交互式模式"
interactive_mode
log_info "脚本执行完毕" log_info "脚本执行完毕"
} }
......
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
#### 检测需求 #### 检测需求
##### SSH连接(✅ 已实现): ##### 1、SSH连接(✅ 已实现):
支持预设服务器列表和手动输入(IP/端口/用户名/密码) 支持预设服务器列表和手动输入(IP/端口/用户名/密码)
##### 平台识别(✅ 已实现): ##### 2、平台识别(✅ 已实现):
自动检测目标服务器平台类型(检测 /data/services 目录,如果没有则是传统平台) 自动检测目标服务器平台类型(检测 /data/services 目录,如果没有则是传统平台)
##### 系统识别(✅ 已实现): ##### 3、系统识别(✅ 已实现):
自动检测目标服务器的系统类型(检测容器分为三种:ujava、upython、upython_voice,如果有ujava则有会议预定系统、python对应运维集控系统、upython_voice对应转录系统) 自动检测目标服务器的系统类型(检测容器分为三种:ujava、upython、upython_voice,如果有ujava则有会议预定系统、python对应运维集控系统、upython_voice对应转录系统)
##### 服务进程检测(✅ 已实现): ##### 4、服务进程检测(✅ 已实现):
根据平台类型不同需要分别在不同的位置进行检测,具体如下: 根据平台类型不同需要分别在不同的位置进行检测,具体如下:
###### 新统一平台(✅ 已实现): ###### 新统一平台(✅ 已实现):
...@@ -79,13 +79,13 @@ ...@@ -79,13 +79,13 @@
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 105/memcached tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 105/memcached
tcp6 0 0 :::11211 :::* LISTEN 105/memcached tcp6 0 0 :::11211 :::* LISTEN 105/memcached
##### DNS解析问题(✅ 已实现): ##### 5、DNS解析问题(✅ 已实现):
检测目标服务器的DNS配置,能否正常进行解析等相关操作 检测目标服务器的DNS配置,能否正常进行解析等相关操作
##### 服务器资源分析(✅ 已实现): ##### 6、服务器资源分析(✅ 已实现):
检查目标服务器的磁盘空间情况、内存使用情况、cpu使用情况、防火墙开放端口情况、服务器架构以及操作系统记录 检查目标服务器的磁盘空间情况、内存使用情况、cpu使用情况、防火墙开放端口情况、服务器架构以及操作系统记录
##### 服务日志导出(✅ 已实现): ##### 7、服务日志导出(✅ 已实现):
将目标服务器上的服务日志采集,需判断传统平台还是新统一平台 将目标服务器上的服务日志采集,需判断传统平台还是新统一平台
传统平台: 传统平台:
如果有ujava容器: 如果有ujava容器:
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
8、将/data/services/api/java-meeting/java-mqtt/logs目录下的ubains-INFO-AND-ERROR.log日志文件导出命名为MQTT_ubains-INFO-AND-ERROR.log 8、将/data/services/api/java-meeting/java-mqtt/logs目录下的ubains-INFO-AND-ERROR.log日志文件导出命名为MQTT_ubains-INFO-AND-ERROR.log
9、将/data/services/api/java-meeting/java-quartz/logs目录下的ubains-INFO-AND-ERROR.log日志文件导出命名为定时任务_ubains-INFO-AND-ERROR.log 9、将/data/services/api/java-meeting/java-quartz/logs目录下的ubains-INFO-AND-ERROR.log日志文件导出命名为定时任务_ubains-INFO-AND-ERROR.log
##### 配置文件IP检测(✅ 已实现) ##### 8、配置文件IP检测(✅ 已实现)
检测目标服务器上的配置文件中的IP地址配置是否正确为目标服务器IP,需判断传统平台还是新统一平台 检测目标服务器上的配置文件中的IP地址配置是否正确为目标服务器IP,需判断传统平台还是新统一平台
传统平台: 传统平台:
如果有ujava容器: 如果有ujava容器:
...@@ -155,12 +155,12 @@ ...@@ -155,12 +155,12 @@
注意:如果遇到有172.17.0.1、127.0.0.1的IP地址以及和目标服务器IP地址一致的需判断为正确!检测日志需要打印出配置文件的路径,不要进行修改IP的操作!将单个配置文件内的IP地址检测收集结果后再标注打印,并增加配置项地址。日志需要更简洁明了! 注意:如果遇到有172.17.0.1、127.0.0.1的IP地址以及和目标服务器IP地址一致的需判断为正确!检测日志需要打印出配置文件的路径,不要进行修改IP的操作!将单个配置文件内的IP地址检测收集结果后再标注打印,并增加配置项地址。日志需要更简洁明了!
##### 服务器NTP服务检测(✅ 已实现): ##### 9、服务器NTP服务检测(✅ 已实现):
检测目标服务器上的ntp服务是否开启并能够正确进行同步时间操作,ntp服务应该分为:ntp和chronyd两种,并且需要检测目标服务器时间和北京时间是否一致。 检测目标服务器上的ntp服务是否开启并能够正确进行同步时间操作,ntp服务应该分为:ntp和chronyd两种,并且需要检测目标服务器时间和北京时间是否一致。
注意:此检测步骤需要在日志导出之前执行。不要做ntp配置文件的修改操作,此脚本只做检测! 注意:此检测步骤需要在日志导出之前执行。不要做ntp配置文件的修改操作,此脚本只做检测!
##### 文件权限检测(✅ 已实现): ##### 10、文件权限检测(✅ 已实现):
检测目标服务器上的数据库用户权限、nginx用户权限、启动文件权限、redis配置文件权限以及rc.local文件权限; 检测目标服务器上的数据库用户权限、nginx用户权限、启动文件权限、redis配置文件权限以及rc.local文件权限;
传统平台: 传统平台:
如果有ujava容器: 如果有ujava容器:
...@@ -204,7 +204,7 @@ ...@@ -204,7 +204,7 @@
2、数据库用户权限需要进入umysql容器内,数据库账号为root,密码为dNrprU&2S 2、数据库用户权限需要进入umysql容器内,数据库账号为root,密码为dNrprU&2S
注意:此检测函数需要在日志导出函数前执行,并且main主函数和日志记录函数都需要补充调用!将文件权限打印出来! 注意:此检测函数需要在日志导出函数前执行,并且main主函数和日志记录函数都需要补充调用!将文件权限打印出来!
##### 现场数据备份(✅ 已实现): ##### 11、现场数据备份(✅ 已实现):
函数名称:DataBakup 函数名称:DataBakup
先判断目标服务器是新统一平台还是传统平台,再备份对应平台的服务包与配置文件等数据,最后在目标服务器上压缩成tar.gz格式文件导出到电脑上。 先判断目标服务器是新统一平台还是传统平台,再备份对应平台的服务包与配置文件等数据,最后在目标服务器上压缩成tar.gz格式文件导出到电脑上。
...@@ -224,12 +224,19 @@ ...@@ -224,12 +224,19 @@
最后将/home/bakup目录压缩成tar.gz格式文件并导出,文件命名补充时间戳,导出完成后清理/home目录下的这个备份文件。 最后将/home/bakup目录压缩成tar.gz格式文件并导出,文件命名补充时间戳,导出完成后清理/home目录下的这个备份文件。
##### 容器信息收集(待实现): ##### 12、容器信息收集(✅ 已实现):
函数名称:Test-ContainerInformation 函数名称:Test-ContainerInformation
查询当前服务器上所有容器信息(包含未运行与运行中的信息),可以通过docker inspect来获取MAC地址、端口映射信息、启动文件位置。 查询当前服务器上所有容器信息(包含未运行与运行中的信息),可以通过docker inspect来获取MAC地址、端口映射信息、启动文件位置。
信息打印排版:先打印运行中的容器信息,再打印未运行的容器信息。 信息打印排版:先打印运行中的容器信息,再打印未运行的容器信息。
##### 定时任务查询(待实现): ##### 13、定时任务查询(待实现):
##### 14、上传修复脚本(待实现):
函数名称:Upload_the_repair_script
功能描述:函数只做上传脚本及脚本调用,上传当前目录下的issue_handler.sh脚本,将脚本上传到目标服务器,并且通过传入的修复函数,调用issue_handler对应的函数来修复。
例如:当前判断目标服务器的NTP服务存在异常,那么调用issue_handler脚本中的fix_ntp_config函数,脚本执行:./issue_handler.sh --action fix_ntp_config
##### 服务自检报告输出(✅ 已实现): ##### 服务自检报告输出(✅ 已实现):
将服务自检的所有操作步骤与结果输出到日志文件中!自检报告需要补充成md格式! 将服务自检的所有操作步骤与结果输出到日志文件中!自检报告需要补充成md格式!
\ No newline at end of file
#Requires -Version 5.1 #Requires -Version 5.1
<# <#
.SYNOPSIS .SYNOPSIS
服务自检脚本 (Windows 版本) 服务自检脚本 (Windows 版本)
...@@ -87,19 +87,19 @@ $ServerList = @{ ...@@ -87,19 +87,19 @@ $ServerList = @{
User = "root" User = "root"
Pass = "Ubains@123" Pass = "Ubains@123"
Desc = "标准版预定运维服务器" Desc = "标准版预定运维服务器"
} };
"2" = @{ "2" = @{
IP = "192.168.5.67" IP = "192.168.5.67"
User = "root" User = "root"
Pass = "Ubains@123" Pass = "Ubains@123"
Desc = "阿曼项目预定服务器" Desc = "阿曼项目预定服务器"
} };
"3" = @{ "3" = @{
IP = "192.168.5.47" IP = "192.168.5.47"
User = "root" User = "root"
Pass = "Ubains@1234" Pass = "Ubains@1234"
Desc = "标准版预定运维测试发布服务器" Desc = "标准版预定运维测试发布服务器"
} };
"4" = @{ "4" = @{
IP = "192.168.5.44" IP = "192.168.5.44"
User = "root" User = "root"
...@@ -2243,6 +2243,8 @@ function Check-NTPService { ...@@ -2243,6 +2243,8 @@ function Check-NTPService {
[string]$Password [string]$Password
) )
$summary = @{ Status = '未执行'; Detail = '' } $summary = @{ Status = '未执行'; Detail = '' }
$needRepair = $false
$serverForRepair = @{ IP = $ServerIP; User = $Username; Pass = $Password; Port = 22 }
Write-Host "开始检测目标服务器的NTP服务..." -ForegroundColor Yellow Write-Host "开始检测目标服务器的NTP服务..." -ForegroundColor Yellow
...@@ -2261,7 +2263,6 @@ function Check-NTPService { ...@@ -2261,7 +2263,6 @@ function Check-NTPService {
Write-Log -Level "INFO" -Message "[NTP] 服务器时间戳: $([string]::Join(' ', $ServerTimeResult.Output))" Write-Log -Level "INFO" -Message "[NTP] 服务器时间戳: $([string]::Join(' ', $ServerTimeResult.Output))"
if ($ServerTimeResult.ExitCode -eq 0) { if ($ServerTimeResult.ExitCode -eq 0) {
$ServerTimeUTC = [int]($ServerTimeResult.Output | Select-Object -First 1).Trim() $ServerTimeUTC = [int]($ServerTimeResult.Output | Select-Object -First 1).Trim()
# 不再手动加8小时,直接比较时间戳
$LocalTime = [int](Get-Date -UFormat %s) $LocalTime = [int](Get-Date -UFormat %s)
$TimeDifference = [math]::Abs($ServerTimeUTC - $LocalTime) $TimeDifference = [math]::Abs($ServerTimeUTC - $LocalTime)
Write-Log -Level "INFO" -Message "[NTP] 本地时间戳: $LocalTime, 差值: $TimeDifference 秒" Write-Log -Level "INFO" -Message "[NTP] 本地时间戳: $LocalTime, 差值: $TimeDifference 秒"
...@@ -2273,20 +2274,46 @@ function Check-NTPService { ...@@ -2273,20 +2274,46 @@ function Check-NTPService {
Write-Log -Level "WARN" -Message "[NTP] 时间偏差 ${TimeDifference} 秒" Write-Log -Level "WARN" -Message "[NTP] 时间偏差 ${TimeDifference} 秒"
$summary.Status = '偏差' $summary.Status = '偏差'
$summary.Detail = "时间差 ${TimeDifference}s" $summary.Detail = "时间差 ${TimeDifference}s"
$needRepair = $true
} }
} else { } else {
Write-Log -Level "ERROR" -Message "[NTP] 获取服务器时间失败" Write-Log -Level "ERROR" -Message "[NTP] 获取服务器时间失败"
$summary.Status = '异常'; $summary.Detail = '获取服务器时间失败' $summary.Status = '异常'; $summary.Detail = '获取服务器时间失败'
$needRepair = $true
} }
} else { } else {
Write-Log -Level "ERROR" -Message "[NTP] timedatectl 不可用" Write-Log -Level "ERROR" -Message "[NTP] timedatectl 不可用"
$summary.Status = '异常'; $summary.Detail = 'timedatectl 不可用' $summary.Status = '异常'; $summary.Detail = 'timedatectl 不可用'
$needRepair = $true
} }
} else { } else {
Write-Log -Level "WARN" -Message "[NTP] 未检测到 NTP/Chrony 服务" Write-Log -Level "WARN" -Message "[NTP] 未检测到 NTP/Chrony 服务"
$summary.Status = '未安装'; $summary.Detail = '未检测到 ntp/chronyd' $summary.Status = '未安装'; $summary.Detail = '未检测到 ntp/chronyd'
$needRepair = $true
} }
Write-Log -Level "INFO" -Message "[NTP] 检测结束" Write-Log -Level "INFO" -Message "[NTP] 检测结束"
# 若异常/未安装/偏差,则上传并执行修复动作
if ($needRepair) {
Write-Log -Level "INFO" -Message "[NTP] 触发远端修复: ./issue_handler.sh --action fix_ntp_config --ntp-auto"
try {
$repairRes = Upload_the_repair_script -Server $serverForRepair -Action "fix_ntp_config" -Platform "auto" -RemoteDir "/home/repair_scripts"
if ($repairRes -and $repairRes.Success) {
Write-Log -Level "SUCCESS" -Message "[NTP] 远端修复已执行成功 (fix_ntp_config)"
if ([string]::IsNullOrWhiteSpace($summary.Detail)) {
$summary.Detail = "已尝试修复"
} else {
$summary.Detail = "$($summary.Detail) | 已尝试修复"
}
} else {
$err = if ($repairRes -and $repairRes.Error) { [string]::Join(' ', $repairRes.Error) } else { '未知错误' }
Write-Log -Level "ERROR" -Message "[NTP] 远端修复执行失败: $err"
}
} catch {
Write-Log -Level "ERROR" -Message "[NTP] 调用 Upload_the_repair_script 异常: $($_.Exception.Message)"
}
}
return $summary return $summary
} }
...@@ -2366,8 +2393,155 @@ function Check-FilePermissions { ...@@ -2366,8 +2393,155 @@ function Check-FilePermissions {
return @{ Summary = $summaryText; Lines = $lines } return @{ Summary = $summaryText; Lines = $lines }
} }
# ================================
# 上传修复脚本函数
# ================================
function Upload_the_repair_script {
param(
[Parameter(Mandatory = $true)] [hashtable]$Server,
[Parameter(Mandatory = $true)] [string]$Action,
[Parameter(Mandatory = $false)] [ValidateSet('auto','new','old')] [string]$Platform = 'auto',
[Parameter(Mandatory = $false)] [string]$RemoteDir = "/home/repair_scripts",
[Parameter(Mandatory = $false)] [string]$LocalIssueHandlerPath
)
Write-Host ""
Write-Log -Level "INFO" -Message "========== 上传修复脚本并执行 =========="
Write-Log -Level "INFO" -Message "目标: $($Server.User)@$($Server.IP):$($Server.Port) | 动作: $Action | 平台: $Platform"
# 1) 定位 pscp
$pscpPath = $script:PSCP_PATH
if (-not $pscpPath -or -not (Test-Path $pscpPath)) {
$cmdInPath = Get-Command pscp -ErrorAction SilentlyContinue
if ($cmdInPath) { $pscpPath = $cmdInPath.Source }
}
if (-not $pscpPath -or -not (Test-Path $pscpPath)) {
Write-Log -Level "ERROR" -Message "pscp.exe 未找到,无法上传脚本"
Write-Log -Level "ERROR" -Message "请将 pscp.exe 放在脚本同目录,或加入 PATH。下载: https://the.earth.li/~sgtatham/putty/latest/w64/pscp.exe"
return @{
Success = $false
Step = "CheckPSCP"
Message = "pscp.exe not found"
}
}
Write-Log -Level "INFO" -Message "已找到 pscp: $pscpPath"
# 2) 定位本地 issue_handler.sh
if (-not $LocalIssueHandlerPath) {
$candidates = @(
(Join-Path $SCRIPT_DIR "issue_handler.sh"),
(Join-Path (Split-Path $SCRIPT_DIR -Parent) "常见问题处理\issue_handler.sh"),
(Join-Path (Split-Path (Split-Path $SCRIPT_DIR -Parent) -Parent) "辅助工具\脚本工具\常见问题处理\issue_handler.sh")
) | Select-Object -Unique
$LocalIssueHandlerPath = ($candidates | Where-Object { Test-Path $_ } | Select-Object -First 1)
}
if (-not $LocalIssueHandlerPath -or -not (Test-Path $LocalIssueHandlerPath)) {
Write-Log -Level "ERROR" -Message "未找到本地 issue_handler.sh"
Write-Log -Level "ERROR" -Message "请确认脚本存在,或通过 -LocalIssueHandlerPath 指定路径"
return @{
Success = $false
Step = "FindLocalScript"
Message = "Local issue_handler.sh not found"
}
}
Write-Log -Level "INFO" -Message "本地脚本: $LocalIssueHandlerPath"
# 3) 远端准备目录
$prepCmd = "mkdir -p '$RemoteDir'"
$prepRes = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $prepCmd
if ($prepRes.ExitCode -ne 0) {
Write-Log -Level "ERROR" -Message "远端目录创建失败: $RemoteDir"
return @{
Success = $false
Step = "MkdirRemote"
ExitCode = $prepRes.ExitCode
Output = $prepRes.Output
Error = $prepRes.Error
}
}
Write-Log -Level "INFO" -Message "远端目录已就绪: $RemoteDir"
# 4) 上传脚本
$remoteTarget = "$($Server.User)@$($Server.IP):$RemoteDir/"
Write-Log -Level "INFO" -Message "开始上传 -> $remoteTarget"
$pscpArgs = @(
"-P", "$($Server.Port)",
"-pw", "$($Server.Pass)",
"$LocalIssueHandlerPath",
$remoteTarget
)
try {
$null = & "$pscpPath" @pscpArgs
} catch {
Write-Log -Level "ERROR" -Message "pscp 执行异常: $($_.Exception.Message)"
return @{
Success = $false
Step = "Upload"
Message = $_.Exception.Message
}
}
Write-Log -Level "SUCCESS" -Message "脚本上传完成"
# 5) 远端修复换行符并赋权
$remoteFile = "$RemoteDir/issue_handler.sh"
$fixCmd = @(
"set -e",
"chmod +x '$remoteFile' || true",
"if command -v dos2unix >/dev/null 2>&1; then dos2unix '$remoteFile' || true; else sed -i 's/\r$//' '$remoteFile' || true; fi"
) -join " && "
$fixRes = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $fixCmd
if ($fixRes.ExitCode -ne 0) {
Write-Log -Level "ERROR" -Message "远端脚本准备失败 (chmod/dos2unix)"
return @{
Success = $false
Step = "PrepareRemoteScript"
ExitCode = $fixRes.ExitCode
Output = $fixRes.Output
Error = $fixRes.Error
}
}
Write-Log -Level "INFO" -Message "远端脚本就绪: $remoteFile"
# 6) 远端执行修复动作
$platArg = if ($Platform -and $Platform.Length -gt 0) { "--platform $Platform" } else { "" }
$extraArgs = ""
if ($Action -eq "fix_ntp_config") {
# 对 NTP 修复追加无交互参数,避免远端卡住
$extraArgs = "--ntp-auto"
}
$execCmd = @(
"set -e",
"cd '$RemoteDir'",
"./issue_handler.sh --action $Action $platArg $extraArgs"
) -join " && "
Write-Log -Level "INFO" -Message "开始执行远端修复: $execCmd"
$execRes = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $execCmd
# 根据执行结果设置成功标志并输出日志
$succ = ($execRes.ExitCode -eq 0)
if ($succ) {
Write-Log -Level "SUCCESS" -Message "远端修复执行成功: $Action"
} else {
Write-Log -Level "ERROR" -Message "远端修复执行失败,ExitCode=$($execRes.ExitCode)"
}
return @{
Success = $succ
Action = $Action
Platform = $Platform
RemoteDir = $RemoteDir
RemoteFile = $remoteFile
ExitCode = $execRes.ExitCode
Output = $execRes.Output
Error = $execRes.Error
}
}
# ================================ # ================================
# 检测 DataBakup 服务 (待实现) # 检测 DataBakup 服务
# ================================ # ================================
function DataBakup { function DataBakup {
param ( param (
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论