#! /bin/bash
#
# This is a bash wrapper around ipmitool to provide the same interface
# like the fence_ipmilan tool from the fence-agents package how it is used
# by cobbler.
#
# It read options via STDIN. Commandline parameter are not supported.
#
# action=<on, off, reboot, status>
# login=<user>
# passwd=<password>
# ipaddr=<IP or hostname>
#
# It tries first to use "lanplus" interface. If this is not supported,
# it switches to "lan" interface

CMD=""
STATE_OFF=96
STATE_ON=92
POWER_WAIT=5
DEBUG="no"
PROTOCOL="lanplus"

function ipmi_op() {
    local action="$1"
    local ret=1
    local msg=""

    CMD="/usr/bin/ipmitool -I $PROTOCOL -H '$ipaddr'"
    if [ -n "$login" ]; then
        CMD="$CMD -U '$login'"
    fi
    if [ -n "$passwd" ]; then
        CMD="$CMD -E"
        export IPMI_PASSWORD="$passwd"
    else
        CMD="$CMD -P ''"
    fi

    case "$action" in
        on)
            CMD="$CMD chassis power on"
            ;;
        off)
            CMD="$CMD chassis power off"
            ;;
        status)
            CMD="$CMD chassis power status"
            ;;
    esac

    test "$DEBUG" = "yes" && echo "DBG: EXEC $CMD" >&2
    msg=`eval $CMD`
    ret=$?
    unset IPMI_PASSWORD

    test "$DEBUG" = "yes" && echo "DBG: $msg : $ret" >&2
    echo "$msg"
    return $ret
}

function ipmi_on() {
    local ret=1
    local retries=7
    local msg=""

    ipmi_status
    ret=$?
    case $ret in
        $STATE_ON)
            return 0
            ;;
        $STATE_OFF)
            ;;
        *)
            return $ret
    esac

    while [ $retries -gt 0 ]; do
        msg=$(ipmi_op "on")
        ret=$?
        if [ "$ret" != "0" ]; then
            return $ret
        fi

        sleep $POWER_WAIT
        ((retries--))
        ipmi_status
        ret=$?
        case $ret in
            $STATE_OFF)
                ;;
            $STATE_ON)
                return 0
                ;;
            *)
                $retries=0
                ;;
        esac
    done
    echo "ipmilan: Power still off" >&2
    return $ret
}

function ipmi_off() {
    local ret=1
    local retries=7
    local msg=""

    ipmi_status
    ret=$?
    case $ret in
        $STATE_ON)
            ;;
        $STATE_OFF)
            return 0
            ;;
        *)
            return $ret
    esac

    while [ $retries -gt 0 ]; do
        msg=$(ipmi_op "off")
        ret=$?
        if [ "$ret" != "0" ]; then
            return $ret
        fi

        sleep $POWER_WAIT
        ((retries--))
        ipmi_status
        ret=$?
        case $ret in
            $STATE_OFF)
                return 0
                ;;
            $STATE_ON)
                ;;
            *)
                $retries=0
                ;;
        esac
    done
    echo "ipmilan: Power still on" >&2
    return $ret
}

export -f ipmi_op

function ipmi_status() {
    local msg=""
    local ret=1

    msg=`ipmi_op "status"`
    ret=$?

    if [ "$ret" != "0" ]; then
        return 1
    fi
    if echo "$msg" | grep -i "Chassis Power is on" >/dev/null 2>&1; then
        return $STATE_ON
    fi
    if echo "$msg" | grep -i "Chassis Power is off" >/dev/null 2>&1; then
        return $STATE_OFF
    fi
    return 1
}


while read -t 2 -r line
do
    key="${line%%=*}"
    val=`echo "${line##*=}" | sed "s/'/'\\\\\''/g"`
    test "$DEBUG" = "yes" && echo "$key='$val'" >&2
    eval "$key='$val'"
done

test "$DEBUG" = "yes" && echo "action=$action" >&2
test "$DEBUG" = "yes" && echo "login=$login" >&2
test "$DEBUG" = "yes" && echo "passwd=$passwd" >&2
test "$DEBUG" = "yes" && echo "ipaddr=$ipaddr" >&2
test "$DEBUG" = "yes" && echo "port=$port" >&2

if [ -z "$ipaddr" ]; then
    echo "no IP address specified" >&2
    exit 1
fi

if [ "x$option" != "x" ]; then
    action="$option"
elif [ "x$operation" != "x" ]; then
    action="$operation"
elif [ "x$action" == "x" ]; then
    action="reboot"
fi

if [ "$action" != "on" -a "$action" != "off" -a \
     "$action" != "reboot" -a "$action" != "status" ]; then
     echo "operation must be 'on', 'off', 'status' or 'reboot'" >&2
     exit 1
fi

if [ ! -e "/usr/bin/ipmitool" ]; then
    echo "ipmitool not found!" >&2
    echo "Initialization failed" >&2
    exit 1
fi

code=1
# protocol test
ipmi_status
if [ "$?" == "1" ]; then
    # Error: lets switch to lan protocol
    PROTOCOL="lan"
fi

case "$action" in
    reboot)
        ipmi_off
        code=$?
        if [ "$code" != "0" ]; then
            exit 1
        fi
        ipmi_on
        code=$?
        ;;
    on)
        ipmi_on
        code=$?
        ;;
    off)
        ipmi_off
        code=$?
        ;;
    status)
        ipmi_status
        code=$?
        case $code in
            $STATE_ON)
                echo "Chassis power = On"
                exit 0
                ;;
            $STATE_OFF)
                echo "Chassis power = Off"
                exit 2
                ;;
            *)
                echo "Chassis power = Unknown"
                exit 1
                ;;
        esac
        ;;
esac

if [ "$code" == "0" ]; then
    echo "Done"
else
    echo "Failed"
fi

exit $ret

