#!/bin/bash

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
}

# Current Raid type
card_type=''

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;
    }
}

CMD_SMARTCTL="get_cache smartctl"

function get_disk_info() {
    local sn=$1
    local key=$2

    if [[ $card_type = 'lsi_hba_2x' ]];then
        get_sas2ircu_info $sn $key
    elif [[ $card_type = 'lsi_hba_3x' ]];then
        get_sas3ircu_info $sn $key
    elif [[ $card_type = 'lsi_raid' ]];then
        get_storcli_info $sn $key
    elif [[ $card_type = 'pmc_hba' ]];then
        get_arcconf_info $sn $key
    else
        error_quit "Can not Support this card type '$card_type'"
    fi
        
}

function get_sas3ircu_info() {
    local sn=$1
    local key=$2

    local fullinfo=`get_cache /opt/op/sas3ircu 0 display`
    local info=`echo "$fullinfo"|grep $sn -B8 -A3`

    echo "$info"|grep "$key"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'

}

function get_sas2ircu_info() {
    local sn=$1
    local key=$2

    local fullinfo=`get_cache /opt/op/sas2ircu 0 display`
    local info=`echo "$fullinfo"|grep $sn -B8 -A3`

    echo "$info"|grep "$key"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'

    return $code
}

function get_storcli_info() {
    local sn=$1
    local key=$2

    local fullinfo=`get_cache /opt/MegaRAID/storcli/storcli64 /c0/eall/sall show all`
    local info=`echo "$fullinfo"|grep $sn -B2`
    eid=`echo "$info"|sed -n 's/.*\/e\([0-9]*\)\/.*/\1/p'`
    sid=`echo "$info"|sed -n 's/.*\/s\([0-9]*\) .*/\1/p'`
    if [[ $key == 'Enclosure' ]];then
        echo $eid
    elif [[ $key == 'Slot' ]];then
        echo $sid
    elif [[ $key == 'State' ]];then
        echo "$fullinfo"|grep "^$eid:$sid"|awk '{print $3}'
    fi

    return $code
}

function get_arcconf_info() {
    local sn=$1
    local key=$2

    local fullinfo=`get_cache arcconf getconfig 1 pd nodiskinfo`
    local info=`echo "$fullinfo"|grep $sn -B11 -A29`

    if [[ $key = 'Enclosure' ]];then
        local location=`echo "$info"|grep 'Reported Location'|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'`
        echo "$location"|sed "s/Enclosure \([0-9]*\),.*/\1/"
    elif [[ $key = 'Slot' ]];then
        local location=`echo "$info"|grep 'Reported Location'|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'`
        echo "$location"|sed "s/.*Slot \([0-9]*\).*/\1/"
    else
        echo "$info"|grep "$key"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'
    fi

    return $code
}

function get_volume_status() {
    if [[ $card_type = 'lsi_hba_2x' ]];then
        local fullinfo=`get_cache /opt/op/sas2ircu 0 display`
        local info=`echo "$fullinfo"|grep 'IR Volume information' -A9`
        local volume_status=`echo "$info"|grep "Status of volume"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'`
    elif [[ $card_type = 'lsi_hba_3x' ]];then
        local fullinfo=`get_cache /opt/op/sas3ircu 0 display`
        local info=`echo "$fullinfo"|grep 'IR Volume information' -A9`
        local volume_status=`echo "$info"|grep "Status of volume"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'`
    elif [[ $card_type = 'lsi_raid' ]];then
        local fullinfo=`get_cache /opt/MegaRAID/storcli/storcli64 /c0/vall show`
        local info=`echo "$fullinfo"|grep 'RAID'`
        local volume_status=`echo "$info"|awk '{print $3}'`
    elif [[ $card_type = 'pmc_hba' ]];then
        local fullinfo=`get_cache arcconf getconfig 1 ld nodiskinfo`
        local volume_status=`echo "$fullinfo"|grep "Status of Logical Device"|awk -F":" '{gsub(/^[ \t]+/,"",$2);gsub(/[ \t]+$/,"",$2);print $2}'`
    else
        error_quit "Can not Support this card type '$card_type'"
    fi
    if [[ $volume_status =~ "Okay" || $volume_status =~ "Optimal" || $volume_status =~ "Optl" ]];then
        value=0
    else
        value=1
    fi

    if [[ -n $volume_status ]];then
        echo '[{"value": '$value', "tags": "disk=/dev/sda"}]'
    fi

}


function error_quit() {
    echo "$1" > /dev/null 2>&1
    exit 1
}

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 join_string() {
    local arr=("${!2}")
    local result=$(printf "$1%s" "${arr[@]}")
    result=${result:1}
    echo -n $result
}

# detect vm
function detect_vm() {
    `cat /proc/cpuinfo | grep 'flags' | grep -q 'hypervisor'`
    if [ $? -eq 0 ]; then
        error_quit "Not Support VM"
    fi
}

# execute
function hba_status() {
    local flag=$1
    local full_result=()
    local result
    local i=0

    local disks=`lsscsi|grep disk|grep ATA|grep -E "/dev/[s]da?[a-z]"|awk '{print $NF}'`

    # valid physical disk not found
    if [ -z "$disks" ]; then
        error_quit "No physical disk found!"
    fi

    # ignore sda
    ignore_sda=(/dev/sda)
    disks=("${disks[@]/$ignore_sda}")


    check_cmd_exist $CMD_SMARTCTL

    if [ $? -ne 0 ]; then
        break
    fi
    for disk in ${disks[@]}; do
        local disk_sn=$(get_sn $disk)
        local Enclosure_Device_ID=$(get_disk_info $disk_sn 'Enclosure')
        local Slot_ID=$(get_disk_info $disk_sn 'Slot')

        case "$flag" in
            udma)
                result=`$CMD_SMARTCTL -a $disk| grep "UDMA_CRC_Error_Count" | awk '{print $NF}'`
                ;;
            pending)
                result=`$CMD_SMARTCTL -a $disk| grep "Current_Pending_Sector" | awk '{print $NF}'`
                ;;
            reallocated)
                result=`$CMD_SMARTCTL -a $disk | grep "Reallocated_Sector_Ct" | awk '{print $NF}'`
                ;;
            temperature_celsius)
                result=`$CMD_SMARTCTL -a $disk | grep "Temperature_Celsius" | sed 's/(.*)//' | awk '{print $NF}'`
                ;;
            smart_health)
                result=`$CMD_SMARTCTL -a $disk| grep "SMART overall-health" | awk '{print $NF}'`
                if [[ $result == "PASSED" ]];then
                    local value=0
                else
                    local value=1
                fi
                result=$value
                ;;
            state)
                result=`get_disk_info $sn 'State'`
                if [[ $result =~ "Optimal" || $result =~ 'Ready' || $result =~ 'Present' || $result =~ 'Onln' || $result =~ 'Standby' ]];then
                    local value=0
                else
                    local value=1
                fi
                result=$value
                ;;
            *)
                exit 1
                ;;
            esac
        full_result[i]='{"value": '$result', "tags": "Enclosure_Device_ID='$Enclosure_Device_ID',slot='$Slot_ID',disk='$disk'"}'
        ((i++))
    done

    local hb_col=$(join_string "," full_result[@])

    echo -n "[$hb_col]"
}

function get_sn() {
    local disk=$1

    local result=`$CMD_SMARTCTL -a $disk | grep 'Serial Number:' | awk -F':' '{print $2}' | sed 's/ //g'`
    result=`sed 's/-//g' <<< $result`

    echo -n $result
}

function collect_raid_info() {
    detect_vm

    if [[ `get_cache lspci` =~ 'RAID bus controller' ]];then
        error_quit "Can not Support this device"
        #local card=`get_cache lspci|grep 'RAID bus controller'`
        ### 3408是HBA卡，但按照RAID卡使用strorcli工具
        #if [[ $card =~ '3408' ]];then
        #    card_type='lsi_raid'
        #else
        #    error_quit "Can not Support this device"
        #fi
    else
        local card=`get_cache lspci|grep 'Serial Attached SCSI controller:'`
        if [[ $? -eq 0 ]];then
            if [[ $card =~ '2308' || $card =~ '2008' ]];then
                card_type='lsi_hba_2x'
            elif [[ $card =~ '3008' ]];then
                card_type='lsi_hba_3x'
            elif [[ $(lspci -v|grep -a1 Adaptec|grep "Subsystem"|grep -c "Adaptec SmartHBA") -ne 0 ]];then
                card_type='pmc_hba'
            elif [[ $(lspci -v|grep -a1 Adaptec|grep "Subsystem"|grep -c 8460) -ne 0 ]];then
                card_type='pmc_hba'
            elif [[ $(lspci -v|grep -a1 Adaptec|grep "Subsystem"|grep -c "HBA") -ne 0 ]];then
                card_type='pmc_hba'
            else
                error_quit "Can not Support this device: $card"
            fi
        else
            error_quit "Can not Support this device"
        fi
    fi

    while getopts s: o; do
        case "$o" in
            s)
                local opt=$OPTARG
                if [[ $opt = 'volume_status' ]];then
                    get_volume_status
                else
                    hba_status $opt
                fi
                ;;
            *)
                exit 1
                ;;
        esac
    done
}


collect_raid_info $@

