#!/bin/bash

<<COMMENT
This script is This script is used for byte bare-metal troubleshooting.
Author: zhaochangming 
Created: 2024-5-28 
COMMENT

# 系统变量
export LANG=C
export PATH=/bin/:/sbin:/usr/bin/:/usr/sbin:/usr/local/sbin/:/usr/local/bin/:$PATH

# 用户变量
promise_bw=$(cat /etc/xyapp/network.json | jq -r .host_config.networkbw)
promise_bw_press=$(echo $promise_bw | awk '{print$0+int($0*0.1)}')
wxhostname=$(cat /etc/xyapp/hostname)
[ -e /etc/global_env.json ] && zjhostname=$(cat /etc/global_env.json | jq -r .base_info.hostname)
timestamp=$(date +%Y%m%d%H%M%S)
[ ! -e /tmp/init/${timestamp} ] && mkdir -p /tmp/init/${timestamp}
workdir="/tmp/init/${timestamp}"
resource_code=$(curl -sL  http://127.0.0.1:5981/api/pppoeConfig | jq -r .code)
[ ${resource_code} -eq 0 ] && resource_type=0 || resource_type=1
tag_code=0

# 定义内控SGP状态数组
declare -A status_array
status_array["0"]="审核"
status_array["10"]="待审核"
status_array["20"]="审核拒绝"
status_array["30"]="审核通过"
status_array["100"]="部署"
status_array["110"]="待检测"
status_array["120"]="检测中"
status_array["130"]="检测成功"
status_array["140"]="检测失败"
status_array["150"]="待部署"
status_array["160"]="部署中"
status_array["170"]="部署成功"
status_array["180"]="部署失败"
status_array["200"]="交付"
status_array["210"]="待交付"
status_array["220"]="已交付"
status_array["300"]="运营",
status_array["310"]="运行中"
status_array["320"]="下线"
status_array["330"]="用户调整下线(用户主动沟通下线)"
status_array["340"]="内部调整下线-不结算"
status_array["400"]="清退"
status_array["410"]="待清退"
status_array["420"]="已清退"

# 0 定义显示格式
func_display_message(){
    local status=$1
    local message=$2
    
    if [ "$status" = "fail" ]; then
        message=$(echo "$message" | sed 's/fail/'$'\e[0;31m''&'$'\e[0m''/g')
    elif [ "$status" = "warning" ]; then
        message=$(echo "$message" | sed 's/warning/'$'\e[0;33m''&'$'\e[0m''/g')
    elif [ "$status" = "ok" ]; then
        message=$(echo "$message"| sed 's/ok/'$'\e[0;32m''&'$'\e[0m''/g')
    fi
    #echo "主机名:${wxhostname}|字节主机名:${zjhostname:-null}|$message"
    echo "$message"
}

# 1.节点状态检查:内控SGP交付状态 
func_sgp_status_code(){
    sgp_status_code=$(cat /etc/xyvod/extraInfo.json | jq -r .step_status)
    value=${status_array[$sgp_status_code]}
    if [ $(echo ${sgp_status_code}) -ne 310 ];then
        func_display_message "fail" "检查项:内控SGP节点状态|检查结果:fail|要求:运营-运行中|当前:${value}|处理建议:请确认当前状态,请校正状态."
        tag_code=1
    fi
}

# 1.节点状态检查:交付期判断
func_delivery_schedule(){
    if [ -e /etc/global_env.json ];then
        modify_time=$(stat -c %Y /etc/hostname)
        current_time=$(date +%s)
        time_diff=$((current_time - modify_time))
        duration=$(echo ${time_diff} | awk '{printf "%d小时%d分钟%d秒",$0/3600,($0%3600)/60,$0%60}')
        if [ $time_diff -lt 10800 ];then
            func_display_message "fail" "检查项:外控CSCM入库时长|检查结果:fail|要求:>3小时|当前:${duration}|处理建议:正在部署中,无异常情况入库3小时后起量,请稍后观察."
            tag_code=1
        fi
    else
        func_display_message "fail" "检查项:外控CSCM是否入库|检查结果:fail|要求:节点需在外控CSCM入库|当前:未入库|处理建议:请在外控CSCM平台提交入库."
        tag_code=1
    fi
}

# 1.节点状态检查:外控cscm节点状态
func_cscm_status(){
    if [ -e /opt/tiger/byteDetectAgent/logs/byteDetectAgent.log ];then
        cscm_status=$(cat /opt/tiger/byteDetectAgent/logs/byteDetectAgent.log | grep "target_status" | tail -n 5 | grep -o '{.*$' | jq -r '.monitor_node_status' | sort -r | uniq | head -n 1)
        if [ $(echo ${cscm_status} | grep -wci active) -eq 0 ];then
            func_display_message "fail" "检查项:外控CSCM节点状态|检查结果:fail|要求:Active|当前:${cscm_status:-null}|处理建议:状态异常,离线或资源问题被调度拉黑,当前脚本诊断无异常后,请前往CSCM平台恢复上线."
            tag_code=1
        fi
    fi
}

# 1.节点检查
func_capacity_check(){
    if [ -e /etc/global_env.json ];then
        # 调度带宽下压
        capacity=$(cat /etc/global_env.json | jq -r '.base_info.isp_info[] | .capacity')
        capacity_plan=$(cat /etc/global_env.json | jq -r '.base_info.isp_info[] | .capacity_plan')
        result=$(echo "$capacity < $capacity_plan" | bc -l)
        if [ $result -eq 1 ];then
            func_display_message "fail" "检查项:外控CSCM调度带宽是否下调|检查结果:fail|要求:节点带宽与调度带宽一致|当前:节点带宽(${capacity}G)调度带宽($capacity_plan)|处理建议:质量问题下压,当前诊断无异常后,请前往CSCM平台恢复上线."
            tag_code=1
        fi
     
        # 线路带宽调整未同步
        capacity_Mb=$(echo "$capacity * 1000 / 1" | bc)
        if [ ${promise_bw} -gt ${capacity_Mb} ];then
            func_display_message "fail" "检查项:外控CSCM带宽大小是否同步|检查结果:fail|要求:外控节点带宽不小于内控节点带宽|当前:内网SGP(${promise_bw}M)外控CSCM(${capacity_Mb}M)|处理建议:用户调整线路,未同步至外控平台,请前往CSCM平台修正带宽大小,如为合建模式暂可忽略."
            tag_code=1
        fi
    fi
}

# 2.硬件检查:检查服务器硬件日志
func_comm_check_hardware_log(){

    # 检查CPU
    if [ $(grep -ic 'Machine check events' /var/log/messages) -ne 0 ];then
        func_display_message "fail" "检查项:CPU硬件|要求:正常|当前:CPU存在MCE错误日志|处理建议:存在宕机或反复重启风险,请联系用户处理."
        tag_code=1
    fi

    # 检查内存
    if [ -f /sys/devices/system/edac/mc ];then
       mem_ce_error=$(grep "[0-9]" /sys/devices/system/edac/mc/mc*/csrow*/ch*_ce_count)
       mem_ce_error_num=$(echo ${mem_ce_error} | awk -F':' '$NF>1000 {print$0}')
       if [ -n "${mem_ce_error_num}" ];then
           func_display_message "fail" "检查项:内存硬件|要求:正常|当前:以下内存存在MCE错误日志|处理建议:请联系用户处理."
           echo ${mem_ce_error}
           tag_code=1
       fi
    fi

    # 检查demsg日志
    dmesg_log=$(dmesg -T | grep -iE "error" | egrep -v "ERST|pcspkr|EXT4-fs|EDAC|ACPI|segfault|GPT")
    if [ ! -z "${dmesg_log}" ];then
        func_display_message "fail" "检查项:dmesg日志|检查结果:fail|要求:硬件启动正常|当前:存在下面错误日志|处理建议:请联系用户处理."
        echo "${dmesg_log}" | head -n 5
        tag_code=1
    fi

    # 检查带外日志
    if  [ -f /dev/ipmi0 ] || [ -f /dev/ipmi/0 ] || [ -f /dev/ipmidev/0 ];then
        if [ $(ipmitool sel elist | grep -ic error) -ne 0 ];then
            func_display_message "fail" "检查项:IPMI日志|检查结果:fail|要求:正常|当前:存在下面错误日志|处理建议:请联系用户处理."
            ipmitool sel elist | grep -i error | head -n 5
            tag_code=1
        fi
    fi    
}

# 2.硬件检查:磁盘性能测试
func_comm_check_fio_disk(){

    # 系统盘硬盘
    sys_disk=$(lsblk -l | egrep -B 1 "/$|boot|swap" | egrep -v "lvm|luks|--" | awk '{print $1}' | sed -e '/sd/s/[0-9]//' -e '/nvme/s/p[0-9]//' -e '/vd/s/[0-9]//' | sort|uniq)
    all_disk=$(lsblk |  grep -E  "^sd|^n" | awk '{print$1}' | sort)
    
    # 硬盘压测
    func_comm_disk_fio(){
        dev=$1
        if echo ${dev} | grep -q ${sys_disk};then
            fio -direct=1 -ioengine=libaio -iodepth=32 -bs=4k -size=4G -filename=/dev/${dev} -name=/${dev}/fiotest -runtime=5 -output-format=json -rw=randread -thread -time_base --output=${workdir}/${dev}.json >/dev/null 2>&1
            [ $? -ne 0 ] && func_display_message "fail" "检查项:系统盘可用性|检查结果:fail|要求:读写正常|当前:${dev}硬盘存在故障|处理建议:请联系用户处理." && tag_code=1
            read_iops=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.iops' | awk '{print int($0)}')
            if [ ${read_iops} -lt  30000 ];then
                func_display_message "warning" "检查项:系统盘性能|检查结果:warning|要求:随机读IOPS>=3W|当前:${dev}:${read_iops}|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
            fi
        else
            fio -direct=1 -ioengine=libaio -iodepth=32 -bs=4k -size=4G -filename=/dev/${dev} -name=/${dev}/fiotest -runtime=5 -output-format=json -rw=randread -thread -time_base --output=${workdir}/${dev}.json >/dev/null 2>&1
            if [ $? -ne 0 ];then
                func_display_message "fail" "检查项:数据盘可用性|检查结果:fail|要求:读写正常|当前:${dev}硬盘存在故障|处理建议:请联系用户处理." 
                tag_code=1
            else
                read_iops=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.iops' | awk '{print int($0)}')
                read_lat=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.lat.mean' | awk '{print int($0/1000)}')
                vol=$(lsblk -b | grep  "^${dev}" | awk '{print int($4/1000/1000/1000)}')       
                if [ ${read_iops} -gt 2000 ];then
                    if [ ${read_iops} -lt 30000 ];then     
                        func_display_message "warning" "检查项:数据盘性能|检查结果:warning|要求:SSD硬盘随机读IOPS>=3W|当前:[${dev}:${read_iops}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${read_lat} -gt 5 ];then     
                        func_display_message "warning" "检查项:数据盘性能|检查结果:warning|要求:SSD硬盘随机读时延<5ms|当前:[${dev}:${read_lat}ms]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi
   
                    echo "SSD ${dev} ${vol}" >> ${workdir}/data_disk_list.log
                else
                    if [ ${read_iops} -lt 75 ];then     
                        func_display_message "warning" "检查项:数据盘性能|检查结果:warning|要求:HDD硬盘随机读IOPS>=75|当前:[${dev}:${read_lat}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi
   
                    if [ ${read_lat} -gt 200 ];then
                        func_display_message "warning" "检查项:数据盘性能|检查结果:warning|要求:HDD硬盘随机读时延<200ms|当前:[${dev}:${read_lat}ms]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整." 
                    fi        
                    echo "HDD ${dev} ${vol}" >> ${workdir}/data_disk_list.log
                fi
            fi
        fi   
    }

    # 遍历
    for i in  ${all_disk};do
        func_comm_disk_fio ${i}
    done
}

# 2.硬件检查:硬件配置检查-1
func_comm_check_hardware(){
    
    # CPU
    cpu_threads=$(lscpu | grep "^CPU(s)" | awk '{print$2}')
    
    # 内存
    mem_total=$(cat /proc/meminfo | grep MemTotal | awk '{print int($2/1024/1024)}')
    
    # 硬盘
    func_comm_check_fio_disk
    disk_sys_drive=$(lsblk -l | egrep -B 1 "/$|boot|swap" | egrep -v "lvm|luks|--" | awk '{print $1}' | sed -e '/sd/s/[0-9]//' -e '/nvme/s/p[0-9]//' -e '/vd/s/[0-9]//' | sort | uniq)
    disk_sys_drive_capacity=$(lsblk -b | grep "^${sys_disk}" | awk '{print int($4/1000/1000/1000)}')
    
    if [ -e ${workdir}/data_disk_list.log ];then
        ssd_vol=$(cat ${workdir}/data_disk_list.log | grep "^SSD" | awk '{sum+= $3} END{print int(sum)}')
        hdd_vol=$(cat ${workdir}/data_disk_list.log | grep "^HDD" | awk '{sum+= $3} END{print int(sum)}')
        ssd_qun=$(cat ${workdir}/data_disk_list.log | grep "^SSD" | wc -l )
        hdd_qun=$(cat ${workdir}/data_disk_list.log | grep "^HDD" | wc -l )
        total_qun=$(cat ${workdir}/data_disk_list.log | wc -l )
        ssd_min_vol=$(cat ${workdir}/data_disk_list.log |grep "^SSD" | awk '{print$3}' | sort -n | head -n 1)
        hdd_min_vol=$(cat ${workdir}/data_disk_list.log |grep "^HDD" | awk '{print$3}' | sort -n | head -n 1)
        ssd_phy=$(cat ${workdir}/data_disk_list.log | grep "^SSD" | awk '{print$3"G"}' | sort | uniq -c | sed 's/^[ \t]*//g' | sed s/[[:space:]]/*/g | tr '\n' '+' | sed 's#+$# #g' | sed s/[[:space:]]//g )
        hdd_phy=$(cat ${workdir}/data_disk_list.log | grep "^HDD" | awk '{print$3"G"}' | sort | uniq -c | sed 's/^[ \t]*//g' | sed s/[[:space:]]/*/g | tr '\n' '+' | sed 's#+$# #g' | sed s/[[:space:]]//g)
    fi
    phy_summ=$(echo "${cpu_threads}C+${mem_total}G+SYS:${disk_sys_drive_capacity}GSSD+DATA:(SSD:${ssd_phy}[${ssd_vol}G]HDD:${hdd_phy}[${hdd_vol}G]"\))
}

# 2.硬件检查:硬件配置检查-2
func_comm_check_hardware_detailed(){
    # 检查硬件配置
    func_comm_check_hardware

    ## 检查系统盘容量
    if [ ${disk_sys_drive_capacity} -lt 200 ];then
        func_display_message "warning" "检查项:系统盘容量|检查结果:warning|要求:系统盘容量>=200G|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
    fi

    ## 检查CPU线程数、内存大小、带宽大小
    if [ ${resource_type} -eq 1 ];then
        ### B1专线业务
        #### CPU要求
        if [ ${cpu_threads} -lt 20 ];then
            func_display_message "fail" "检查项:CPU最低要求|检查结果:fail|要求:CPU线程>=20|当前:[${phy_summ}]|处理建议:建议用户参考最佳配置调整."
            tag_code=1
        else
            if [ $promise_bw -ge 4000 ] && [ $promise_bw -lt 6000 ];then
                if [ ${cpu_threads} -lt 32 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4-6G带宽要求CPU线程>=32|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi
            elif [ $promise_bw -ge 6000 ] && [ $promise_bw -lt 8000 ];then
                if [ ${cpu_threads} -lt 48 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:6-8G带宽要求CPU线程>=48|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi
            elif [ $promise_bw -ge 8000 ];then
                if [ ${cpu_threads} -lt 64 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:8G及以上带宽要求CPU线程>=64|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi
            fi           
        fi
          
        #### 内存要求
        if [ ${mem_total} -lt 28 ];then
            func_display_message "fail" "检查项:内存容量最低要求|检查结果:fail|要求:内存容量>=32G|当前:[${phy_summ}]|处理建议:建议用户参考最佳配置调整."
            tag_code=1
        else
            if [ $promise_bw -ge 4000 ] && [ $promise_bw -lt 6000 ];then
                if [ ${mem_total} -lt 58 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4-6G带宽要求内存>=64|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi
            else
                if [ ${mem_total} -lt 115 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:6G以上带宽要求内存>=128|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi
            fi 
        fi

        #### 带宽要求
        if [ $promise_bw -lt 2000 ];then
            func_display_message "fail" "检查项:带宽最低要求|检查结果:fail|要求:>=2G|当前:[${promise_bw}]|处理建议:建议用户参考最佳配置调整."
            tag_code=1
        fi
    else
        ### B2汇聚业务
        #### CPU检查
        if [ ${cpu_threads} -lt 32 ];then
            func_display_message "fail" "检查项:CPU最低要求|检查结果:fail|要求:CPU线程>=32|当前:[${phy_summ}]|处理建议:建议用户参考最佳配置调整."
        fi

        if [ ${mem_total} -lt 58 ];then
            func_display_message "fail" "检查项:内存容量最小要求|检查结果:fail|要求:>=64G|当前:${phy_summ}|处理建议:建议用户参考最佳硬件配置."
            tag_code=1
        fi
        #### 带宽要求
        if [ $promise_bw -lt 1000 ];then
            func_display_message "fail" "检查项:带宽最低要求|检查结果:fail|要求:>=1G|当前:[${promise_bw}]|处理建议:建议用户参考最佳配置调整."
            tag_code=1
        fi
    fi 

    ## 检查硬盘配置
    if [ ${total_qun} -lt 2 ];then
        func_display_message "fail" "检查项:数据盘个数要求|检查结果:fail|要求:>=2个|当前:[${phy_summ}]|处理建议:一块数据盘会做日志存储,当前没有缓存盘,建议用户参考最佳配置调整."
        tag_code=1
    fi
    if [ ${resource_type} -eq 1 ];then
        ### B1专线业务
        if [ -e ${workdir}/data_disk_list.log ];then
            if [ ${hdd_qun:-0} -lt 5 ];then
                func_display_message "warning" "检查项:数据盘HDD个数要求|检查结果:warning|要求:>=5个|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
            fi

            if [ ${ssd_qun:-0} -lt 2 ];then
               func_display_message "warning" "检查项:数据盘SSD个数要求|检查结果:warning|要求:>=2个|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
            fi

            if [ ${hdd_min_vol:-0} -lt 1800 ];then
               func_display_message "warning" "检查项:数据盘HDD单盘容量要求|检查结果:warning|要求:>=2T|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
            fi

            if [ ${ssd_min_vol:-0} -lt 750 ];then
               func_display_message "warning" "检查项:数据盘HDD单盘容量要求|检查结果:warning|要求:>=1T|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
            fi
           
            if [ $promise_bw -ge 2000 ] && [ $promise_bw -lt 4000 ];then
                if [ ${ssd_vol:-0} -lt 1800 ] || [ ${hdd_vol:-0} -lt 8000 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:2-4G带宽SSD>=2T,HDD>=10T|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi        
            elif [ $promise_bw -ge 4000 ] && [ $promise_bw -lt 6000 ];then    
                if [ ${ssd_vol:-0} -lt 3600 ] || [ ${hdd_vol:-0} -lt 18000 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4-6G带宽SSD>=4T,HDD>=20T|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi       
            elif [ $promise_bw -ge 6000 ] && [ $promise_bw -lt 8000 ];then    
                if [ ${ssd_vol:-0} -lt 5400 ] || [ ${hdd_vol:-0} -lt 18000 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:6-8G带宽SSD>=6T,HDD>=20T|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi 
            elif [ $promise_bw -ge 80000 ];then   
                if [ ${ssd_vol:-0} -lt 9000 ] || [ ${hdd_vol:-0} -lt 18000 ];then
                    func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:8G及以上带宽SSD>=10T,HDD>=20T|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi        
            fi      
        else
            func_display_message "fail" "检查项:数据盘|检查结果:fail|要求:需要一定数据盘缓存|当前:[${phy_summ}]|处理建议:未检测到数据盘,建议用户参考最佳配置调整."
            tag_code=1
        fi
    else
        ### B2汇聚业务
        if [ "${hdd_min_vol}" ] && [ "${hdd_min_vol}" -lt 1350 ];then
            func_display_message "warning" "检查项:数据盘HDD单盘容量要求|检查结果:warning|要求:>=1.5T|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
        fi
        if [ "${ssd_min_vol}" ] && [ "${ssd_min_vol}" -lt 630 ];then
            func_display_message "warning" "检查项:数据盘SSD单盘容量要求|检查结果:warning|要求:>=700G|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
        fi

        if [ -e ${workdir}/data_disk_list.log ];then
            if [ $(cat ${workdir}/data_disk_list.log | grep -ci HDD) -ne 0 ];then
                ##### HDD+SDD硬盘配置
                if [ ${hdd_qun:-0} -lt 3  ];then
                    func_display_message "warning" "检查项:数据盘HDD个数要求|检查结果:warning|要求:>=3个|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi

                if [ ${ssd_qun:-0} -lt 2  ];then
                    func_display_message "warning" "检查项:数据盘SSD个数要求|检查结果:warning|要求:>=2个|当前:[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                fi

                if [ $promise_bw -ge 1000 ] && [ $promise_bw -lt 2000 ];then
                    if [ ${hdd_qun:-0} -lt 3 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:1-2G带宽HDD个数>=3个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${ssd_qun:-0} -lt 2 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:1-2G带宽SSD个数>=2个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 2000 ] && [ $promise_bw -lt 3000 ];then
                    if [ ${hdd_qun:-0} -lt 3 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:2-3G带宽HDD个数>=3个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${ssd_qun:-0} -lt 3 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:2-3G带宽SSD个数>=3个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 3000 ] && [ $promise_bw -lt 4000 ];then
                    if [ ${hdd_qun:-0} -lt 4 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:3-4G带宽HDD个数>=4个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${ssd_qun:-0} -lt 3 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:3-4G带宽SSD个数>=3个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 4000 ] && [ $promise_bw -lt 5000 ];then
                    if [ ${hdd_qun:-0} -lt 4 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4-5G带宽HDD个数>=4个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${ssd_qun:-0} -lt 3 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4-5G带宽SSD个数>=4个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 5000 ];then
                    if [ ${hdd_qun:-0} -lt 5 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:5G及以上带宽HDD个数>=5个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                    if [ ${ssd_qun:-0} -lt 4 ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:5G及以上带宽SSD个数>=4个|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi
                fi
            else
                if [ $promise_bw -ge 1000 ] && [ $promise_bw -lt 2000 ];then
                    if [ ${ssd_qun:-0} -lt 3  ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:1-2G带宽SSD个数>=3|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 2000 ] && [ $promise_bw -lt 3000 ];then
                    if [ ${ssd_qun:-0} -lt 4  ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:2-3G带宽SSD个数>=4|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 3000 ] && [ $promise_bw -lt 4000 ];then
                    if [ ${ssd_qun:-0} -lt 5  ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:3-4G带宽SSD个数>=5|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi

                elif [ $promise_bw -ge 4000 ];then
                    if [ ${ssd_qun:-0} -lt 6  ];then
                        func_display_message "warning" "检查项:带宽大小对应硬件配置|检查结果:warning|要求:4G及以上带宽SSD个数>=6|当前:带宽[${promise_bw}Mbps]配置[${phy_summ}]|处理建议:非官方建议最佳配置,建议用户参考最佳配置调整."
                    fi
                fi
            fi
        else
            func_display_message "fail" "检查项:数据盘|检查结果:fail|要求:需要一定数据盘缓存|当前:[${phy_summ}]|处理建议:未检测到数据盘,建议用户参考最佳配置调整."
            tag_code=1
        fi
    fi
}


# 3.网络检查:带宽压测
func_comm_bw_stress(){
   
    # 判断网络类型专线or汇聚 
    code=$(curl -sL  http://127.0.0.1:5981/api/pppoeConfig | jq -r .code)
    wget -q -O /tmp/speedtest http://tw15b0178.onething.net:9090/tool/scripts/speedtest

    if [ ${code} -eq 20001 ] || [ ${code} -eq 20003 ];then
        # 专线资源压测
        nic=$(route -n | grep "^0.0.0.0" | awk '{print$NF}' | head -n 1)
        
        # 上行压测
        echo "业务网卡|线路带宽(Mbps)|上行压测带宽(Mbps)|上线行压测丢包率" >> ${workdir}/press_tx.result
        /tmp/speedtest tx --quiet --json --bind_nic ${nic} ${promise_bw}Mb 20s > ${workdir}/${nic}_press_tx.json
        tx_bw=$(cat ${workdir}/${nic}_press_tx.json | jq -r '.SendNicBitps' | awk '{print int($0/1000/1000)}')
        tx_drop_rate=$(cat ${workdir}/${nic}_press_tx.json | jq -r '.DropRate' | awk '{printf "%.2f\n",$0}' )
        echo "${nic}|${promise_bw}|${tx_bw}|${tx_drop_rate}" >> ${workdir}/press_tx.result

        # 下行压测
        echo "业务网卡|线路带宽(Mbps)|下行压测带宽(Mbps)|下行压测丢包率" >> ${workdir}/press_rx.result
        /tmp/speedtest rx --quiet  --json --bind_nic ${nic} --line_bw  ${promise_bw}Mb --duration 20s > ${workdir}/${nic}_press_rx.json
        rx_bw=$(cat ${workdir}/${nic}_press_rx.json | jq -r '.RecvNicBitps' | head -n1 | awk '{print int($0/1000/1000)}')
        rx_drop_rate=$(cat ${workdir}/${nic}_press_rx.json | jq -r '.DropRate' | head -n1 | awk '{printf "%.2f\n",$0}' )
        echo "${nic}|${promise_bw}|${rx_bw}|${rx_drop_rate}" >> ${workdir}/press_rx.result
    else
        # 汇聚资源
        wget -O ${workdir}/diagnose_new.py http://tw15b0178.onething.net:9090/tool/diagnose_new.py &>/dev/null && chmod +x ${workdir}/diagnose_new.py
        /usr/bin/python2.7 ${workdir}/diagnose_new.py > ${workdir}/diagnose.log
        # 检查连接状态异常线路
        code_col=$(awk -F'|' 'NR==4 {for(i=1;i<=NF;i++) if($i=="CODE") print i}' ${workdir}/diagnose.log)
        if [ $(cat ${workdir}/diagnose.log | awk -F'|' -v col=$code_col 'NR>4 && $col != 0' | wc -l) -ne 0 ];then
            func_display_message "fail" "检查项:线路检查|检查结果:fail|要求:线路保持在线|当前:以下线路异常|处理建议:请联系用户处理." 
            awk 'NR==4' ${workdir}/diagnose.log
            cat ${workdir}/diagnose.log | awk -F'|' -v col=$code_col 'NR>4 && $col != 0'
            tag_code=1
        fi

        # 上行压测 
        echo "业务网卡|线路带宽(Mbps)|上行压测带宽(Mbps)|上行压测丢包率" >> ${workdir}/press_tx.result
        IFS=$'\n'
        for i in $( cat ${workdir}/diagnose.log | awk -F'|' 'NR >4 {print$3"|"$NF}');do
            {
	        nic=$(echo $i | awk -F'|' '{print$1}')
	        bw=$(echo $i | awk -F'|' '{print$2}')
		/tmp/speedtest tx --quiet --json --bind_nic ${nic} ${bw}Mb 20s > ${workdir}/${nic}_press_tx.json
		tx_bw=$(cat ${workdir}/${nic}_press_tx.json | jq -r '.SendNicBitps' | awk '{print int($0/1000/1000)}')
		tx_drop_rate=$(cat ${workdir}/${nic}_press_tx.json | jq -r '.DropRate' | awk '{printf "%.2f\n",$0}' )
		echo "${nic}|${bw}|${tx_bw}|${tx_drop_rate}" >> ${workdir}/press_tx.result
	    }&
        done
        wait
        unset IFS

        # 下行压测
        echo "业务网卡|线路带宽(Mbps)|下行压测带宽(Mbps)|下行压测丢包率" >> ${workdir}/press_rx.result
        IFS=$'\n'
        for i in $( cat ${workdir}/diagnose.log | awk -F'|' 'NR >4 {print$3"|"$NF}');do
            {
                nic=$(echo $i | awk -F'|' '{print$1}')
                bw=$(echo $i | awk -F'|' '{print$2}')
                /tmp/speedtest rx --quiet  --json --bind_nic ${nic} --line_bw  ${bw}Mb --duration 20s > ${workdir}/${nic}_press_rx.json
                rx_bw=$(cat ${workdir}/${nic}_press_rx.json | jq -r '.RecvNicBitps' | head -n1 | awk '{print int($0/1000/1000)}')
                rx_drop_rate=$(cat ${workdir}/${nic}_press_rx.json | jq -r '.DropRate' | head -n1 | awk '{printf "%.2f\n",$0}' )
                echo "${nic}|${bw}|${rx_bw}|${rx_drop_rate}" >> ${workdir}/press_rx.result
            }&
        done
        wait
        unset IFS
    fi

    # 检查网络压测结果
    if [ $(cat ${workdir}/press_tx.result | awk -F'|' 'NR>1 && $3 < $2*0.8' | wc -l ) -ne 0 ];then
        func_display_message "fail" "检查项:上行带宽压测|检查结果:fail|要求:>=80%承诺带宽|当前:以下线路不合格|处理建议:请联系用户处理,如当前本身跑有业务流量,请下线后压测."
        head -n 1 ${workdir}/press_tx.result
        cat ${workdir}/press_tx.result | awk -F '|' 'NR>1 && $3 < $2*0.8'
        tag_code=1
    fi

    if [ $(cat ${workdir}/press_tx.result | awk -F'|' 'NR>1 && int($NF) >= 5' | wc -l ) -ne 0 ];then
        func_display_message "fail" "检查项:上行带宽压测|检查结果:fail|要求:丢包<=5%|当前:以下线路不合格|处理建议:请联系用户处理,如当前本身跑有业务流量,请下线后压测."
        head -n 1 ${workdir}/press_tx.result
        cat ${workdir}/press_tx.result | awk -F'|' 'NR>1 && int($NF) >= 5'
    fi    

    if [ $(cat ${workdir}/press_rx.result | awk -F'|' 'NR>1 && $3 < $2*0.2' | wc -l ) -ne 0 ];then
        func_display_message "fail" "检查项:下行带宽压测|检查结果:fail|要求:>=20%承诺带宽|当前:以下线路不合格|处理建议:请联系用户处理,如当前本身跑有业务流量,请下线后压测."
        head -n 1 ${workdir}/press_tx.result
        cat ${workdir}/press_rx.result | awk -F'|' 'NR>1 && $3 < $2*0.2'
        tag_code=1
    fi

    if [ $(cat ${workdir}/press_rx.result | awk -F'|' 'NR>1 && int($NF) >= 5' | wc -l ) -ne 0 ];then
        func_display_message "fail" "检查项:下行带宽压测|检查结果:fail|要求:丢包<=5%|当前:以下线路不合格|处理建议:请联系用户处理,如当前本身跑有业务流量,请下线后压测."
        head -n 1 ${workdir}/press_rx.result
        cat ${workdir}/press_rx.result | awk -F'|' 'NR>1 && int($NF) >= 5'
        tag_code=1
    fi
}

# 3.网络检查:网络简单ping测试
func_comm_ping_test(){
    # 检查主机丢包情况
    domains=( "www.aliyun.com" "www.baidu.com" "www.qq.com" "www.jd.com" ) 
    total_loss=0
    count=0 

    for domain in "${domains[@]}"; do
        result=$(ping -c 10 $domain | grep 'packet loss' | awk '{print $6}' | tr -d '%')
        if [ "$result" != "" ]; then
            total_loss=$(echo "$total_loss + $result" | bc)
            ((count++))
        fi
    done

    if [ "$count" -gt 0 ]; then
        average_loss=$(echo "scale=2; $total_loss / $count" | bc)
        awk -v n1="${average_loss}" 'BEGIN { if (int(n1) > 5 ) exit 0; else exit 1 }'
        [ $? -eq 0 ] && func_display_message "fail" "检查项:PING测丢包|检查结果:fail|要求:丢包率<5%|当前:丢包率[${average_loss}%]|处理建议:请联系用户处理."
    fi 
}

# 3.网络检查:检查出口轮巡
func_comm_cklx(){
   lines=$(curl -sL http://127.0.0.1:5981/api/pppoeStatus | jq -r '.data.multidial | map(select(.errcode == 0)) | length')
   if [ $lines -gt 1 ];then
       cklx=$(for i in `seq 50`;do curl -sL myip.ipip.net ;done | sort | uniq -c | wc -l)
       if [ ${cklx} -le 1 ];then
           func_display_message "fail" "检查项:出口轮巡|检查结果:fail|要求:线路负载均衡|当前:在线线路数量[$lines]出口IP统计[$cklx]|处理建议:请查看内控PPPOE负载均衡模式是否打开."
           tag_code=1
       fi 
   fi
}

# 3.网络检查:检查内网
func_comm_check_lan(){
    landev=$(ip -br -c a  | grep -v lan0 | grep UP | grep  "10.0.[0-9]*.[0-9]*" | awk '{print$1}')
    if [ -n "${landev}" ] ;then
        # 检查内网卡速率
        lan_speed=$(ethtool ${landev} | grep Speed | awk -F":" '{print$2}' | tr -cd '0-9')
        if [ ${lan_speed} -lt 10000 ];then
            func_display_message "fail" "检查项:集群内网|检查结果:fail|要求:万兆内网|当前:内网网卡速率[${lan_speed}]|处理建议:请联系用户处理."
            tag_code=1
        fi
        
        # 检查内网是否互联
        command  -v  fping >/dev/null 2>&1 || apt -y install fping > /dev/null 2>&1
        lan_ip_range=$(ip -br -c a show dev ${landev} | grep -o "10.0.[0-9]*")
        fping -g "${lan_ip_range}.0/24" > /dev/null 2>&1
        if [ $(arp -a -n | grep -v "incomplete" | grep -c ${lan_ip_range}) -eq 0 ];then
            func_display_message "fail" "检查项:集群内网|检查结果:fail|要求:万兆内网互联|当前:内网互联不通|处理建议:请联系用户处理."
            tag_code=1
        fi
    fi
   
    # 检查内网是否掉线
    if [ -e /etc/global_env_new.json ];then
        inner_ip=$(cat /etc/global_env_new.json |jq -r .inner_ip.IPv4[0])
        if [ $(ifconfig | grep -wc ${inner_ip}) -eq 0 ];then
            func_display_message "fail" "检查项:集群内网是否在线|检查结果:fail|要求:保持内网IP在线|当前:未检测到内网IP[${inner_ip}]|处理建议:请重新配置内网IP."
            tag_code=1
        fi
    fi
}

# 3.nat类型探测
func_nat_type_check(){
    iptables -I INPUT 1 -p udp -m multiport --dports 50000:50100 -m comment --comment "NAT_TYPE_DETECTION" -j ACCEPT
    if [ ! -e /tmp/natclient-1.0.3-300c4b21-20231013191842-x86/natclient ];then
        wget -O /tmp/natclient-1.0.3-300c4b21-20231013191842-x86.tar.gz http://tw15b0178.onething.net:9090/tool/natclient-1.0.3-300c4b21-20231013191842-x86.tar.gz > /dev/null 2>&1 
        tar xf /tmp/natclient-1.0.3-300c4b21-20231013191842-x86.tar.gz -C /tmp
    fi
    echo '网卡|IP|出口IP|NAT类型' > ${workdir}/nat_type_detection.log
    if [ ${resource_type} -eq 1 ];then
        # 专线资源
        nic=$(route -n | grep "^0.0.0.0" | awk '{print$NF}' | head -n 1)
        /tmp/natclient-1.0.3-300c4b21-20231013191842-x86/natclient --nic ${nic} --bind_min_port 50000 --bind_max_port 50100 | jq -r '"\(.nic)|\(.ip)|\(.nat_cip)|\(.udp_nat)"' >> ${workdir}/nat_type_detection.log
    else
        nic=$(awk -F'|' 'NR >1 {print$1}' ${workdir}/press_rx.result)
        for i in ${nic};do 
            /tmp/natclient-1.0.3-300c4b21-20231013191842-x86/natclient --nic ${i} --bind_min_port 50000 --bind_max_port 50100 | jq -r '"\(.nic)|\(.ip)|\(.nat_cip)|\(.udp_nat)"' >> ${workdir}/nat_type_detection.log
        done
    fi
    iptables -D INPUT -p udp -m multiport --dports 50000:50100 -m comment --comment "NAT_TYPE_DETECTION" -j ACCEPT
    nat_type_code_count=$(awk -F"|" '$NF == 3 || $NF == 4 || $NF == 5 {count++} END {print count? count:0}' ${workdir}/nat_type_detection.log)
    if [ ${nat_type_code_count} -ne 0 ];then
        func_display_message "fail" "检查项:nat类型|检查结果:fail|要求:全锥型以上|当前:以下不符合标准|处理建议:请联系用户处理."
        awk -F'|' ' \
	    BEGIN { \
    	    nat_type_array[0] = "未知"; \
            nat_type_array[1] = "卓越公网"; \
            nat_type_array[2] = "全锥型"; \
            nat_type_array[3] = "IP限制型"; \
            nat_type_array[4] = "端口限制型"; \
            nat_type_array[5] = "对称型"; \
            nat_type_array[6] = "DMZ公网"; \
            nat_type_array[7] = "映射公网"; \
        } \
            NR == 1 || $NF == 3 || $NF == 4 || $NF == 5 { \
            if ($NF in nat_type_array ){ 
                print $1"|"$2"|"$3"|"nat_type_array[$NF]; \
            } else { \
                print $0
            }
        }' ${workdir}/nat_type_detection.log
    fi 
}

# 3.业务端口探测
func_port_check(){
    func_check_port(){
        nic=$1
        wanip=$2  
        port=$3
        curl -s -o /dev/null "${wanip}:$port"
        if [ $? -eq 0 ]; then
            echo "${nic}|${wanip}|${port}|ok" >> ${workdir}/port_check.log
        else
            echo "${nic}|${wanip}|${port}|fail" >> ${workdir}/port_check.log
        fi
    }

    lsof -iTCP -sTCP:LISTEN -P | grep -q 8888
    if [ $? -eq 0 ];then
        echo "nic|wanip|port|status" > ${workdir}/port_check.log
        tail -n +2 "${workdir}/nat_type_detection.log" | while IFS='|' read -r nic innerip nat_cip udp_nat;do
            if [ ${udp_nat} -eq 1 ] || [ ${udp_nat} -eq 6 ] || [ ${udp_nat} -eq 7 ];then
                func_check_port $nic $nat_cip 8888
                func_check_port $nic $nat_cip 8889
                func_check_port $nic $nat_cip 9928
            fi
        done
        port_status_count=$(cat ${workdir}/port_check.log | awk -F'|' '$NF == "fail" {count++} END {print count? count:0}')
        if [ ${port_status_count} -ne 0 ];then
            func_display_message "fail" "检查项:业务端口连通性|检查结果:fail|要求:业务端口可连接|当前:下面线路端口不合格|处理建议:请联系用户处理."
            cat ${workdir}/port_check.log | awk -F'|' 'NR >1 || $NF == "fail" {print$0}'
            tag_code=1
        fi
    else
        func_display_message "fail" "检查项:业务端口监听|检查结果:fail|要求:业务端口监听状态|当前:端口未监听|处理建议:业务程序未部署,请检查节点当前外控状态."
        tag_code=1
    fi 
}

# main函数
func_acceptance_main(){
   
    # 提示
    echo "主机名:${wxhostname}|字节主机名:${zjhostname:-null},正在检测中,可能需要几分钟..."

    # 状态检查
    func_sgp_status_code
    func_delivery_schedule
    func_cscm_status
    func_capacity_check

    # 硬件检查
    func_comm_check_hardware_log
    func_comm_check_hardware_detailed

    # 网络检查
    func_comm_bw_stress
    func_comm_ping_test
    [ ${resource_type} -eq 0 ] &&  func_comm_cklx
    [ ${resource_type} -eq 1 ] &&  func_comm_check_lan
    func_nat_type_check 
    func_port_check

    # 检查结论
    if [ ${tag_code} -eq 0 ];then
        func_display_message "ok" "检查结果:ok|处理建议:内部检查未发现严重异常,请在字节客户群中报障."
    else
        func_display_message "warning" "检查结果:warning|处理建议:请将检查结果为fail的检查项参考处理建议进行修复,请修复后再次尝试."
    fi
}

# 脚本执行入口
func_acceptance_main

