#!/bin/sh
source /OSM/script/os_load_base.sh
#制作补丁时，修改GProcess、GSuffix、GVersion、GoldProcess、GoldProcessInDisk、Cgroup.
#GProcess：替换的进程全路径名称  GSuffix：补丁二进制的文件名后缀 GVersion：补丁版本号 Cgroup：该进程所属的Cgroup组名
#GoldProcess：升级组备份的进程名 GoldProcessInDisk:升级组解决部分版本打补丁后内存文件占用较多问题，会将补丁文件移动到盘目录
GProcess=/OSM/bin/ccdb_server
GSuffix=DTS2024010916276V
GVersion=SPH060
GoldProcess=/OSM/bin/ccdb_server_origin
GoldProcessInDisk=/OSM/coffer_data/patch_backup/V300R006C61/ccdb_server_origin
Cgroup=ccdb
infra_backup_common_path=/OSM/coffer_data/ccdb/ccdb_patch_backup
infra_component_lib_path=/usr/local/lib/
libcls_mon_client_so_name=libcls_mon_client.so
libcls_mon_client_so_replace_name=libcls_mon_client_DTS2024010916276.so
libpaxos_so_name=libpaxos.so
libpaxos_so_replace_name=libpaxos_DTS2024010916276.so
so_origin_suffix=v300r006c61sph60_origin
so_pre_suffix=v300r006c61sph60_pre
# 记录备份文件MD5值
infra_crc_file=${infra_backup_common_path}/ccdb_backup_file_crc_v300r006c61
SH_NAME=$(basename $0)

function loopRun()
{
    local counter=0
    while [ $counter -le 5 ]
    do
        ((counter++))
        if [ $counter -gt 3 ];then
            sleep 1
        fi
        
        "$@"
        local cmdRet=$?
        [ ${cmdRet} -eq 0 ] && return 0
        OS_echo "[$SH_NAME] error=${cmdRet}, Failed to run: $*." 
    done

    return 1
}

function check_backup_file_integrity()
{
    L_CHECK_FILE=$1
    L_VERSION_KEY=$2
    if [ ! -f "${infra_crc_file}" ]; then
        OS_echo "[$SH_NAME] ${infra_crc_file} is not exist."
        return 1
    fi
    L_LIB_RECORD_VERSION=`cat ${infra_crc_file} |grep $L_VERSION_KEY|awk -F '=' '{print $2}'`
    L_LIB_CAL_VERSION=`md5sum $L_CHECK_FILE | awk '{print $1}'`
    if [ -z "${L_LIB_RECORD_VERSION}" ] || [ -z "${L_LIB_CAL_VERSION}" ]; then
        OS_echo "[$SH_NAME] L_LIB_RECORD_VERSION[$L_LIB_RECORD_VERSION] or L_LIB_CAL_VERSION:[$L_LIB_CAL_VERSION] is null."
        return 1
    fi
 
    if [ $L_LIB_RECORD_VERSION != $L_LIB_CAL_VERSION ]; then
        OS_echo "[$SH_NAME] check file[${L_CHECK_FILE}] integrity failed,record[$L_LIB_RECORD_VERSION] not equal current[$L_LIB_CAL_VERSION]."
        return 1
    fi
    OS_echo "[$SH_NAME] check ${L_CHECK_FILE} integrity success, version[$L_LIB_CAL_VERSION]."
    return 0
}


function do_backup()
{
    L_LIB_PATH=$1
    L_LIB_ORIGIN=$2
    L_LIB_PRE=$3
    L_LIB_REPLACE=$4
    L_LIB_SO_NAME=$5

    if [ ! -d ${infra_backup_common_path} ]; then
        mkdir -p ${infra_backup_common_path}
    fi

    cmp ${L_LIB_REPLACE} ${L_LIB_PATH}
    if [ $? -eq 0 ]; then
        OS_echo "${SH_NAME} cold patch: ${L_LIB_PATH} no need backup"
        return 1
    fi

    if [ -f "$L_LIB_ORIGIN" ]; then
        check_backup_file_integrity $L_LIB_ORIGIN $L_LIB_SO_NAME
        if [ $? -eq 0 ]; then
            OS_echo "[$SH_NAME] ${L_LIB_ORIGIN} bak already exist."
            return 1
        fi
    fi

    cp -arf ${L_LIB_PATH} ${L_LIB_PRE}
    if [ $? -ne 0 ]; then
        OS_echo "[$SH_NAME] bak cp ${L_LIB_PATH} ${L_LIB_PRE} failed"
        return 2
    fi
    mv ${L_LIB_PRE} ${L_LIB_ORIGIN}
    if [ $? -ne 0 ]; then
        OS_echo "[$SH_NAME] bak mv ${L_LIB_PRE} ${L_LIB_ORIGIN} failed"
        return 2
    fi

    L_LIB_VERSION=`md5sum ${L_LIB_ORIGIN} | awk '{print $1}'`
    if [ ! -f "${infra_crc_file}" ]; then
        echo "$L_LIB_SO_NAME=$L_LIB_VERSION" >> ${infra_crc_file}
    else
        L_EXIST=`cat ${infra_crc_file} | grep $L_LIB_SO_NAME`
        if [ -z "${L_EXIST}" ]; then
            echo "$L_LIB_SO_NAME=$L_LIB_VERSION" >> ${infra_crc_file}
        else
            sed -i -r "/^$L_LIB_SO_NAME=/ s/=.*$/=${L_LIB_VERSION}/" ${infra_crc_file}
        fi
    fi

    OS_echo "[$SH_NAME] bak ${L_LIB_PATH} ${L_LIB_ORIGIN} success"
    return 0
}

function do_replace()
{
    L_LIB_PATH=$1
    L_SRC_PATH=$2

    cmp ${L_LIB_PATH} ${L_SRC_PATH}
    if [ $? -eq 0 ]; then
        OS_echo "${SH_NAME} cold patch: ${L_SRC_PATH} has already install"
        return 1
    fi

    mv ${L_LIB_PATH} ${L_SRC_PATH}
    if [ $? -ne 0 ]; then
        OS_echo "[$SH_NAME] cold patch: install cold path ${L_LIB_PATH} to ${L_SRC_PATH} failed"
        return 2
    fi
    
    chmod 550 ${L_SRC_PATH}
    OS_echo "${SH_NAME} cold patch: install cold path ${L_SRC_PATH} success"
    return 0
}

function do_backup_and_replace_so()
{
    do_backup ${infra_component_lib_path}/${libcls_mon_client_so_name} ${infra_backup_common_path}/${libcls_mon_client_so_name}_${so_origin_suffix} ${infra_backup_common_path}/${libcls_mon_client_so_name}_${so_pre_suffix} ${infra_component_lib_path}/${libcls_mon_client_so_replace_name} ${libcls_mon_client_so_name}
    L_RET=$?
    if [ $L_RET -eq 2 ]; then
        OS_echo "${SH_NAME} cold patch: backup file ${infra_component_lib_path}/${libcls_mon_client_so_name} failed"
        return 1
    fi

    do_backup ${infra_component_lib_path}/${libpaxos_so_name} ${infra_backup_common_path}/${libpaxos_so_name}_${so_origin_suffix} ${infra_backup_common_path}/${libpaxos_so_name}_${so_pre_suffix} ${infra_component_lib_path}/${libpaxos_so_replace_name} ${libpaxos_so_name}
    L_RET=$?
    if [ $L_RET -eq 2 ]; then
        OS_echo "${SH_NAME} cold patch: backup file ${infra_component_lib_path}/${libpaxos_so_name} failed"
        return 1
    fi

    do_replace ${infra_component_lib_path}/${libcls_mon_client_so_replace_name} ${infra_component_lib_path}/${libcls_mon_client_so_name}
    L_RET=$?
    if [ $L_RET -eq 2 ]; then
        OS_echo "${SH_NAME} cold patch: do replace ${infra_component_lib_path}/${libcls_mon_client_so_name} failed"
        return 1
    fi

    do_replace ${infra_component_lib_path}/${libpaxos_so_replace_name} ${infra_component_lib_path}/${libpaxos_so_name}
    L_RET=$?
    if [ $L_RET -eq 2 ]; then
        OS_echo "${SH_NAME} cold patch: do replace ${infra_component_lib_path}/${libpaxos_so_name} failed"
        return 1
    fi
    return 0
}

PATCH_START()
{
    local RETRY_TIMES=0
    local ProcessDir

    do_backup_and_replace_so
    L_RET=$?
    if [ $L_RET -ne 0 ]; then
        OS_echo "${SH_NAME} cold patch: do backup and replace so failed"
        return 1
    fi

    #新增判断 如果文件大小为0，则拷贝基线进程过来。解决小补丁大小超过1M限制方案。
    if [ -f $GProcess ]; then
        FILE_SIZE=`du -sb $GProcess | awk '{print $1}'`
        while [ $? -ne 0 -a $RETRY_TIMES -lt 3 ]
        do
            ((RETRY_TIMES++))
            OS_echo "[$SH_NAME] Check $GProcess size, times($RETRY_TIMES)."
            sleep 0.1
            FILE_SIZE=`du -sb $GProcess | awk '{print $1}'`
        done
        if [ $FILE_SIZE -eq 0 ]; then
            if [ -f $GoldProcess ]; then
                ProcessDir=$GoldProcess
            fi
            if [ -f $GoldProcessInDisk ]; then
                ProcessDir=$GoldProcessInDisk
            fi
            if [ ! -f $ProcessDir ]; then
                OS_echo "[$SH_NAME] Do not find origin file."
                return 0
            fi
            OS_echo "[$SH_NAME] Local process backup dir is $ProcessDir."
            loopRun install $ProcessDir $GProcess
            if [ $? -ne 0 ]; then
                return 0
            fi
            loopRun chmod 550 $GProcess
            if [ $? -ne 0 ]; then
                return 0
            fi
            OS_echo "[$SH_NAME] The $GProcess size is $FILE_SIZE."
            return 0
        fi

        OS_echo "[$SH_NAME] The $GProcess size is $FILE_SIZE."

    fi

    chmod 775 $GProcess
    tar zxf $GProcess -C /OSM/bin
    L_RET=$?
    if [ $L_RET -ne 0 ]; then
        OS_echo "${SH_NAME} tar $GProcess failed"
        return 1
    fi
    rm -f $GProcess
    mv $GProcess"_"$GSuffix $GProcess
    L_RET=$?
    if [ $L_RET -ne 0 ]; then
        OS_echo "${SH_NAME} mv $GProcess"_"$GSuffix to $GProcess failed"
        return 1
    fi
    chmod 550 $GProcess

    #判定该进程是否已经被加载，是否还在运行
    red=$(ps -ww -eo pid,cmd | grep $GProcess | grep -v grep | awk '{print $1}')
    OS_echo "[$SH_NAME] $GProcess oldPid: $red"
    if [ "$red" = "" ]; then
        #进程不在位，只有daemon不在位的情况，同时如果不在位资源利用率也不会太高，此处不考虑，直接返回OK
        return 0
    fi

    OS_echo "[$SH_NAME] $GProcess will be killed."
    daemon -s $GProcess
    if [ $? -ne 0 ]; then
        OS_echo "[$SH_NAME] stop $GProcess failed."
        daemon -s $GProcess
        if [ $? -ne 0 ]; then
            OS_echo "[$SH_NAME] stop $GProcess failed again."
            #停进程失败了。直接return 不exit.不影响打补丁。
            return 0
        fi
    fi
    
    daemon $GProcess "/OSM/bin/cgroup_manage.sh -g $Cgroup"

    rednew=$(ps -ww -eo pid,cmd | grep $GProcess | grep -v grep | awk '{print $1}')
    RETRY_TIMES=0
    while [ -z "$rednew" -a $RETRY_TIMES -lt 5 ] || [ $red -eq $rednew -a $RETRY_TIMES -lt 5 ]
    do
        ((RETRY_TIMES++))
        OS_echo "[$SH_NAME] Check $GProcess status, times($RETRY_TIMES)."
        sleep 0.2
        rednew=$(ps -ww -eo pid,cmd | grep $GProcess | grep -v grep | awk '{print $1}')
    done
    
    OS_echo "[$SH_NAME] newPid: $rednew"
    if [ "$rednew" = "" ] || [ $red -eq $rednew ]; then
        OS_echo "[$SH_NAME] $GProcess old pid is $red, new pid is $rednew."
        return 0
    fi
    return 0
}

PATCH_END()
{
    return 0
}

PATCH_ROLLBACK()
{
    return 0
}

PATCH_ROLLEND()
{
    return 0
}

L_CMD=$1
case $L_CMD in
    "start") PATCH_START
               L_RET=$?
               ;;
    "end") PATCH_END
               L_RET=$?
               ;;
    "rollstart") PATCH_ROLLBACK
               L_RET=$?
               ;;
    "rollend") PATCH_ROLLEND
               L_RET=$?
               ;;
    *)
        OS_echo "unsupported option."
        L_RET=0
esac
exit $L_RET