#!/bin/sh
#
# External STONITH module using IPMI.
# This modules uses uses the ipmitool program available from 
# http://ipmitool.sf.net/ for actual communication with the 
# managed device. 
#
# Copyright (c) 2007 Martin Bene <martin.bene@icomedias.com>
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

# Initialization -- fix locale settings so we can parse output from
# binaries if we need it
LANG=C
LC_ALL=C

RESET="power reset"
POWEROFF="power off"
POWERON="power on"
STATUS="power status"
IPMITOOL=${ipmitool:-"`which ipmitool 2>/dev/null`"}

have_ipmi() {
	test -x "${IPMITOOL}"
}

# Wrapper function for ipmitool that sets the correct host IP address,
# username, and password, and invokes ipmitool with any arguments
# passed in
run_ipmitool() {
	local ipmitool_opts privlvl=""
	have_ipmi || {
		ha_log.sh err "ipmitool not installed"
		return 1
	}
	if [ -z "${ipaddr}" -o -z "${userid}" -o -z "${passwd}" ]; then
		ha_log.sh err "ipaddr, userid or passwd missing; check configuration"
		return 1
	fi

	if [ -z "${interface}" ]; then
		# default to "lan" interface
		interface="lan"
	fi
	if [ -n "${priv}" ]; then
		# default to "lan" interface
		privlvl="-L $priv"
	fi

	ipmitool_opts="-I ${interface} -H ${ipaddr} $privlvl"

        case "${passwd_method}" in
            param|'')
                passwd_method=param
                M="-P"
                ;;
            env)
                M="-E"
                ;;
            file)
                M="-f"
                ;;
            *)
		ha_log.sh err "invalid passwd_method: \"${passwd_method}\""
		return 1
        esac

	action="$*"

        if [ $passwd_method = env ]
        then
            IPMI_PASSWORD="${passwd}" ${IPMITOOL} $ipmitool_opts -U "${userid}" -E ${action}
        else
            ${IPMITOOL} $ipmitool_opts -U "${userid}" $M "${passwd}" ${action}
        fi 2>&1
}

# Yet another convenience wrapper that invokes run_ipmitool, captures
# its output, logs the output, returns either 0 (on success) or 1 (on
# any error)
do_ipmi() {
	if outp=`run_ipmitool $*`; then
		ha_log.sh debug "ipmitool output: `echo $outp`"
		return 0
	else
		ha_log.sh err "error executing ipmitool: `echo $outp`"
		return 1
	fi
}

# Check if the managed node is powered on. To do so, issue the "power
# status" command. Should return either "Chassis Power is on" or
# "Chassis Power is off".
ipmi_is_power_on() {
	local outp
	outp=`run_ipmitool ${STATUS}`
	case "${outp}" in
	    *on)
		return 0
		;;
	    *off)
		return 1
		;;
	esac
}


case ${1} in
gethosts)
	echo $hostname
	exit 0
	;;
on)
	do_ipmi "${POWERON}"
	exit
	;;
off)
	do_ipmi "${POWEROFF}"
	exit
	;;
reset)
	if ipmi_is_power_on; then
		do_ipmi "${RESET}"
	else
		do_ipmi "${POWERON}"
	fi
	exit
	;;
status)
	# "status" reflects the status of the stonith _device_, not
	# the managed node. Hence, only check if we can contact the
	# IPMI device with "power status" command, don't pay attention
	# to whether the node is in fact powered on or off.
	do_ipmi "${STATUS}"
	exit $?
	;;
getconfignames)
	for i in hostname ipaddr userid passwd interface; do
		echo $i
	done
	exit 0
	;;
getinfo-devid)
	echo "IPMI STONITH device"
	exit 0
	;;
getinfo-devname)
	echo "IPMI STONITH external device"
	exit 0
	;;
getinfo-devdescr)
	echo "ipmitool based power management. Apparently, the power off"
	echo "method of ipmitool is intercepted by ACPI which then makes"
	echo "a regular shutdown. If case of a split brain on a two-node"
	echo "it may happen that no node survives. For two-node clusters"
	echo "use only the reset method."
	exit 0
	;;
getinfo-devurl)
	echo "http://ipmitool.sf.net/"
	exit 0
	;;
getinfo-xml)
	cat << IPMIXML
<parameters>
<parameter name="hostname" unique="1">
<content type="string" />
<shortdesc lang="en">
Hostname
</shortdesc>
<longdesc lang="en">
The name of the host to be managed by this STONITH device.
</longdesc>
</parameter>

<parameter name="ipaddr" unique="1">
<content type="string" />
<shortdesc lang="en">
IP Address
</shortdesc>
<longdesc lang="en">
The IP address of the STONITH device.
</longdesc>
</parameter>

<parameter name="userid" unique="0">
<content type="string" />
<shortdesc lang="en">
Login
</shortdesc>
<longdesc lang="en">
The username used for logging in to the STONITH device.
</longdesc>
</parameter>

<parameter name="passwd" unique="0">
<content type="string" />
<shortdesc lang="en">
Password
</shortdesc>
<longdesc lang="en">
The password used for logging in to the STONITH device.
</longdesc>
</parameter>

<parameter name="passwd_method" unique="0">
<content type="string" default="param"/>
<shortdesc lang="en">
Method for passing passwd parameter
</shortdesc>
<longdesc lang="en">
Method for passing the passwd parameter to ipmitool
  param: pass as parameter (-P)
  env:   pass via environment (-E)
  file:  value of "passwd" is actually a file name, pass with (-f)
</longdesc>
</parameter>

<parameter name="interface" unique="0">
<content type="string" default="lan"/>
<shortdesc lang="en">
IPMI interface
</shortdesc>
<longdesc lang="en">
IPMI interface to use, such as "lan" or "lanplus".
</longdesc>
</parameter>

<parameter name="priv" unique="0">
<content type="string" default=""/>
<shortdesc lang="en">
The privilege level of the user.
</shortdesc>
<longdesc lang="en">
The privilege level of the user, for instance OPERATOR. If
unspecified the privilege level is ADMINISTRATOR. See
ipmitool(1) -L option for more information.
</longdesc>
</parameter>

<parameter name="ipmitool" unique="0">
<content type="string" default=""/>
<shortdesc lang="en">
IPMI command(ipmitool) 
</shortdesc>
<longdesc lang="en">
Specify the full path to IPMI command.
</longdesc>
</parameter>

</parameters>
IPMIXML
	exit 0
	;;
*)
	exit 1
	;;
esac
