#!/bin/env bash
##Description: stop primary replicate

script_run_role="PRIMARY,STANDBY"
script_base_name="tidb_so_primary_stoprepl"

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_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_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_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_runsqlfile
{
    _sqlfile=$1
    _ip=$2

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

    f_PrintLog "Info" "START TO RUN SQL:${_sqlfile}, DBinfo ${_ip}:${_port}"
    echo "*************************************************************"
    cat ${_sqlfile}
    echo "*************************************************************"
    f_PrintLog "Info" "PLS CHECK ALL COMMANDS IN FILE, SLEEP 3......"
    sleep 3
    echo "mysql ${connstr} -vvv < ${_sqlfile}"
    mysql ${connstr} -vvv < ${_sqlfile}
    return $?
}

function f_tiupcmd
{
    f_PrintLog "Info" "Start to run f_tiupcmd."
    cls_name="$1"
    component_name="$2"
    action="$3"
    
    f_PrintLog "Info" "Start to ${action} ${component_name} on cluster ${cls_name} ..."
    sleep 3
    #clsinfo 
    tiup cluster ${action} ${cls_name} -N${component_name} --yes --wait-timeout 60
    rt_code=$?
    if [ ${rt_code} -eq 0 ]
    then
        f_PrintLog "Info" "${action} ${component_name} on cluster ${cls_name} successfully!"
        return ${rt_code}
    else
        f_PrintLog "Error" "${action} ${component_name} on cluster ${cls_name} failed!!!"
        return ${rt_code}
    fi
}


function f_stopdrainer
{
    _clsname=$1
    _drainerid=$2
    f_PrintLog "Info" "Start to run f_stopdrainer."

    #check tidb
    tiup cluster display ${_clsname} 
    
    action="stop"
    f_tiupcmd "${_clsname}" "${_drainerid}" "${action}"
    rt_code=$?
    
    tiup cluster display ${_clsname} 
    drok=$(tiup cluster display ${_clsname}  2>/dev/null |awk -v dip="${_drainerid}" '{
        if($1==dip && $2=="drainer" && $6=="Down"){printf "%s\n",$1;exit}
        }')
    
    if [ ${rt_code} -eq 0 -a -n "${drok}" ]
    then
        f_PrintLog "Info" "cluster ${_clsname} node ${_drainerid}, role:${drok}, ${action} finish!"    
    else
        f_PrintLog "Error" "cluster ${_clsname} node ${_drainerid}, role:${drok}, ${action} failed !!!"
        exit 1
    fi
}

function f_checkdrinittso
{
    f_PrintLog "Info" "Start to run f_checkdrinittso."

    #cluster edit-config
    metaFile="${TidbHome}/.tiup/storage/cluster/clusters/${clsName}/meta.yaml"
    drainerDeployDir=$(tiup cluster display ${clsName}  2>/dev/null |awk -v dip="${tidbDrainerId}" '{
        if($1==dip && $2=="drainer"){printf "%s",$NF;exit}
        }')
    drainerDeployConfig="${drainerDeployDir}/conf/drainer.toml"
    
    if [ ! -f "${metaFile}" ]
    then
        f_PrintLog "Error" "tiup config meta yaml not exists,${metaFile}, exit!!!"
        exit 1
    fi

    drinittsOk0=$(cat ${metaFile} | awk -F: '{if($1~"initial-commit-ts" && $2!~"-1"){printf "%s",$2}}')
    # echo "tiup cluster exec ${clsName} -N${tidbIp_s} --command grep initial-commit-ts ${drainerDeployConfig}"
    # stdout=$(tiup cluster exec ${clsName} -N${tidbIp_s} --command "grep initial-commit-ts ${drainerDeployConfig}")
    # drinitts=$(echo ${stdout}| awk -F"stdout:" '{print $2}')
    # drinittsOk1=$(echo ${drinitts}| awk -F= '{if($1~"initial-commit-ts" && $2!~"-1"){printf "%s",$2}}')
    
    if [ -n "${drinittsOk0}" -o -n "${drinittsOk1}" ]
    then
        f_PrintLog "Error" "drainer config initial-commit-ts != -1, meta config:${drinittsOk0}, drainer config:${drinittsOk1}, exit!!!"
        exit 1
    else
        f_PrintLog "Info" "drainer config initial-commit-ts = -1, check pass!"
    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

}

###############################################################################
##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"
user="timon";pAsswd=""
tidbsoconfig="${TidbHome}/switchover/cluster_switchover.config"
[ -f ${tidbsoconfig} ] && source ${tidbsoconfig}
###############################################################################
###############################################################################
##Get inopt
[ -z "${ShellOption}" -a -z "${primaryhostname}" -a -z "${standbyhostname}" ] && f_syntax;
# [ -n "${ShellOption}" ] && f_syntax;
# [ -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_readandcheckconfig
{

    f_PrintLog "Info" "Start to run f_readandcheckconfig."
    #
    [ -f ${tidbsoconfig} ] && source ${tidbsoconfig} 
    appusers="${PRIMARYAPPUSERS}"
    tidbPasswd=$(echo "${PASSWD}="|base64 -d)
    tidbIp="${PRIMARYIP}"
    tidbIp_s="${STANDBYIP}"
    tidbPort="${PRIMARYPORT}"
    clsName="${PRIMARYCLUSTERNAME}"
    clsName_s="${STANDBYCLUSTERNAME}"
    tidbDrainerId="${PRIMARYT2TDRAINER%,*}"
    backupdir="${BACKUPDIR:-/tidbbackup}"
    
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"

    f_PrintLog "Info" "Check config hostname and cluster name."
    clsNamelocal=$(tiup cluster list 2>/dev/null|awk '{if($3~"v" && $4~"tiup"){printf "%s\n",$1;exit}}') 
    if [ -z "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Can not find valid cluster name using:tiup cluster list"
        exit 1
    else
        f_PrintLog "Info" "Find valid local cluster: ${clsNamelocal}"
        tiup cluster display ${clsNamelocal} 
    fi

    if [ "${HostRole}" = "PRIMARY" -a "${clsName}" != "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Check config clsname failed, PRIMARY CLUSTERNAME: ${clsName} != ${clsNamelocal}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "PRIMARY" -a "${PRIMARYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Error" "Check config hostname failed, PRIMARY HOSTNAME: ${PRIMARYHOSTNAME} != ${HostName}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "STANDBY" -a "${clsName_s}" != "${clsNamelocal}" ]
    then
        f_PrintLog "Error" "Check config clsname failed, STANDBY CLUSTERNAME: ${clsName_s} != ${clsNamelocal}, exit!!!"
        exit 1
    elif [ "${HostRole}" = "STANDBY" -a "${STANDBYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Error" "Check config hostname failed, STANDBY HOSTNAME: ${STANDBYHOSTNAME} != ${HostName}, exit!!!"
        exit 1
    fi

    f_check_runtime "${tidbsoconfig}" 
}


function f_stoprepl_main
{
    f_PrintLog "Info" "Start to run f_stoprepl_main."

    #user
    # p_passwd=$(echo "${passwd}="|base64 -d)
    # s_passwd=${p_passwd}


    #revoke app user,primary
    f_runsqlfile "${app_rvkfile}" "${tidbIp}" 
    _rt_code=$?
    if [ ${_rt_code} -eq 0 ]
    then
        f_PrintLog "Info" "revoke app user privileges finish!"
    else
        f_PrintLog "Error" "revoke app user privileges failed!!!"
        exit 1
    fi
    
    #check connection
    tmp_file="./logs/tmp_apps.txt"
    echo "" > ${tmp_file}
    f_checkconnection "${tidbIp}"
    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


    f_stopdrainer "${clsName}" "${tidbDrainerId}"

    # revoke repl user standby
    # f_runsqlfile "${repl_rvkfile}" "${tidbIp_s}" "${tidbPort}"
    # _rt_code1=$?

    # scp stopok
    stopdrok="${TidbHome}/switchover/tmp_stopdrok_primary"
    echo "${clsName} $(date "+%Y%m%d.%H%M%S")" > ${stopdrok} 
    tiup cluster push ${clsName} ${stopdrok} ${stopdrok} -N${tidbIp_s}
    f_PrintLog "Info" "send stopdrok file to ${tidbIp_s}!"
    echo "************************"
    cat ${stopdrok}
    echo "************************"

    # grant repl user primary
    f_runsqlfile "${repl_bakfile}" "${tidbIp}" 
    _rt_code=$?
    # _rt_code=$((_rt_code1+_rt_code2))
    if [ ${_rt_code} -eq 0 ]
    then
        f_PrintLog "Info" "grant repl user privileges finish!"
    else
        f_PrintLog "Error" "grant repl user privileges failed!!!"
        exit 1
    fi

    f_PrintLog "Info" "rm stopdrok file:${stopdrok} now!"
    echo "************************"
    cat ${stopdrok}
    echo "************************"
    rm -f ${stopdrok}
}


function f_standby_waitstop_main
{
    [ "${HostRole}" = "PRIMARY" ] && return 0
    f_PrintLog "Info" "Start to run f_standby_waitstop_main."
    stopdrok="${TidbHome}/switchover/tmp_stopdrok_primary"
    
    i=0
    while [ $i -le 30 ]
    do
        if [ -f "${stopdrok}" ]
        then
            stopdrok_ts=$(grep "${PRIMARYCLUSTERNAME} $(date +%Y%m%d)" ${stopdrok} | wc -l)
            if [ ${stopdrok_ts:-0} -ge 1 ]
            then
                f_PrintLog "Info" "get stopdrok file from primary host:${PRIMARYHOSTNAME}, ${tidbIp}!"
                echo "************************"
                cat "${stopdrok}"
                echo "************************"
                break
            else
                f_PrintLog "Info" "find incorrect stopdrok file, continue wait..."                
                cat "${stopdrok}"
            fi
        else
            f_PrintLog "Info" "wait stopdrok file from primary host:${PRIMARYHOSTNAME}, ${tidbIp}, sleep 5, i=${i}"            
        fi
        i=$((i+1))
        sleep 5
    done
    
    if [ ! -f "${stopdrok}" -o ${stopdrok_ts:-0} -eq 0 ]
    then
        f_PrintLog "Error" "Can not get stopdrok file from primary host:${PRIMARYHOSTNAME}, ${tidbIp}, not revoke repl user privileges, exit!!!"
        exit 1
    fi

    # revoke repl user standby
    f_runsqlfile "${repl_rvkfile}" "${tidbIp_s}"
    _rt_code=$?
    if [ ${_rt_code} -eq 0 ]
    then
        f_PrintLog "Info" "revoke repl user privileges finish!"
    else
        f_PrintLog "Error" "revoke repl user privileges failed!!!"
        exit 1
    fi

    f_PrintLog "Info" "rm stopdrok file:${stopdrok} now!"
    echo "************************"
    cat ${stopdrok}
    echo "************************"
    rm -f ${stopdrok}

}


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


function f_primary_stoprepl_main
{
    f_PrintLog "Info" "Start to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."

    if [ -f ${tidbsoconfig} ] 
    then
        f_PrintLog "Info" "Start to buildin config variables, ${tidbsoconfig}."
        source ${tidbsoconfig}
        curdt=$(date +%Y%m%d)
        if [ -z $(echo ${PRIMARYRUNTIME} | grep ${curdt}) ]
        then
            f_PrintLog "Error" "Invalid config file, RUNTIME:${PRIMARYRUNTIME}, ${tidbsoconfig}."
            exit 1
        fi
    else
        f_PrintLog "Error" "Can not find valid config, ${tidbsoconfig}, exit"
        exit 1
    fi 
    
    #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}"

    #check script var
    #check host role
    if [ "${primaryhostname}" != "${HostName}" -a "${standbyhostname}" != "${HostName}" ] 
    then
        f_PrintLog "Error" "InputHost are ${primaryhostname} and ${standbyhostname}, but now i am ${HostName}, exit"
        # exit 1
    fi
    
    if [ "${primaryhostname}" = "${HostName}" ] 
    then
        HostRole="PRIMARY"
    elif [ "${standbyhostname}" = "${HostName}" ]
    then
        HostRole="STANDBY"
    else
        HostRole="UNKNOWN"
    fi
    
    if [ "${PRIMARYHOSTNAME}" != "${HostName}" -a "${STANDBYHOSTNAME}" != "${HostName}" ]
    then
        f_PrintLog "Info" "Current hostname is ${HostName}, the script need to run on  ${PRIMARYHOSTNAME}, quit"
        exit 0
    fi


    #获取脚本执行需要的集群信息
    f_readandcheckconfig  
    f_PrintLog "Info" "Get ${HostRole} cluster info finished. clsname:${clsName}, clsname_s:${clsName_s}, Ip:${tidbIp}, standbyIp:${tidbIp_s}, drainerId:${tidbDrainerId}"
    
    #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"

    if [ "${HostRole}" = "STANDBY" ]
    then
        #备集群等待远程drainer进程停止后,执行repl权限回收,最多等待5分钟
        f_standby_waitstop_main
        rt_code=$?
        f_PrintLog "Info" "Script ${script_base_name} run on ${HostRole} Node finished, quit."
        exit $rt_code
    fi

    f_checkdrinittso

    #执行主集群的复制暂停
    f_stoprepl_main

    #执行dumpling
    f_PrintLog "Info" "Successful to run Script ${ShellName} on ${HostName}, script_base_name ${script_base_name}."

}
 
f_primary_stoprepl_main | tee -a ${LogFile}
exit ${PIPESTATUS[0]} 


