#!/usr/bin/bash
# /usr/libexec/scoutfs-fenced/run/ipmi-remote-host

# ipmi configuration
SCOUTFS_IPMI_CONFIG_FILE=${SCOUTFS_IPMI_CONFIG_FILE:-/etc/scoutfs/scoutfs-ipmi.conf}
SCOUTFS_IPMI_HOSTS_FILE=${SCOUTFS_IPMI_HOSTS_FILE:-/etc/scoutfs/scoutfs-ipmi-hosts.conf}

## hosts file format
## SCOUTFS_HOST_IP IPMI_ADDRESS
## ex:
#  192.168.1.1     192.168.10.1

# command setup
IPMI_POWER="/sbin/ipmipower"
SSH_CMD="ssh -o ConnectTimeout=3 -o BatchMode=yes -o StrictHostKeyChecking=no"
LOGGER="/bin/logger -p local3.crit -t scoutfs-fenced"

$LOGGER "ipmi fence script invoked: IP: $SCOUTFS_FENCED_REQ_IP RID: $SCOUTFS_FENCED_REQ_RID TEST: $IPMITEST"

echo_fail() {
    echo "$@" >&2
    $LOGGER "fence failed: $@"
    exit 1
}

echo_log() {
    echo "$@" >&2
    $LOGGER "fence info: $@"
}

echo_test_pass() {
    echo -e "\xE2\x9C\x94 $@"
}

echo_test_fail() {
    echo -e "\xE2\x9D\x8C $@"
}

test -n "$SCOUTFS_IPMI_CONFIG_FILE" || \
    echo_fail "SCOUTFS_IPMI_CONFIG_FILE isn't set"
test -r "$SCOUTFS_IPMI_CONFIG_FILE" || \
    echo_fail "$SCOUTFS_IPMI_CONFIG_FILE isn't readable file"
. "$SCOUTFS_IPMI_CONFIG_FILE"
test -n "$SCOUTFS_IPMI_HOSTS_FILE" || \
    echo_fail "SCOUTFS_IPMI_HOSTS_FILE isn't set"
test -r "$SCOUTFS_IPMI_HOSTS_FILE" || \
    echo_fail "$SCOUTFS_IPMI_HOSTS_FILE isn't readable file"
test -x "$IPMI_POWER" || \
    echo_fail "$IPMI_POWER not found, need to install freeimpi?"

export ip="$SCOUTFS_FENCED_REQ_IP"
export rid="$SCOUTFS_FENCED_REQ_RID"

getIPMIhost () {
    host=$(awk -v ip="$1" '$1 == ip {print $2}' "$SCOUTFS_IPMI_HOSTS_FILE") || \
        echo_fail "lookup ipmi host failed"
    echo "$host"
}

powerOffHost() {
    # older versions of ipmipower inverted wait-until-off/wait-until-on, so specify both
    $IPMI_POWER $IPMI_OPTS -h "$1" --wait-until-off --wait-until-on --off || \
        echo_fail "ipmi power off $1 failed"

    ipmioutput=$($IPMI_POWER $IPMI_OPTS -h "$1" --stat) || \
        echo_fail "ipmi power stat $1 failed"

    if [[ ! "$ipmioutput" =~ off ]]; then
        echo_fail "ipmi stat $1 not off"
    fi

    $LOGGER "ipmi fence power down $1 success"

    exit 0
}

if [ -n "$IPMITEST" ]; then
    for i in $(awk '!/^($|[[:space:]]*#)/ {print $1}' "$SCOUTFS_IPMI_HOSTS_FILE"); do
        if ! $SSH_CMD "$i" /bin/true; then
            echo_test_fail "ssh $i"
        else
            echo_test_pass "ssh $i"
        fi
	host=$(getIPMIhost "$i")
        if [ -z "$host" ]; then
            echo_test_fail "ipmi config $i $host"
        else
            if ! $IPMI_POWER $IPMI_OPTS -h "$host" --stat; then
                echo_test_fail "ipmi $i"
            else
                echo_test_pass "ipmi $i"
            fi
        fi
    done
    exit 0
fi

if [ -z "$ip" ]; then
    echo_fail "no IP given for fencing"
fi

host=$(getIPMIhost "$ip")
if [ -z "$host" ]; then
    echo_fail "no IPMI host found for fence IP"
fi

# first check via ssh if the mount still exists
# if ssh succeeds, we will only power down the node if mounted
if ! output=$($SSH_CMD "$ip" "echo BEGIN; LC_ALL=C egrep -m 1 '(^0x*|^$rid$)' /sys/kernel/boot_params/version /sys/fs/scoutfs/f*r*/rid; echo END"); then
    # ssh not working, just power down host
    powerOffHost "$host"
fi

if [[ ! "$output" =~ BEGIN ]]; then
    # ssh failure
    echo_log "no BEGIN"
    powerOffHost "$host"
fi

if [[ ! "$output" =~ \/boot_params\/ ]]; then
    # ssh failure
    echo_log "no boot params"
    powerOffHost "$host"
fi

if [[ ! "$output" =~ END ]]; then
    # ssh failure
    echo_log "no END"
    powerOffHost "$host"
fi

if [[ "$output" =~ "rid:$rid" ]]; then
    # rid still mounted, power down
    echo_log "rid $rid still mounted"
    powerOffHost "$host"
fi

$LOGGER "ipmi fence host $ip/$host success (rid $rid not mounted)"
exit 0

