From mboxrd@z Thu Jan 1 00:00:00 1970 From: kupcevic@sourceware.org Date: 16 Apr 2007 22:33:44 -0000 Subject: [Cluster-devel] cluster/fence/agents apc/fence_apc_snmp.py apc ... Message-ID: <20070416223344.6993.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Branch: RHEL4 Changes by: kupcevic at sourceware.org 2007-04-16 23:33:40 Modified files: fence/agents/apc: fence_apc_snmp.py fence/agents/apc_snmp: fence_apc_snmp.py Log message: Fixed bz193064 (fence_apc_snmp doesn't support linked switches) Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/apc/fence_apc_snmp.py.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.1.2.3&r2=1.1.2.4 http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/fence/agents/apc_snmp/fence_apc_snmp.py.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.1.2.3&r2=1.1.2.4 --- cluster/fence/agents/apc/fence_apc_snmp.py 2007/02/14 16:23:21 1.1.2.3 +++ cluster/fence/agents/apc/fence_apc_snmp.py 2007/04/16 22:33:37 1.1.2.4 @@ -4,7 +4,7 @@ ############################################################################# ## ## Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -## Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. +## Copyright (C) 2004-2007 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 @@ -22,7 +22,7 @@ import getopt, sys import os -import time +import datetime import select import signal from glob import glob @@ -37,49 +37,251 @@ POWER_OFF="outletOff" POWER_REBOOT="outletReboot" + +# oid defining fence device +oid_sysObjectID = '.1.3.6.1.2.1.1.2.0' + + + +class SNMP: + def __init__(self, params): + self.hostname = params['ipaddr'] + self.udpport = params['udpport'] + self.community = params['community'] + + def get(self, oid): + args = ['/usr/bin/snmpget'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + strr, code = execWithCaptureStatus("/usr/bin/snmpget", args) + if code: + raise Exception, 'snmpget failed' + l = strr.strip().split() + return l[0], ' '.join(l[1:]) + + def set_int(self, oid, value): + args = ['/usr/bin/snmpset'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + args.append('i') + args.append(str(value)) + strr,code = execWithCaptureStatus("/usr/bin/snmpset", args) + if code: + raise Exception, 'snmpset failed' + + def walk(self, oid): + args = ['/usr/bin/snmpwalk'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + strr,code = execWithCaptureStatus("/usr/bin/snmpwalk", args) + if code: + raise Exception, 'snmpwalk failed' + lines = strr.strip().splitlines() + ret = [] + for line in lines: + l = line.strip().split() + ret.append((l[0], ' '.join(l[1:]).strip('"'))) + return ret + + + +class FenceAgent: + + def __init__(self, params): + self.snmp = SNMP(params) + + def resolve_outlet(self): + raise Exception, 'resolve_outlet() not implemented' + + def status(self): + oid = self.status_oid % self.resolve_outlet() + dummy, stat = self.snmp.get(oid) + if stat == self.state_on: + return 'on' + elif stat == self.state_off: + return 'off' + else: + raise Exception, 'invalid status ' + stat + + def power_off(self): + oid = self.control_oid % self.resolve_outlet() + self.snmp.set_int(oid, self.turn_off) + + def power_on(self): + oid = self.control_oid % self.resolve_outlet() + self.snmp.set_int(oid, self.turn_on) + + + + + + + + +class MasterSwitch(FenceAgent): + + def __init__(self, params): + FenceAgent.__init__(self, params) + + self.status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%s' + self.control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%s' + self.outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2' + + self.state_on = '1' + self.state_off = '2' + + self.turn_on = '1' + self.turn_off = '2' + + self.port = params['port'] + + def resolve_outlet(self): + outlet = None + try: + outlet = str(int(self.port)) + except: + table = self.snmp.walk(self.outlet_table_oid) + for row in table: + if row[1] == self.port: + t = row[0].strip().split('.') + outlet = t[len(t)-1] + if outlet == None: + raise Exception, 'unable to resolve ' + self.port + else: + self.port = outlet + return outlet + + +class MasterSwitchPlus(FenceAgent): + def __init__(self, params): + FenceAgent.__init__(self, params) + + self.status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%s.1.%s' + self.control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%s.1.%s' + self.outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4' + + self.state_on = '1' + self.state_off = '2' + + self.turn_on = '1' + self.turn_off = '3' + + try: + self.switch = params['switch'] + except: + self.switch = '' + self.port = params['port'] + + def resolve_outlet(self): + switch = None + outlet = None + try: + switch = str(int(self.switch)) + outlet = str(int(self.port)) + except: + table = self.snmp.walk(self.outlet_table_oid) + for row in table: + if row[1] == self.port: + t = row[0].strip().split('.') + outlet = t[len(t)-1] + switch = t[len(t)-3] + if outlet == None: + raise Exception, 'unable to resolve ' + self.port + else: + self.switch = switch + self.port = outlet + return (switch, outlet) + + + + + + def usage(): - print "Usage:"; - print ""; - print "Options:"; - print " -a IP address or hostname of MasterSwitch"; - print " -h usage"; - print " -l Login name"; - print " -n Outlet number to change"; - print " -o Action: Reboot (default), Off or On"; - print " -p Login password"; - print " -q quiet mode"; - print " -V version"; - print " -v Log to file /tmp/apclog"; + print "Usage:" + print "" + print "Options:" + print " -h Usage" + print " -a IP address or hostname of fence device" + print " -u UDP port to use (default 161)" + print " -c SNMP community (default 'private')" + print " -n Outlet name/number to act on" + print " -o Action: Reboot (default), On, Off and Status" + print " -v Verbose mode - write to /tmp/apclog" + print " -V Version" - sys.exit(0); + 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 +file_log = None +def set_logging(verbose): + global file_log + if verbose: + file_log = open('/tmp/apclog', 'a') + file_log.write('\n----------- ') + file_log.write(datetime.datetime.today().ctime()) + file_log.write(' -----------\n') +def log(msg, error=False): + global file_log + if msg.rfind('\n') != len(msg)-1: + msg += '\n' + if file_log != None: + file_log.write(msg) + if error: + o = sys.stderr + else: + o = sys.stdout + o.write(msg) + - 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) +def main(): + try: + main2() + return 0 + except Exception, e: + log(str(e), True) + sys.exit(1) +def main2(): + + agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5' : MasterSwitch, + '.1.3.6.1.4.1.318.1.3.4.4' : MasterSwitchPlus} + + verbose = False + params = {} + if len(sys.argv) > 1: try: - opts, args = getopt.getopt(sys.argv[1:], "a:hl:p:n:o:vV", ["help", "output="]) + opts, args = getopt.getopt(sys.argv[1:], "ha:u:c:n:o:vV", ["help", "output="]) except getopt.GetoptError: - #print help info and quit usage() sys.exit(2) for o, a in opts: + o = o.strip() + a = a.strip() if o == "-v": verbose = True if o == "-V": @@ -89,229 +291,122 @@ 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() + sys.exit(0) if o == "-a": - address = a - - if address == "": - usage() - sys.exit(1) - - if port == "": - usage() - sys.exit(1) + params['ipaddr'] = a + if o == "-u": + params['udpport'] = a + if o == "-c": + params['community'] = a + if o == "-n": + switch = '' + port = a + if ':' in port: + idx = port.find(':') + switch = port[:idx] + port = port[idx+1:] + params['switch'] = switch + params['port'] = port + if o == "-o": + params['option'] = a.lower() else: #Get opts from stdin - params = {} - #place params in dict for line in sys.stdin: - val = line.split("=") + val = line.strip().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) - + o = val[0].strip().lower() + a = val[1].strip() + if o == 'verbose': + if a.lower() == 'on' or a.lower() == 'true' or a == '1': + verbose = True + else: + params[o] = a + - 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() - + set_logging(verbose) + + + ### validation ### + + try: + if params['ipaddr'] == '': + raise Exception, 'missing ipadddr' + except: + log("FENCE: Missing ipaddr param for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'udpport' not in params: + params['udpport'] = '161' + try: + t = int(params['udpport']) + if t >= 65536 or t < 0: + raise Exception, 'invalid udpport' + except: + log("FENCE: Invalid udpport for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'community' not in params: + params['community'] = 'private' + try: + port = params['port'] + if len(port) == 0: + raise Exception, 'missing port' + except: + log("FENCE: Missing port param for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'switch' not in params: + params['switch'] = '' + try: + act = params['option'].lower() + if act in ['on', 'off', 'reboot', 'status']: + params['option'] = act + else: + usage() + sys.exit(3) + except: + params['option'] = 'reboot' + + ### End of validation ### + + if verbose: + log('called with ' + str(params)) + + agent = None + dummy, sys_id = SNMP(params).get(oid_sysObjectID) + if sys_id not in agents_dir: + log('Fence device with \'oid_sysObjectID=' + sys_id + '\' is not supported', True) + sys.exit(1) + agent = agents_dir[sys_id](params) + + if params['option'] == 'status': + log('Outlet "%s" - %s is %s' % (params['port'], + str(agent.resolve_outlet()), + agent.status())) + elif params['option'] == 'on': + agent.power_on() + if agent.status() != 'on': + raise Exception, 'Error turning outlet on' + elif params['option'] == 'off': + agent.power_off() + if agent.status() != 'off': + raise Exception, 'Error turning outlet off' + elif params['option'] == 'reboot': + agent.power_off() + if agent.status() != 'off': + raise Exception, 'Error turning outlet off' + agent.power_on() + if agent.status() != 'on': + raise Exception, 'Error turning outlet on' 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) + print 'nothing to do' + sys.exit(1) + pass + - 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" + raise Exception, command + " cannot be run" (read, write) = os.pipe() @@ -364,4 +459,5 @@ return (rc, status) if __name__ == "__main__": - main() + ret = main() + sys.exit(ret) --- cluster/fence/agents/apc_snmp/Attic/fence_apc_snmp.py 2007/03/06 15:27:30 1.1.2.3 +++ cluster/fence/agents/apc_snmp/Attic/fence_apc_snmp.py 2007/04/16 22:33:40 1.1.2.4 @@ -4,7 +4,7 @@ ############################################################################# ## ## Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -## Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. +## Copyright (C) 2004-2007 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 @@ -22,7 +22,7 @@ import getopt, sys import os -import time +import datetime import select import signal from glob import glob @@ -37,49 +37,251 @@ POWER_OFF="outletOff" POWER_REBOOT="outletReboot" + +# oid defining fence device +oid_sysObjectID = '.1.3.6.1.2.1.1.2.0' + + + +class SNMP: + def __init__(self, params): + self.hostname = params['ipaddr'] + self.udpport = params['udpport'] + self.community = params['community'] + + def get(self, oid): + args = ['/usr/bin/snmpget'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + strr, code = execWithCaptureStatus("/usr/bin/snmpget", args) + if code: + raise Exception, 'snmpget failed' + l = strr.strip().split() + return l[0], ' '.join(l[1:]) + + def set_int(self, oid, value): + args = ['/usr/bin/snmpset'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + args.append('i') + args.append(str(value)) + strr,code = execWithCaptureStatus("/usr/bin/snmpset", args) + if code: + raise Exception, 'snmpset failed' + + def walk(self, oid): + args = ['/usr/bin/snmpwalk'] + args.append('-Oqn') + args.append('-v') + args.append('1') + args.append('-c') + args.append(self.community) + args.append('-m') + args.append('ALL') + args.append(self.hostname + ':' + self.udpport) + args.append(oid) + strr,code = execWithCaptureStatus("/usr/bin/snmpwalk", args) + if code: + raise Exception, 'snmpwalk failed' + lines = strr.strip().splitlines() + ret = [] + for line in lines: + l = line.strip().split() + ret.append((l[0], ' '.join(l[1:]).strip('"'))) + return ret + + + +class FenceAgent: + + def __init__(self, params): + self.snmp = SNMP(params) + + def resolve_outlet(self): + raise Exception, 'resolve_outlet() not implemented' + + def status(self): + oid = self.status_oid % self.resolve_outlet() + dummy, stat = self.snmp.get(oid) + if stat == self.state_on: + return 'on' + elif stat == self.state_off: + return 'off' + else: + raise Exception, 'invalid status ' + stat + + def power_off(self): + oid = self.control_oid % self.resolve_outlet() + self.snmp.set_int(oid, self.turn_off) + + def power_on(self): + oid = self.control_oid % self.resolve_outlet() + self.snmp.set_int(oid, self.turn_on) + + + + + + + + +class MasterSwitch(FenceAgent): + + def __init__(self, params): + FenceAgent.__init__(self, params) + + self.status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%s' + self.control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%s' + self.outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2' + + self.state_on = '1' + self.state_off = '2' + + self.turn_on = '1' + self.turn_off = '2' + + self.port = params['port'] + + def resolve_outlet(self): + outlet = None + try: + outlet = str(int(self.port)) + except: + table = self.snmp.walk(self.outlet_table_oid) + for row in table: + if row[1] == self.port: + t = row[0].strip().split('.') + outlet = t[len(t)-1] + if outlet == None: + raise Exception, 'unable to resolve ' + self.port + else: + self.port = outlet + return outlet + + +class MasterSwitchPlus(FenceAgent): + def __init__(self, params): + FenceAgent.__init__(self, params) + + self.status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%s.1.%s' + self.control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%s.1.%s' + self.outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4' + + self.state_on = '1' + self.state_off = '2' + + self.turn_on = '1' + self.turn_off = '3' + + try: + self.switch = params['switch'] + except: + self.switch = '' + self.port = params['port'] + + def resolve_outlet(self): + switch = None + outlet = None + try: + switch = str(int(self.switch)) + outlet = str(int(self.port)) + except: + table = self.snmp.walk(self.outlet_table_oid) + for row in table: + if row[1] == self.port: + t = row[0].strip().split('.') + outlet = t[len(t)-1] + switch = t[len(t)-3] + if outlet == None: + raise Exception, 'unable to resolve ' + self.port + else: + self.switch = switch + self.port = outlet + return (switch, outlet) + + + + + + def usage(): - print "Usage:"; - print ""; - print "Options:"; - print " -a IP address or hostname of MasterSwitch"; - print " -h usage"; - print " -l Login name"; - print " -n Outlet number to change"; - print " -o Action: Reboot (default), Off or On"; - print " -p Login password"; - print " -q quiet mode"; - print " -V version"; - print " -v Log to file /tmp/apclog"; + print "Usage:" + print "" + print "Options:" + print " -h Usage" + print " -a IP address or hostname of fence device" + print " -u UDP port to use (default 161)" + print " -c SNMP community (default 'private')" + print " -n Outlet name/number to act on" + print " -o Action: Reboot (default), On, Off and Status" + print " -v Verbose mode - write to /tmp/apclog" + print " -V Version" - sys.exit(0); + 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 +file_log = None +def set_logging(verbose): + global file_log + if verbose: + file_log = open('/tmp/apclog', 'a') + file_log.write('\n----------- ') + file_log.write(datetime.datetime.today().ctime()) + file_log.write(' -----------\n') +def log(msg, error=False): + global file_log + if msg.rfind('\n') != len(msg)-1: + msg += '\n' + if file_log != None: + file_log.write(msg) + if error: + o = sys.stderr + else: + o = sys.stdout + o.write(msg) + - 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) +def main(): + try: + main2() + return 0 + except Exception, e: + log(str(e), True) + sys.exit(1) +def main2(): + + agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5' : MasterSwitch, + '.1.3.6.1.4.1.318.1.3.4.4' : MasterSwitchPlus} + + verbose = False + params = {} + if len(sys.argv) > 1: try: - opts, args = getopt.getopt(sys.argv[1:], "a:hl:p:n:o:vV", ["help", "output="]) + opts, args = getopt.getopt(sys.argv[1:], "ha:u:c:n:o:vV", ["help", "output="]) except getopt.GetoptError: - #print help info and quit usage() sys.exit(2) for o, a in opts: + o = o.strip() + a = a.strip() if o == "-v": verbose = True if o == "-V": @@ -89,229 +291,122 @@ 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() + sys.exit(0) if o == "-a": - address = a - - if address == "": - usage() - sys.exit(1) - - if port == "": - usage() - sys.exit(1) + params['ipaddr'] = a + if o == "-u": + params['udpport'] = a + if o == "-c": + params['community'] = a + if o == "-n": + switch = '' + port = a + if ':' in port: + idx = port.find(':') + switch = port[:idx] + port = port[idx+1:] + params['switch'] = switch + params['port'] = port + if o == "-o": + params['option'] = a.lower() else: #Get opts from stdin - params = {} - #place params in dict for line in sys.stdin: - val = line.split("=") + val = line.strip().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) - + o = val[0].strip().lower() + a = val[1].strip() + if o == 'verbose': + if a.lower() == 'on' or a.lower() == 'true' or a == '1': + verbose = True + else: + params[o] = a + - 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() - + set_logging(verbose) + + + ### validation ### + + try: + if params['ipaddr'] == '': + raise Exception, 'missing ipadddr' + except: + log("FENCE: Missing ipaddr param for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'udpport' not in params: + params['udpport'] = '161' + try: + t = int(params['udpport']) + if t >= 65536 or t < 0: + raise Exception, 'invalid udpport' + except: + log("FENCE: Invalid udpport for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'community' not in params: + params['community'] = 'private' + try: + port = params['port'] + if len(port) == 0: + raise Exception, 'missing port' + except: + log("FENCE: Missing port param for fence_apc_snmp...exiting", True) + sys.exit(1) + if 'switch' not in params: + params['switch'] = '' + try: + act = params['option'].lower() + if act in ['on', 'off', 'reboot', 'status']: + params['option'] = act + else: + usage() + sys.exit(3) + except: + params['option'] = 'reboot' + + ### End of validation ### + + if verbose: + log('called with ' + str(params)) + + agent = None + dummy, sys_id = SNMP(params).get(oid_sysObjectID) + if sys_id not in agents_dir: + log('Fence device with \'oid_sysObjectID=' + sys_id + '\' is not supported', True) + sys.exit(1) + agent = agents_dir[sys_id](params) + + if params['option'] == 'status': + log('Outlet "%s" - %s is %s' % (params['port'], + str(agent.resolve_outlet()), + agent.status())) + elif params['option'] == 'on': + agent.power_on() + if agent.status() != 'on': + raise Exception, 'Error turning outlet on' + elif params['option'] == 'off': + agent.power_off() + if agent.status() != 'off': + raise Exception, 'Error turning outlet off' + elif params['option'] == 'reboot': + agent.power_off() + if agent.status() != 'off': + raise Exception, 'Error turning outlet off' + agent.power_on() + if agent.status() != 'on': + raise Exception, 'Error turning outlet on' 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) + print 'nothing to do' + sys.exit(1) + pass + - 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" + raise Exception, command + " cannot be run" (read, write) = os.pipe() @@ -364,4 +459,5 @@ return (rc, status) if __name__ == "__main__": - main() + ret = main() + sys.exit(ret)