#!/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 error_quit() {
    echo "$1" > /dev/null 2>&1
    exit 1
}

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

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_hp_raid_info() {
    detect_vm

    check_cmd_exist $CMD_LSPCI

    local result=`$CMD_LSPCI`
    case $result in
        *"RAID"*)
            case $result in
                *"Hewlett-Packard Company"* )
                    hp_raid_collect $@
                    # echo "Can not Support this device: $g_cur_raid_type!" && exit 1;
                    ;;
                * )
                    # echo "Can not Support this device: $result"
                    exit 1;
                    ;;
            esac
            ;;
        * )
            # echo "Can not Support this device: $result" &&
            exit 1;
            ;;
    esac
}

CMD_HPSSACLI="get_cache ssacli"
CMD_LSPCI="get_cache lspci"

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
}

# status for request
function hp_raid_status() {
    local flag=$1
    local slots=$(get_slots)

    local status=()
    local i=0
    for slot in ${slots[@]}; do
        #hpssacli ctrl slot=0 show config detail
        local result=$($CMD_HPSSACLI ctrl slot=$slot show config detail)

        local slotstatus
        case "$flag" in
            ctrl)
                slotstatus=$(get_value "$(grep "Controller Status" <<< "$result")" ":")
                ;;
            cache)
                slotstatus=$(get_value "$(grep "Cache Status:" <<< "$result")" ":")
                ;;
            bc)
                slotstatus=$(get_value "$(grep "Battery/Capacitor Status" <<< "$result")" ":")
                ;;
            *) # unsupport flag
                exit 1
                ;;
            esac

        if [[ -z "$slotstatus" ]]; then
            # not found
            continue
        fi

        if [[ $slotstatus == "OK" ]];then
            status_result=0
        else
            status_result=1
        fi
        status[i]='{"value": '$status_result', "tags":"slot='$slot'"}'
        ((i++))
    done

    local laststatus=$(join_string "," status[@])
    echo -n "[$laststatus]"
}

# slot
function hp_raid_physical() {
    local slots=$(get_slots)
    local raid="HP"

    local pd_result=()
    local i=0
    for slot in ${slots[@]}; do
        #hpssacli ctrl slot=0 pd all show status
        local result=$($CMD_HPSSACLI ctrl slot=$slot pd all show status)
        local pd_info=$(grep "physicaldrive" <<< "$result")
        while read pd; do
            local s_pd=($pd) #physicaldrive 1I:1:1 (port 1I:box 1:bay 1, 1 TB): OK
            if [[ ${s_pd[8]} == "OK" ]];then
                value=0
            else
                value=1
            fi
            port=`echo ${s_pd[1]} | awk -F: '{print $1}'`
            box=`echo ${s_pd[1]} | awk -F: '{print $2}'`
            bay=`echo ${s_pd[1]} | awk -F: '{print $3}'`
            pd_result[i]='{"value": '$value', "tags": "raid_type='$raid',slot='$slot',port='$port',box='$box',bay='$bay',size='${s_pd[6]}${s_pd[7]::-2}'"}'
            ((i++))
        done <<< "$pd_info"
    done

	local pd_col=$(join_string "," pd_result[@])
	echo -n "[$pd_col]"
}

# slot
function hp_raid_logical() {
    local slots=$(get_slots)
    local raid="HP"

    local ld_result=()
    local i=0
    for slot in ${slots[@]}; do
        #hpssacli ctrl slot=0 ld all show status
        local result=$($CMD_HPSSACLI ctrl slot=$slot ld all show status)
        local ld_info=$(grep "logicaldrive" <<< "$result")

        while read ld; do
            local s_ld=($ld) #logicaldrive 1 (931.5 GB, 1): OK
            if [[ $ld =~ "OK" ]];then
                value=0
            else
                value=1
            fi

            ld_result[i]='{"value": '$value', "tags": "raid_type='$raid',number='${s_ld[1]}',slot='$slot'"}'
            ((i++))
        done <<< "$ld_info"
    done

    local ld_col=$(join_string "," ld_result[@])
    echo -n "[$ld_col]"
}

function hp_check_rebuild() {
	local slots=$(get_slots)
    local cr_result=()
    local raid="HP"
    local i=0
    local result

    for slot in ${slots[@]}; do
        local ld_status=`$CMD_HPSSACLI ctrl slot=$slot ld all show status`
        local ld_info=$(grep "logicaldrive" <<< "$ld_status")

        while read ld; do
            local s_ld=($ld)
            local CHECK_REBUILD=$(grep "Recovering" <<< "$s_ld")
            result=$(check_rebuild_log ${s_ld[1]} $CHECK_REBUILD)
            cr_result[i]='{"value": '$result', "tags":"raid_type='$raid',slot='$slot',number='${s_ld[1]}'"}'
            ((i++))
        done <<< "$ld_info"
    done

    local cr_col=$(join_string "," cr_result[@])
    echo -n "[$cr_col]"
}

function check_rebuild_log() {
    local disk=$1
    local command_result=$2
    local log_file="/tmp/rebuild_$slot_$disk"
    if [ ! -e $log_file ];then 
        touch $log_file
    fi

    if [[ ! -s $command_result ]];then
        unixtime_now=`date +%s`
        if [ ! -s $log_file ];then
            echo $unixtime_now > $log_file
            echo "0"
        else
            old_time=`cat < $log_file`
            duration=`expr $unixtime_now - $old_time`
            if [ $duration -ge 54000 ]; then
                echo "1"
                sed -i '1d' $log_file
            else
                echo "0"
            fi
        fi
    else
        if [[ -s $log_file ]];then
            sed -i '1d' $log_file
        fi
        echo "0"
    fi
}

function get_slots() {
    local result=$($CMD_HPSSACLI ctrl all show config detail)
        # get slot
    local slots=$(get_value "$(grep "Slot:" <<< "$result")" ":")
    echo -n $slots
}

# status: -s [ctrl | cache | bc]
# pd: -p
# ld: -l
function hp_raid_collect() {
    check_cmd_exist $CMD_HPSSACLI
    
    while getopts ps:lr o; do
        case "$o" in
            s)
                local opt=$OPTARG
                hp_raid_status $opt
                ;;
            p)
                hp_raid_physical
                ;;
            l)
                hp_raid_logical
                ;;
            r)
                hp_check_rebuild
                ;;
            *)
                exit 1
                ;;
            esac
        done
}

collect_hp_raid_info $@
