#!/usr/bin/env bash

current_dir=$(dirname $0)
log=${current_dir}/install.log
sudobinpath=/usr/local/uniepsudobin
osconfig=yes
source ${current_dir}/get_os_info.sh
START_CODE=1
SUCCESS_CODE=100
FAIL_CODE=255


echo "[$(date)] start to install os_mediation." | tee ${log}

############################################################
# Name:        read_pwd
# Description: 获取输入的密码，非无线场景，至少需要ossadm的密码
#              ftpuser的可选；无线场景，不要密码
############################################################
function read_pwd() {
    if [ ! -z "${wireless}" ] && [ "${wireless}" = "yes" ];then
        echo "[$(date)] wireless installation, no need to read input."
        return 0
    fi

    if [ ! -z "${increment}" ] && [ "${increment}" = "yes" ];then
        echo "[$(date)] increment installation, no need to read input."
        return 0
    fi

    echo "[$(date)] start to read info from input."

    # 获取输入的ossadm密码
    ossadm_pwd_list=("product_pwd_ossadm" "all_os_default_passwd" "os_others_user_pwd")
    for ossadm_pwd_var_name in "${ossadm_pwd_list[@]}"; do
        # 此处的'es_input: '一定要输出到前台，easysuite捕获后才会输入密码，否则会卡住等待
        echo "es_input: ${ossadm_pwd_var_name}"
        read -rs product_pwd_ossadm
        if [ -n "${product_pwd_ossadm}" ]; then
           break;
        fi
    done

    # 密码为空退出
    if [ "X${product_pwd_ossadm}" == "X" ];then
        echo "[$(date)] product_pwd_ossadm is null" | tee -a ${log}
        return 1
    fi

    # 获取ftpuser的密码,ftpuser密码可选
    ftpuser_pwd_list=("product_pwd_ftpuser" "all_os_default_passwd")
    for ftpuser_pwd_var_name in "${ftpuser_pwd_list[@]}"; do
        # 此处的'es_input: '一定要输出到前台，easysuite捕获后才会输入密码，否则会卡住等待
        echo "es_input: ${ftpuser_pwd_var_name}"
        read -rs product_pwd_ftpuser
        if [ -n "${product_pwd_ftpuser}" ]; then
           break;
        fi
    done

    echo "[$(date)] finish to get info from input."
    return 0
}

############################################################
# Name:        unzip_package
# Description: 解压osconfig和sudoconfig包到/opt目录下
#
############################################################
function unzip_package()
{
    sudo_package="`ls ${current_dir}/sudoconfig_*.tar.gz`"
    if [ ! -f "${sudo_package}" ]; then
        echo "[$(date)] \"${sudo_package}\" package is not exist."
        return 1
    fi

    sudoconfig_path="/opt/sudoconfig_nce_`date '+%Y%m%d%H%M%S'`"
    mkdir "${sudoconfig_path}"
    if [ $? -ne 0 ];then
        echo "[$(date)] mkdir \"${sudoconfig_path}\" is failed."
        return 1
    fi
    echo "[$(date)] mkdir \"${sudoconfig_path}\" is finished."

    tar xvfz "${sudo_package}" -C "${sudoconfig_path}" --no-same-owner >/dev/null 2>&1
    if [ $? -ne 0 ];then
        echo "[$(date)] unzip \"${sudo_package}\" to \"${sudoconfig_path}\" is failed."
        return 1
    fi
    local osconfig_package=
    if [ ${OS_TYPE} == "suse" ]; then
        echo "[$(date)] current os type is SuSE"
        osconfig_package="`ls ${current_dir}/osconfig-*.zip | grep -vi euler`"
    else
        # 欧拉 和 centos统一用欧拉的包
        osconfig_package="`ls ${current_dir}/osconfig-*.zip | grep -i euler`"
    fi

    if [ ! -f "${osconfig_package}" ];then
        echo "[$(date)] \"${osconfig_package}\" package is not exist."
        return 1
    fi

    osconfig_path="/opt/osconfig_nce_`date '+%Y%m%d%H%M%S'`"
    mkdir "${osconfig_path}"
    if [ $? -ne 0 ];then
        echo "[$(date)] mkdir \"${osconfig_path}\" is failed."
        return 1
    fi
    echo "[$(date)] mkdir \"${osconfig_path}\" is finished."

    unzip -d ${osconfig_path} -o ${osconfig_package} >/dev/null 2>&1
     if [ $? -ne 0 ];then
        echo "[$(date)] unzip \"${osconfig_package}\" to \"${osconfig_path}\" is failed."
        return 1
    fi
    # 复制扩展包
    if [ "${osconfig}" == "yes" ]; then
        cp ${current_dir}/custom-* ${osconfig_path}/ >/dev/null 2>&1
        cp ${current_dir}/framework-* ${osconfig_path}/ >/dev/null 2>&1
        cp ${current_dir}/default-* ${osconfig_path}/ >/dev/null 2>&1
    fi
    # centos场景需要增加python适配包
    if [ ${OS_TYPE} == "centos" ]
    then
        cp ${current_dir}/python-* ${osconfig_path}/ >/dev/null 2>&1
    fi
    return 0
}


############################################################
# Name:        clean_env
# Description: 清理环境，卸载osconfig
#
############################################################
function clean_env() {
    # 微服务需要执行卸载相关旧场景，需在此卸载
    # 卸载osconfig，ossadm会统一处理
    if [ -d /usr/local/osconfig ];then
        echo "[$(date)] start to uninstall osconfig"
        su - ossadm -c "bash /usr/local/osconfig/os/bin/uninstall.sh"
        echo "result: $?"
        echo "[$(date)] uninstall osconfig finished"
    fi

    if [ "${OS_TYPE}" = "kylin" ];then
        # kylin 镜像安装后，iptables-save命令自带"-A INPUT -j REJECT --reject-with icmp-host-prohibited"
        # 此规则会导致管理面无法连接，需要清空配置文件，清除所有规则，才能消除执行iptables-save后此条的输出
        iptables -F
        iptables-save > /etc/sysconfig/iptables
        systemctl stop firewalld.service
    fi

    # 1-无线场景，ossadm由无线创建，不删除，避免删除无线的ossadm互信；2-仲裁三方站点，增量安装场景，不修改ossadm
    [ ! -z "${wireless}" ] && [ "${wireless}" = "yes" ] && return 0
    [ ! -z "${increment}" ] && [ "${increment}" = "yes" ] && return 0
    # 删除用户，更新密码
    userdel -rf ossadm
    [ $? -eq 0 ] && echo "[$(date)] success to remove ossadm"
    pre_config_ssh >> ${log} 2>&1 || return 1
    return 0
}


############################################################
# Name:        install_sudo
# Description: 安装sudoconfig
#
############################################################
function install_sudo()
{
    logsPath="${current_dir}"
    [ ! -d "${current_dir}" ] && mkdir -p "${current_dir}"
    config_sudo="${sudoconfig_path}/rebuild/script/config_sudo/config_sudo.sh"
    if [ ! -f "${config_sudo}" ];then
        echo "[$(date)] \"${config_sudo}\" is not exist."
        return 1
    fi

    install_ipsi="${sudoconfig_path}/rebuild/script/install_ipsi/install_ipsi.sh"
    if [ ! -f "${install_ipsi}" ];then
        echo "[$(date)] \"${install_ipsi}\" is not exist."
        return 1
    fi

    echo -n "" > /etc/security/opasswd

    # MAE无线场景，ossadm已经存在，不需要传入密码
    if [ ! -z "${wireless}" ] && [ "${wireless}" = "yes" ];then
        bash "${config_sudo}" -d ${sudobinpath} > "${logsPath}/install_sudo.log"
    elif [ ! -z "${increment}" ] && [ "${increment}" = "yes" ];then
        # 仲裁三方站点，增量安装场景，不修改ossadm
        bash "${config_sudo}" -d ${sudobinpath} > "${logsPath}/install_sudo.log"
    else
        { echo -e "${product_pwd_ossadm}" ;} | bash "${config_sudo}" -d ${sudobinpath} > "${logsPath}/install_sudo.log"
        chage --maxdays 99999 ossadm
    fi

    cat "${logsPath}/install_sudo.log" | grep "Configure Sudo Successfully" >/dev/null 2>&1
    res=$?
    cat "${logsPath}/install_sudo.log" | grep "MAIN_RET=0" >/dev/null 2>&1
    if [ $? -ne 0 -o ${res} -ne 0 ];then
        echo "[$(date)] Excute the script \"${config_sudo}\" failed."
        echo "[$(date)] please read log in ${sudoconfig_path}/rebuild/script/logs/config_sudo/"
        return 1
    fi
    echo "[$(date)] Excute the script \"${config_sudo}\" success."

    bash "${install_ipsi}" > "${logsPath}/install_ipsi.log"
    cat "${logsPath}/install_ipsi.log" | grep "Install ipsi end" >/dev/null 2>&1
    res=$?
    cat "${logsPath}/install_ipsi.log" | grep "MAIN_RET=0" >/dev/null 2>&1
    if [ $? -ne 0 -o ${res} -ne 0 ];then
        echo "[$(date)] Excute the script \"${install_ipsi}\" failed."
        echo "[$(date)] please read $(realpath ${logsPath}/install_ipsi.log) or read log in ${sudoconfig_path}/rebuild/script/logs/install_ipsi/"
        return 1
    fi
    rm -rf /opt/sudoconfig_nce_*
    echo "[$(date)] Excute the script \"${install_ipsi}\" success."
    return 0
}


############################################################
# Name:        install_osconfig
# Description: 安装osconfig
#
############################################################
function install_osconfig()
{
    chmod -R 700 ${osconfig_path}
    chown -R ossadm:ossgroup ${osconfig_path}

    echo "[$(date)] start to install osconfig"
    su - ossadm -c "bash ${osconfig_path}/install.sh -sudobinpath ${sudobinpath}"
    if [ $? -ne 0 ];then
        echo "[$(date)] install osconfig failed"
        echo "[$(date)] please read log in ${osconfig_path}/logs/"
        return 1
    fi
    rm -rf /opt/osconfig_nce_*
    su - ossadm -c "find /usr/local/osconfig/os -type f -name sudobin*_pkg.tar -exec chmod 400 {} + &> /dev/null"
    echo "[$(date)] install osconfig finished"
    return 0
}


############################################################
# Name:        check_args
# Description: 校验入参，确定安装方式
#
############################################################
function check_args(){
    # 参数获取，无参数配置是采用默认值
    # 默认进行参数配置 默认sudoconfig路径为/usr/local/uniepsudobin
    local param_num=$#
    if [ $# = 0 ]; then
        echo "[$(date)] no input args."
        return 0
    fi
    # 获取参数 有定制参数时 采用定制参数值
    while true;
    do
        case "${1}" in
            -sudobinpath)
                case "${2}" in
                     "")
                        sudobinpath=/usr/local/uniepsudobin;
                        shift 2;
                        ;;
                     *)
                        sudobinpath=${2};
                        shift 2;
                        ;;
                esac
                 ;;
            -option)
                case "${2}" in
                     "no_os_config")
                        osconfig=no;
                        shift 2;
                        ;;
                     *)
                        osconfig=yes;
                        shift 2;
                        ;;
                esac
                 ;;
            -wireless)
                case "$2" in
                    "wireless_install")
                    wireless=yes;
                    shift 2;
                    ;;
                esac
                 ;;
            -increment)
                case "$2" in
                    "increment_install")
                    increment=yes;
                    shift 2;
                    ;;
                esac
                 ;;
            *)
                shift
                break
                ;;
        esac
    done

    if [ $# != 0 -a -z "${sudobinpath}" ]
    then
        echo "parameter sudobinpath is empty."
        return 1
    fi
    echo "[$(date)] input args: ${sudobinpath} ${osconfig} "
    return 0

}

############################################################
# Name:        common_osconfig
# Description: 确认入参是否需要创建ftpuser；配置操作系统入口函数
#
############################################################
function create_user() {
    local user=$1
    local pwd=$2
    local shell_path
    if [ "${OS_TYPE}" = "euler" ] || [ "${OS_TYPE}" = "kylin" ];then
        shell_path="/usr/libexec/openssh/sftp-server"
    else
        shell_path="/usr/lib/ssh/sftp-server"
    fi
    mkdir -p /opt/backup/ftpboot
    useradd -g ossgroup -u 4001 -m -d /opt/backup/ftpboot -s "${shell_path}" -G "" ftpuser
    [ $? -ne 0 ] && echo "[$(date)] failed to create ftpuser" && return 1
    chage --maxdays 99999 ftpuser
    pwd=$(echo ${pwd} | sed 's/ //g')
    if [ "${OS_TYPE}" = "euler" ] || [ "${OS_TYPE}" = "kylin" ];then
        echo ${pwd} | passwd --stdin ${user}
    else
        pwd=$(echo ${pwd} | sed 's/\\/\\\\\\/g' | sed 's/{/\\{/g' | sed 's/}/\\}/g' | sed 's/\[/\\[/g' | sed 's/\$/\\\\\\$/g' | sed 's/`/\\`/g' | sed 's/\"/\\\\\\"/g')
expect <<- EOF
set timeout 30
spawn passwd ${user}
expect "New password:" { send "${pwd}\r" }
expect {
"Retype new password:" { send "${pwd}\r" }
"BAD PASSWORD:*" { exit 1 }
"passwd: Have exhausted maximum number of retries for service" { exit 1 }
}
expect eof
catch wait result
exit [lindex \$result 3]
EOF
    fi
}


############################################################
# Name:        common_osconfig
# Description: 确认入参是否需要创建ftpuser；配置操作系统入口函数
#
############################################################
function common_osconfig() {
    if [ "X${product_pwd_ftpuser}" == "X" ];then
        echo "[$(date)] product_pwd_ftpuser is null, no need to create ftpuser"
    else
        # 平台接口会判断homepath的上层目录是否存在。。  暂时规避一下 先创建上层/opt/backup目录
        # useradd命令直接创建是不需要父目录存在的 建议平台优化 按照useradd的逻辑 不要直接报错
        # 平台用户创建接口（addosuser.sh） 执行日志可查看/var/log/os_tool/user/log.log
        # 无线场景，仲裁三方站点增量安装，不传ftpuser密码，不会进入此分支
        userdel -rf ftpuser
        [ $? -eq 0 ] && echo "[$(date)] success to remove ftpuser"
        echo "[$(date)] start to create ftpuser"
        create_user "ftpuser" "${product_pwd_ftpuser}" >/dev/null 2>&1
        [ $? -ne 0 ] && echo "[$(date)] failed to create or passwd ftpuser..." && return 1
    fi

    if [ "${osconfig}" == "yes" ]; then
        echo "[$(date)] start to config OS"
        su - ossadm -c "bash /usr/local/osconfig/os/bin/commonosconfig.sh install" || return 1
    fi
    return 0
}


############################################################
# Name:        unlock
# Description: 安装欧方前解锁 避免系统文件被锁
#
############################################################
function unlock() {
    [[ -f /usr/lib/systemd/system/lock.service ]] || return 0
    # 重启服务，不重启服务有可能无法解锁目录
    echo "[$(date)] status of lock:$(systemctl status lock)"
    systemctl restart lock
    systemctl disable lock
    local unlockResult=$?
    if [[ ${unlockResult} != 0 ]]
    then
        #记录下失败日志
        echo "disable lock failed with ${unlockResult}"
        return 1
    fi
    systemctl stop lock
    unlockResult=$?
    echo "[$(date)] unlockResult: $unlockResult"
    if [[ ${unlockResult} != 0 ]]
    then
        #记录下失败日志
        echo "stop lock failed with ${unlockResult}"
        return 1
    fi
    return 0
}

############################################################
# Name:        config_pre_install
# Description: 适配部分需要在安装欧方前的操作
#
############################################################
function config_pre_install() {
    # 企业分析需要使用/opt/sudobin目录作为欧方提权目录；旧版ICMR会在安装时删除并创建/opt/sudobin，二者冲突，需要将之前的步骤提到安装欧方前
    # imap需要依赖/opt/sudibin目录的存在与否 来将脚本存放于此 并执行提权脚本；需要推动imap整改，暂时保证目录存在，后续整改完成后删除目录创建
    # 此步骤对应configostool_sudo.sh的create_sudobin
    # 无线场景不涉及，因为无线场景/opt/sudobin目录中存在无线的脚本，不能清空
    [ ! -z "${wireless}" ] && [ "${wireless}" = "yes" ] && return 0
    local path=/opt/sudobin
    [ -d "${path}" ] && rm -rf "${path}"
    mkdir -p "${path}"
    chown root:root "${path}"
    chmod 500 "${path}"
    echo "[$(date)] succes to clean /opt/sudobin."
    return 0
}


############################################################
# Name:        check_user
# Description: 检查当前用户
#
############################################################
function check_user() {
    local user=$(whoami)
    if [ "${user}" != "root" ];then
        echo "[$(date)] please execute by root"
        return 1
    fi
    echo "[$(date)] user is ${user}"
    return 0
}

############################################################
# Name:        check_user
# Description: 生成eaysuite action.json的check file，用于异步安装
#
############################################################
function create_check_file() {
    # 企业场景不使用异步安装，无/opt/install目录，直接返回
    [ ! -d "/opt/install" ] && return 0
    local file="/opt/install/check_os_mediation_install.sh"
    echo "#!/bin/bash" >"${file}"
    echo "echo  RESULT:${START_CODE}" >>"${file}"
    chmod 750 "${file}"
    return 0
}

############################################################
# Name:        get_check_result
# Description: 异步安装，检验是否安装成功
#
############################################################
function get_check_result() {
    # 企业场景不使用异步安装，无/opt/install目录，直接返回
    [ ! -d "/opt/install" ] && return 0
    local file="/opt/install/check_os_mediation_install.sh"
    local para=$1
    if [ ${para} -eq 0 ];then
       echo "#!/bin/bash
echo  RESULT:${SUCCESS_CODE} && rm -f ${file}
    ">"${file}"
    else
       echo "#!/bin/bash
echo  RESULT:${FAIL_CODE} && rm -f ${file}
    ">"${file}"
    fi
    chmod 750 "${file}" > /dev/null 2>&1
}

############################################################
# Name:        pre_config_ssh
# Description: 修改ssh指纹算法
#
############################################################
function pre_config_ssh() {
    # 在创建用户前重置ssh指纹算法,避免安全加固后安全等级低的ssh指纹算法被删除,原host key不可用
    local sshd_conf="/etc/ssh/sshd_config"
    sshd -t >/dev/null
    if [ $? -ne 0 ]; then
        echo "[$(date)] faild to config ssh because ${sshd_conf} contains incorrect configurations."
        return 1
    fi

    echo "[$(date)] start to config ssh host key."
    sed -i "/^HostKey.*/d" "${sshd_conf}"
    # 计算云环境可能存在配置文件末行无换行符情况,需要特殊处理
    last_letter=$(tail -c 1 ${sshd_conf} | od -x -A n)
    if [ $last_letter != "000a" ]; then
        echo >> ${sshd_conf}
    fi
    echo "HostKey /etc/ssh/ssh_host_rsa_key" >> ${sshd_conf}
    echo "HostKey /etc/ssh/ssh_host_ed25519_key" >> ${sshd_conf}
    local start_times=1
    local ssh_result
    while [ ${start_times} -le 3 ]; do
        systemctl restart sshd
        ssh_result=$?
        if [ ${ssh_result} -eq 0 ]; then
            echo "[$(date)] success to restart sshd."
            break
        fi
        sleep 10
        echo "[$(date)] failed to restart sshd for ${start_times} times."
        start_times=$((start_times+1))
    done
    if [ ${ssh_result} -ne 0 ]; then
        echo "[$(date)] failed to restart sshd."
        return 1
    fi

    # 删除旧host key
    local root_ssh_host="/root/.ssh/known_hosts"
    [ -f ${root_ssh_host} ] && rm -f ${root_ssh_host}
    echo "[$(date)] success to config ssh host key."
}

############################################################
# Name:        main
# Description: 主函数入口
#
############################################################
function main() {
    create_check_file || return 1
    check_user >> ${log} 2>&1 || return 1
    check_args "$@" >> ${log} 2>&1 || return 1
    read_pwd || return 1
    clean_env >> ${log} 2>&1 || return 1
    config_pre_install >> ${log} 2>&1 || return 1
    unlock >> ${log} 2>&1 || return 1
    unzip_package >> ${log} 2>&1 || return 1
    install_sudo >> ${log} 2>&1 || return 1
    install_osconfig >> ${log} 2>&1 || return 1

    # 若需要进行参数配置则配置，目前企业不需要参数配置只需要安装osconfig和sudoconfig
    if [ "${osconfig}" == "yes" ]; then
        echo "[$(date)] start to configure the operating system.." | tee -a ${log}
        common_osconfig >> ${log} 2>&1 || return 1
    fi
    return 0
}

main "$@"
res=$?
if [ "${res}" -eq 0 ];then
    echo "install os mediation success." > ${current_dir}/osmediation.flag
    echo "[$(date)] install os mediation success, exit code:0" | tee -a ${log}
else
    echo "[$(date)] failed to install os mediation, please read $(realpath ${log})" | tee -a ${log}
fi
get_check_result "${res}"
exit "${res}"
