#!/bin/bash set -o pipefail LOG_DIR="/var/log/okcc5upgrade" LOG_FILE="$LOG_DIR/okcc5_upgrade_$(date +%Y%m%d_%H%M%S).log" mkdir -p "$LOG_DIR" exec > >(tee -a "$LOG_FILE") 2>&1 echo "=== OKCC5 升级脚本启动于 $(date) ===" echo "日志文件: $LOG_FILE" echo "" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # 版本比较函数:vercmp v1 v2 # 返回值:0 if v1 == v2, 1 if v1 > v2, 2 if v1 < v2 vercmp() { local a b i IFS='.' read -ra a <<< "${1//[^0-9.]/}" IFS='.' read -ra b <<< "${2//[^0-9.]/}" local len=$(( ${#a[@]} > ${#b[@]} ? ${#a[@]} : ${#b[@]} )) for ((i=0; i 10#$y )); then return 1; fi if (( 10#$x < 10#$y )); then return 2; fi done return 0 } # 检测 CentOS/RHEL 大版本号(6/7) detect_os_major() { local rel="" if [ -f /etc/redhat-release ]; then rel=$(cat /etc/redhat-release) elif [ -f /etc/centos-release ]; then rel=$(cat /etc/centos-release) else rel=$(uname -a) fi # 典型格式:CentOS Linux release 7.9.2009 (Core) # CentOS release 6.10 (Final) local major major=$(echo "$rel" | sed -n 's/.*release[[:space:]]\+\([0-9]\+\)\..*/\1/p' | head -n1) if [[ -z "$major" ]]; then # 兜底:rpm if command -v rpm >/dev/null 2>&1; then major=$(rpm -q --qf '%{VERSION}\n' centos-release 2>/dev/null | head -n1) fi fi echo "$major" } OS_MAJOR="$(detect_os_major)" if [[ "$OS_MAJOR" != "6" && "$OS_MAJOR" != "7" ]]; then echo -e "${YELLOW}警告:未能可靠识别系统大版本(检测到: ${OS_MAJOR:-unknown})。脚本将按 CentOS6 路径执行(不升级 MySQL)。${NC}" OS_MAJOR="6" fi echo -e "${GREEN}检测到系统大版本:CentOS/RHEL $OS_MAJOR${NC}" # 检查 curl 是否存在(用于发送通知邮件) if ! command -v curl >/dev/null 2>&1; then echo -e "${RED}错误:未检测到 curl 命令,无法发送通知邮件!${NC}" read -p "是否继续执行?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "操作已取消。" exit 1 fi fi # 检查磁盘空间(根分区 >=20G)- 兼容 CentOS6/7 check_disk_space() { local avail_kb avail_gb avail_kb=$(df -Pk / | awk 'NR==2{print $4}') if [[ -z "$avail_kb" || ! "$avail_kb" =~ ^[0-9]+$ ]]; then echo -e "${YELLOW}警告:无法获取磁盘剩余空间信息,跳过检查。${NC}" return 0 fi avail_gb=$((avail_kb / 1024 / 1024)) if (( avail_gb < 20 )); then for i in {1..3}; do echo -e "${RED}警告:根分区可用空间不足 20GB!当前可用:${avail_gb}GB${NC}" done return 1 else echo -e "${GREEN}根分区空间充足(${avail_gb}GB ≥ 20GB)${NC}" return 0 fi } # 主菜单提示 echo "执行前请将安装包和 upgrade3to5.tar.gz 下载到本地" echo "scp root@ai.dipcc.com:/home/package/okcc5/upgrade3to5.tar.gz /home/package/" echo "scp root@ai.dipcc.com:/home/package/okcc5/V5.0.6.33-BIN.tar.gz /home/package/" echo "scp root@ai.dipcc.com:/home/package/OKCC-FS/FS-V3.6.7-BIN.tar.gz /home/package/" if [[ "$OS_MAJOR" == "7" ]]; then echo "(CentOS7 额外)scp root@ai.dipcc.com:/home/package/okcc5/upgrade/Mysql_Upgrade_V5.7.44_BY3.0.tar.gz /home/package/" fi echo "" echo "请选择操作:" echo "1. 升级前验证数据库(请在业务空闲期执行)" echo "2. 升级 OKCC5" read -p "请输入选项 (1 或 2): " choice case "$choice" in 1) echo -e "${YELLOW}正在执行数据库验证...${NC}" cd /home/package/ || { echo -e "${RED}目录 /home/package/ 不存在!${NC}"; exit 1; } if [ ! -f upgrade3to5.tar.gz ]; then echo -e "${RED}错误:/home/package/upgrade3to5.tar.gz 不存在!${NC}" exit 1 fi tar -xf upgrade3to5.tar.gz cd /home/package/upgrade || { echo -e "${RED}解压后目录 /home/package/upgrade 不存在!${NC}"; exit 1; } if [ ! -f ./check.sh ]; then echo -e "${RED}错误:/home/package/upgrade/check.sh 不存在!${NC}" exit 1 fi if [ ! -x ./check.sh ]; then echo -e "${YELLOW}检测到 check.sh 缺少执行权限,正在添加...${NC}" chmod +x ./check.sh || { echo -e "${RED}错误:无法为 check.sh 添加执行权限!${NC}"; exit 1; } fi echo -e "${YELLOW}开始执行 check.sh...${NC}" ./check.sh echo -e "${GREEN}数据库验证完成。请检查上述输出是否有表损坏或字段缺失。如有问题,请手动修复后再继续升级。${NC}" ;; 2) # ========== 配置参数 ========== LICENSE_DIR="/home/license5" REQUIRED_LICENSE_FILES=("data10.dat" "license") UPGRADE_BASE_DIR="/home/package/upgrade" # CentOS7 才需要 MySQL 升级包 MYSQL_UPGRADE_TAR="Mysql_Upgrade_V5.7.44_BY3.0.tar.gz" MYSQL_UPGRADE_DIR_NAME="Mysql_Upgrade_V5.7.44_BY3.0" MYSQLD_BIN="/usr/local/mysql/bin/mysqld" MYSQL_BIN="/usr/local/mysql/bin/mysql" DATA_UPGRADE_TAR="Upgrade-V3.0-to-V5.0.tar.gz" DATA_UPGRADE_DIR_NAME="Upgrade-V3.0-to-V5.0" PHP_BIN="/usr/local/php/bin/php" LIC_TARGET_DIR="/etc/lics/SCv5" FS_TAR="FS-V3.6.7-BIN.tar.gz" FS_DIR_NAME="FS-V3.6.7" # =================================================== echo -e "${YELLOW}=== 升级 OKCC5 ===${NC}" # 版本检查 VERSION_FILE="/ipcc/etc/pub/version" if [ ! -f "$VERSION_FILE" ]; then echo -e "${RED}错误:版本文件不存在 → $VERSION_FILE${NC}" exit 1 fi CURRENT_VERSION=$(cat "$VERSION_FILE" | tr -d '[:space:]') if [ -z "$CURRENT_VERSION" ]; then echo -e "${RED}错误:无法读取当前版本号!${NC}" exit 1 fi echo -e "${GREEN}当前系统版本:$CURRENT_VERSION${NC}" vercmp "$CURRENT_VERSION" "3.1.12.3" cmp_result=$? if [ $cmp_result -eq 2 ]; then echo -e "${RED}错误:当前版本 $CURRENT_VERSION 小于 3.1.12.3,不支持升级!${NC}" exit 1 elif [ $cmp_result -eq 0 ]; then echo -e "${YELLOW}当前版本等于 3.1.12.3,允许升级。${NC}" else echo -e "${GREEN}当前版本高于 3.1.12.3,继续升级。${NC}" fi # 磁盘空间检查 if ! check_disk_space; then echo -e " ${YELLOW}注意:磁盘空间不足可能引发升级失败或系统异常! ${NC}" read -p "是否仍要继续升级?(y/N): " disk_confirm if [[ ! "$disk_confirm" =~ ^[Yy]$ ]]; then echo -e " ${GREEN}升级已取消。 ${NC}" exit 0 else echo -e " ${YELLOW}用户选择忽略磁盘空间警告,继续升级... ${NC}" fi fi echo -e "${YELLOW}重要提示:请确保已将 OKCC5 的授权文件 data10.dat 和 license 放置在 $LICENSE_DIR 目录中。${NC}" echo -e "${YELLOW}授权文件路径要求:${NC}" for f in "${REQUIRED_LICENSE_FILES[@]}"; do echo " - $LICENSE_DIR/$f" done echo echo -e "${YELLOW}同时,请确认以下升级包已存在于 $UPGRADE_BASE_DIR 目录中:${NC}" echo " - $DATA_UPGRADE_TAR" if [[ "$OS_MAJOR" == "7" ]]; then echo " - $MYSQL_UPGRADE_TAR (仅 CentOS7 需要)" fi echo -e "${YELLOW}同时,请确认以下升级包已存在于 /home/package/ 目录中:${NC}" echo " - $FS_TAR (用于升级 FS)" echo read -p "是否确认已准备好并开始执行升级?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "升级已取消。" exit 0 fi # 检查授权文件 for f in "${REQUIRED_LICENSE_FILES[@]}"; do if [ ! -f "$LICENSE_DIR/$f" ]; then echo -e "${RED}错误:授权文件缺失 → $LICENSE_DIR/$f${NC}" echo "请将 OKCC5 授权文件放入 $LICENSE_DIR 后重试。" exit 1 fi done # 获取客户信息 read -p "请输入当前升级客户名称: " client_name read -p "请输入升级完成后接收通知的邮箱: " recipient_email if ! [[ "$recipient_email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then echo -e "${YELLOW}警告:邮箱格式可能不正确,请确认。${NC}" read -p "是否继续?(y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "操作已取消。" exit 1 fi fi echo -e "${GREEN}客户名称: $client_name${NC}" echo -e "${GREEN}通知邮箱: $recipient_email${NC}" echo # ========== 准备升级包 ========== UPGRADE_TAR_SOURCE="/home/package/upgrade3to5.tar.gz" UPGRADE_BASE_DIR="/home/package/upgrade" need_extract=false if [ ! -d "$UPGRADE_BASE_DIR" ]; then need_extract=true else if [ ! -f "$UPGRADE_BASE_DIR/$DATA_UPGRADE_TAR" ]; then need_extract=true fi if [[ "$OS_MAJOR" == "7" && ! -f "$UPGRADE_BASE_DIR/$MYSQL_UPGRADE_TAR" ]]; then need_extract=true fi fi if $need_extract; then echo -e "${YELLOW}检测到升级包未就绪,尝试从 $UPGRADE_TAR_SOURCE 解压...${NC}" if [ ! -f "$UPGRADE_TAR_SOURCE" ]; then echo -e "${RED}错误:源升级包不存在 → $UPGRADE_TAR_SOURCE${NC}" echo "请确保 upgrade3to5.tar.gz 已放置在 /home/package/ 目录中。" exit 1 fi cd /home/package/ || { echo -e "${RED}无法进入 /home/package/${NC}"; exit 1; } echo -e "${YELLOW}正在解压 $UPGRADE_TAR_SOURCE ...${NC}" tar -xf "$UPGRADE_TAR_SOURCE" if [ ! -d "$UPGRADE_BASE_DIR" ]; then echo -e "${RED}错误:解压后 $UPGRADE_BASE_DIR 目录不存在!${NC}" echo "请确认 upgrade3to5.tar.gz 内容结构正确(应包含 upgrade/ 子目录)。" exit 1 fi if [ ! -f "$UPGRADE_BASE_DIR/$DATA_UPGRADE_TAR" ]; then echo -e "${RED}错误:解压后缺少数据升级包 → $DATA_UPGRADE_TAR${NC}" exit 1 fi if [[ "$OS_MAJOR" == "7" && ! -f "$UPGRADE_BASE_DIR/$MYSQL_UPGRADE_TAR" ]]; then echo -e "${RED}错误:解压后缺少 MySQL 升级包 → $MYSQL_UPGRADE_TAR${NC}" exit 1 fi echo -e "${GREEN}升级包已成功解压并验证通过。${NC}" else echo -e "${GREEN}升级包已就绪,跳过解压。${NC}" fi # ========== 升级 FS ========== echo -e "${YELLOW}正在升级 FS 模块...${NC}" cd /home/package/ || { echo -e "${RED}无法进入 /home/package/${NC}"; exit 1; } if [ ! -f "$FS_TAR" ]; then echo -e "${RED}错误:FS 升级包缺失 → /home/package/$FS_TAR${NC}" exit 1 fi tar -xf "$FS_TAR" if [ ! -d "$FS_DIR_NAME" ]; then echo -e "${RED}错误:解压后 FS 目录 $FS_DIR_NAME 不存在!${NC}" exit 1 fi cd "$FS_DIR_NAME/BIN/" || { echo -e "${RED}无法进入 FS 安装目录${NC}"; exit 1; } if [ ! -f install.sh ]; then echo -e "${RED}错误:FS install.sh 不存在!${NC}" exit 1 fi chmod +x install.sh ./install.sh || { echo -e "${RED}错误:FS 升级失败!${NC}"; exit 1; } echo -e "${GREEN}FS 模块升级完成。${NC}" # 停止监控(如果存在) if [ -d "/opt/moni" ]; then echo -e "${YELLOW}正在停止服务器性能监控...${NC}" cd /opt/moni || { echo -e "${RED}无法进入 /opt/moni${NC}"; exit 1; } if [ -f ./stop_monitor.sh ]; then chmod +x ./stop_monitor.sh 2>/dev/null ./stop_monitor.sh else echo -e "${YELLOW}警告:/opt/moni/stop_monitor.sh 不存在,跳过监控停止。${NC}" fi else echo "未检测到 /opt/moni,跳过监控停止。" fi # 解压升级包 echo -e "${YELLOW}正在解压升级包...${NC}" cd "$UPGRADE_BASE_DIR" || exit 1 # CentOS7:升级 MySQL if [[ "$OS_MAJOR" == "7" ]]; then tar -xf "$MYSQL_UPGRADE_TAR" if [ ! -d "$MYSQL_UPGRADE_DIR_NAME" ]; then echo -e "${RED}错误:解压 $MYSQL_UPGRADE_TAR 后,目录 $MYSQL_UPGRADE_DIR_NAME 不存在!${NC}" exit 1 fi echo -e "${YELLOW}正在升级 MySQL 到 5.7.44...${NC}" cd "$UPGRADE_BASE_DIR/$MYSQL_UPGRADE_DIR_NAME" || { echo -e "${RED}无法进入 MySQL 升级目录${NC}"; exit 1; } if [ ! -f ./install.sh ]; then echo -e "${RED}错误:MySQL install.sh 不存在!${NC}" exit 1 fi chmod +x ./install.sh 2>/dev/null ./install.sh || { echo -e "${RED}错误:MySQL 升级 install.sh 执行失败!${NC}"; exit 1; } echo -e "${YELLOW}验证 MySQL 版本...${NC}" if ! "$MYSQLD_BIN" --version 2>/dev/null | grep -q "5.7.44"; then echo -e "${RED}错误:MySQL 升级未成功,版本不是 5.7.44!当前输出:${NC}" "$MYSQLD_BIN" --version 2>&1 || echo "(mysqld 命令不可用)" exit 1 else echo -e "${GREEN}MySQL 5.7.44 验证通过。${NC}" fi cd "$UPGRADE_BASE_DIR" || exit 1 fi # 解压数据升级包 tar -xf "$DATA_UPGRADE_TAR" if [ ! -d "$DATA_UPGRADE_DIR_NAME" ]; then echo -e "${RED}错误:解压 $DATA_UPGRADE_TAR 后,目录 $DATA_UPGRADE_DIR_NAME 不存在!${NC}" exit 1 fi # 验证 PHP 模块(保持原逻辑:有 PHP 才继续) echo -e "${YELLOW}验证 PHP 模块加载...${NC}" if ! "$PHP_BIN" -m > /dev/null 2>&1; then echo -e "${RED}错误:PHP 模块加载失败!${NC}" exit 1 else echo -e "${GREEN}PHP 模块加载正常。${NC}" fi # 执行数据升级(必须检查返回码) echo -e "${YELLOW}正在执行数据升级(V3.0 → V5.0)...${NC}" cd "$UPGRADE_BASE_DIR/$DATA_UPGRADE_DIR_NAME" || { echo -e "${RED}无法进入数据升级目录${NC}"; exit 1; } if [ ! -f ./install.sh ]; then echo -e "${RED}错误:数据升级 install.sh 不存在!${NC}" exit 1 fi chmod +x ./install.sh 2>/dev/null ./install.sh if [ $? -ne 0 ]; then echo -e "${RED}错误:数据升级执行失败,终止后续安装!${NC}" exit 1 fi # ========== 安装 V5.0.6.33 ========== echo -e "${YELLOW}正在安装 V5.0.6.33...${NC}" PKG=(V5.0.6.33 V5.0.18) check_mysql_connection() { local MYSQL_USER="root" local MYSQL_PASS="sg6d9ybbnMv41SKT" local MYSQL_HOST="localhost" if "$MYSQL_BIN" -u"$MYSQL_USER" -p"$MYSQL_PASS" -h"$MYSQL_HOST" -e "SELECT 1;" >/dev/null 2>&1; then return 0 fi return 1 } mkdir -p /var/log for I in "${PKG[@]}"; do echo "$(date +'%F %H:%M:%S') install start $I" >> /var/log/install_package.log echo -e "${YELLOW}开始安装包: $I${NC}" PKG_FILE="/home/package/${I}-BIN.tar.gz" if [ ! -f "$PKG_FILE" ]; then echo -e "${RED}错误:安装包缺失 → $PKG_FILE${NC}" echo "$(date +'%F %H:%M:%S') $I - Package not found, skipping." >> /var/log/install_package.log echo "*********************Install $I finished (skipped)**************************" continue fi cd /home/package || { echo -e "${RED}无法进入 /home/package${NC}"; exit 1; } tar -xf "$PKG_FILE" if [ ! -d "/home/package/$I/BIN" ]; then echo -e "${RED}错误:解压后 $I/BIN 目录不存在!${NC}" echo "$(date +'%F %H:%M:%S') $I - BIN dir missing after extract." >> /var/log/install_package.log echo "*********************Install $I finished (failed)**************************" continue fi cd "/home/package/$I/BIN" || { echo -e "${RED}无法进入 $I/BIN${NC}"; continue; } mysql_ready=false for attempt in {1..3}; do if check_mysql_connection; then mysql_ready=true break else echo "$(date +'%F %H:%M:%S') $I - MySQL not ready (attempt $attempt/3), waiting 5s..." >> /var/log/install_package.log sleep 5 fi done if [ "$mysql_ready" = false ]; then echo "$(date +'%F %H:%M:%S') FATAL: MySQL unreachable after 3 attempts during $I install." >> /var/log/install_package.log echo -e "${RED}致命错误:MySQL 无法连接,升级流程中止!${NC}" echo -e "${YELLOW}正在发送数据库连接失败告警邮件...${NC}" curl -X POST http://ai.dipcc.com:18080/send-email/ \ -H "Content-Type: application/json" \ -H "User-Agent: DIPCCZENTAO_Roger" \ -d "{\"client_name\": \"$client_name\", \"recipient_email\": \"$recipient_email\", \"custom_message\": \"因数据库连接失败,暂停升级,请手动检查!\"}" || true exit 1 fi if [ ! -f ./install.sh ]; then echo -e "${RED}错误:$I/BIN/install.sh 不存在!${NC}" echo "$(date +'%F %H:%M:%S') $I - install.sh missing." >> /var/log/install_package.log echo "*********************Install $I finished (failed)**************************" continue fi chmod +x ./install.sh 2>/dev/null ./install.sh install_result=$? if [ $install_result -eq 0 ]; then echo "$(date +'%F %H:%M:%S') $I" >> /var/log/install_package.log echo -e "${GREEN}✅ $I 安装成功。${NC}" else echo "$(date +'%F %H:%M:%S') $I Install fail..." >> /var/log/install_package.log echo -e "${RED}❌ $I 安装失败(退出码: $install_result)。${NC}" exit 1 fi echo "*********************Install $I finished...**************************" sleep 2 done echo -e "${GREEN}V5.0.6.33 安装完成。${NC}" # 更新授权文件 echo -e "${YELLOW}正在更新授权文件到 $LIC_TARGET_DIR...${NC}" mkdir -p "$LIC_TARGET_DIR" for f in "${REQUIRED_LICENSE_FILES[@]}"; do mv "$LICENSE_DIR/$f" "$LIC_TARGET_DIR/" || { echo -e "${RED}错误:移动授权文件失败 → $f${NC}"; exit 1; } done echo -e "${GREEN}授权文件更新完成。${NC}" # 参数更新(保持原逻辑) "$MYSQL_BIN" -uroot -psg6d9ybbnMv41SKT -e "UPDATE ccsys.tbl_parameters SET parameter_value='1' WHERE parameter_name='login_template';" || true MYSQL_USER="root" MYSQL_PWD="sg6d9ybbnMv41SKT" DB_NAME="ccsys" TABLE_NAME="tbl_parameters" PARAMS=( "display_line_mode|1" "login_template|1" ) insert_param_if_not_exists() { local param_name="$1" local param_value="$2" local count count=$("$MYSQL_BIN" -u"${MYSQL_USER}" -p"${MYSQL_PWD}" "${DB_NAME}" -sN -e \ "SELECT COUNT(*) FROM ${TABLE_NAME} WHERE parameter_name = '${param_name}';" 2>/dev/null) if [ -z "$count" ]; then echo "错误:查询参数 ${param_name} 时数据库连接失败,请检查参数或数据库状态!" echo -e "${YELLOW}正在发送数据库连接失败告警邮件...${NC}" curl -X POST http://ai.dipcc.com:18080/send-email/ \ -H "Content-Type: application/json" \ -H "User-Agent: DIPCCZENTAO_Roger" \ -d "{\"client_name\": \"$client_name\", \"recipient_email\": \"$recipient_email\", \"custom_message\": \"因数据库连接失败,display_line_mode 或 login_template 插入失败,请手动检查!\"}" || true return 1 fi if [ "$count" -eq 0 ]; then "$MYSQL_BIN" -u"${MYSQL_USER}" -p"${MYSQL_PWD}" "${DB_NAME}" -e \ "INSERT INTO ${TABLE_NAME} (parameter_name, parameter_value, \`default\`, res1, res2) VALUES ('${param_name}', '${param_value}', '', '0', '0');" \ || return 1 echo "成功:插入记录 ${param_name} = ${param_value} 完成!" else echo "提示:记录 ${param_name} = ${param_value} 已存在,无需插入!" fi return 0 } for param in "${PARAMS[@]}"; do param_name="${param%%|*}" param_value="${param##*|}" insert_param_if_not_exists "$param_name" "$param_value" || exit 1 done # 发送通知邮件 echo -e "${YELLOW}正在发送升级完成通知邮件...${NC}" curl -X POST http://ai.dipcc.com:18080/send-email/ \ -H "Content-Type: application/json" \ -H "User-Agent: DIPCCZENTAO_Roger" \ -d "{\"client_name\": \"$client_name\", \"recipient_email\": \"$recipient_email\"}" || true echo -e "${YELLOW}升级完成,即将重启服务器...${NC}" sleep 3 reboot ;; *) echo -e "${RED}无效选项!请运行脚本并选择 1 或 2。${NC}" exit 1 ;; esac