1#!/bin/sh
2#
3# External STONITH module for APC Switched Rack PDU
4#
5# Copyright (c) 2008 Sergey Maznichenko <msergeyb@gmail.com> <inbox@it-consultant.su>
6# Version 1.2
7#
8# See http://www.it-consultant.su/rackpdu
9# for additional information
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of version 2 of the GNU General Public License as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it would be useful, but
16# WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18#
19# Further, this software is distributed without any warranty that it is
20# free of the rightful claim of any third person regarding infringement
21# or the like.  Any license provided herein, whether implied or
22# otherwise, applies only to this software file.  Patent licenses, if
23# any, provided herein do not apply to combinations of this program with
24# other software, or any other product whatsoever.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program; if not, write the Free Software Foundation,
28# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
29#
30
31SWITCH_ON="1"
32SWITCH_OFF="2"
33SWITCH_RESET="3"
34
35DEFAULT_NAMES_OID=".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2"
36DEFAULT_COMMAND_OID=".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4"
37
38if [ -z "$oid" ]; then
39    oid=$DEFAULT_COMMAND_OID
40fi
41
42if [ -z "$names_oid" ]; then
43    names_oid=$DEFAULT_NAMES_OID
44fi
45
46if [ -z "$outlet_config" ]; then
47    outlet_config="none"
48fi
49
50GetOutletNumber() {
51    local nodename=$1
52
53    if [ "$outlet_config" != "none" ]; then
54	# Get outlet number from file
55
56	if [ -f "$outlet_config" ]; then
57    	    local outlet_num=`grep $nodename $outlet_config | tr -d ' ' | cut -f2 -d'='`
58	    if [ -z "$outlet_num" ]; then
59		ha_log.sh err "Outlet number not found for node $nodename. Check configuration file $outlet_config"
60		return 0
61	    fi
62	    return $outlet_num
63	else
64	    ha_log.sh err "File $outlet_config not found."
65	    return 0
66	fi
67    else
68	# Get outlet number from device
69
70	local outlet_num=1
71	local snmp_result
72	snmp_result=`snmpwalk -v1 -c $community $pduip $names_oid 2>&1`
73	if [ $? -ne 0 ]; then
74	    ha_log.sh err "snmpwalk $community $pduip $names_oid failed. Result: $snmp_result"
75	    return 0
76	fi
77
78	local names
79	names=`echo "$snmp_result" | cut -f2 -d'"' | tr ' ' '_' | tr '\012' ' '`
80	for name in $names; do
81	    if [ "$name" != "$nodename" ]; then
82		local outlet_num=`expr $outlet_num + 1`
83		continue
84    	    fi
85
86	    return $outlet_num
87	done
88
89	ha_log.sh err "Outlet number not found for node $nodename. Result: $snmp_result"
90	return 0
91    fi
92}
93
94SendCommand() {
95
96    local host=$1
97    local command=$2
98
99    GetOutletNumber $host
100    local outlet=$?
101
102    if [ $outlet -gt 0 ]; then
103        local set_result
104        set_result=`snmpset -v1 -c $community $pduip $oid.$outlet i $command 2>&1`
105        if [ $? -ne 0 ]; then
106            ha_log.sh err "Write SNMP to $pduip value $oid.$outlet=$command failed. Result: $set_result"
107            return 1
108        fi
109        if echo "$set_result" | grep -qs "Timeout"; then
110            ha_log.sh err "Write SNMP to $pduip value $oid.$outlet=$command timed out. Result: $set_result"
111            return 1
112        fi
113        return 0
114    else
115        return 1
116    fi
117}
118
119hostlist=`echo $hostlist | tr ',' ' '`
120incommand=$1
121innode=$2
122
123case $incommand in
124gethosts)
125	if [ "$hostlist" = "AUTO" ]; then
126	    snmp_result=`snmpwalk -v1 -c $community $pduip $names_oid 2>&1`
127        if [ $? -ne 0 ]; then
128            ha_log.sh err "snmpwalk $community $pduip $names_oid failed. Result: $snmp_result"
129            exit 1
130        fi
131        if echo "$snmp_result" | grep -qs "Timeout"; then
132            ha_log.sh err "snmpwalk $community $pduip $names_oid timed out. Result: $snmp_result"
133            exit 1
134	    else
135		hostlist=`echo "$snmp_result" | cut -f2 -d'"' | tr ' ' '_' | tr '\012' ' '`
136	    fi
137	fi
138
139	for h in $hostlist ; do
140    	    echo $h
141	done
142
143	exit 0
144	;;
145on)
146	if
147	    SendCommand $innode $SWITCH_ON
148	then
149	    exit 0
150	else
151	    exit 1
152	fi
153	;;
154off)
155	if
156	    SendCommand $innode $SWITCH_OFF
157	then
158	    exit 0
159	else
160	    exit 1
161	fi
162	;;
163reset)
164	if
165	    SendCommand $innode $SWITCH_RESET
166	then
167	    exit 0
168	else
169	    exit 1
170	fi
171	;;
172status)
173        if [ -z "$pduip" ]; then
174    	    exit 1
175	fi
176
177	if ping -w1 -c1 $pduip >/dev/null 2>&1; then
178    	    exit 0
179	else
180	    exit 1
181	fi
182	;;
183getconfignames)
184	echo "hostlist pduip community"
185	exit 0
186	;;
187getinfo-devid)
188	echo "rackpdu STONITH device"
189	exit 0
190	;;
191getinfo-devname)
192	echo "rackpdu STONITH external device"
193	exit 0
194	;;
195getinfo-devdescr)
196	echo "APC Switched Rack PDU"
197	exit 0
198	;;
199getinfo-devurl)
200	echo "http://www.apcc.com/products/family/index.cfm?id=30"
201	exit 0
202	;;
203getinfo-xml)
204	cat << PDUXML
205<parameters>
206    <parameter name="hostlist" unique="1" required="1">
207	<content type="string" default="AUTO" />
208	<shortdesc lang="en">Hostlist</shortdesc>
209	<longdesc lang="en">
210The list of hosts that the STONITH device controls (comma or space separated).
211If you set value of this parameter to AUTO, list of hosts will be get from Rack PDU device.
212	</longdesc>
213    </parameter>
214
215    <parameter name="pduip" unique="1" required="1">
216	<content type="string" />
217	<shortdesc lang="en">Name or IP address of Rack PDU device.</shortdesc>
218	<longdesc lang="en">Name or IP address of Rack PDU device.</longdesc>
219    </parameter>
220
221    <parameter name="community" unique="1" required="1">
222	<content type="string" default="private" />
223	<shortdesc lang="en">Name of write community.</shortdesc>
224	<longdesc lang="en">Name of write community.</longdesc>
225    </parameter>
226
227    <parameter name="oid" unique="1" required="0">
228    <content type="string" />
229    <shortdesc lang="en">
230	The OID without the outlet number.
231    </shortdesc>
232    <longdesc lang="en">
233The SNMP OID for the PDU. minus the outlet number.
234Try .1.3.6.1.4.1.318.1.1.12.3.3.1.1.4 (default value)
235or use mib from ftp://ftp.apcc.com/apc/public/software/pnetmib/mib/
236Varies on different APC hardware and firmware.
237Warning! No dot at the end of OID
238    </longdesc>
239    </parameter>
240
241    <parameter name="names_oid" unique="1" required="0">
242	<content type="string" />
243	<shortdesc lang="en">The OID for getting names of outlets.</shortdesc>
244	<longdesc lang="en">
245The SNMP OID for getting names of outlets.
246It is required to recognize outlet number by nodename.
247Try ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.2" (default value)
248or use mib from ftp://ftp.apcc.com/apc/public/software/pnetmib/mib/
249Names of nodes must be equal names of outlets, in other way use outlet_config parameter.
250If you set 'names_oid' parameter then parameter outlet_config must not be use.
251Varies on different APC hardware and firmware.
252Warning! No dot at the end of OID
253	</longdesc>
254    </parameter>
255
256    <parameter name="outlet_config" unique="1" required="0">
257    <content type="string" />
258    <shortdesc lang="en">Configuration file. Other way to recognize outlet number by nodename.</shortdesc>
259    <longdesc lang="en">
260Configuration file. Other way to recognize outlet number by nodename.
261Configuration file which contains
262node_name=outlet_number
263strings.
264
265Example:
266server1=1
267server2=2
268
269If you use outlet_config parameter then names_oid parameter can have any value and it is not uses.
270    </longdesc>
271    </parameter>
272
273</parameters>
274PDUXML
275	exit 0
276	;;
277*)
278	exit 1
279	;;
280esac
281