#!/bin/env bash
##Description: green check before true switch

script_run_role="PRIMARY,STANDBY"
script_base_name="tidb_so_precheck"

function f_syntax
{
    [ ! -z "$1" ] && echo ">>[$(date "+%Y%m%d.%H%M%S")] $1"
    echo " "
    echo "bash ${ShellName}  [-primaryhostname <hostname>]"
    echo "-standbyhostname <hostname_standby> "
    echo " "
    echo " #Description:"
    echo " -primaryhostname ,the primary cluster manager host"
    echo " -standbyhostname ,the standby cluster manager host"
    echo " "
    echo " #sample:"
    echo " #sh ${ShellName} -primaryhostname node1 -standbyhostname sa-172-16-4-81" 
    echo " "
    exit 22
}

function f_PrintLog
{
    _LogFlag=$(echo "$1"|tr "a-z" "A-Z")
    _LogMessage=$2
    [ $(echo "$1"|wc -L) -eq 4 ] && _LogFlag=$(echo "${_LogFlag}_")
    echo "$(date "+%Y%m%d.%H%M%S"):[${_LogFlag}]:${UserName}@${HostName}:${2}";
}

###############################################################################

function f_checkusedtool
{
    f_PrintLog "Info" "Start to run f_checkusedtool."
    binary_list="$1"
    f_PrintLog "Info" "Start to check command: ${binary_list}"
    total_fail=0
    total_cmd=0
    for bin_cmd in $(echo ${binary_list})
    do 
        _rt=$(which ${bin_cmd} 2>/dev/null)
        cmd_ok=$?
        if [ ${cmd_ok} -eq 0 ]
        then
            f_PrintLog "Info" "command ${bin_cmd} was installed on ${_rt}."
        else
            f_PrintLog "Warn" "command ${bin_cmd} was not installed. ${_rt}"
            total_fail=$(($total_fail+1))
        fi
        total_cmd=$(($total_cmd+1))
    done
    [ ${total_fail} -gt 0 ] && _flag="Error" || _flag="Info"
    f_PrintLog "${_flag:-INFO}" "check command failed, fail/total num is ${total_fail}/${total_cmd}"
}

function f_backfile
{
    _filename=$1
    _filepath="${_filename%/*}/baktmp"
    [ ! -d ${_filepath} ] && mkdir -p "${_filepath}"
    if [ -f "${_filename}" ]
    then
        f_PrintLog "Warn" "file ${_filename} already exists, rename it now!!"
        ls -l ${_filename}
        sleep 1
        mv "${_filename}" "${_filepath}/${_filename##*/}.bak_$(date +%Y%m%d.%H%M%S)"
    fi
}

function f_generate_so_config
{
    f_PrintLog "Info" "Start to run Script f_generate_so_config"
    #init cluster parameter

    so_config="${TidbHome}/switchover/cluster_switchover_config_${HostRole:0:1}.cnf"
    if [ -f "${so_config}" ]
    then
        f_backfile "${so_config}" 
    fi

    #备集群drainer配置
    scaleDrYaml="${TidbHome}/switchover/${clsName}_scaleout_slave_drainer.yaml"
    if [ "${HostRole}" = "STANDBY" -a -n "${t2tDrId}" ]
    then
        tidbIp_s=${t2tDrId%:*}
        f_PrintLog "Info" "Standby to Primary remote ip and dr:${tidbIp_s} ${t2tDrId}"
    elif [ "${HostRole}" = "STANDBY" -a -f "${scaleDrYaml}" ]
    then
        tidbIp_s=$(awk -F: '{if($1~" host"){gsub(" ","",$2);print $2;exit}}' ${scaleDrYaml} 2>/dev/null)
        f_PrintLog "Info" "Standby to Primary remote ip and yaml:${tidbIp_s} ${scaleDrYaml}"
    fi


    if [ "${HostRole}" = "PRIMARY" ]
    then
        echo "PRIMARYRUNTIME=$(date +%Y%m%d.%H%M%S)"          >> "${so_config}"
        echo "PRIMARYTIDBHOME=${TidbHome}"          >> "${so_config}"
        echo "PRIMARYHOSTNAME=${HostName}"          >> "${so_config}"
        echo "PRIMARYCLUSTERNAME=${clsName}"        >> "${so_config}"
        echo "PRIMARYIP=${tidbIp}"                  >> "${so_config}"
        echo "PRIMARYPORT=${tidbPort:-4000}"        >> "${so_config}"
        echo "STANDBYIP=${tidbIp_s}"                >> "${so_config}"
        echo "PRIMARYAPPUSERS=${appUsers}"          >> "${so_config}"
        echo "PRIMARYT2TDRAINER=${t2tDrId}"         >> "${so_config}"
        echo "PRIMARYT2FDRAINER=${t2fDrId}"         >> "${so_config}"
    elif [ "${HostRole}" = "STANDBY" ]
    then
        echo "STANDBYRUNTIME=$(date +%Y%m%d.%H%M%S)"          >> "${so_config}"
        echo "STANDBYTIDBHOME=${TidbHome}"          >> "${so_config}"
        echo "STANDBYHOSTNAME=${HostName}"          >> "${so_config}"
        echo "STANDBYCLUSTERNAME=${clsName}"        >> "${so_config}"
        echo "STANDBYIP=${tidbIp}"                  >> "${so_config}"
        echo "STANDBYPORT=${tidbPort:-4000}"        >> "${so_config}"
        echo "STANDBYAPPUSERS=${appUsers}"          >> "${so_config}"
        echo "STANDBYT2TDRAINER=${t2tDrId}"         >> "${so_config}"
        echo "STANDBYT2FDRAINER=${t2fDrId}"         >> "${so_config}"
        echo "PRIMARYIP=${tidbIp_s}"                >> "${so_config}"
    fi

    #default var
    echo "PASSWD="             >> "${so_config}"
    echo "BACKUPDIR=${backupdir}"             >> "${so_config}"
    echo "SYNCDIFFTABLES=${syncdifftables}"  >> "${so_config}"

    echo "************************"
    cat "${so_config}" | grep -v "PASSWD"
    echo "************************"
    f_PrintLog "Info" "Config file generate on ${so_config}, pls check the context"
    sleep 10

}

function f_runscp
{
    _file_source=$1
    _file_tartget=$2
    _nodid=$3
    _action=$4
    f_PrintLog "Info" "Start to ${_action} file:${_file_source} ${_file_tartget}, remote:${_nodid}"
    echo "tiup cluster ${_action} ${clsName} ${_file_source} ${_file_tartget} -N${_nodid}"
    tiup cluster ${_action} ${clsName} ${_file_source} ${_file_tartget} -N${_nodid}
    if [ $? -ne 0 ]
    then
        f_PrintLog "Error" "tiup scp file failed, remote host:${_nodid}, file:${_file_source}"
        exit 1
    else
        f_PrintLog "Info" "tiup scp file finish, remote host:${_nodid}, file:${_file_source}"
    fi
}

function f_checkconfig
{
    _pk=$1
    _sk=$2

    _pv=$(awk -F= -v ck="${_pk}" '{if($1==ck){print $2;exit}}' ${primaryconfig}  2>/dev/null)
    _sv=$(awk -F= -v ck="${_sk}" '{if($1==ck){print $2;exit}}' ${standbyconfig}  2>/dev/null)

    if [ "${_pv}" = "${_sv}" ]
    then
        f_PrintLog "Info" "Primary and Standby config ${_pk} matched, ${_pv} = ${_sv}, check pass!"
    else
        f_PrintLog "Error" "Primary and Standby config ${_pk} not match, ${_pv} != ${_sv}, exit!!!"
        exit 1
    fi

}

function f_check_runtime
{
    _so_config=$1
    f_PrintLog "Info" "Start to run Script f_check_runtime"
    _ts1=$(awk -F= '{if($1=="PRIMARYRUNTIME"){gsub("\\.","",$2);printf "%d",$2;exit}}' ${_so_config} 2>/dev/null)
    _ts2=$(awk -F= '{if($1~"STANDBYRUNTIME"){gsub("\\.","",$2);printf "%d",$2;exit}}' ${_so_config} 2>/dev/null)

    f_PrintLog "Info" "Get runtime from config PRIMARYRUNTIME:${_ts1}, STANDBYRUNTIME:${_ts2}."
    
    curdt=$(date +%Y%m%d)
    if [ "${curdt}" != "${_ts1:0:8}" -o "${curdt}" != "${_ts2:0:8}" ]
    then
        f_PrintLog "Info" "The runtime ${_ts1:0:8},${_ts2:0:8} is not today ${curdt}, check failed!!!"
        exit 1
    fi

    # _tsdiff=$(expr ${_ts1} - ${_ts2})
    # if [ ${_tsdiff} -le 100 -a ${_tsdiff} -ge -100 ]
    # then
    #     f_PrintLog "Info" "The runtime diff is ${_tsdiff}, check pass!"
    # else
    #     f_PrintLog "Info" "The runtime diff is ${_tsdiff}, config file may wrong, check failed!!!"
    #     exit 1
    # fi
}

function f_merge_so_config
{
    f_PrintLog "Info" "Start to run Script f_generate_so_config"
    #get standby config
    soconfig="${TidbHome}/switchover/cluster_switchover.config"
    primaryconfig="${TidbHome}/switchover/cluster_switchover_config_P.cnf"
    standbyconfig="${TidbHome}/switchover/cluster_switchover_config_S.cnf"
    remotefile="./switchover/cluster_switchover_config_S.cnf"
    f_backfile "${soconfig}" 
    f_backfile "${localfile}" 
    f_runscp "${remotefile}" "${standbyconfig}" "${tidbIp_s}" "pull"
    
    #two PRIMARY
    _pv=$(awk -F= -v ck="PRIMARYHOSTNAME" '{if($1==ck){print $2;exit}}' ${primaryconfig}  2>/dev/null)
    _sv=$(awk -F= -v ck="PRIMARYHOSTNAME" '{if($1==ck){print $2;exit}}' ${standbyconfig}  2>/dev/null)
    if [ -n "${_pv}" -a -n "${_sv}" -a "${_pv}" != "${_sv}" ]
    then
        f_PrintLog "Error" "Get two primary node ${_pv} and ${_sv}, pls check the input hostname, exit!!!"
        exit 1        
    fi

    #check config 
    f_checkconfig "STANDBYIP" "STANDBYIP"
    f_checkconfig "PRIMARYIP" "PRIMARYIP"
    f_checkconfig "PRIMARYAPPUSERS" "STANDBYAPPUSERS"

    curdt=$(date +%Y%m%d)
    _sc_ok=$(awk -F= -v dt="${curdt}" '{if($1="STANDBYRUNTIME" && $2~dt){print $2;exit}}' ${standbyconfig})
    
    if [ -z "${_sc_ok}" ]
    then
        _sc_ok=$(awk -F= '{if($1="STANDBYRUNTIME"){print $2;exit}}' ${standbyconfig})
        f_PrintLog "Error" "Invalid config file, RUNTIME:${_sc_ok}, ${standbyconfig}."
        exit 1
    fi

    f_PrintLog "Info" "Start to merge two config file, ${soconfig}"

    cat ${primaryconfig} ${standbyconfig} |sort -u|grep -v "APPUSERS|" > ${soconfig}
    echo "************************"
    cat ${soconfig} | grep -v "PASSWD"
    echo "************************"
    f_PrintLog "Info" "cluster ${clsName} switchover config is ready, pls check the file context, ${soconfig}"
    sleep 10
    f_runscp "${soconfig}" "${soconfig}" "${tidbIp_s}" "push"
    f_check_runtime "${soconfig}" 
}



function f_committs_diff
{
    _ip_s=$1

    f_PrintLog "Info" "Start to run f_committs_diff."

    #主备区分执行
    if [ "${_ip_s}" = "${tidbIpLocal}" ]
    then 
        connstr="--login-path=${locallogin:-tidblogin}"
    else
        connstr="-h${_ip_s} -P${tidbPort} -u${user} -p${tidbPasswd:-123}"
    fi

    #最多检查3次,每次间隔10s
    for i in 1 2 3 
    do
        #commit tso
        ck_sql="select checkPoint from ${checkpointschema}.checkpoint order by clusterID desc limit 1"
        f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${_ip_s}"
        exec_result=$(mysql ${connstr} -NBe "${ck_sql}")
        cmt_tso=$(echo $exec_result  | python -m json.tool | awk '{
        if($1~"commitTS"){gsub(",","",$2);printf "%s\n",$2;exit}
        }')
        echo $exec_result  | python -m json.tool

        ck_sql="select from_unixtime(conv(left(bin('${cmt_tso}'),41),2,10)/1000) "
        f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${_ip_s}"
        exec_result=$(mysql ${connstr} -NBe "${ck_sql}")
        cmt_ts=$(mysql ${connstr} -NBe "${ck_sql}")
        
        #time-tso diff
        ck_sql="select timestampdiff(SECOND,TIDB_PARSE_TSO(${cmt_tso}),NOW()) "
        f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${_ip_s}"
        exec_result=$(mysql ${connstr} -NBe "${ck_sql}")
        f_PrintLog "Info" "Binlog commitTS is ${cmt_tso}, ${cmt_ts}, is ${exec_result} seconds (should<30) away from now!"
        
        [ ${exec_result} -lt 30 ] && return 0
        sleep 10
    done 
    return 1
}

function f_runsqlstmt2
{
    _execsql=$1
    f_PrintLog "Info" "START TO RUN SQL STMT:${_execsql}, DBinfo:${connOk}"
    exec_result=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${_execsql}")
    _rt_code=$?
    if [ $_rt_code -ne 0 ]
    then
        f_PrintLog "Error" "Run stmt failed, exit"
        exit 1
    fi
}

function f_runsqlstmt
{
    _ip=$1
    _port=$2
    _user=$3
    _passwd=$4
    _execsql=$5

    f_PrintLog "Info" "START TO RUN SQL STMT:${_execsql}, DBinfo ${_ip}:${_port}"
    mysql -h${_ip} -P${_port} -u${_user} -p${_passwd:-123} -vvv -e "${_execsql}"
    return $?
}

function f_checkpointflag
{
    f_PrintLog "Info" "Start to run Script f_checkpointflag"
    #检查是否存在checkpoint表
    ck_sql="select count(1) from information_schema.tables where table_name='checkpoint' and table_schema='${checkpointschema}'"
    f_runsqlstmt2 "${ck_sql}"
    if [ $exec_result -eq 0 ]
    then 
        CkpointRole="PRIMARY"
        f_PrintLog "Info" "Current cluster ${clsName} checkpoint table not exists, the cluster role should be ${CkpointRole}"  
        return 0
    else
        f_PrintLog "Info" "Current cluster ${clsName} checkpoint exists, continue check"  
    fi

    #checkpoint表只能有1条记录
    ck_sql="select count(1) from ${checkpointschema}.checkpoint"
    f_runsqlstmt2 "${ck_sql}"
    if [ $exec_result -gt 1 ]
    then 
        f_PrintLog "Error" "Current cluster ${clsName} checkpoint contain more then 1 rows, exit"  
        exit 1
    fi

    #只有备集群的checkpoint表变化
    f_committs_diff "${tidbIp}"
    _rt_code=$?
    if [ $_rt_code -eq 0 ]
    then
        CkpointRole="STANDBY"
        f_PrintLog "Info" "Current cluster ${clsName} checkpoint tso ${exec_result} seconds away from now, the cluster role should be ${CkpointRole}"  
    else
        CkpointRole="PRIMARY"
        f_PrintLog "Info" "Current cluster ${clsName} checkpoint tso ${exec_result} seconds close to now, the cluster role should be ${CkpointRole}"  
    fi
}

function f_backupsizecheck
{
    _clsname=$1

    f_PrintLog "Info" "Start to run f_backupsizecheck."
    
    pdNode=$(tiup cluster display ${_clsname}  2>/dev/null |awk  '{
        if($2=="pd" && $6~"Up"){printf "%s\n",$1;exit}
        }')
    f_PrintLog "Info" "Get cluster size pd-ctl ${pdNode}"
    pdRepls=$(pd-ctl --pd="http://${pdNode}" config show replication | awk -F: '{if($1~"max-replicas"){gsub(",","",$2);printf "%d",$2;exit}}')
    storeSize=$(pd-ctl --pd="http://${pdNode}" store | awk '{if($1~"used_size"){gsub(",","",$2);gsub("\"","",$2);printf "%s\t",$2}}')
    sizeMB=0
    for _size in ${storeSize}
    do
        _sizemb=$(echo ${_size}|awk '
            /.*KiB/{gsub("KiB","",$1);sz=$1/1000}
            /.*MiB/{gsub("MiB","",$1);sz=$1}
            /.*GiB/{gsub("GiB","",$1);sz=$1*1000}
            /.*TiB/{gsub("TiB","",$1);sz=$1*1000000}
            END{printf "%d\n",sz}
            ')
        sizeMB=$((sizeMB+_sizemb))
    done
    f_PrintLog "Info" "Cluster ${clsName} size is ${sizeMB}MiB, max-replicas:${pdRepls}"
    sizeMB=$((sizeMB/pdRepls*3/2))
    
    df -h
    diskFree=$(df -P -m ${backupdir}|awk '!/Filesystem/{printf "%d",$4;exit}')
    if [ ${diskFree:-1} -gt ${sizeMB:-1} ]
    then
        f_PrintLog "Info" "backup dir ${backupdir} free space is ${diskFree}MB, greater then dbsize ${sizeMB}MB"
    else
        f_PrintLog "Error" "backup dir ${backupdir} free space is ${diskFree}MB, less then dbsize ${sizeMB}MB, quit!!!"
        exit 1
    fi
}

function f_checktidb
{

    f_PrintLog "Info" "Start to run f_checktidb."

    #tidb status
    f_PrintLog "Info" "the Up node list:" 
    echo "${tidbclsinfo}"|awk '{
        if(NF>=8 && $2~"[pd|ti|pr|pu|dr|pr]" && $6~"Up"){printf "%20s %15s %10s\n",$1,$2,$6}
        }'
    
    f_PrintLog "Warn" "the Down node list:" 
    echo "${tidbclsinfo}"|awk '{
        if(NF>=8 && $2~"[pd|ti|pr|pu|dr|pr]" && $6!~"Up"){printf "%20s %15s %10s\n",$1,$2,$6}
        }'

    # drainer_down=$(echo "${tidbclsinfo}" | awk -F: '{
    #     if($1~"binlog_status" && $2!~"On"){gsub("[, ]","",$2);gsub("\"","",$2);printf "%s",$2;exit}
    # }')
    drainer_status=$(tiup cluster display ${clsName}  2>/dev/null |awk -v dip="${tidbDrainerId}" '{
        if($1==dip && $2=="drainer"){printf "%s",$6;exit}
        }')
    
    if [ -z "$(echo "${drainer_status:-Up}" | grep -E "Up|Down")" ]
    then
        f_PrintLog "Error" "drainer status check failed. drainer status is ${tidbDrainerId}:${drainer_status}"
        [ "${HostRole}" = "PRIMARY" ] && exit 1
    else
        f_PrintLog "Info" "drainer status is ok."
    fi
}

function f_checktidbbinlog
{
    binlog_url=$1

    f_PrintLog "Info" "Start to run f_checktidbbinlog"
    # binlogstatus=$(curl "http://${binlog_url}/info/all")
    # f_formatjson ${binlogstatus}
    binlog_down=$(curl -s "http://${binlog_url}/info/all" | awk -F: '{
        if($1~"binlog_status" && $2!~"On"){gsub("[, ]","",$2);gsub("\"","",$2);printf "%s",$2;exit}
    }')

    binlog_up=$(curl -s "http://${binlog_url}/info/all" | awk -F: '{
        if($1~"binlog_status" && $2~"On"){gsub("[, ]","",$2);gsub("\"","",$2);printf "%s",$2;exit}
    }')
    
    curl -s "http://${binlog_url}/info/all" | awk -F: '
    /^[ "]*ip.*/{gsub("[, ]","",$2);gsub("\"","",$2);ip=$2}
    /^[ "]*listening_port.*/{gsub("[, ]","",$2);gsub("\"","",$2);port=$2}
    /^[ "]*binlog_status.*/{gsub("[, ]","",$2);gsub("\"","",$2);binlog=$2}
    /^[ "]*server_id.*/{TiDB[$2]=tidb;IP[$2]=ip;Port[$2]=port;Binlog[$2]=binlog;}
    END{for(a in TiDB){printf "binlog_status: %s:%s %s\n",IP[a],Port[a],Binlog[a]}}
    '

    if [ "${binlog_down:-On}" = "On" -a "${binlog_up:-Off}" = "On" ]
    then
        f_PrintLog "Info" "binlog_status is ok."
    else
        f_PrintLog "Error" "binlog_status check failed. binlog_status is ${binlog_up}:${binlog_down}"
        exit 1
    fi
}

function f_checkconnection
{
    _ip=$1

    f_PrintLog "Debug" "Start to run f_checkconnection."
    # f_PrintLog "Info" "Check process privileges, current user:${tidbuser}!"
    # mysql -u${user} -p${passwd} -h${ip} -P${port} -vvv -e "show grants for ${tidbuser}"
    ignoreusers=${adminusers}
    f_PrintLog "Info" "Start to check applications, ignoreusers:${ignoreusers}!!"
    mysql --login-path=${locallogin:-tidblogin}  -vvv -e "select user,count(1) from information_schema.cluster_processlist group by user"
    if [ $? -ne 0 ]
    then
        f_PrintLog "Error" "failed to run processlist query, pls check!!!"
        exit 1
    fi
    mysql --login-path=${locallogin:-tidblogin} -NBe "select user,count(1) from information_schema.cluster_processlist group by user" | while read username appcount
    do
        if [ -z "$(echo ${ignoreusers} | grep -w ${username})" ]
        then
            f_PrintLog "Error" "find connections in database, user:${username} appcount:${appcount}, pls stop or kill these connections!!!"
            echo "${username} ${appcount}" >> ${tmp_file}
        else
            f_PrintLog "Info" "find connections in database, user:${username} appcount:${appcount}, ignore these connections!"
        fi
    done

    app_counts=$(wc ${tmp_file}|awk '{printf "%d",$1+$2}')
    if [ ${app_counts} -gt 1 ]
    then
        f_PrintLog "Error" "some applications still use database, check failed, pls stop applications and kill all connections!!!"
        exit 1
    else
        f_PrintLog "Info" "all connections are closed, check pass!"
    fi
}

function f_runsqlstmt1
{
    _execsql=$1
    f_PrintLog "Info" "START TO RUN SQL STMT:${_execsql}, DBinfo:${connOk}"
    mysql --login-path=${locallogin:-tidblogin} -vvv -e "${_execsql}"
    _rt_code=$?
    if [ $_rt_code -ne 0 ]
    then
        f_PrintLog "Error" "Run stmt failed, exit"
        # exit 1
    fi
}



function f_check_insert
{
    _ip=$1
    _ip_s=$2

    #insert into primary, check standby replicate
    f_PrintLog "Info" "Start to run f_check_insert."
    f_PrintLog "Info" "Start to insert ${_ip} -> ${_ip_s}."

    #sql
    tmp_table="test.drainer_delay"
    create_tab="create table If Not Exists ${tmp_table}(ts datetime)"
    delete_tab="delete from ${tmp_table}"
    insert_tab="insert into ${tmp_table}(ts) values(now())"
    select_tab="select max(ts) from ${tmp_table}"
    #
    
    #Primary
    f_runsqlstmt1 "${create_tab}"
    f_runsqlstmt1 "${delete_tab}"
    f_runsqlstmt1 "${insert_tab}"
    f_runsqlstmt1 "${select_tab}"

    
    p_val=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${select_tab}")
    if [ $? -ne 0 ]
    then
        f_PrintLog "Error" "exec sql failed, stmt: ${select_tab}"
    fi
    
    sleep 1
    #Standby
    # f_PrintLog "Info" "START TO RUN SQL STMT:${select_tab}, DBinfo ${s_ip}:${s_port} "
    f_runsqlstmt "${_ip_s}" "${tidbPort}" "${user}" "${tidbPasswd:-123}"  "${select_tab}"
    for i in 1 2 3
    do
        f_runsqlstmt "${_ip_s}" "${tidbPort}" "${user}" "${tidbPasswd:-123}"  "${select_tab}"
        s_val=$(mysql -h${_ip_s} -P${tidbPort} -u${user} -p${tidbPasswd:-123} -NBe "${select_tab}")
        if [ "${s_val:-0}" = "${p_val:-1}" ]
        then
            # break
            f_PrintLog "Info" "Real time Data replicate successful: ${p_val}=${s_val}, check pass! "
            f_PrintLog "Succ" "Tmp table insert and replicate successful, drainer working good!"
            return 0
        fi
        f_PrintLog "Warn" "Real time Data replicate failed: ${p_val}!=${s_val}, continue ${i} !!! "
        sleep 3
    done

    f_PrintLog "Error" "Real time data replicate:${p_val}!=${s_val}, check failed!!!"
    f_PrintLog "Error" "Tmp table insert and replicate failed, pls check data in ${tmp_table} !!!"
    exit 1
}

function f_tsmap_stable
{
    _ip_s=$1

    #获取checkpoint表中的tsmap信息
    f_PrintLog "Info" "Start to run f_tsmap_stable."
    #tsmap
    ck_sql="select checkPoint from ${checkpointschema}.checkpoint order by clusterID desc limit 1"
    f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${_ip_s}"
    exec_result=$(mysql -h${_ip_s} -P${tidbPort} -u${user} -p${tidbPasswd:-123} -NBe "${ck_sql}")
    tsmap_tso=$(echo $exec_result  | python -m json.tool | awk '{if($0~"ry-ts"){printf "%s",$2}}')
    echo $exec_result  | python -m json.tool

    if [ -z "${tsmap_tso}" ]
    then
        f_PrintLog "Warn" "Binlog tsmap get failed!!!"
        exit 1
    else
        f_PrintLog "Info" "Binlog tsmap is ${tsmap_tso}!"
    fi
}

# function f_committs_diff2
# {
#     # _ip_s=$1

#     f_PrintLog "Info" "Start to run f_committs_diff2."
#     #最多检查3次,每次间隔10s
#     for i in 1 2 3 
#     do
#         #commit tso
#         ck_sql="select checkPoint from ${checkpointschema}.checkpoint order by clusterID desc limit 1"
#         f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${connOk}"
#         exec_result=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${ck_sql}")
#         cmt_tso=$(echo $exec_result  | python -m json.tool | awk '{
#         if($1~"commitTS"){gsub(",","",$2);printf "%s\n",$2;exit}
#         }')
#         echo $exec_result  | python -m json.tool

#         ck_sql="select from_unixtime(conv(left(bin('${cmt_tso}'),41),2,10)/1000) "
#         f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${connOk}"
#         exec_result=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${ck_sql}")
#         cmt_ts=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${ck_sql}")
        
#         #time-tso diff
#         ck_sql="select timestampdiff(SECOND,TIDB_PARSE_TSO(${cmt_tso}),NOW()) "
#         f_PrintLog "Info" "START TO RUN SQL:${ck_sql}, DBinfo ${connOk}"
#         exec_result=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${ck_sql}")
#         f_PrintLog "Info" "Binlog commitTS is ${cmt_tso}, ${cmt_ts}, is ${exec_result} seconds (should<30) away from now!"
        
#         [ ${exec_result} -lt 30 ] && return 0
#         sleep 10
#     done 
#     return 1
# }


function f_usergrantsbak
{
    f_PrintLog "Info" "Start to run f_usergrantsbak."
    #提供用户名清单\备份文件名,默认备份全部用户权限
    _filename=$1
    _userlist=$(echo "$2"|tr "," " ")
    _ip=$3
    _port=$4
    f_PrintLog "Info" "start to backup user grants, userlist:${_userlist}, bakfile:${_filename}"
    
    #backup file
    if [ ! -f ${_filename} ]
    then 
        echo "--  start backup user grants. $(date +%Y%m%d.%H%M%S)">${_filename}
    elif [ -w ${_filename} ]
    then
        f_PrintLog "Warn" "backup file ${_filename} exist, clean content and overwrite it now."
        ls -l ${_filename}
        sleep 1
        echo "--  start backup user grants. $(date +%Y%m%d.%H%M%S)">${_filename}
    else
        ls -l ${_filename}
        f_PrintLog "Error" "file ${_filename} can not write, quit!!!"
        exit 1
    fi
    
    #backup grants info
    for _user in ${_userlist}
    do
        if [ -z "$(echo ${_user}|grep "@")" ] 
        then 
            _user="${_user}@'%'"
        else
            _user="${_user%%@*}@'${_user##*@}'"
        fi

        echo "--  ${_user}" | tee -a "${_filename}"
        _execsql="SHOW GRANTS FOR ${_user}"
        f_PrintLog "Info" "START TO RUN SQL:${_execsql}, DBinfo ${_ip}:${_port}"
        # echo "mysql -h${tidbip} -P${tidbport} -u${tidbuser} -p123 -NBe ${_execsql} "
        mysql -h${_ip} -P${_port} -u${user} -p${tidbPasswd:-123}  -NBe "${_execsql}" |tee -a "${_filename}"
    done

    #add ;
    sed -i 's/^GRANT.*/&;/g' ${_filename}
    f_PrintLog "Info" "backup user grants finish, backup file is ${_filename}"
    ls -l ${_filename}
}

function f_generatesqlfile
{
f_PrintLog "Info" "Start to run f_generatesqlfile."
f_PrintLog "Info" "parameters: $1 $2 $3 $4"

python -c "
import re,sys

args = sys.argv
infile = args[1]
outfile = args[2]
userlist = args[3]
rvktype = args[4]

userlist_lst = userlist.split(',')
revoke_lst = []

for username in userlist_lst:
    if username == '':
        continue
    with open(infile, mode='r') as f:
        for line in f:
            line_trim = line.replace('\'','')
            if not re.search(username, line) and not re.search(username, line_trim):
                continue
            elif line.startswith('--'):
                revoke_lst.append(line)
                continue
            elif line.startswith('GRANT USAGE ON'):
                continue
            elif line.startswith('GRANT SELECT ON'):
                continue
            else:
                line_user = re.findall(r'[\']*\w+[\']*@[\'\w\%]*', line)
                if not re.search(username, line_user[0].replace('\'','')):
                    continue

                revoke_all = re.sub(r'(GRANT )([\w, .*]+)( TO )([ \']*\w+[\']*@.*)', r'REVOKE \2 FROM \4', line)
                revoke_read = re.sub(r'(GRANT [\w, .*]+ ON )(.* TO [ \']*\w+[\']*@.*)', r'REVOKE  SELECT  FROM \2', line)
                grant_read = re.sub(r'(GRANT [\w, ]+)( ON .* TO .*)', r'GRANT  SELECT  \2', line, re.IGNORECASE)
            
            if rvktype == 'all':
                revoke_lst.append(revoke_all.replace('WITH GRANT OPTION', ''))
            elif rvktype == 'write':
                revoke_lst.append(revoke_all.replace('WITH GRANT OPTION', ''))
                revoke_lst.append(grant_read)
            elif rvktype == 'read':
                revoke_lst.append(revoke_read.replace('WITH GRANT OPTION', ''))

with open(outfile, mode='w') as f:
     f.write(''.join(revoke_lst))
" "${1}" "${2}" "${3}" "${4}"
f_PrintLog "Info" "Start generate revoke sqlfile finish, sqlfile: ${2}"
ls -l ${2}
#cat ${2}
}

function f_scpgrantsql
{
    f_PrintLog "Info" "Start to run f_scpgrantsql."
    tiup cluster exec ${clsName} -N${tidbIp_s} --command "mkdir -p ./switchover/grantsql" 
    # tiup cluster push ${clsName} ${app_bakfile} "./grantsql/usergrant_app_${tidbIp}_$(date +%Y%m%d).sql" -N${tidbIp_s}
    f_runscp ${app_bakfile} "${TidbHome}/switchover/grantsql/usergrant_app_${tidbIp}_$(date +%Y%m%d).sql" "${tidbIp_s}" "push"
    f_runscp ${app_rvkfile} "${TidbHome}/switchover/grantsql/userrevoke_app_${tidbIp}_$(date +%Y%m%d).sql" "${tidbIp_s}" "push"
    f_runscp ${repl_bakfile} "${TidbHome}/switchover/grantsql/usergrant_repl_${tidbIp_s}_$(date +%Y%m%d).sql" "${tidbIp_s}" "push"
    f_runscp ${repl_rvkfile} "${TidbHome}/switchover/grantsql/userrevoke_repl_${tidbIp_s}_$(date +%Y%m%d).sql" "${tidbIp_s}" "push"

}

###############################################################################
##Init##
export LANG=en_US
TidbHome=$(awk -F: -v un="tidb" '{if($1==un){print $6;exit}}' /etc/passwd 2>/dev/null)
NumProc=$(awk '/^processor[ |\t]*:/{c++}END{print c}' /proc/cpuinfo 2>/dev/null)
ShellName="$(echo $0|awk -F / '{print $NF}')";ShellOption="$@";
WorkDir="$(echo $0|sed s/${ShellName}//g)";[ -z "${WorkDir}" ] && WorkDir=${PWD};cd ${WorkDir};WorkDir=${PWD}
LogDir="${TidbHome}/switchover/logs";mkdir -p ${LogDir};
RunTs=$(date "+%Y%m%d.%H%M%S")
LogFile="${LogDir}/${script_base_name}_${ShellName}.${RunTs}.log";
Shellcksum=$(cksum ${WorkDir%/}/${ShellName} 2>/dev/null|awk '{printf "%d",$1}')
declare -i UserID=$(id -u);declare UserName=$(whoami);declare HostName=$(hostname);
###############################################################################
##TiDB Var##
locallogin="tidblogin"
adminusers="root,tidb,timon,repl"
checkpointschema="tidb_binlog"
backupdir="/data2/tidbbackup"
soconfig="${TidbHome}/switchover/cluster_switchover.config"
user="timon";pAsswd=""
###############################################################################
###############################################################################
##Get inopt
[ -z "${ShellOption}" -a -z "${primaryhostname}" -a -z "${standbyhostname}" ] && f_syntax;
for inopt in ${ShellOption}
do
    case $(echo $inopt|tr a-z A-Z) in
    -PRIMARYHOSTNAME|-HOSTNAME) CurOpt="-HOSTNAME_P";continue;;
    -STANDBYHOSTNAME) CurOpt="-HOSTNAME_S";continue;;
    -HELP|--HELP|-H) f_syntax;;
    -*) CurOpt="";continue;;
    esac
    case "${CurOpt}" in
    -HOSTNAME_P) declare primaryhostname="${inopt}";continue;;
    -HOSTNAME_S) declare standbyhostname="${inopt}";continue;;
    esac
done

f_PrintLog "Info" "Start to run Script ${ShellName}, the Shellcksum is ${Shellcksum}"
f_PrintLog "Info" "Script Options:${ShellOption}"

function f_checkparamandcluster
{

    f_PrintLog "Info" "Start to run Script f_checkparamandcluster"
    f_PrintLog "Info" "Input Parameter: script_run_role:${script_run_role}, primaryhostname:${primaryhostname}, standbyhostname:${standbyhostname}"

    #没有tiup的机器非管理节点,不执行
    tiupOk=$(which tiup 2>/dev/null)
    if [ $? -ne 0 ]
    then
        f_PrintLog "Error" "Current host ${HostName} not contain tiup, exit!"
        # exit 1
    else
        f_PrintLog "Info" "Current host ${HostName} contain tiup, check pass!"
    fi

    #没有4000端口的机器,不符合规范,不执行
    tidb4kOk=$(ps -ef | grep "tidb-server -P 4000"| grep -v grep|wc -l)
    if [ ${tidb4kOk:-0} -lt 1 ]
    then
        f_PrintLog "Error" "Current host ${HostName} not contain valid tidb 4000, exit"
        exit 1
    else
        f_PrintLog "Info" "Current host ${HostName} contain valid tidb 4000, check pass!"
    fi

    #不能使用loginpath=tidblogin登录的机器,不符合部署规范,不执行
    connOk=$(mysql --login-path=${locallogin:-tidblogin} -NBe "select user()")
    if [ -z "${connOk}" ]
    then
        f_PrintLog "Error" "No passwd login failed, pls check mysql --login-path=${locallogin:-tidblogin} "
        exit 1
    else
        f_PrintLog "Info" "No passwd login successfully, connect user is ${connOk}, check pass!"
    fi

    #check binary command
    binary_list="tiup mysql pd-ctl dumpling sync_diff_inspector"
    f_checkusedtool "${binary_list}"
    if [ ${total_fail} -gt 0 ] 
    then
        f_PrintLog "Error" "check binary command in PATH failed, fail/total num is ${total_fail}/${total_cmd}"
        exit 1
    else
        f_PrintLog "Info" "check binary command in PATH finish, check pass!"
    fi

    #没有本地drianer进程的,为主集群的备用tiup,不执行
    drainerProc=$(ps -ef | grep "bin/drainer"| grep -v grep| wc -l)
    if [ ${drainerProc} -eq 0 ]
    then
        f_PrintLog "Error" "Current host ${HostName} not contain valid drainer, count ${drainerProc}, check pass!"
        # exit 1
    else
        f_PrintLog "Info" "Current host ${HostName} contain valid drainer, count ${drainerProc}, check pass!"
    fi

    if [ "${primaryhostname}" == "${HostName}" ] 
    then
        HostRole="PRIMARY"
        f_PrintLog "Info" "Current host ${HostName}=${primaryhostname}, the cluster role should be ${HostRole}"
    elif [ "${standbyhostname}" == "${HostName}" ]
    then
        HostRole="STANDBY"
        f_PrintLog "Info" "Current host ${HostName}=${standbyhostname}, the cluster role should be ${HostRole}"
    else
        HostRole="UNKNOWN"
        f_PrintLog "Error" "Current host ${HostName} not in input hosts:${primaryhostname} ${standbyhostname}, exit"
        exit 1
    fi

    #获取集群信息
    f_getclusterinfo

    #Checkpoint表判断主备
    f_checkpointflag

    #只有在切换前的初始状态可进行如下判断
    #有一个本地drainer进程,集群有一个远程drainer进程,即为主集群的主管理tiup节点
    #有零个本地drainer进程,集群有一个远程drainer进程,即为主集群的次管理tiup节点
    #有两个本地drainer进程,集群没有远程drainer进程,即为备集群的管理tiup节点
    #脚本应该在standby指定tiup运行
    # drainerLocal=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp%.*}" '{
    #     if($1~id && $2=="drainer" && $6=="Up"){printf "%s",$1;exit}
    #     }')
    # drainerRemote=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp%.*}" '{
    #     if($1!~id && $2=="drainer" && $6=="Up"){printf "%s",$1;exit}
    #     }')

    if [ -n "${drainerRemote}" -a -z "${drainerLocal}" -a ${drainerProc} -lt 1 ]
    then
        TiupRole="STANDBY"
        HostRoleDr="PRIMARY"
        f_PrintLog "Info" "Current host ${HostName}, local drainer:${drainerLocal}, ps:${drainerProc}, remote drainer:${drainerRemote}, maybe primary cluster ${TiupRole} tiup"
    elif [ -n "${drainerRemote}" -a -n "${drainerLocal}" -a ${drainerProc} -le 1 ]
    then
        TiupRole="PRIMARY"
        HostRoleDr="PRIMARY"
        f_PrintLog "Info" "Current host ${HostName}, local drainer:${drainerLocal}, ps:${drainerProc}, remote drainer:${drainerRemote}, maybe primary cluster ${TiupRole} tiup"
    elif [ -z "${drainerRemote}" -a -n "${drainerLocal}" -a ${drainerProc} -ge 1 ]
    then
        TiupRole="PRIMARY"
        HostRoleDr="STANDBY"
        f_PrintLog "Info" "Current host ${HostName}, local drainer:${drainerLocal}, ps:${drainerProc}, remote drainer:${drainerRemote}, maybe standby cluster ${TiupRole} tiup"
    else
        f_PrintLog "Warn" "Current host ${HostName}, local drainer:${drainerLocal}, ps:${drainerProc}, remote drainer:${drainerRemote}, can not get correct role"        
        exit 1
    fi

    if [ "${HostRole}" = "${HostRoleDr}" ]
    then
        f_PrintLog "Info" "Current cluster role was confirmed, ${HostRole}"        
    else
        f_PrintLog "Error" "Current cluster role was confused, Host:${HostRole} != Dr:${HostRoleDr}, pls check input host sequence" 
        exit 1       
    fi

    #备份空间充足
    f_backupsizecheck "${clsName}"

    #备集群检查ssh

}


function f_getclusterinfo
{
    f_PrintLog "Info" "Start to run f_getclusterinfo."
    # clsname,connip,connport,dbsize,dbs,userlist,drainernode,backupdir,repluser
    clsName=$(tiup cluster list 2>/dev/null|awk '{if($3~"v" && $4~"tiup"){printf "%s\n",$1;exit}}') 
    if [ -z "${clsName}" ]
    then
        f_PrintLog "Error" "Can not find valid cluster name using:tiup cluster list"
        exit 1
    fi
    f_PrintLog "Info" "find valid cluster name is ${clsName}"
    tiup cluster display ${clsName} 

    tidbclsinfo=$(tiup cluster display ${clsName} 2>/dev/null)
    IPList=$(ip a |awk '/^[1-9]/{gsub(":","",$2);en=$2}
     /^[ |\t]*inet /{gsub(".*:","",$2);gsub("/.*","",$2);if(en!~"^lo")N[$2]=en}
     END{for(ip in N){printf "%s\n",ip}}')
    tidbProc=$(ps -ef | grep "tidb-server -P 4000"| grep -v grep)
    tidbPort=$(echo ${tidbProc}|awk -F"-P" '{print $2}'|awk '{printf "%d",$1}')
    tidbIp=$(echo ${tidbProc}|awk -F"--advertise-address=" '{print $2}'|awk '{printf "%s",$1}')

    tidbNodeId=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp}:${tidbPort}" '{
     if($1==id && $2=="tidb" && $6=="Up" ){printf "%s",$1;exit}
     }')

    [ -z "${tidbNodeId}" ] && f_PrintLog "Warn" "Can not find valid tidb node ${tidbIp}:${tidbPort}, the cluster name is ${clsName}"

    #根据drainerid是否等于tidbid判断drainer归属
    tidb_urls=$(tiup cluster display ${clsName} 2>/dev/null|awk '{if($2=="tidb"){gsub(":.*","",$1);printf "%s ",$1}}')
    dr_urls=$(tiup cluster display ${clsName} 2>/dev/null|awk '{if($2=="drainer"){printf "%s,%s ",$1,$6}}')
    for drid in ${dr_urls}
    do
        _localflag=$(echo ${tidb_urls} |grep -w ${drid%:*})
        _Upflag=$(echo ${drid} |grep -w "Up")
        if [ -z "${_localflag}" ]
        then
            drainerRemote="${drainerRemote}${drid}"
            [ -n "${_Upflag}" ] && drainerRemoteUp="${drainerRemoteUp}${drid}"
            f_PrintLog "Info" "Find a remote drainer ${drid}, drainerRemote:${drainerRemote}"
        else
            drainerLocal="${drainerLocal}${drid}"
            [ -n "${_Upflag}" ] && drainerLocalUp="${drainerLocalUp}${drid}"
            f_PrintLog "Info" "Find a locale drainer ${drid}, drainerLocal:${drainerLocal}"
        fi
    done
    
    _drCt=$(echo ${drainerRemote}|awk -F: '{print NF}')
    if [ ${_drCt} -gt 2 ]
    then
        f_PrintLog "Error" "The remote drainer count is ${_drCt}, exit!!!"
        exit 1
    fi

    t2fDrId=${drainerLocal}
    t2tDrId=${drainerRemote}
    tidbDrainerId=${drainerRemote}
    drainerRemote=${drainerRemoteUp}

    # t2fDrId=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp%.*}" '{
    #    if($1~id && $2=="drainer"){printf "%s,%s",$1,$6;exit}
    #    }')
    # t2tDrId=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp%.*}" '{
    #    if($1!~id && $2=="drainer"){printf "%s,%s",$1,$6;exit}
    #    }')

    # tidbDrainerId=$(tiup cluster display ${clsName} 2>/dev/null|awk -v id="${tidbIp%.*}" '{
    #  if($1!~id && $2=="drainer"){printf "%s",$1;exit}
    #  }')

    if [ -z "${tidbDrainerId}" ] 
    then
        f_PrintLog "Warn" "Can not find valid drainer node, the cluster name is ${clsName}"
    else
        tidbIp_s=${tidbDrainerId%:*}
    fi

    adminusers_sql=$(echo "${adminusers}"|sed "s/,/','/g")
    _execsql="select group_concat(concat(user,'@',host) SEPARATOR ',') from  mysql.user where user not in ('${adminusers_sql}')"
    f_PrintLog "Info" "START TO RUN SQL:${_execsql}, DBinfo ${tidbIp}:${tidbPort}"
    appUsers=$(mysql --login-path=${locallogin:-tidblogin} -NBe "${_execsql}")

    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, Ip:${tidbIp}, Port:${tidbPort}, drainerId:${tidbDrainerId}, standbyIp:${tidbIp_s}, appUser:${appUsers}"
}



###################
####    Main   ####
###################

function greencheck_main
{
    #获取脚本执行需要的集群信息
    f_checkparamandcluster  

    #
    f_generate_so_config
    #获取脚本执行需要的数据库连接信息 
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"

    [ "${HostRole}" = "PRIMARY" ] && f_merge_so_config
}

function f_checkrepl_main
{
    #check tidb
    tidbclsinfo=$(tiup cluster display ${clsName}  2>/dev/null)
    f_checktidb ${clsName}

    
    #check binlog status
    tidburl=$(echo "${tidbclsinfo}"|awk '{
        if(NF>=8 && $2=="tidb" && $6=="Up" ){gsub(".*/","",$4);printf "%s:%s\n",$3,$4;exit}
        }')
    if [ -z "${tidburl}" ] 
    then
        f_PrintLog "Error" "Failed to check tidb binlog status. tidburl is null!!!"
        exit 1
    else
        f_PrintLog "Info" "Start to check tidb binlog status. tidburl: http://${tidburl}/info/all "
        f_checktidbbinlog ${tidburl}
    fi

    
    #check connection
    tmp_file="${LogDir}/tmp_apps.txt"
    echo "" > ${tmp_file}
    f_checkconnection "${tidbIp}"
    
    #check replicate 
    f_check_insert "${tidbIp}" "${tidbIp_s}"
    sleep 3

    #
    f_tsmap_stable "${tidbIp_s}"
    tsmap_a=${tsmap_tso}

    f_committs_diff "${tidbIp_s}"
    rt_code=$?

    #
    f_PrintLog "Info" "Start sleep 100, and confirm tsmap do not change !"
    sleep 100
    f_tsmap_stable "${tidbIp_s}"
    tsmap_b=${tsmap_tso}


    if [ ${rt_code} -eq 0 -a "${tsmap_a}" = "${tsmap_b}" ]
    then 
        f_PrintLog "Info" "Binlog checkpoint's commitTS and tsmap, ${tsmap_a}=${tsmap_b}, check pass!"
    elif [ "${tsmap_a}" != "${tsmap_b}" ]
    then
        f_PrintLog "Warn" "Binlog tsmap changed in 2 minutes, ${tsmap_a}!=${tsmap_b}, drainer still working, check failed!!!"
        exit 1
    elif [ ${rt_code} -ne 0 ]
    then
        f_PrintLog "Warn" "Binlog commitTS not close to now, drainer status may abnormal or stopped already, check failed!!!"
        exit 1
    else
        f_PrintLog "Warn" "Binlog checkpoint's commitTS and tsmap check failed!"
        exit 1
    fi
}


function f_bakuser_main
{
    f_PrintLog "Info" "Start to run f_bakusermain."
    #grant sql files
    grantsqldir="${TidbHome}/switchover/grantsql"
    mkdir -p ${grantsqldir}
    app_bakfile=${grantsqldir}"/usergrant_app_${tidbIp}_$(date +%Y%m%d).sql"
    app_rvkfile=${grantsqldir}"/userrevoke_app_${tidbIp}_$(date +%Y%m%d).sql"
    repl_bakfile=${grantsqldir}"/usergrant_repl_${tidbIp_s}_$(date +%Y%m%d).sql"
    repl_rvkfile=${grantsqldir}"/userrevoke_repl_${tidbIp_s}_$(date +%Y%m%d).sql"
    replUser="repl"
    rvkpriv="write"

    #backup primary app user privileges
    _appUsers=""
    for _user in $(echo ${appUsers}|tr "," " ")
    do
      # _appUsers="${_appUsers},${_user%%@*}"
      _appUsers="${_appUsers},${_user}"
    done

    f_backfile "${app_bakfile}" 
    f_usergrantsbak "${app_bakfile}" "${_appUsers}" "${tidbIp}" "${tidbPort}"
    bakok=$(grep "^GRANT" ${app_bakfile} | wc -l)
    if [ ${bakok:-0} -eq 0 ]
    then
        f_PrintLog "Error" "user:${_appUsers} backup failed, pls check ${app_bakfile} !!!"
        exit 1
    fi
    
    #generate revoke write sql
    f_backfile "${app_rvkfile}" 
    f_generatesqlfile "${app_bakfile}" "${app_rvkfile}" "${_appUsers}" "${rvkpriv}"


    #backup standby repl user privileges
    f_backfile "${repl_bakfile}"
    f_usergrantsbak "${repl_bakfile}" "${replUser}" "${tidbIp_s}" "${tidbPort}"
    bakok=$(grep "^GRANT" ${repl_bakfile} | wc -l)
    if [ ${bakok:-0} -eq 0 ]
    then
        f_PrintLog "Error" "user:${replUser} backup failed, pls check ${repl_bakfile} !!!"
        exit 1
    fi

    f_backfile "${repl_rvkfile}"
    f_generatesqlfile "${repl_bakfile}" "${repl_rvkfile}" "${replUser}" "${rvkpriv}"

    #scp app sql file to standby
    f_scpgrantsql
}

function precheck_main
{
    f_PrintLog "Info" "Start to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."
    #local var
    localProc=$(ps -ef | grep "tidb-server -P 4000"| grep -v grep)
    localPort=$(echo ${localProc}|awk -F"-P" '{print $2}'|awk '{printf "%d",$1}')
    localIp=$(echo ${localProc}|awk -F"--advertise-address=" '{print $2}'|awk '{printf "%s",$1}')
    tidbIpLocal="${localIp}"

    #获取脚本执行需要的集群信息
    greencheck_main  
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"
    
    [ "${HostRole}" = "STANDBY" ] && return 0
    tidbPasswd=$(echo "${pAsswd}="|base64 -d)
    #执行切换前检查
    f_checkrepl_main

    #备份用户权限
    f_bakuser_main

    f_PrintLog "Info" "Successful to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."
}
 
precheck_main | tee -a ${LogFile}
exit ${PIPESTATUS[0]} 


