expect scripts are not very reliable, let's add an alternative snmp method.
Signed-off-by: Dmitry Monakhov <[email protected]> --- conmux/drivers/fence_apc_snmp.py | 370 ++++++++++++++++++++++++++++++++++++++ conmux/drivers/module.mk | 2 +- conmux/examples/apc_snmp.cf | 4 + 3 files changed, 375 insertions(+), 1 deletions(-) create mode 100755 conmux/drivers/fence_apc_snmp.py create mode 100644 conmux/examples/apc_snmp.cf diff --git a/conmux/drivers/fence_apc_snmp.py b/conmux/drivers/fence_apc_snmp.py new file mode 100755 index 0000000..18c7303 --- /dev/null +++ b/conmux/drivers/fence_apc_snmp.py @@ -0,0 +1,370 @@ +#!/usr/bin/python + +############################################################################# +############################################################################# +## +## Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. +## Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. +## +## This copyrighted material is made available to anyone wishing to use, +## modify, copy, or redistribute it subject to the terms and conditions +## of the GNU General Public License v.2. +## +############################################################################# +## This APC Fence script uses snmp to control the APC power +## switch. This script requires that net-snmp-utils be installed +## on all nodes in the cluster, and that the powernet369.mib file be +## located in /usr/share/snmp/mibs/ +############################################################################# +############################################################################# + + + +import getopt, sys +import os +import time +import select +import signal +from glob import glob + +#BEGIN_VERSION_GENERATION +FENCE_RELEASE_NAME="" +REDHAT_COPYRIGHT="" +BUILD_DATE="" +#END_VERSION_GENERATION + +POWER_ON="outletOn" +POWER_OFF="outletOff" +POWER_REBOOT="outletReboot" + +def usage(): + print "Usage:"; + print ""; + print "Options:"; + print " -a <ip> IP address or hostname of MasterSwitch"; + print " -h usage"; + print " -l <name> Login name"; + print " -n <num> Outlet number to change"; + print " -o <string> Action: Reboot (default), Off or On"; + print " -p <string> Login password"; + print " -q quiet mode"; + print " -V version"; + print " -v Log to file /tmp/apclog"; + + print sys.argv + sys.exit(0); + + + +def main(): + apc_base = "enterprises.apc.products.hardware." + apc_outletctl = "masterswitch.sPDUOutletControl.sPDUOutletControlTable.sPDUOutletControlEntry.sPDUOutletCtl." + apc_outletstatus = "masterswitch.sPDUOutletStatus.sPDUOutletStatusMSPTable.sPDUOutletStatusMSPEntry.sPDUOutletStatusMSP." + + address = "" + output = "" + port = "" + action = "outletReboot" + status_check = False + verbose = False + + if not glob('/usr/share/snmp/mibs/powernet*.mib'): + sys.stderr.write('This APC Fence script uses snmp to control the APC power switch. This script requires that net-snmp-utils be installed on all nodes in the cluster, and that the powernet369.mib file be located in /usr/share/snmp/mibs/\n') + sys.exit(1) + + if len(sys.argv) > 1: + try: + opts, args = getopt.getopt(sys.argv[1:], "a:hl:p:n:o:vV", ["help", "output="]) + except getopt.GetoptError: + #print help info and quit + usage() + sys.exit(2) + + for o, a in opts: + if o == "-v": + verbose = True + if o == "-V": + print "%s\n" % FENCE_RELEASE_NAME + print "%s\n" % REDHAT_COPYRIGHT + print "%s\n" % BUILD_DATE + sys.exit(0) + if o in ("-h", "--help"): + usage() + sys.exit(0) + if o == "-n": + port = a + if o == "-o": + lcase = a.lower() #Lower case string + if lcase == "off": + action = "outletOff" + elif lcase == "on": + action = "outletOn" + elif lcase == "reboot": + action = "outletReboot" + elif lcase == "status": + #action = "sPDUOutletStatusMSPOutletState" + action = "" + status_check = True + else: + usage() + sys.exit() + if o == "-a": + address = a + + if address == "": + usage() + sys.exit(1) + + if port == "": + usage() + sys.exit(1) + + else: #Get opts from stdin + params = {} + #place params in dict + for line in sys.stdin: + val = line.split("=") + if len(val) == 2: + params[val[0].strip()] = val[1].strip() + + try: + address = params["ipaddr"] + except KeyError, e: + sys.stderr.write("FENCE: Missing ipaddr param for fence_apc...exiting") + sys.exit(1) + try: + login = params["login"] + except KeyError, e: + sys.stderr.write("FENCE: Missing login param for fence_apc...exiting") + sys.exit(1) + + try: + passwd = params["passwd"] + except KeyError, e: + sys.stderr.write("FENCE: Missing passwd param for fence_apc...exiting") + sys.exit(1) + + try: + port = params["port"] + except KeyError, e: + sys.stderr.write("FENCE: Missing port param for fence_apc...exiting") + sys.exit(1) + + + try: + a = params["option"] + if a == "Off" or a == "OFF" or a == "off": + action = POWER_OFF + elif a == "On" or a == "ON" or a == "on": + action = POWER_ON + elif a == "Reboot" or a == "REBOOT" or a == "reboot": + action = POWER_REBOOT + except KeyError, e: + action = POWER_REBOOT + + ####End of stdin section + + apc_command = apc_base + apc_outletctl + port + + args_status = list() + args_off = list() + args_on = list() + + args_status.append("/usr/bin/snmpget") + args_status.append("-Oqu") #sets printing options + args_status.append("-v") + args_status.append("1") + args_status.append("-c") + args_status.append("private") + args_status.append("-m") + args_status.append("ALL") + args_status.append(address) + args_status.append(apc_command) + + args_off.append("/usr/bin/snmpset") + args_off.append("-Oqu") #sets printing options + args_off.append("-v") + args_off.append("1") + args_off.append("-c") + args_off.append("private") + args_off.append("-m") + args_off.append("ALL") + args_off.append(address) + args_off.append(apc_command) + args_off.append("i") + args_off.append("outletOff") + + args_on.append("/usr/bin/snmpset") + args_on.append("-Oqu") #sets printing options + args_on.append("-v") + args_on.append("1") + args_on.append("-c") + args_on.append("private") + args_on.append("-m") + args_on.append("ALL") + args_on.append(address) + args_on.append(apc_command) + args_on.append("i") + args_on.append("outletOn") + + cmdstr_status = ' '.join(args_status) + cmdstr_off = ' '.join(args_off) + cmdstr_on = ' '.join(args_on) + +##This section issues the actual commands. Reboot is split into +##Off, then On to make certain both actions work as planned. +## +##The status command just dumps the outlet status to stdout. +##The status checks that are made when turning an outlet on or off, though, +##use the execWithCaptureStatus so that the stdout from snmpget can be +##examined and the desired operation confirmed. + + if status_check: + if verbose: + fd = open("/tmp/apclog", "w") + fd.write("Attempting the following command: %s\n" % cmdstr_status) + strr = os.system(cmdstr_status) + print strr + if verbose: + fd.write("Result: %s\n" % strr) + fd.close() + + else: + if action == POWER_OFF: + if verbose: + fd = open("/tmp/apclog", "w") + fd.write("Attempting the following command: %s\n" % cmdstr_off) + strr = os.system(cmdstr_off) + time.sleep(1) + strr,code = execWithCaptureStatus("/usr/bin/snmpget",args_status) + if verbose: + fd.write("Result: %s\n" % strr) + fd.close() + if strr.find(POWER_OFF) >= 0: + print "Success. Outlet off" + sys.exit(0) + else: + if verbose: + fd.write("Unable to power off apc outlet") + fd.close() + sys.exit(1) + + elif action == POWER_ON: + if verbose: + fd = open("/tmp/apclog", "w") + fd.write("Attempting the following command: %s\n" % cmdstr_on) + strr = os.system(cmdstr_on) + time.sleep(1) + strr,code = execWithCaptureStatus("/usr/bin/snmpget",args_status) + #strr = os.system(cmdstr_status) + if verbose: + fd.write("Result: %s\n" % strr) + if strr.find(POWER_ON) >= 0: + if verbose: + fd.close() + print "Success. Outlet On." + sys.exit(0) + else: + print "Unable to power on apc outlet" + if verbose: + fd.write("Unable to power on apc outlet") + fd.close() + sys.exit(1) + + elif action == POWER_REBOOT: + if verbose: + fd = open("/tmp/apclog", "w") + fd.write("Attempting the following command: %s\n" % cmdstr_off) + strr = os.system(cmdstr_off) + time.sleep(1) + strr,code = execWithCaptureStatus("/usr/bin/snmpget",args_status) + #strr = os.system(cmdstr_status) + if verbose: + fd.write("Result: %s\n" % strr) + if strr.find(POWER_OFF) < 0: + print "Unable to power off apc outlet" + if verbose: + fd.write("Unable to power off apc outlet") + fd.close() + sys.exit(1) + + if verbose: + fd.write("Attempting the following command: %s\n" % cmdstr_on) + strr = os.system(cmdstr_on) + time.sleep(1) + strr,code = execWithCaptureStatus("/usr/bin/snmpget",args_status) + #strr = os.system(cmdstr_status) + if verbose: + fd.write("Result: %s\n" % strr) + if strr.find(POWER_ON) >= 0: + if verbose: + fd.close() + print "Success: Outlet Rebooted." + sys.exit(0) + else: + print "Unable to power on apc outlet" + if verbose: + fd.write("Unable to power on apc outlet") + fd.close() + sys.exit(1) + +def execWithCaptureStatus(command, argv, searchPath = 0, root = '/', stdin = 0, + catchfd = 1, closefd = -1): + + if not os.access (root + command, os.X_OK): + raise RuntimeError, command + " cannot be run" + + (read, write) = os.pipe() + + childpid = os.fork() + if (not childpid): + if (root and root != '/'): os.chroot (root) + if isinstance(catchfd, tuple): + for fd in catchfd: + os.dup2(write, fd) + else: + os.dup2(write, catchfd) + os.close(write) + os.close(read) + + if closefd != -1: + os.close(closefd) + + if stdin: + os.dup2(stdin, 0) + os.close(stdin) + + if (searchPath): + os.execvp(command, argv) + else: + os.execv(command, argv) + + sys.exit(1) + + os.close(write) + + rc = "" + s = "1" + while (s): + select.select([read], [], []) + s = os.read(read, 1000) + rc = rc + s + + os.close(read) + + pid = -1 + status = -1 + try: + (pid, status) = os.waitpid(childpid, 0) + except OSError, (errno, msg): + print __name__, "waitpid:", msg + + if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0): + status = os.WEXITSTATUS(status) + else: + status = -1 + + return (rc, status) + +if __name__ == "__main__": + main() diff --git a/conmux/drivers/module.mk b/conmux/drivers/module.mk index 0cc24f9..4d17ca6 100644 --- a/conmux/drivers/module.mk +++ b/conmux/drivers/module.mk @@ -5,7 +5,7 @@ DRIVERS:=blade hmc reboot-netfinity reboot-newisys reboot-numaq \ reboot-rsa reboot-rsa2 zseries-console x3270_glue.expect \ - reboot-acs48 reboot-apc reboot-laurel + reboot-acs48 reboot-apc reboot-laurel fence_apc_snmp.py install:: @[ -d $(BASE)/lib/drivers ] || mkdir $(BASE)/lib/drivers diff --git a/conmux/examples/apc_snmp.cf b/conmux/examples/apc_snmp.cf new file mode 100644 index 0000000..d0a4add --- /dev/null +++ b/conmux/examples/apc_snmp.cf @@ -0,0 +1,4 @@ +listener localhost/ts63 +socket console 'console' 'localhost:13467' +command 'config' 'Show conmux configuration' 'cat /usr/local/conmux/etc/apc_snmp.cf' +command 'hardreset' 'initiated a hard reset' 'fence_apc_snmp.py -a pdu.xx.com -n 11 -l root' -- 1.7.2.3 _______________________________________________ Autotest mailing list [email protected] http://test.kernel.org/cgi-bin/mailman/listinfo/autotest
