#!/bin/bash

# set -x
function wait_other() {
    local cmd=$1
    for i in {0..30};do
        ps -e|grep -q $cmd
        if [[ $? -ne 0 ]];then
            return 0
        fi
        sleep 1
    done
    error_quit "other '$cmd' still running"
}

function get_cache() {
    local cmd=$@
    local pname=$(basename $(echo "$1"|awk '{print $1}'))
    local cache_name="monitor_"`echo $*|tr ' ' '_'|tr '/' '_'|sed 's/[:,]//g'`
    local cache_file=/dev/shm/$cache_name
    local cache_time='0'
    local code=0

    wait_other $pname

    if [[ -f $cache_file ]];then
        cache_time=`stat -c %Z $cache_file`
    fi
    if [[ $(($(date +%s) - $cache_time)) -gt 300 ]];then
        $cmd > $cache_file
        code=$?
    fi
    cat $cache_file

    return $code
}

function check_cmd_exist() {
    local cmd=$1
    type $cmd > /dev/null 2>&1 || {
        echo >&2 "require command [$cmd] but it's not installed. Aborting."
        exit 1
    }
}

function collect_pmc_raid_info() {
    check_cmd_exist $CMD_LSPCI

    if [[ $(lspci|grep Adaptec|grep -c "RAID bus controller") -ne 0 ]];then
        RaidType="PMC_RAID"
    elif [[ $(lspci -v|grep -a1 Adaptec|grep "Subsystem"|grep -c c460) -ne 0 ]];then
        RaidType="PMC_RAID"
    fi

    if [[ $RaidType = 'PMC_RAID' ]];then
        # echo pmc_count: $pmc_count
        pmc_raid_collect $@
    else
        # echo "Can not Support this device"
        exit 1;
    fi
}

CMD_ARCCONF="get_cache arcconf"
CMD_LSPCI="get_cache lspci"
RAID_TYPE="PMC"

function join_string() {
    local arr=("${!2}")
    local result=$(printf "$1%s" "${arr[@]}")
    result=${result:1}
    echo -n $result
}

function get_value() {
    local ori_str="$1"
    local trim_cmd="awk"
    if [ $# -gt 1 ] && [ "$2" != " " ]; then
        trim_cmd="$trim_cmd -F$2"
    fi

    local result=$($trim_cmd '{
        gsub(/^[ \t]+/, "", $2);
        gsub(/[ \t]+$/, "", $2);
        print $2}' <<< "$ori_str")
    echo -n $result
}

function pmc_raid_ctrl() {
    #{{Physical Slot}}:{{Controller Serial Number}}:{{Controller Status|Health}}
    local flag=$1
    local controllers=$(get_controller)
    local result=()
    local total=0
    for controller in ${controllers[@]}; do
        local item=()
        local result=$($CMD_ARCCONF getconfig $controller ad)
        item[0]=$(get_value "$(grep "Physical Slot" <<< "$result")" ":")
        item[1]=$(get_value "$(grep "Controller Serial Number" <<< "$result")" ":")

        case "$flag" in
            status)
                item[2]=$(get_value "$(grep "Controller Status" <<< "$result")" ":")
                if [ "${item[2]}" == "Optimal" ];then
                    value=0
                else
                    value=1
                fi
                ;;
            battery)
                item[2]=$(get_value "$(grep "Health" <<< "$result")" ":" | awk '{print $1}')
                value="${item[2]}"
                ;;
            *) # unsupport flag
                exit 1
                ;;
            esac
        result[$total]='{"value": '$value', "tags": "raid_type='$RAID_TYPE',slot='${item[0]}',controller_sn='${item[1]}',result='${item[2]}'"}'
        ((total++))
    done
    local res=$(join_string "," result[@])
    echo -n "[$res]"
}

function get_controller() {
    controller_out=$($CMD_ARCCONF list | egrep "Controller [0-9]+" | awk -F: '{print $1}' | awk '{print $2}')
    echo $controller_out
}

function pmc_raid_physical() {
    local controllers=$(get_controller)
    local result=()
    local total=0
    local disks=()
    local i=0
    # 获取控制器上的设备信息，放入device_infos数组中
    for controller in ${controllers[@]}; do
        local r=$($CMD_ARCCONF getconfig $controller PD | sed -n -e '/Device #/,/^$/p')
        device_infos=()
        n=0
        while read line; do
            if [[ -z "$line" ]];then
                ((n++))
                continue
            fi
            device_infos[$n]=`echo -e "${device_infos[$n]}\n$line"`
        done <<< "$r"
        # 过滤掉非磁盘设备
        m=0
        pd_infos=()
        OLD_IFS=$IFS
        IFS=$'\n'
        i=0
        while [ $i -lt ${#device_infos[@]} ];do
            while read l; do
                if [[ -n $(echo "$l" | grep "Device is a Hard drive") ]];then
                    pd_infos[$m]="${device_infos[$i]}"
                    ((m++))
                    break
                fi
            done <<< "${device_infos[$i]}"
            ((i++))
        done
        # 处理每个磁盘的信息
        i=0
        while [ $i -lt ${#pd_infos[@]} ];do
            local pd_info_kv=`awk -F: 'NF>=2 {gsub(/^[ \t]+/, "", $1);
                    gsub(/[ \t]+$/, "", $1);
                    gsub(/^[ \t]+/, "", $2);
                    printf("%s\t%s\n", $1, $2)}'  <<< "${pd_infos[$i]}"`
            IFS=$'\n'
            local item=()
            while read li; do
                if [[ -n $li ]];then
                    IFS=$OLD_IFS
                    local key=$(get_key "$li" '\t')
                    local value=$(get_val "$li" '\t')
                    case $key in
                        "Reported Location")
                            local enclosure=$(echo $value | awk -F, '{print $1}' | awk '{print $2}')
                            item[0]=$enclosure
                            local slot=$(echo $value | awk -F, '{print $2}' | sed 's/(.*)//g' | awk '{print $2}')
                            item[1]=$slot
                            ;;
                        "Total Size")
                            item[2]=$(echo $value | sed 's/\s//g')
                            ;;
                        "State")
                            item[3]=$value
                            ;;
                    esac
                fi
            done <<< "$pd_info_kv"
            if [ -z "${item[2]}" ]; then
                item[3]=""
            fi
            if [ "${item[3]}" == "Online" ];then
                value=0
            else
                value=1
            fi

            local subresult='{"value": '$value', "tags": "raid_type='$RAID_TYPE',controller='$controller',enclosure='${item[0]}',slot='${item[1]}',size='${item[2]}'"}'
            result[$total]=$subresult
            ((total++))
            ((i++))
        done
        IFS=$OLD_IFS
        #echo ${pd_infos[1]}
        #echo ${#pd_infos[@]}
    done
    local res=$(join_string "," result[@])
    echo -n "[$res]"
}

function pmc_raid_logical() {
    local controllers=($(get_controller))
    local total=0
    for controller in ${controllers[@]}; do
        local r=$($CMD_ARCCONF getconfig $controller LD | sed -n -e '/Logical Device number/,/^$/p')
        logic_infos=()
        n=0
        while read line; do
            if [[ -z "$line" ]];then
                ((n++))
                continue
            fi
            logic_infos[$n]=`echo -e "${logic_infos[$n]}\n$line"`
        done <<< "$r"
        # 处理每个逻辑盘的信息
        i=0
        while [ $i -lt ${#logic_infos[@]} ];do
            item=()
            ld_number=$(echo "${logic_infos[$i]}" | grep "Logical Device number" | awk '{print $4}')
            item[0]=$ld_number
            local ld_info_kv=`awk -F: 'NF>=2 {gsub(/^[ \t]+/, "", $1);
                gsub(/[ \t]+$/, "", $1);
                gsub(/^[ \t]+/, "", $2);
                printf("%s\t%s\n", $1, $2)}'  <<< "${logic_infos[$i]}"`

            while read li; do
                if [[ -n $li ]];then
                    local key=$(get_key "$li" '\t')
                    local value=$(get_val "$li" '\t')
                    case $key in
                        "RAID level")
                            item[1]=$value
                            ;;
                        "Size")
                            item[2]=$(echo $value | sed 's/\s//g')
                            ;;
                        "Status of Logical Device")
                            item[3]=$value
                            ;;
                    esac
                fi
            done <<< "$ld_info_kv"
            if [ "${item[3]}" == "Optimal" ];then
                value=0
            else
                value=1
            fi

            local subresult='{"value": '$value', "tags": "raid_type='$RAID_TYPE',controller='$controller',ld_num='${item[0]}',raid_level='${item[1]}',size='${item[2]}'"}'
            result[$total]=$subresult
            ((total++))
            ((i++))
        done
    done
    local res=$(join_string "," result[@])
    echo -n "[$res]"
}

function pmc_check_rebuild() {
    local controllers=($(get_controller))
    if [ ! -e /tmp/rebuild_check.log ];then
        touch /tmp/rebuild_check.log
    fi

    for controller in ${controllers[@]}; do
        CHECK_REBUILD=`$CMD_ARCCONF getstatus $controller | grep "Rebuild"`
        if [ $? -eq 0 ];then
            unixtime_now=`date +%s`
            if [ ! -s /tmp/rebuild_check.log ];then
                echo $unixtime_now > /tmp/rebuild_check.log
                echo -n '[{"value": 0, "tags": "raid_type='$RAID_TYPE',rebuild_too_long=not"}]'
            else
                old_time=`cat < /tmp/rebuild_check.log`
                duration=`expr $unixtime_now - $old_time`
                if [ $duration -ge 54000 ]; then
                    echo -n '[{"value": 1, "tags": "raid_type='$RAID_TYPE',rebuild_too_long=yes"}]'
                    rm -f /tmp/rebuild_check.log
                else
                    echo -n '[{"value": 0, "tags": "raid_type='$RAID_TYPE',rebuild_too_long=not"}]'
                fi
            fi
        else
            if [ -s /tmp/rebuild_check.log ];then
                rm -f /tmp/rebuild_check.log
            fi
            echo -n '[{"value": 0, "tags": "raid_type='$RAID_TYPE',rebuild_too_long=not"}]'
        fi
    done
}

function get_key_or_val() {
    local ori_str="$1"
    local cmd="awk"
    local index=2
    if [ $# -gt 1 ]; then
        index=$2
    fi

    if [ $# -gt 2 ]; then
        cmd="$cmd -F$3"
    fi

    echo $($cmd -v idx=$index '{
        gsub(/^[ \t]+/, "", $idx);
        gsub(/[ \t]+$/, "", $idx);
        print $idx;}' <<< "$ori_str")
}

function get_val() {
    local ori_str="$1"
    local split_char=$2
    get_key_or_val "$ori_str" 2 $split_char
}

function get_key() {
    local ori_str="$1"
    local split_char=$2
    get_key_or_val "$ori_str" 1 $split_char
}

# controller: -c [status | battery]
# physical drive: -p
# logic drive: -l
function pmc_raid_collect() {
    check_cmd_exist $CMD_ARCCONF
    
    while getopts pc:lr o; do
        case "$o" in
            c)
                local opt=$OPTARG
                pmc_raid_ctrl $opt
                ;;
            p)
                pmc_raid_physical
                ;;
            l)
                pmc_raid_logical
                ;;
            r)
                pmc_check_rebuild
                ;;
            *)
                exit 1
                ;;
            esac
        done
}

collect_pmc_raid_info $@
