#!/bin/sh
#
# External STONITH module using IP Power 9258 or compatible devices.
#
# Copyright (c) 2010 Helmut Weymann (Helmut (at) h-weymann (dot) de)
# 
# 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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
# Warning:
#
#   Aviosys provides different types and versions of IP Power 9258. 
#   Especially IP Power 9258 HP uses a new http interface.
#   This script was tested with firmware version: V1.55 2009/12/22
#
# Documentation: 
#
#   Manufacturer URL: http://www.aviosys.com/ippower9258.htm
#   Manual URL: http://www.aviosys.com/manual.htm
#   Manual current version URL: http://www.aviosys.com/images/9258_manual_20081104.pdf
#
#   The documentation of the http command interface defines three supported commands:
#
#   GetPower          - useful for testing status of the device and of each port
#   SetPower          - used to control status of each port
#   SetSchedule+Power - useless for stonith
#
#   Common documented structure of these three commands is
#
#       http://username:password@a.b.c.d/Set.cmd?CMD=command[+param=value...]
#       param is one or more of P60 to P67 and value is 0 or 1
#       expected response for GetPower is of the format
#       <html>P60=1,P61=0,P62=1,P63=1,P64=0,P65=0,P66=0,P67=0</html>
#       SetPower does respond with the same format but restricts the list to the modified ports.
#
#   There is no documented http command to retrieve the port names via the http command interface.
#   The device is currently available with four or eight power outlets. This script assumes a one to one mapping 
#   between names of hostlist and port attributes of power outlet:
#
#	1st hostname in hostlist connected to 1st power outlet with port status P60 and port name pw1Name.
#	...
#	8th hostname in hostlist connected to 8th power outlet with port status P67 and port name pw8Name.
#
#   IP Power 9258 allows to assign port names (pw1Name to pw8Name) to each port. These names can be used
#   with the web interface (web form with post-method /tgi/iocontrol.tgi) and
#   with the program interface available for windows.
#   P60 to P67 represent the status of the power outlet 1 to 8: 0 <=> power off; 1 <=> power on.
#
#   Script specific documentation
#
#   This script actually allows any number of hostnames in the hostlist.
#   A reserved hostname is NULL. This is intended as a placeholder for unused outlets.
#
#   Basic parameters

DEVICE="IP Power 9258"
IPPowerOn="1"
IPPowerOff="0"
IPGetPower="Set.cmd?CMD=GetPower"
IPSetPower="Set.cmd?CMD=SetPower"
IPPort_name="P"
IPPort0=60
HTTP_COMMAND="wget -q -O - --"

#
# prepare environment and parameters
#
# Rewrite the hostlist to accept "," as a delimeter for hostnames too.
# copied from external/ssh
hostlist=`echo $hostlist | tr ',' ' '`
# standard device username is admin. IP Power 9258 does not allow user management.
if [ "X${username}" = "X" ]
then
  username="admin"
fi

#
# script functions
#

send_request() {
# ececution of http commands supported by the device
	$HTTP_COMMAND "http://${username}:${password}@${deviceip}/${1}"
}

resolve_name_to_port() {
# translate hostname to port P6x (x:0...7)
	i=`expr $IPPort0`
        port="invalid"
	for h in $hostlist ; do
		if [ $h = ${1} ]
                then
                   port="$IPPort_name"$i
                fi
                i=`expr $i + 1`
	done
	echo $port
}

set_port() {
# port status is always set. Even if requested status is current status.
# host status is not considered.
	host=${1}
	status=${2} # 0 or 1
	port=`resolve_name_to_port ${host}`;
        if [ "${host}" = "NULL" ]
        then
            exit 1
        fi
        if [ "${port}" = "invalid" ]
        then
            exit 1
        fi
	ret=`send_request "$IPSetPower+${port}=${status}" | cut -b 11`
        if [ "${ret}" != "${status}" ]
        then
            exit 1
        fi
}

get_status() {
# status is ony invalid if no response is caught. Bad responses are not discovered.
	ret=`send_request "$IPGetPower"`
        if [ "X${ret}" = "X" ]
        then
            exit 1
        fi
}

#
# the script
#

case ${1} in
gethosts)
	# copied from external/ssh
	for h in $hostlist ; do
		echo $h
	done
	exit 0
	;;
on)
	host=${2}
        set_port ${host} $IPPowerOn
	exit 0
	;;
off)
	host=${2}
        set_port ${host} $IPPowerOff
	exit 0
	;;
reset)
	host=${2}
	set_port ${host} $IPPowerOff
	sleep 5
	set_port ${host} $IPPowerOn
	
	exit 0
	;;
status)
	# try to fetch the status of the port to see if we can stonith.
	get_status
	exit 0
	;;
getconfignames)
	# return all the config names
	for ipparam in deviceip password hostlist username
	do
		echo ${ipparam}
	done;
	exit 0
	;;
getinfo-devid)
	echo "IP Power 9258"
	exit 0
	;;
getinfo-devname)
	echo "IP Power 9258 power switch"
	exit 0
	;;
getinfo-devdescr)
	echo "Power switch IP Power 9258 with 4 or 8 power outlets. WARNING: It is different from IP Power 9258 HP"
	exit 0
	;;
getinfo-devurl)
	echo "http://www.aviosys.com/manual.htm"
	exit 0
	;;
getinfo-xml)
	cat << IPPOWERXML
<parameters>
<parameter name="deviceip" unique="1" required="1">
<content type="string" />
<shortdesc lang="en">
Device IP address or hostname
</shortdesc>
<longdesc lang="en">
The IP Address or the hostname of the device.
</longdesc>
</parameter>

<parameter name="password" unique="1" required="1">
<content type="string" />
<shortdesc lang="en">
Password
</shortdesc>
<longdesc lang="en">
The password to log in with.
</longdesc>
</parameter>

<parameter name="hostlist" unique="1" required="1">
<content type="string" />
<shortdesc lang="en">
Hostlist
</shortdesc>
<longdesc lang="en">
The list of hosts that the device controls.
The list must be in the same order as the power outlets. 
Unused power outlets can have the name NULL.
</longdesc>
</parameter>

<parameter name="username" unique="1" required="0">
<content type="string" />
<shortdesc lang="en">
Account Name
</shortdesc>
<longdesc lang="en">
The user to log in with. Default username is admin.
</longdesc>
</parameter>

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

