#!/bin/bash
NGINX_SERVICE_URL="https://127.0.0.1:8088"
DEVICE_MANAGER_DIR="/OSM/coffer_data/ISM/device-manager"
DEVICE_MANAGER_NGINX_DIR="${DEVICE_MANAGER_DIR}/nginx"
DEVICE_MANAGER_SCRIPT_DIR="${DEVICE_MANAGER_DIR}/script"
DEVICE_MANAGER_OWNER="OceanStorMgrUser"
DEVICE_MANAGER_OWNER_GROUP="mgrgroup"
NGINX_LOG_DIR="/OSM/coffer_log/log/ismlog/dmlogs/"
DEPLOY_LOG_PATH="${NGINX_LOG_DIR}/deploy.log"
NGINX_PID_FILE="$DEVICE_MANAGER_NGINX_DIR/conf/nginx.pid"
NGINX_REST_PID_FILE="$DEVICE_MANAGER_NGINX_DIR/conf/nginx_rest.pid"
NGINX_INNER_PID_FILE="$DEVICE_MANAGER_NGINX_DIR/conf/nginx_inner.pid"
source ${DEVICE_MANAGER_SCRIPT_DIR}/log4sh.sh

function check_url()
{
    status=$(curl -m 20 -ksi ${NGINX_SERVICE_URL} | grep 'HTTP/1.1 200 OK')
    if [ ! -n "${status}" ]; then
        logAndEchoError "Nginx service is abnormal <out -- vrf>."
        return 1
    fi
    ###检查内部vrf###
    status=$(curl -m 20 -si --unix-socket /tmp/inner.socket http://127.0.0.1/index.html | grep 'HTTP/1.1 200 OK')
    if [ ! -n "${status}" ]; then
        logAndEchoError "Nginx service is abnormal <inner -- vrf>."
        return 1
    fi

    return 0
}

function check_web()
{
    source ${DEVICE_MANAGER_SCRIPT_DIR}/env.sh
    for var in $IPV4
    do
        status=$(curl -m 5 -ksi https://${var}:8088/login | grep 'HTTP/1.1 200 OK')
        if [ ! -n "${status}" ]; then
            logAndEchoError "Nginx web service is abnormal.[ip=$var]"
            return 1
        fi
    done
    for var in $IPV6
    do
        status=$(curl -m 5 -ksi https://[${var}]:8088/login | grep 'HTTP/1.1 200 OK')
        if [ ! -n "${status}" ]; then
            logAndEchoError "Nginx web service is abnormal.[ip=$var]"
            return 1
        fi
    done

    return 0
}

function start_nginx()
{
    web_only=$1

    cd ${DEVICE_MANAGER_NGINX_DIR}/sbin/
    chmod -R 550 ${DEVICE_MANAGER_DIR}
    chmod -R 640 ${DEVICE_MANAGER_NGINX_DIR}/conf/cert/*
    chmod -R 750 ${DEVICE_MANAGER_NGINX_DIR}/*_temp
    chmod 600 ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx.conf
    chmod 500 ${DEVICE_MANAGER_DIR}/script/kmc2_*
    chmod 500 ${DEVICE_MANAGER_DIR}/script/*_password.sh

    chmod 550 /OSM/script/tar_dm_log.sh
    chmod 550 /OSM/script/setup.hook/before/dm_clear.sh

    rm -rf ${DEVICE_MANAGER_NGINX_DIR}/logs
    mkdir -p ${NGINX_LOG_DIR}
    ln -sfn ${NGINX_LOG_DIR} ${DEVICE_MANAGER_NGINX_DIR}/logs
    chmod 750 ${NGINX_LOG_DIR}
    chmod 640 ${NGINX_LOG_DIR}/*.log
    if [ ! -f "$NGINX_PID_FILE" ]; then
        touch $NGINX_PID_FILE
    fi
    if [ ! -f "$NGINX_REST_PID_FILE" ]; then
        touch $NGINX_REST_PID_FILE
    fi
    if [ ! -f "$NGINX_INNER_PID_FILE" ]; then
        touch $NGINX_INNER_PID_FILE
    fi
    chmod 640 ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx.pid
    chmod 640 ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx_rest.pid
    chmod 640 ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx_inner.pid
    chown -R ${DEVICE_MANAGER_OWNER}:${DEVICE_MANAGER_OWNER_GROUP} ${NGINX_LOG_DIR}

    chmod 750 ${DEVICE_MANAGER_NGINX_DIR}
    chown -R ${DEVICE_MANAGER_OWNER}:${DEVICE_MANAGER_OWNER_GROUP} ${DEVICE_MANAGER_DIR}

    if [[ $web_only -ne 1 ]]; then
        rm -f /tmp/inner.socket
        rm -f /tmp/outter.socket
    fi

    chmod u+s nginx
    sh /OSM/bin/cgroup_manage.sh -g omm -i $$ start
        ./nginx >> ${DEPLOY_LOG_PATH} 2>&1
        if [[ $web_only -ne 1 ]]; then
            ./nginx -c ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx_rest.conf
            ip vrf exec vrf-inner ./nginx -c ${DEVICE_MANAGER_NGINX_DIR}/conf/nginx_inner.conf
        fi
    sh /OSM/bin/cgroup_manage.sh -i $$ end
    chmod -R 600 ${DEVICE_MANAGER_NGINX_DIR}/conf/cert/*
    if [ $? -ne 0 ];then
        logAndEchoError "Failed to start nginx service."
    else
        logAndEchoInfo "Succeed to start nginx service."
    fi
    return 0
}

function decrypt_key_password()
{
	cd ${DEVICE_MANAGER_SCRIPT_DIR} && sh decrypt_key_password.sh > /dev/null 2>&1
    return $?
}

function delete_plain_password()
{
    cd ${DEVICE_MANAGER_SCRIPT_DIR} && sh delete_plain_password.sh > /dev/null 2>&1
    return $?
}

function handle_log()
{
    # 先检查日志处理脚本是否正在运行，如果在运行则不再调用，否则后台调用
    handle_log_path="$DEVICE_MANAGER_SCRIPT_DIR/dm_log_rotate.sh"
    count=$(ps -ef | grep "$handle_log_path" | grep -v "grep" | wc -l)

    if [ $count == 0 ]; then
        nohup sh $handle_log_path > /dev/null 2>&1 &
    fi
    return 0
}

function handle_ip()
{
    sh $DEVICE_MANAGER_SCRIPT_DIR/handle_manage_ip.sh > /dev/null 2>&1
    return $?
}

function handle_oem()
{
    sh $DEVICE_MANAGER_SCRIPT_DIR/oem.sh > /dev/null 2>&1
    return $?
}

function restart_nginx()
{
    killall nginx

    decrypt_key_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to decrypt primary key password."
        return 1
    fi
    start_nginx
    sleep 1
    delete_plain_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to delete plain password file."
    fi
}

# 文件中的pid是否为正在运行的nginx实例。如果误杀另外的nginx实例，也可以接受。
function is_pid_correct()
{
    local pid_file=$1
    local nginx_pid=$(cat $pid_file)

    # 校验是否该pid是否为nginx进程，避免误杀
    local nginx_status=$(ps -p ${nginx_pid} | grep nginx)
    if [[ -z ${nginx_status} ]]; then
        logAndEchoError "[${pid_file}]nginx pid ${nginx_pid} is not correct."
        return 1
    fi

    return 0
}

# @param pid_file
# @param signal -9, -HUP
function kill_nginx_by_pid_file()
{
    pid_file=$1
    signal=$2
    if [ -f $pid_file ]; then
        # 如果线程不存在或者不是nginx的线程，不Kill
        is_pid_correct $pid_file
        if [ $? -eq 0 ]; then
            pid=$(cat $pid_file)
            kill $signal $pid
            logAndEchoInfo "Kill nginx by pid file '$pid_file', cmd is 'kill $signal $pid'."
        fi
    else
        logAndEchoError "The File $pid_file is not exist."
    fi
}

function kill_nginx_web()
{
    kill_nginx_by_pid_file $NGINX_PID_FILE -9

    # 杀掉监听127.0.0.2:8088的nginx工作进程
    for i in {1..100}; do
        pid=$(netstat -lnp | grep 127.0.0.2:8088 | awk '{for(i=1; i<=NF; i++){p=match($i, /\/nginx/); if(p) print substr($i,0,p-1)}}')
        if [ $pid ]; then
            kill -9 $pid
            logAndEchoInfo "Kill web nginx pid=${pid}."
            sleep 0.5
        else
            logAndEchoInfo "Succeed to kill all web nginx."
            return
        fi
    done
}

function restart_nginx_web()
{
    # 清空nginx.conf中的IP
    local NGINX_CONF=$DEVICE_MANAGER_NGINX_DIR/conf/nginx.conf
    local listens=$(grep ".*listen .*:8088 ssl;" ${NGINX_CONF})
    local ips=$(echo "$listens" | sed 's/.*listen \(.*\):8088 ssl;/\1/g')

    for ip in ${ips[@]}
    do
        # 跳过127.0.0.2
        if [[ "$ip" =~ "127.0.0.2" ]];then
            continue
        fi
        logAndEchoInfo "delete ip:$ip"
        # 转义特殊字符。在sed替换中，"["需要转义，"]"不需要转义，并且没法一个命令一次将左右中括号替换掉。
        ip=$(echo "$ip" | sed -e 's/[.:]/\\&/g' | sed -e 's/]/\\&/g' | sed -e 's/\[/\\&/g')
        sed -i '/'"$ip"'/d' ${NGINX_CONF}
    done

    # 清空env.sh中的IP
    sed -i "s/IPV4='.*'/IPV4=''/g" ${DEVICE_MANAGER_SCRIPT_DIR}/env.sh
    sed -i "s/IPV6='.*'/IPV6=''/g" ${DEVICE_MANAGER_SCRIPT_DIR}/env.sh

    kill_nginx_web

    decrypt_key_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to decrypt primary key password."
        return 1
    fi

    start_nginx 1
    sleep 1

    delete_plain_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to delete plain password file."
    fi
}


function reload_nginx_web()
{
    is_pid_correct $NGINX_PID_FILE || return 1

    decrypt_key_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to decrypt primary key password."
        return 1
    fi

    kill -HUP `cat $NGINX_PID_FILE`

    # 延迟等待nginx reload完成再删除plain_password
    sleep 5
    logAndEchoInfo "Succeed to reload nginx."
    delete_plain_password > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to delete plain password file."
    fi
}

function restore_ngxin_conf()
{
    # todo-tx，根据查询控制器状态，判断扩控完成，查一次，不要反复查
    python $DEVICE_MANAGER_SCRIPT_DIR/handle_nginx_conf.py -restore  > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        logAndEchoError "Failed to restore customized nginx configurations."
    fi
}

# 判断nginx进程是否存在，进程存在则返回1，否则返回0.
# 由于ps 结果不可靠，这里需要循环3次检查进程均不存在才认为不存在
function check_nginx_master()
{
    local retryTimes=3
    local i=0
    while [[ $i -lt $retryTimes ]]; do
        status=$(ps -ef | grep 'nginx: master process' | grep -v 'grep')
        if [[ -n "${status}" ]]; then
            return 1
        fi

        sleep 0.1
        let i++
    done
    return 0
}

while :
do
    handle_log
    handle_oem
    # 升级、扩控、换控等场景，将用户自定义的配置恢复回来
    restore_ngxin_conf

    # 检查nginx_rest实例服务是否可用
    check_url
    url_rsp=$?
    if [ $url_rsp -eq 1 ]; then
        restart_nginx
        continue
    fi

    handle_ip
    ip_rsp=$?
    if [ $ip_rsp -eq 1 ]; then
        reload_nginx_web
        continue
    fi

    # 检查nginx_web实例服务是否可用
    check_web
    web_rsp=$?
    if [ $web_rsp -eq 1 ]; then
        restart_nginx_web
        continue
    fi

    check_nginx_master
    master_status=$?
    if [ $master_status -eq 0 ]; then
        restart_nginx
        continue
    fi

    sleep 5
done
