#!/bin/sh

export PATH=/bin/:/sbin:/usr/bin/:/usr/sbin:/usr/local/sbin/:/usr/local/bin/:$PATH
timestamp=$(date +%Y%m%d%H%M%S)
[ ! -e /tmp/server_hw_deliver/${timestamp} ] && mkdir -p  /tmp/server_hw_deliver/${timestamp}
[ ! -e /var/lock/server_hw_deliver ] && mkdir -p /var/lock/server_hw_deliver
workdir="/tmp/server_hw_deliver/${timestamp}"
hwsn=$(dmidecode  -t 1 | grep "Serial Number" | awk -F ":" '{print$2}')

#定义一个颜色输出字符串函数
echo_color(){
    case $1 in
        green)
            echo -e "\033[32m[ OK ] $2\033[0m"
            ;;
        red)
            #echo -e "\033[31m\033[01m\033[05m$2\033[0m"
            echo -e  "\033[31m\033[01m[FAIL] $2\033[0m"
            ;;
        yellow)
            echo -e "\033[33m[WARN] $2\033[0m"
            ;;
        *)
            echo "Example: echo_color red string"
    esac
}

# 定义一个退出打印语句
echo_sayno(){
    echo_color red  "result:${hwsn}==========>已退出,请检查后重试!!!"
}


# 判断安装镜像
if [ -e /etc/redhat-release ];then
    os_ver=1
elif [ -e  /etc/debian_version ];then
    os_ver=2
else 
    echo_color red "result:${hwsn}==========>未知镜像系统!"
    echo_sayno && exit 110  
fi

# 1.基础配置
basic_setup(){

    # 配置dns
    if [ ${os_ver} -eq 1 ];then 
        ping -c 3 -w 3 www.xunlei.com &>/dev/null
        if [ $? -ne 0 ];then
            echo -e 'nameserver 114.114.114.114' > /etc/resolv.conf
            ping -c 3 -w 3 www.xunlei.com &>/dev/null
            if [ $? -ne 0 ];then
                echo_color red "result:${hwsn}==========>1.1-外网不通!"
                echo_sayno && exit 110
            fi
        fi
    fi

    # 配置软件源
    if [ ! -e /var/lock/server_hw_deliver/yum.pid ];then
        if [ ${os_ver} -eq 1 ];then
            command  -v wget &>/dev/null || yum  -y install  wget &>/dev/null
            mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_backup_`date +%F-%H-%M-%S`
            wget http://centos.yum.sandai.net/.help/CentOS-Base7.repo -O /etc/yum.repos.d/CentOS-Base.repo -o /dev/null &>/dev/null
            rpm -ivh http://centos.yum.sandai.net/epel/epel-release-latest-7.noarch.rpm  &>/dev/null
            mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo_backup_`date +%F-%H-%M-%S`
            wget http://centos.yum.sandai.net/.help/epel7.repo -O /etc/yum.repos.d/epel.repo -o /dev/null &>/dev/null
            wget http://centos.yum.sandai.net/epel/RPM-GPG-KEY-EPEL-7 -O /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 -o /dev/null &>/dev/null
            yum clean all &>/dev/null
            yum makecache &>/dev/null

            #安装基础软件包
            yum install epel-release -y &>/dev/null
            yum -y install bc fio jq &>/dev/null
            if [ $? -ne 0 ];then
                echo_color red "result:${hwsn}==========>1.2-软件源配置失败!"
                echo_sayno && exit 110
            else
               touch /var/lock/server_hw_deliver/yum.pid
            fi
        elif [ ${os_ver} -eq 2 ];then 
            apt-get update &>/dev/null
            apt install -y fio bc jq &>/dev/null 2>/dev/null
            if [ $? -ne 0 ];then
               echo_color red "result:${hwsn}==========>1.2-软件源配置失败!"
               echo_sayno && exit 110
            else
              touch /var/lock/server_hw_deliver/yum.pid
            fi
        fi
    fi
  
    echo_color green "result:${hwsn}==========>1-基础环境必要软件包安装完成!"
}

# 2 检查CPU
check_cpu(){
    
    check_cpu_sno=0

    # 检查CPU性能模式
    CUR_MHz=$(lscpu | grep 'CPU MHz' | awk '{print$NF}')
    PHY_MHz=$(lscpu | grep 'Model name' | awk '{print$NF}')
    if [ $(cat /proc/cpuinfo | grep  -i mhz | sort | uniq | wc -l) -ne 1 ];then
        echo_color yellow  "result:${hwsn}==========>2.1-CPU高性能非最佳模式,非必选,建议调整![当前频率:${CUR_MHz} 标准频率:${PHY_MHz}]"
        check_cpu_sno=1
    fi
    
    # CPU压测5分钟
    cpu_press(){
        CPU_NUM=`grep processor /proc/cpuinfo|wc -l`
        CPU_NUM_TEST=$(echo ${CPU_NUM} | awk '{print int($0*9/10)}') 
        for i in `seq $CPU_NUM_TEST`;do
            {
                echo "scale=16;$i/39"|bc -l &>/dev/null
                echo "scale=3000; 4*a(1)"|bc -l &>/dev/null
            }&
        done
        wait
    }
 
    LIMITTIME=$(echo $(date +%s) + 300 | bc)
    while true;do
        CURTIME=`date +%s`
        [ ${CURTIME} -gt ${LIMITTIME} ] && break
        cpu_press
    done

    # 检查cpu错误日志 
    if [ $(grep -c 'Machine check events' /var/log/messages) -ne 0 ];then
        echo_color red "result:${hwsn}==========>2.2-CPU存在mce错误日志!"
        check_cpu_sno=1
        echo > /var/log/messages
    fi
 
    if [ ${check_cpu_sno} -eq 0 ];then
         echo_color green  "result:${hwsn}==========>2-CPU检测通过!"
    fi
}

# 3 检查内存
check_mem(){

    check_mem_sno=0    
 
    # 压测内存
    mem_press(){
        total_mem=$(cat /proc/meminfo  | awk '/MemTotal/ {print int($2/1024/1024*9/10)}')
        for i in `seq ${total_mem}`;do
            {
                if [ -d /tmp/memory$i ];then
	            rm -rf /tmp/memory$i/block
		    umount -f /tmp/memory$i
		    rm -rf /tmp/memory$i
	        else
		    mkdir /tmp/memory$i
		    mount -t tmpfs -o size=1G tmpfs /tmp/memory$i
		    dd if=/dev/zero of=/tmp/memory$i/block bs=1M count=1024 &>/dev/null
		    rm -rf /tmp/memory$i/block
		    umount /tmp/memory$i
		    rmdir /tmp/memory$i
	        fi
	} &
	done
	wait  
   }

   LIMITTIME=$(echo $(date +%s) + 300 | bc)
   while true;do
       CURTIME=`date +%s`
       [ ${CURTIME} -gt ${LIMITTIME} ] && break
       mem_press
    done
 
   # 检查内存检测校验包
   if [ -d /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>0 {print$0}')
       if [ -n "${mem_ce_error_num}" ];then
           echo_color yellow "result:${hwsn}==========>3.1-内存存在CE错误日志!\n[${mem_ce_error}]"
           check_mem_sno=1
       fi
   else 
       echo_color yellow "result:${hwsn}==========>3.1-驱动模块不支持Edac,请升级固件驱动尝试!"
       check_mem_sno=1   
 
   fi 
 
 
   if [ ${check_mem_sno} -eq  0 ];then
       echo_color green  "result:${hwsn}==========>3-内存检测通过!"
   fi

}


# 4检测磁盘性能
check_disk(){

    check_disk_sno=0
    
    # 检测数据磁盘可写
    #sys_disk=$(mount | grep -w '/' | awk '{print$1}' | awk -F '/' '{print$NF}' | sed s/[0-9]//g)
    #data_disk=$(lsblk  | grep -E "^s|^n" | awk '{print$1}' | grep -Ev "${sys_disk}|sr0")
    sys_disk=$(lsblk -l| egrep -B 1 "/$|boot|swap" | awk '{print $1}'| egrep -v "luks|lvm|--" | sed -e '/sd/s/[0-9]//' -e '/nvme/s/p[0-9]//' -e '/vd/s/[0-9]//'|sort|uniq)
    #
    lsblk |grep "disk" |egrep -v "sr|fd|${sys_disk}" |awk '{print $1}' |sort |uniq > /tmp/fdisk_txt
    for m in ${sys_disk};do
            sed -i "/$m/d" /tmp/fdisk_txt
    done
    data_disk=$(cat /tmp/fdisk_txt)
    if [ -n "${data_disk}" ];then
        for i in  ${data_disk};do
            timeout 60 dd if=/dev/zero of=/dev/${i} bs=1M count=1000 &>/dev/null
            if [ $? -ne 0 ];then
                echo_color red "result:${hwsn}==========>4.1-${i}数据盘不可写,请检查后再试!"
                check_disk_sno=1
            fi
    done
    fi

    # 删除数据盘的逻辑卷或软raid
    #if [ $(lsblk -l | egrep -v "${sys_disk}" | grep -c lvm) -ne 0 ] ;then
    #     lvs |grep -v LV|awk '{print "lvremove -f /dev/"$2"/"$1}'| sh &>/dev/null                                                                                
    #    vgs |grep -v VG |awk '{print "vgremove -f "$1}'| sh &>/dev/null                                                                                         
    #    pvs |grep -v PV|awk '{print "pvremove -f "$1}'| sh &>/dev/null                                                                                          
    #elif [ $(lsblk -l | egrep -v "${sys_disk}"| grep -c raid) -ne 0 ];then
    #    dmsetup remove_all &>/dev/null
    #fi 
    #for i in  ${data_disk};do
    #    if [ $(lsblk -l /dev/${i} | grep -c LVM) -ne 0 ];then
    #
    #    elif [ $(lsblk -l /dev/${i}| grep -c raid) -ne 0];then 

    #    fi
    #done

    # 测试磁盘性能
    disk_press(){
        dev=${i}
        press_time=300
        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=${press_time} -output-format=json -rw=randread -thread -time_base > ${workdir}/${dev}.json
            read_iops=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.iops' | awk '{print int($0)}')
            read_lat_ns=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.lat_ns.mean' | awk '{print int($0/1000000)}')
            if [ ${read_iops} -lt  30000 ];then 
                echo_color red "result:${hwsn}==========>4.2-${i}系统盘不合格,要求读IOPS大于30000."
                check_disk_sno=1
            fi
            if [ ${read_lat_ns} -ge 5 ];then 
                echo_color red "result:${hwsn}==========>4.3-${i}系统盘不合格,要求读awit小于5毫秒."
                check_disk_sno=1
            fi
            
        else
            fio -direct=1 -ioengine=libaio -iodepth=32 -bs=4k -size=4G -filename=/dev/${dev} -name=/${dev}/fiotest -runtime=${press_time} -output-format=json -rw=randrw -rwmixread=80 -thread -time_base > ${workdir}/${dev}.json
            read_iops=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.iops' | awk '{print int($0)}')
            write_iops=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].write.iops' | awk '{print int($0)}')
            read_lat_ns=$(cat ${workdir}/${dev}.json | jq '.jobs|.[].read.lat_ns.mean' | awk '{print int($0/1000000)}')
            vol=$(lsblk -b | grep  "^${dev}" | awk '{print int($4/1000/1000/1000)}')       
            
            if [ ${read_iops} -gt 2000 ];then
                # SSD
                if [ ${read_iops} -lt 30000 ];then     
                    echo_color red "result:${hwsn}==========>4.4-${i}数据盘SSD不合格,要求读IOPS大于30000."
                    check_disk_sno=1
                fi
                if [ ${write_iops} -lt 8000 ];then     
                    echo_color red "result:${hwsn}==========>4.5-${i}数据盘SSD不合格,要求写IOPS大于8000."
                    check_disk_sno=1
                fi
                if [ ${read_lat_ns} -gt 5 ];then     
                    echo_color red "result:${hwsn}==========>4.6-${i}数据盘SSD不合格,要求读await小于5毫秒."
                    check_disk_sno=1
                fi   
                echo "SSD ${dev} ${vol}" >> ${workdir}/data_disk_list.log
            else
                # HDD
                if [ ${read_iops} -lt 100 ];then     
                    echo_color yellow "result:${hwsn}==========>4.7-${i}数据盘HDD不合格,要求读IOPS大于100."
                    check_disk_sno=1
                fi
                if [ ${write_iops} -lt 20 ];then     
                    echo_color red "result:${hwsn}==========>4.8-${i}数据盘HDD不合格,要求写IOPS大于20."
                    check_disk_sno=1
                fi
                if [ ${read_lat_ns} -gt 150 ];then     
                    echo_color red "result:${hwsn}==========>4.9-${i}数据盘HDD不合格,要求读await小于200毫秒."
                    check_disk_sno=1
                fi        
                echo "HDD ${dev} ${vol}" >> ${workdir}/data_disk_list.log
            fi 
        fi   
    }
    
    # 批量测试硬盘
    all_disk=$(lsblk |  grep -E  "^sd|^n" | awk '{print$1}' | sort)
    for i in  ${all_disk};do
        disk_press ${i} &
        num=$(ps aux | grep fio|grep -v grep|wc -l)
        while [ $num -ge 6 ];do
            sleep 3;
            num=$(ps aux | grep fio|grep -v grep|wc -l)
        done
    done
    wait
    
    if [ $(echo ${check_disk_sno}) -eq 0 ];then
        echo_color green "result:${hwsn}==========>4-磁盘检测通过!" 
    fi
}


# 2.4检验硬件配置，入门配置20c+32G+120GSSD系统盘+2*1TSSD + 数据盘
check_hardware(){

    check_hardware_sno=0
    
    cpu_threads=$(lscpu | grep "^CPU(s)" | awk '{print$2}')
    # 内存
    mem_total=$(cat /proc/meminfo | grep MemTotal | awk '{print int($2/1024/1024)}')
    # 硬盘
    disk_sys_drive=$(mount | grep -w "\/" | awk -F"[/ ]" '{print$3}' | sed s#[0-9]##g)
    disk_sys_drive_capacity=$(lsblk -b | grep "^${disk_sys_drive}" | awk '{print int($4/1000/1000/1000)}')
    ssd_vol=$(cat ${workdir}/data_disk_list.log 2>/dev/null | grep "^SSD" | awk '{sum+= $3} END{print int(sum)}')
    hdd_vol=$(cat ${workdir}/data_disk_list.log 2>/dev/null | grep "^HDD" | awk '{sum+= $3} END{print int(sum)}')
    ssd_phy=$(cat ${workdir}/data_disk_list.log 2>/dev/null | 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)
    phy_summ=$(echo "cpu:${cpu_threads}c+内存:${mem_total}g+系统盘:1*${disk_sys_drive_capacity}GSSD+数据盘:SSD:${ssd_phy:-"0"} HDD:${hdd_phy:-"0"}")
   
      
    if [ $(echo ${disk_sys_drive:-'N/A'} | grep -c sda) -eq 0 ];then
        echo_color red "result:${hwsn}==========>5.1-系统盘符非sda：当前系统盘符：[${disk_sys_drive}]"
        check_hardware_sno=1
    fi
  
    
    if [ ${disk_sys_drive_capacity:-0} -lt 100 ];then
        echo_color red "result:${hwsn}==========>5.2-硬件最低配置检测不通过! 系统盘容量小于120G.当前配置：[${phy_summ}]"
        check_hardware_sno=1
    fi

    if [ ${check_hardware_sno} -eq 0 ];then
        echo_color green "result:${hwsn}==========>5-硬件配置检测通过!当前配置：[${phy_summ}]"
    fi
}

#2.5检查网卡速率
check_network(){
   
    check_network_sno=0    

    net_dev=$(cat /proc/net/dev | grep -vE "tun|face|lo|Inter|ppp|docker|galaxy|virbr|macvlan|docker0|docker0|edge-hub-dummy|Bond|bond" | awk -F":" '{print$1}' | sed s/[[:space:]]//g | sort)
    for i in $(echo ${net_dev});do
        #net_dev_speed=$(ethtool ${i} | grep Speed| sed s/[^[:digit:]]//g)
        net_dev_speed=$(ethtool ${i} |grep base|tail -1|grep -Eo "[0-9]+")
        net_dev_comb=$(ethtool -l ${i} |  grep Combined |  head -n1 |awk -F":" '{print$2}'|sed s/[[:space:]]//g)
        net_dev_type=$(ethtool $i | grep 'Supported ports' | awk '{print $(NF-1)}' | grep -c TP)
        [ ${net_dev_type} -ne 0 ] && net_ports="电口" || net_ports="光口"
        #net_ports=$(ethtool $i | grep 'Supported ports' | awk '{print $(NF-1)}')
        if [ ${net_dev_comb:-0} -lt 8 ];then
            echo_color red "result:${hwsn}==========>6.1-网卡队列数检测不通过! 要求不少于8.当前配置：[${i}:${net_dev_comb:-0}]"
            check_network_sno=1
        fi
        echo "${net_dev_speed}Mbps ${net_ports}" >> ${workdir}/net_list.log 
    done
   
    all_net_dev=$(cat ${workdir}/net_list.log | sort -n | uniq -c | sed 's/^[ ]*//g' | sed s/' '/*/ | sed s/[[:space:]]//g|awk BEGIN{RS=EOF}'{gsub(/\n/," ");print}')
    
    if [ ${check_network_sno} -eq 0 ];then
        echo_color green "result:${hwsn}==========>6-网卡检查通过!当前配置：[${all_net_dev}]"
    fi
}

# 检查dmesg日志
check_sys_log(){
    dmesg_log=$(dmesg  | grep -iE "error" | grep -v "ERST")
    if [ -z "${dmesg_log}" ];then
        echo_color green "result:${hwsn}==========>7-dmesg日志检查通过!"
        
    else
        echo_color red "result:${hwsn}==========>7-dmesg日志存在硬件错误，请检查！日志：\n[${dmesg_log}]"
    fi  
    dmesg -C 
}


# 5.1清除临时文件
clear_temp_file() {
    cd /tmp
    rm -rf ./init
    echo_color green "result:${hwsn}==========>8-清除临时文件完毕!"
}

# 5.2重启服务器
host_reboot(){
    sync;sync;sync
    #echo_color green "result:${hwsn}==========>9-主机已重启!"
    echo_color green "result:${hwsn}==========>9-硬件检查完毕,请手动执行reboot命令重启主机,检查是否重启成功!!!"
    #reboot
}


# 0 主函数
main(){
   
    echo_color green "result:${hwsn}==========>0-开始检测中，请等待5~10分钟!"
   
    # 环境检查
    basic_setup

    # 具体检测
    check_cpu
    check_mem
    check_disk
    check_hardware
    check_network
    check_sys_log
    
    # 清理临时文件
    clear_temp_file
    host_reboot
}

# 执行入口
main
