diff --git a/fence/agents/amt/fence_amt.py b/fence/agents/amt/fence_amt.py index edab61af..4a3f0e22 100644 --- a/fence/agents/amt/fence_amt.py +++ b/fence/agents/amt/fence_amt.py @@ -1,115 +1,115 @@ #!/usr/bin/python -tt import sys, re, os import atexit from pipes import quote sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, is_executable, SUDO_PATH, run_command #BEGIN_VERSION_GENERATION RELEASE_VERSION="Fence agent for Intel AMT" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(_, options): output = amt_run_command(options, create_command(options, "status")) match = re.search('Powerstate:[\\s]*(..)', str(output)) status = match.group(1) if match else None - if (status == None): + if status == None: return "fail" - elif (status == "S0"): # SO = on; S3 = sleep; S5 = off + elif status == "S0": # SO = on; S3 = sleep; S5 = off return "on" else: return "off" def set_power_status(_, options): amt_run_command(options, create_command(options, options["--action"])) return def reboot_cycle(_, options): (status, _, _) = run_command(options, create_command(options, "cycle")) return not bool(status) def amt_run_command(options, command, timeout = None): env = os.environ.copy() env["AMT_PASSWORD"] = quote(options["--password"]) return run_command(options, command, timeout, env) def create_command(options, action): cmd = options["--amttool-path"] # --ip / -a cmd += " " + options["--ip"] # --action / -o if action == "status": cmd += " info" elif action == "on": cmd = "echo \"y\"|" + cmd cmd += " powerup" elif action == "off": cmd = "echo \"y\"|" + cmd cmd += " powerdown" elif action == "cycle": cmd = "echo \"y\"|" + cmd cmd += " powercycle" if action in ["on", "off", "cycle"] and options.has_key("--boot-option"): cmd += options["--boot-option"] # --use-sudo / -d if options.has_key("--use-sudo"): cmd = SUDO_PATH + " " + cmd return cmd def define_new_opts(): all_opt["boot_option"] = { "getopt" : "b:", "longopt" : "boot-option", "help" : "-b, --boot-option=[option] " "Change the default boot behavior of the machine. (pxe|hd|hdsafe|cd|diag)", "required" : "0", "shortdesc" : "Change the default boot behavior of the machine.", "choices" : ["pxe", "hd", "hdsafe", "cd", "diag"], "order" : 1 } all_opt["amttool_path"] = { "getopt" : "i:", "longopt" : "amttool-path", "help" : "--amttool-path=[path] Path to amttool binary", "required" : "0", "shortdesc" : "Path to amttool binary", "default" : "@AMTTOOL_PATH@", "order": 200 } def main(): atexit.register(atexit_handler) device_opt = [ "ipaddr", "no_login", "passwd", "boot_option", "no_port", "sudo", "amttool_path", "method" ] define_new_opts() options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for AMT" docs["longdesc"] = "fence_amt is an I/O Fencing agent \ which can be used with Intel AMT. This agent calls support software amttool\ (http://www.kraxel.org/cgit/amtterm/)." docs["vendorurl"] = "http://www.intel.com/" show_docs(options, docs) if not is_executable(options["--amttool-path"]): fail_usage("Amttool not found or not accessible") result = fence_action(None, options, set_power_status, get_power_status, None, reboot_cycle) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/apc/fence_apc.py b/fence/agents/apc/fence_apc.py index f7445835..4b4c2bc1 100644 --- a/fence/agents/apc/fence_apc.py +++ b/fence/agents/apc/fence_apc.py @@ -1,271 +1,271 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Model Firmware ## +---------------------------------------------+ ## AP7951 AOS v2.7.0, PDU APP v2.7.3 ## AP7941 AOS v3.5.7, PDU APP v3.5.6 ## AP9606 AOS v2.5.4, PDU APP v2.7.3 ## ## @note: ssh is very slow on AP79XX devices protocol (1) and ## cipher (des/blowfish) have to be defined ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="New APC Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): exp_result = 0 outlets = {} conn.send_eol("1") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) version = 0 admin = 0 switch = 0 - if (None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before)): + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): switch = 1 - if (None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before)): - if (0 == options.has_key("--switch")): + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if 0 == options.has_key("--switch"): fail_usage("Failed: You have to enter physical switch number") else: - if (0 == options.has_key("--switch")): + if 0 == options.has_key("--switch"): options["--switch"] = "1" - if (None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before)): + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): version = 2 else: version = 3 - if (None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before)): + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): admin = 0 else: admin = 1 if switch == 0: if version == 2: if admin == 0: conn.send_eol("2") else: conn.send_eol("3") else: conn.send_eol("2") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol("1") else: conn.send_eol(options["--switch"]) while True: exp_result = conn.log_expect(options, ["Press " ] + options["--command-prompt"], int(options["--shell-timeout"])) lines = conn.before.split("\n") show_re = re.compile(r'(^|\x0D)\s*(\d+)- (.*?)\s+(ON|OFF)\s*') for line in lines: res = show_re.search(line) - if (res != None): + if res != None: outlets[res.group(2)] = (res.group(3), res.group(4)) conn.send_eol("") if exp_result != 0: break conn.send(chr(03)) conn.log_expect(options, "- Logout", int(options["--shell-timeout"])) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: try: (_, status) = outlets[options["--plug"]] return status.lower().strip() except KeyError: fail(EC_STATUS) def set_power_status(conn, options): action = { 'on' : "1", 'off': "2" }[options["--action"]] conn.send_eol("1") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) version = 0 admin2 = 0 admin3 = 0 switch = 0 - if (None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before)): + if None != re.compile('.* MasterSwitch plus.*', re.IGNORECASE | re.S).match(conn.before): switch = 1 ## MasterSwitch has different schema for on/off actions action = { 'on' : "1", 'off': "3" }[options["--action"]] - if (None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before)): - if (0 == options.has_key("--switch")): + if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): + if 0 == options.has_key("--switch"): fail_usage("Failed: You have to enter physical switch number") else: - if (0 == options.has_key("--switch")): + if 0 == options.has_key("--switch"): options["--switch"] = 1 - if (None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before)): + if None == re.compile('.*Outlet Management.*', re.IGNORECASE | re.S).match(conn.before): version = 2 else: version = 3 - if (None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before)): + if None == re.compile('.*Outlet Control/Configuration.*', re.IGNORECASE | re.S).match(conn.before): admin2 = 0 else: admin2 = 1 if switch == 0: if version == 2: if admin2 == 0: conn.send_eol("2") else: conn.send_eol("3") else: conn.send_eol("2") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) - if (None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before)): + if None == re.compile('.*2- Outlet Restriction.*', re.IGNORECASE | re.S).match(conn.before): admin3 = 0 else: admin3 = 1 conn.send_eol("1") else: conn.send_eol(options["--switch"]) while 0 == conn.log_expect(options, [ "Press " ] + options["--command-prompt"], int(options["--shell-timeout"])): conn.send_eol("") conn.send_eol(options["--plug"]+"") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) if switch == 0: if admin2 == 1: conn.send_eol("1") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) if admin3 == 1: conn.send_eol("1") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) else: conn.send_eol("1") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol(action) conn.log_expect(options, "Enter 'YES' to continue or to cancel :", int(options["--shell-timeout"])) conn.send_eol("YES") conn.log_expect(options, "Press to continue...", int(options["--shell-timeout"])) conn.send_eol("") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.send(chr(03)) conn.log_expect(options, "- Logout", int(options["--shell-timeout"])) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) def get_power_status5(conn, options): outlets = {} conn.send_eol("olStatus all") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) lines = conn.before.split("\n") show_re = re.compile(r'^\s*(\d+): (.*): (On|Off)\s*$', re.IGNORECASE) for line in lines: res = show_re.search(line) - if (res != None): + if res != None: outlets[res.group(1)] = (res.group(2), res.group(3)) if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: try: (_, status) = outlets[options["--plug"]] return status.lower().strip() except KeyError: fail(EC_STATUS) def set_power_status5(conn, options): action = { 'on' : "olOn", 'off': "olOff" }[options["--action"]] conn.send_eol(action + " " + options["--plug"]) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "switch" ] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [ "\n>", "\napc>" ] all_opt["ssh_options"]["default"] = "-1 -c blowfish" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for APC over telnet/ssh" docs["longdesc"] = "fence_apc is an I/O Fencing agent \ which can be used with the APC network power switch. It logs into device \ via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh connections \ should be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.apc.com" show_docs(options, docs) ## Support for --plug [switch]:[plug] notation that was used before if (options.has_key("--plug") == 1) and (-1 != options["--plug"].find(":")): (switch, plug) = options["--plug"].split(":", 1) options["--switch"] = switch options["--plug"] = plug ## ## Operate the fencing device #### conn = fence_login(options) ## Detect firmware version (ASCII menu vs command-line interface) ## and continue with proper action #### result = -1 firmware_version = re.compile(r'\s*v(\d)*\.').search(conn.before) if (firmware_version != None) and (firmware_version.group(1) == "5"): result = fence_action(conn, options, set_power_status5, get_power_status5, get_power_status5) else: result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) ## ## Logout from system ## ## In some special unspecified cases it is possible that ## connection will be closed before we run close(). This is not ## a problem because everything is checked before. ###### try: conn.send_eol("4") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/apc_snmp/fence_apc_snmp.py b/fence/agents/apc_snmp/fence_apc_snmp.py index 0a0d4091..33f152e9 100644 --- a/fence/agents/apc_snmp/fence_apc_snmp.py +++ b/fence/agents/apc_snmp/fence_apc_snmp.py @@ -1,209 +1,209 @@ #!/usr/bin/python -tt # The Following agent has been tested on: # - APC Switched Rack PDU - SNMP v1 # (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 # AN1:apc_hw02_aos_270.bin AF1:v2.7.3 AN1:apc_hw02_rpdu_273.bin MN:AP7930 HR:B2) # - APC Web/SNMP Management Card - SNMP v1 and v3 (noAuthNoPrivacy,authNoPrivacy, authPrivacy) # (MB:v3.8.6 PF:v3.5.8 PN:apc_hw02_aos_358.bin AF1:v3.5.7 # AN1:apc_hw02_aos_358.bin AF1:v3.5.7 AN1:apc_hw02_rpdu_357.bin MN:AP7900 HR:B2) # - APC Switched Rack PDU - SNMP v1 # (MB:v3.7.0 PF:v2.7.0 PN:apc_hw02_aos_270.bin AF1:v2.7.3 # AN1:apc_hw02_rpdu_273.bin MN:AP7951 HR:B2) # - Tripplite PDUMH20HVNET 12.04.0055 - SNMP v1, v2c, v3 import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="APC SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see ApcRPDU, ApcMSP, ApcMS, TripplitePDU device = None # Port ID port_id = None # Switch ID switch_id = None # Classes describing Device params class TripplitePDU(object): # Rack PDU status_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.2.1.%d' control_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.4.1.%d' outlet_table_oid = '.1.3.6.1.4.1.850.10.2.3.5.1.5' ident_str = "Tripplite" state_on = 2 state_off = 1 turn_on = 2 turn_off = 1 has_switches = False class ApcRPDU(object): # Rack PDU status_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.4.%d' control_oid = '.1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.12.3.5.1.1.2' ident_str = "APC rPDU" state_on = 1 state_off = 2 turn_on = 1 turn_off = 2 has_switches = False class ApcMSP(object): # Master Switch+ status_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.5.%d.1.%d' control_oid = '.1.3.6.1.4.1.318.1.1.6.5.1.1.5.%d.1.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.6.7.1.1.4' ident_str = "APC Master Switch+" state_on = 1 state_off = 2 turn_on = 1 turn_off = 3 has_switches = True class ApcMS(object): # Master Switch - seems oldest, but supported on every APC PDU status_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' control_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.3.%d' outlet_table_oid = '.1.3.6.1.4.1.318.1.1.4.4.2.1.4' ident_str = "APC Master Switch (fallback)" state_on = 1 state_off = 2 turn_on = 1 turn_off = 2 has_switches = False ### FUNCTIONS ### def apc_set_device(conn): global device agents_dir = {'.1.3.6.1.4.1.318.1.3.4.5':ApcRPDU, '.1.3.6.1.4.1.318.1.3.4.4':ApcMSP, '.1.3.6.1.4.1.850.1':TripplitePDU, None:ApcMS} # First resolve type of APC apc_type = conn.walk(OID_SYS_OBJECT_ID) - if (not ((len(apc_type)==1) and (agents_dir.has_key(apc_type[0][1])))): + if not ((len(apc_type)==1) and (agents_dir.has_key(apc_type[0][1]))): apc_type = [[None, None]] device = agents_dir[apc_type[0][1]] conn.log_command("Trying %s"%(device.ident_str)) def apc_resolv_port_id(conn, options): global port_id, switch_id - if (device == None): + if device == None: apc_set_device(conn) # Now we resolv port_id/switch_id - if ((options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit()))): + if (options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) - if (device.has_switches): + if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: - if (x[1].strip('"') == options["--plug"]): + if x[1].strip('"') == options["--plug"]: t = x[0].split('.') - if (device.has_switches): + if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) - if (port_id == None): + if port_id == None: fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): - if (port_id == None): + if port_id == None: apc_resolv_port_id(conn, options) oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) (oid, status) = conn.get(oid) - return (status==str(device.state_on) and "on" or "off") + return status == str(device.state_on) and "on" or "off" def set_power_status(conn, options): - if (port_id == None): + if port_id == None: apc_resolv_port_id(conn, options) oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid, (options["--action"]=="on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): result = {} - if (device == None): + if device == None: apc_set_device(conn) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: t = x[0].split('.') port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) port_name = x[1].strip('"') port_status = "" result[port_num] = (port_name, port_status) return result # Main agent method def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "1" all_opt["community"]["default"] = "private" options = check_input(device_opt, process_input(device_opt)) ## Support for -n [switch]:[plug] notation that was used before - if ((options.has_key("--plug")) and (-1 != options["--plug"].find(":"))): + if (options.has_key("--plug")) and (-1 != options["--plug"].find(":")): (switch, plug) = options["--plug"].split(":", 1) - if ((switch.isdigit()) and (plug.isdigit())): + if switch.isdigit() and plug.isdigit(): options["--switch"] = switch options["--plug"] = plug - if (not (options.has_key("--switch"))): + if not options.has_key("--switch"): options["--switch"] = "1" docs = { } docs["shortdesc"] = "Fence agent for APC, Tripplite PDU over SNMP" docs["longdesc"] = "fence_apc_snmp is an I/O Fencing agent \ which can be used with the APC network power switch or Tripplite PDU devices.\ It logs into a device via SNMP and reboots a specified outlet. It supports \ SNMP v1, v2c, v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://www.apc.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/brocade/fence_brocade.py b/fence/agents/brocade/fence_brocade.py index 35082ee7..3bbb74c0 100644 --- a/fence/agents/brocade/fence_brocade.py +++ b/fence/agents/brocade/fence_brocade.py @@ -1,88 +1,88 @@ #!/usr/bin/python -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Brocade Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 20013" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("portCfgShow " + options["--plug"]) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) show_re = re.compile(r'^\s*Persistent Disable\s*(ON|OFF)\s*$', re.IGNORECASE) lines = conn.before.split("\n") for line in lines: res = show_re.search(line) - if (res != None): + if res != None: # We queried if it is disabled, so we have to negate answer if res.group(1) == "ON": return "off" else: return "on" fail(EC_STATUS) def set_power_status(conn, options): action = { 'on' : "portCfgPersistentEnable", 'off': "portCfgPersistentDisable" }[options["--action"]] conn.send_eol(action + " " + options["--plug"]) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "fabric_fencing" ] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [ "> " ] options = check_input(device_opt, process_input(device_opt)) options["eol"] = "\n" docs = { } docs["shortdesc"] = "Fence agent for HP Brocade over telnet/ssh" docs["longdesc"] = "fence_brocade is an I/O Fencing agent which can be used with Brocade FC switches. \ It logs into a Brocade switch via telnet and disables a specified port. Disabling the port which a machine is \ connected to effectively fences that machine. Lengthy telnet connections to the switch should be avoided while \ a GFS cluster is running because the connection will block any necessary fencing actions. \ \ After a fence operation has taken place the fenced machine can no longer connect to the Brocade FC switch. \ When the fenced machine is ready to be brought back into the GFS cluster (after reboot) the port on the Brocade \ FC switch needs to be enabled. This can be done by running fence_brocade and specifying the enable action" docs["vendorurl"] = "http://www.brocade.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) ## ## Logout from system ## ## In some special unspecified cases it is possible that ## connection will be closed before we run close(). This is not ## a problem because everything is checked before. ###### try: conn.send_eol("exit") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/cisco_mds/fence_cisco_mds.py b/fence/agents/cisco_mds/fence_cisco_mds.py index 0508f905..82b28a01 100644 --- a/fence/agents/cisco_mds/fence_cisco_mds.py +++ b/fence/agents/cisco_mds/fence_cisco_mds.py @@ -1,105 +1,105 @@ #!/usr/bin/python -tt # The Following agent has been tested on: # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Cisco MDS 9xxx SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # Cisco admin status PORT_ADMIN_STATUS_OID = ".1.3.6.1.2.1.75.1.2.2.1.1" # IF-MIB trees for alias, status and port ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" ### GLOBAL VARIABLES ### # OID converted from fc port name (fc(x)/(y)) PORT_OID = "" ### FUNCTIONS ### # Convert cisco port name (fc(x)/(y)) to OID def cisco_port2oid(port): port = port.lower() nums = re.match(r'^fc(\d+)/(\d+)$', port) - if ((nums) and (len(nums.groups()))==2): + if nums and len(nums.groups()) == 2: return "%s.%d.%d"% (PORT_ADMIN_STATUS_OID, int(nums.group(1))+21, int(nums.group(2))-1) else: fail_usage("Mangled port number: %s"%(port)) def get_power_status(conn, options): (_, status) = conn.get(PORT_OID) - return (status=="1" and "on" or "off") + return status == "1" and "on" or "off" def set_power_status(conn, options): conn.set(PORT_OID, (options["--action"]=="on" and 1 or 2)) # Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is # in format a.b.c.d...z and returned dict has key only z def array_to_dict(ar): return dict([[x[0].split(".")[-1], x[1]] for x in ar]) def get_outlets_status(conn, options): result = {} res_fc = conn.walk(PORTS_OID, 30) res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) fc_re = re.compile(r'^"fc\d+/\d+"$') for x in res_fc: if fc_re.match(x[1]): port_num = x[0].split('.')[-1] port_name = x[1].strip('"') port_alias = (res_aliases.has_key(port_num) and res_aliases[port_num].strip('"') or "") port_status = "" result[port_name] = (port_alias, port_status) return result # Main agent method def main(): global PORT_OID device_opt = [ "fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for Cisco MDS" docs["longdesc"] = "fence_cisco_mds is an I/O Fencing agent \ which can be used with any Cisco MDS 9000 series with SNMP enabled device." docs["vendorurl"] = "http://www.cisco.com" show_docs(options, docs) - if (not (options["--action"] in ["list","monitor"])): + if not options["--action"] in ["list","monitor"]: PORT_OID = cisco_port2oid(options["--plug"]) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/cisco_ucs/fence_cisco_ucs.py b/fence/agents/cisco_ucs/fence_cisco_ucs.py index 2d4eaa8d..0a4bff71 100644 --- a/fence/agents/cisco_ucs/fence_cisco_ucs.py +++ b/fence/agents/cisco_ucs/fence_cisco_ucs.py @@ -1,165 +1,165 @@ #!/usr/bin/python -tt import sys, re import pycurl, StringIO import logging import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS, EC_LOGIN_DENIED #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Cisco UCS Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION RE_COOKIE = re.compile("", int(options["--shell-timeout"])) result = RE_STATUS.search(res) - if (result == None): + if result == None: fail(EC_STATUS) else: status = result.group(1) - if (status == "up"): + if status == "up": return "on" else: return "off" def set_power_status(conn, options): del conn action = { 'on' : "up", 'off' : "down" }[options["--action"]] send_command(options, "" + "" + "" + "", int(options["--shell-timeout"])) return def get_list(conn, options): del conn outlets = { } try: res = send_command(options, "", int(options["--shell-timeout"])) lines = res.split("", int(options["--login-timeout"])) result = RE_COOKIE.search(res) - if (result == None): + if result == None: ## Cookie is absenting in response fail(EC_LOGIN_DENIED) except: fail(EC_LOGIN_DENIED) options["cookie"] = result.group(1) ## ## Modify suborg to format /suborg if options["--suborg"] != "": options["--suborg"] = "/" + options["--suborg"].lstrip("/").rstrip("/") ## ## Fence operations #### result = fence_action(None, options, set_power_status, get_power_status, get_list) ### Logout; we do not care about result as we will end in any case send_command(options, "", int(options["--shell-timeout"])) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/drac/fence_drac.py b/fence/agents/drac/fence_drac.py index b858d625..3cd7653f 100644 --- a/fence/agents/drac/fence_drac.py +++ b/fence/agents/drac/fence_drac.py @@ -1,81 +1,81 @@ #!/usr/bin/python -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("getmodinfo") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"\s+(on|off)\s+", re.IGNORECASE).search(conn.before).group(1) - return (status.lower().strip()) + return status.lower().strip() def set_power_status(conn, options): action = { 'on' : "powerup", 'off': "powerdown" }[options["--action"]] conn.send_eol("serveraction -d 0 " + action) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt" ] atexit.register(atexit_handler) opt = process_input(device_opt) if "--username" in opt: all_opt["cmd_prompt"]["default"] = [ "\\[" + opt["--username"] + "\\]# " ] else: all_opt["cmd_prompt"]["default"] = [ "\\[" "username" + "\\]# " ] options = check_input(device_opt, opt) docs = { } docs["shortdesc"] = "I/O Fencing agent for Dell DRAC IV" docs["longdesc"] = "fence_drac is an I/O Fencing agent which can be used with \ the Dell Remote Access Card (DRAC). This card provides remote access to controlling \ power to a server. It logs into the DRAC through the telnet interface of the card. By \ default, the telnet interface is not enabled. To enable the interface, you will need \ to use the racadm command in the racser-devel rpm available from Dell. \ \ To enable telnet on the DRAC: \ \ [root]# racadm config -g cfgSerial -o cfgSerialTelnetEnable 1 \ \ [root]# racadm racreset \ " docs["vendorurl"] = "http://www.dell.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) ## ## Logout from system ## ## In some special unspecified cases it is possible that ## connection will be closed before we run close(). This is not ## a problem because everything is checked before. ###### try: conn.send_eol("exit") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/drac5/fence_drac5.py b/fence/agents/drac5/fence_drac5.py index 7d8fe9aa..6f70dad9 100644 --- a/fence/agents/drac5/fence_drac5.py +++ b/fence/agents/drac5/fence_drac5.py @@ -1,163 +1,163 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## ## DRAC Version Firmware ## +-----------------+---------------------------+ ## DRAC 5 1.0 (Build 06.05.12) ## DRAC 5 1.21 (Build 07.05.04) ## ## @note: drac_version was removed ##### import sys, re, time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Drac5 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): if options["--drac-version"] == "DRAC MC": (_, status) = get_list_devices(conn, options)[options["--plug"]] else: if options["--drac-version"] == "DRAC CMC": conn.send_eol("racadm serveraction powerstatus -m " + options["--plug"]) elif options["--drac-version"] == "DRAC 5": conn.send_eol("racadm serveraction powerstatus") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"(^|: )(ON|OFF|Powering ON|Powering OFF)\s*$", re.IGNORECASE | re.MULTILINE).search(conn.before).group(2) if status.lower().strip() in ["on", "powering on", "powering off"]: return "on" else: return "off" def set_power_status(conn, options): action = { 'on' : "powerup", 'off': "powerdown" }[options["--action"]] if options["--drac-version"] == "DRAC CMC": conn.send_eol("racadm serveraction " + action + " -m " + options["--plug"]) elif options["--drac-version"] == "DRAC 5": conn.send_eol("racadm serveraction " + action) elif options["--drac-version"] == "DRAC MC": conn.send_eol("racadm serveraction -s " + options["--plug"] + " " + action) ## Fix issue with double-enter [CR/LF] ## We need to read two additional command prompts (one from get + one from set command) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) if len(conn.before.strip()) == 0: options["eol"] = options["eol"][:-1] conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) def get_list_devices(conn, options): outlets = { } if options["--drac-version"] == "DRAC CMC": conn.send_eol("getmodinfo") list_re = re.compile(r"^([^\s]*?)\s+Present\s*(ON|OFF)\s*.*$") conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) for line in conn.before.splitlines(): - if (list_re.search(line)): + if list_re.search(line): outlets[list_re.search(line).group(1)] = ("", list_re.search(line).group(2)) elif options["--drac-version"] == "DRAC MC": conn.send_eol("getmodinfo") list_re = re.compile(r"^\s*([^\s]*)\s*---->\s*(.*?)\s+Present\s*(ON|OFF)\s*.*$") conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) for line in conn.before.splitlines(): - if (list_re.search(line)): + if list_re.search(line): outlets[list_re.search(line).group(2)] = ("", list_re.search(line).group(3)) elif options["--drac-version"] == "DRAC 5": ## DRAC 5 can be used only for one computer ## standard fence library can't handle correctly situation ## when some fence devices supported by fence agent ## works with 'list' and other should returns 'N/A' print "N/A" return outlets def define_new_opts(): all_opt["drac_version"] = { "getopt" : "d:", "longopt" : "drac-version", "help" : "-d, --drac-version=[version] Force DRAC version to use (DRAC 5, DRAC CMC, DRAC MC)", "required" : "0", "shortdesc" : "Force DRAC version to use (DRAC 5, DRAC CMC, DRAC MC)", "choices" : [ "DRAC CMC", "DRAC MC", "DRAC 5" ], "order" : 1 } def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "drac_version", "port", "no_port" ] atexit.register(atexit_handler) define_new_opts() all_opt["cmd_prompt"]["default"] = [ r"\$", r"DRAC\/MC:" ] options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for Dell DRAC CMC/5" docs["longdesc"] = "fence_drac5 is an I/O Fencing agent \ which can be used with the Dell Remote Access Card v5 or CMC (DRAC). \ This device provides remote access to controlling power to a server. \ It logs into the DRAC through the telnet/ssh interface of the card. \ By default, the telnet interface is not enabled." docs["vendorurl"] = "http://www.dell.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) if options.has_key("--drac-version") == False: ## autodetect from text issued by fence device if conn.before.find("CMC") >= 0: options["--drac-version"] = "DRAC CMC" elif conn.before.find("DRAC 5") >= 0: options["--drac-version"] = "DRAC 5" elif conn.after.find("DRAC/MC") >= 0: options["--drac-version"] = "DRAC MC" else: ## Assume this is DRAC 5 by default as we don't want to break anything options["--drac-version"] = "DRAC 5" if options["--drac-version"] in ["DRAC MC", "DRAC CMC"]: if 0 == options.has_key("--plug") and 0 == ["monitor", "list"].count(options["--action"].lower()): fail_usage("Failed: You have to enter module name (-n)") result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) ## ## Logout from system ###### try: conn.send_eol("exit") time.sleep(1) conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/dummy/fence_dummy.py b/fence/agents/dummy/fence_dummy.py index aa1e5c23..9f0e950a 100644 --- a/fence/agents/dummy/fence_dummy.py +++ b/fence/agents/dummy/fence_dummy.py @@ -1,142 +1,142 @@ #!/usr/bin/python -tt import sys, random import logging import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Dummy Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION plug_status = "on" def get_power_status_file(conn, options): del conn try: status_file = open(options["--status-file"], 'r') except: return "off" status = status_file.read() status_file.close() return status.lower() def set_power_status_file(conn, options): del conn if not (options["--action"] in [ "on", "off" ]): return status_file = open(options["--status-file"], 'w') status_file.write(options["--action"]) status_file.close() def get_power_status_fail(conn, options): outlets = get_outlets_fail(conn, options) if len(outlets) == 0 or options.has_key("--plug") == 0: fail_usage("Failed: You have to enter existing machine!") else: return outlets[options["--plug"]][0] def set_power_status_fail(conn, options): global plug_status del conn plug_status = "unknown" if options["--action"] == "on": plug_status = "off" def get_outlets_fail(conn, options): del conn result = {} global plug_status if options["--action"] == "on": plug_status = "off" # This fake agent has no port data to list, so we have to make # something up for the list action. if options.has_key("--action") and options["--action"] == "list": result["fake_port_1"] = [plug_status, "fake"] result["fake_port_2"] = [plug_status, "fake"] - elif (options.has_key("--plug") == 0): + elif options.has_key("--plug") == 0: fail_usage("Failed: You have to enter existing machine!") else: port = options["--plug"] result[port] = [plug_status, "fake"] return result def main(): device_opt = [ "no_password", "status_file", "random_sleep_range", "type", "port" ] atexit.register(atexit_handler) all_opt["status_file"] = { "getopt" : "s:", "longopt" : "status-file", "help":"--status-file=[file] Name of file that holds current status", "required" : "0", "shortdesc" : "File with status", "default" : "/tmp/fence_dummy.status", "order": 1 } all_opt["random_sleep_range"] = { "getopt" : "r:", "longopt" : "random_sleep_range", "help":"--random_sleep_range=[seconds] Issue a sleep between 1 and [seconds]", "required" : "0", "shortdesc" : "Issue a sleep between 1 and X seconds. Used for testing.", "order": 1 } all_opt["type"] = { "getopt" : "t:", "longopt" : "type", "help":"--type=[type] Possible types are: file and fail", "required" : "0", "shortdesc" : "Type of the dummy fence agent", "default" : "file", "order": 1 } pinput = process_input(device_opt) if (pinput.has_key("--type") and pinput["--type"] == "file") or (pinput.has_key("--type") == False): # hack to have fence agents that require ports 'fail' and one that do not 'file' device_opt.remove("port") options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Dummy fence agent" docs["longdesc"] = "fence_dummy" docs["vendorurl"] = "http://www.example.com" show_docs(options, docs) # random sleep for testing if options.has_key("--random_sleep_range"): val = int(options["--random_sleep_range"]) ran = random.randint(1, val) logging.info("Random sleep for %d seconds\n" % ran) time.sleep(ran) if options["--type"] == "fail": result = fence_action(None, options, set_power_status_fail, get_power_status_fail, get_outlets_fail) else: result = fence_action(None, options, set_power_status_file, get_power_status_file, None) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/eaton_snmp/fence_eaton_snmp.py b/fence/agents/eaton_snmp/fence_eaton_snmp.py index 24dfd9e4..884fd6dd 100644 --- a/fence/agents/eaton_snmp/fence_eaton_snmp.py +++ b/fence/agents/eaton_snmp/fence_eaton_snmp.py @@ -1,234 +1,234 @@ #!/usr/bin/python -tt # The Following agent has been tested on: # - Eaton ePDU Managed - SNMP v1 # EATON | Powerware ePDU model: Managed ePDU (PW104MA0UB99), firmware: 01.01.01 # - Eaton ePDU Switched - SNMP v1 # EATON | Powerware ePDU model: Switched ePDU (IPV3600), firmware: 2.0.K import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Eaton SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see EatonManagedePDU, EatonSwitchedePDU device = None # Port ID port_id = None # Switch ID switch_id = None # Did we issue a set before get (to adjust OID with Switched ePDU) after_set = False # Classes describing Device params # Managed ePDU class EatonManagedePDU(object): status_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' control_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.3.%d' outlet_table_oid = '.1.3.6.1.4.1.534.6.6.6.1.2.2.1.1' ident_str = "Eaton Managed ePDU" state_off = 0 state_on = 1 state_cycling = 2 # FIXME: not usable with fence-agents turn_off = 0 turn_on = 1 turn_cycle = 2 # FIXME: not usable with fence-agents has_switches = False # Switched ePDU (Pulizzi 2) # NOTE: sysOID reports "20677.1", while data are actually at "20677.2" class EatonSwitchedePDU(object): status_oid = '.1.3.6.1.4.1.20677.2.6.3.%d.0' control_oid = '.1.3.6.1.4.1.20677.2.6.2.%d.0' outlet_table_oid = '.1.3.6.1.4.1.20677.2.6.3' ident_str = "Eaton Switched ePDU" state_off = 2 state_on = 1 state_cycling = 0 # Note: this status doesn't exist on this device turn_off = 2 turn_on = 1 turn_cycle = 3 # FIXME: not usable with fence-agents has_switches = False ### FUNCTIONS ### def eaton_set_device(conn): global device agents_dir = {'.1.3.6.1.4.1.534.6.6.6':EatonManagedePDU, '.1.3.6.1.4.1.20677.1':EatonSwitchedePDU, '.1.3.6.1.4.1.20677.2':EatonSwitchedePDU } # First resolve type of Eaton eaton_type = conn.walk(OID_SYS_OBJECT_ID) - if (not ((len(eaton_type)==1) and (agents_dir.has_key(eaton_type[0][1])))): + if not ((len(eaton_type)==1) and (agents_dir.has_key(eaton_type[0][1]))): eaton_type = [[None, None]] device = agents_dir[eaton_type[0][1]] conn.log_command("Trying %s"%(device.ident_str)) def eaton_resolv_port_id(conn, options): global port_id, switch_id - if (device==None): + if device == None: eaton_set_device(conn) # Restore the increment, that was removed in main for ePDU Managed - if (device.ident_str == "Eaton Switched ePDU"): + if device.ident_str == "Eaton Switched ePDU": options["--plug"] = str(int(options["--plug"]) + 1) # Now we resolv port_id/switch_id - if ((options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit()))): + if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) - if (device.has_switches): + if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: - if (x[1].strip('"')==options["--plug"]): + if x[1].strip('"') == options["--plug"]: t = x[0].split('.') - if (device.has_switches): + if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: - if (device.ident_str == "Eaton Switched ePDU"): + if device.ident_str == "Eaton Switched ePDU": port_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) - if (port_id==None): + if port_id == None: # Restore index offset, to provide a valid error output on Managed ePDU - if (device.ident_str != "Eaton Switched ePDU"): + if device.ident_str != "Eaton Switched ePDU": options["--plug"] = str(int(options["--plug"]) + 1) fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): global port_id, after_set - if (port_id==None): + if port_id == None: eaton_resolv_port_id(conn, options) # Ajust OID for Switched ePDU when the get is after a set - if ((after_set == True) and (device.ident_str == "Eaton Switched ePDU")): + if after_set and device.ident_str == "Eaton Switched ePDU": port_id -= 1 after_set = False oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) try: (oid, status)=conn.get(oid) - if (status==str(device.state_on)): + if status == str(device.state_on): return "on" - elif (status==str(device.state_off)): + elif status == str(device.state_off): return "off" else: return None except: return None def set_power_status(conn, options): global port_id, after_set after_set = True - if (port_id==None): + if port_id == None: eaton_resolv_port_id(conn, options) # Controls start at #2 on Switched ePDU, since #1 is the global command - if (device.ident_str == "Eaton Switched ePDU"): + if device.ident_str == "Eaton Switched ePDU": port_id = int(port_id)+1 oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid,(options["--action"]=="on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): outletCount = 0 result = {} - if (device==None): + if device == None: eaton_set_device(conn) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: outletCount += 1 status = x[1] t = x[0].split('.') # Plug indexing start from zero, so we substract '1' from the # user's given plug number - if (device.ident_str == "Eaton Managed ePDU"): + if device.ident_str == "Eaton Managed ePDU": port_num = str(int(((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1]))) + 1) # Plug indexing start from zero, so we add '1' # for the user's exposed plug number port_name = str(int(x[1].strip('"')) + 1) port_status = "" result[port_num] = (port_name, port_status) else: # Switched ePDU do not propose an outletCount OID! # Invalid status (ie value == '0'), retrieved via the walk, # means the outlet is absent port_num = str(outletCount) port_name = str(outletCount) port_status = "" - if (status != '0'): + if status != '0': result[port_num] = (port_name, port_status) return result # Main agent method def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) all_opt["switch"]["default"] = 1 all_opt["power_wait"]["default"] = 2 all_opt["snmp_version"]["default"] = "1" all_opt["community"]["default"] = "private" options = check_input(device_opt, process_input(device_opt)) # Plug indexing start from zero on ePDU Managed, so we substract '1' from # the user's given plug number. # For Switched ePDU, we will add this back again later. - if ((options.has_key("--plug")) and (options["--plug"].isdigit())): + if options.has_key("--plug") and options["--plug"].isdigit(): options["--plug"] = str(int(options["--plug"]) - 1) docs = { } docs["shortdesc"] = "Fence agent for Eaton over SNMP" docs["longdesc"] = "fence_eaton_snmp is an I/O Fencing agent \ which can be used with the Eaton network power switch. It logs \ into a device via SNMP and reboots a specified outlet. It supports \ SNMP v1 and v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://powerquality.eaton.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/eps/fence_eps.py b/fence/agents/eps/fence_eps.py index 5efc8df7..68a0991e 100644 --- a/fence/agents/eps/fence_eps.py +++ b/fence/agents/eps/fence_eps.py @@ -1,128 +1,128 @@ #!/usr/bin/python -tt # The Following Agent Has Been Tested On: # ePowerSwitch 8M+ version 1.0.0.4 import sys, re import httplib, base64, string, socket import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_LOGIN_DENIED, EC_TIMED_OUT #BEGIN_VERSION_GENERATION RELEASE_VERSION="ePowerSwitch 8M+ (eps)" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION # Run command on EPS device. # @param options Device options # @param params HTTP GET parameters (without ?) def eps_run_command(options, params): try: # New http connection conn = httplib.HTTPConnection(options["--ip"]) request_str = "/"+options["--page"] - if (params!=""): + if params != "": request_str += "?"+params logging.debug("GET %s\n" % request_str) conn.putrequest('GET', request_str) - if (options.has_key("--username")): - if (not options.has_key("--password")): + if options.has_key("--username"): + if not options.has_key("--password"): options["--password"] = "" # Default is empty password # String for Authorization header auth_str = 'Basic ' + string.strip(base64.encodestring(options["--username"]+':'+options["--password"])) logging.debug("Authorization: %s\n" % auth_str) conn.putheader('Authorization', auth_str) conn.endheaders() response = conn.getresponse() logging.debug("%d %s\n"%(response.status, response.reason)) #Response != OK -> couldn't login - if (response.status!=200): + if response.status != 200: fail(EC_LOGIN_DENIED) result = response.read() logging.debug("%s \n" % result) conn.close() except socket.timeout: fail(EC_TIMED_OUT) except socket.error: fail(EC_LOGIN_DENIED) return result def get_power_status(conn, options): del conn ret_val = eps_run_command(options,"") result = {} status = re.findall(r"p(\d{2})=(0|1)\s*\", ret_val.lower()) for out_num, out_stat in status: result[out_num] = ("",(out_stat=="1" and "on" or "off")) - if (not (options["--action"] in ['monitor','list'])): - if (not (options["--plug"] in result)): + if not options["--action"] in ['monitor','list']: + if not options["--plug"] in result: fail_usage("Failed: You have to enter existing physical plug!") else: return result[options["--plug"]][1] else: return result def set_power_status(conn, options): del conn eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"]=="on" and "1" or "0"))) # Define new option def eps_define_new_opts(): all_opt["hidden_page"] = { "getopt" : "c:", "longopt" : "page", "help":"-c, --page=[page] Name of hidden page (default hidden.htm)", "required" : "0", "shortdesc" : "Name of hidden page", "default" : "hidden.htm", "order": 1 } # Starting point of fence agent def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "hidden_page" ] atexit.register(atexit_handler) eps_define_new_opts() options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for ePowerSwitch" docs["longdesc"] = "fence_eps is an I/O Fencing agent \ which can be used with the ePowerSwitch 8M+ power switch to fence \ connected machines. Fence agent works ONLY on 8M+ device, because \ this is only one, which has support for hidden page feature. \ \n.TP\n\ Agent basically works by connecting to hidden page and pass \ appropriate arguments to GET request. This means, that hidden \ page feature must be enabled and properly configured." docs["vendorurl"] = "http://www.epowerswitch.com" show_docs(options, docs) #Run fence action. Conn is None, beacause we always need open new http connection result = fence_action(None, options, set_power_status, get_power_status, get_power_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/hds_cb/fence_hds_cb.py b/fence/agents/hds_cb/fence_hds_cb.py index f895fd39..6caee7f3 100755 --- a/fence/agents/hds_cb/fence_hds_cb.py +++ b/fence/agents/hds_cb/fence_hds_cb.py @@ -1,146 +1,146 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Model Modle/Firmware ## +--------------------+---------------------------+ ## (1) Main application CB2000/A0300-E-6617 ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Compute Blade 2000 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="November, 2012" #END_VERSION_GENERATION RE_STATUS_LINE = r"^([0-9]+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+).*$" def get_power_status(conn, options): #### Maybe should put a conn.log_expect here to make sure #### we have properly entered into the main menu conn.sendline("S") # Enter System Command Mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) result = {} # Status can now be obtained from the output of the PC # command. Line looks like the following: # "P Power Condition LID lamp Mode Auto power on" # "0 On Normal Off Basic Synchronized" # "1 On Normal Off Basic Synchronized" for line in conn.before.splitlines(): # populate the relevant fields based on regex partition = re.search(RE_STATUS_LINE, line) - if( partition != None): + if partition != None: # find the blade number defined in args - if( partition.group(1) == options["--plug"] ): + if partition.group(1) == options["--plug"]: result = partition.group(2).lower() # We must make sure we go back to the main menu as the # status is checked before any fencing operations are # executed. We could in theory save some time by staying in # the partition control, but the logic is a little cleaner # this way. conn.sendline("Q") # Back to system command mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Back to system console main menu conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) return result def set_power_status(conn, options): action = { 'on' : "P", 'off': "F", 'reboot' : "H", }[options["--action"]] conn.sendline("S") # Enter System Command Mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("P") # Enter power control menu conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline(action) # Execute action from array above conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline(options["--plug"]) # Select blade number from args conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Y") # Confirm action conn.log_expect(options, "Hit enter key.", int(options["--shell-timeout"])) conn.sendline("") # Press the any key conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Q") # Quit back to partition control conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.sendline("Q") # Quit back to system command mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Quit back to system console menu conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) def get_blades_list(conn, options): outlets = { } conn.sendline("S") # Enter System Command Mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("PC") # Enter partition control conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) # Status can now be obtained from the output of the PC # command. Line looks like the following: # "P Power Condition LID lamp Mode Auto power on" # "0 On Normal Off Basic Synchronized" # "1 On Normal Off Basic Synchronized" for line in conn.before.splitlines(): partition = re.search(RE_STATUS_LINE, line) - if( partition != None): + if partition != None: outlets[partition.group(1)] = (partition.group(2), "") conn.sendline("Q") # Quit back to system command mode conn.log_expect(options, "SVP>", int(options["--shell-timeout"])) conn.sendline("EX") # Quit back to system console menu conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) return outlets def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "missing_as_off" ] atexit.register(atexit_handler) all_opt["power_wait"]["default"] = "5" all_opt["cmd_prompt"]["default"] = [ r"\) :" ] options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for Hitachi Compute Blade systems" docs["longdesc"] = "fence_hds_cb is an I/O Fencing agent \ which can be used with Hitachi Compute Blades with recent enough firmware that \ includes telnet support." docs["vendorurl"] = "http://www.hds.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_blades_list) ## ## Logout from system ###### try: conn.sendline("X") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ibmblade/fence_ibmblade.py b/fence/agents/ibmblade/fence_ibmblade.py index d1bb0655..f3c810e7 100644 --- a/fence/agents/ibmblade/fence_ibmblade.py +++ b/fence/agents/ibmblade/fence_ibmblade.py @@ -1,78 +1,78 @@ #!/usr/bin/python -tt import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IBM Blade SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # From fence_ibmblade.pl STATUSES_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.5.1.1.4" # remoteControlBladePowerState CONTROL_OID = ".1.3.6.1.4.1.2.3.51.2.22.1.6.1.1.7" # powerOnOffBlade # Status constants returned as value from SNMP STATUS_DOWN = 0 STATUS_UP = 1 # Status constants to set as value to SNMP STATUS_SET_OFF = 0 STATUS_SET_ON = 1 ### FUNCTIONS ### def get_power_status(conn, options): (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) - return (status == str(STATUS_UP) and "on" or "off") + return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): conn.set("%s.%s"%(CONTROL_OID, options["--plug"]), (options["--action"]=="on" and STATUS_SET_ON or STATUS_SET_OFF)) def get_outlets_status(conn, _): result = {} res_blades = conn.walk(STATUSES_OID, 30) for blade_info in res_blades: port_num = blade_info[0].split('.')[-1] port_alias = "" port_status = (blade_info[1]==str(STATUS_UP) and "on" or "off") result[port_num] = (port_alias, port_status) return result # Main agent method def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "1" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for IBM BladeCenter over SNMP" docs["longdesc"] = "fence_ibmblade is an I/O Fencing agent \ which can be used with IBM BladeCenter chassis. It issues SNMP Set \ request to BladeCenter chassis, rebooting, powering up or down \ the specified Blade Server." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ifmib/fence_ifmib.py b/fence/agents/ifmib/fence_ifmib.py index c477ba20..04edbf97 100644 --- a/fence/agents/ifmib/fence_ifmib.py +++ b/fence/agents/ifmib/fence_ifmib.py @@ -1,127 +1,127 @@ #!/usr/bin/python -tt # The Following agent has been tested on: # - Cisco MDS UROS 9134 FC (1 Slot) Chassis ("1/2/4 10 Gbps FC/Supervisor-2") Motorola, e500v2 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Cisco MDS 9124 (1 Slot) Chassis ("1/2/4 Gbps FC/Supervisor-2") Motorola, e500 # with BIOS 1.0.16, kickstart 4.1(1c), system 4.1(1c) # - Partially with APC PDU (Network Management Card AOS v2.7.0, Rack PDU APP v2.7.3) # Only lance if is visible import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IF:MIB SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # IF-MIB trees for alias, status and port ALIASES_OID = ".1.3.6.1.2.1.31.1.1.1.18" PORTS_OID = ".1.3.6.1.2.1.2.2.1.2" STATUSES_OID = ".1.3.6.1.2.1.2.2.1.7" # Status constants returned as value from SNMP STATUS_UP = 1 STATUS_DOWN = 2 STATUS_TESTING = 3 ### GLOBAL VARIABLES ### # Port number converted from port name or index port_num = None ### FUNCTIONS ### # Convert port index or name to port index def port2index(conn, port): res = None - if (port.isdigit()): + if port.isdigit(): res = int(port) else: ports = conn.walk(PORTS_OID, 30) for x in ports: - if (x[1].strip('"')==port): + if x[1].strip('"') == port: res = int(x[0].split('.')[-1]) break - if (res==None): + if res == None: fail_usage("Can't find port with name %s!"%(port)) return res def get_power_status(conn, options): global port_num - if (port_num==None): + if port_num == None: port_num = port2index(conn, options["--plug"]) (_, status) = conn.get("%s.%d"%(STATUSES_OID, port_num)) - return (status==str(STATUS_UP) and "on" or "off") + return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): global port_num - if (port_num==None): + if port_num == None: port_num = port2index(conn, options["--plug"]) conn.set("%s.%d"%(STATUSES_OID, port_num), (options["--action"]=="on" and STATUS_UP or STATUS_DOWN)) # Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is # in format a.b.c.d...z and returned dict has key only z def array_to_dict(ar): return dict([[x[0].split(".")[-1], x[1]] for x in ar]) def get_outlets_status(conn, options): result = {} res_fc = conn.walk(PORTS_OID, 30) res_aliases = array_to_dict(conn.walk(ALIASES_OID, 30)) for x in res_fc: port_number = x[0].split('.')[-1] port_name = x[1].strip('"') port_alias = (res_aliases.has_key(port_number) and res_aliases[port_number].strip('"') or "") port_status = "" result[port_name] = (port_alias, port_status) return result # Main agent method def main(): device_opt = [ "fabric_fencing", "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "2c" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for IF MIB" docs["longdesc"] = "fence_ifmib is an I/O Fencing agent \ which can be used with any SNMP IF-MIB capable device. \ \n.P\n\ It was written with managed ethernet switches in mind, in order to \ fence iSCSI SAN connections. However, there are many devices that \ support the IF-MIB interface. The agent uses IF-MIB::ifAdminStatus \ to control the state of an interface." docs["vendorurl"] = "http://www.ietf.org/wg/concluded/ifmib.html" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/intelmodular/fence_intelmodular.py b/fence/agents/intelmodular/fence_intelmodular.py index e9ef43c5..bdb45b5f 100644 --- a/fence/agents/intelmodular/fence_intelmodular.py +++ b/fence/agents/intelmodular/fence_intelmodular.py @@ -1,92 +1,92 @@ #!/usr/bin/python -tt # Tested with an Intel MFSYS25 using firmware package 2.6 Should work with an # MFSYS35 as well. # # Notes: # # The manual and firmware release notes says SNMP is read only. This is not # true, as per the MIBs that ship with the firmware you can write to # the bladePowerLed oid to control the servers. # # Thanks Matthew Kent for original agent and testing. import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="Intel Modular SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # From INTELCORPORATION-MULTI-FLEX-SERVER-BLADES-MIB.my that ships with # firmware updates STATUSES_OID = ".1.3.6.1.4.1.343.2.19.1.2.10.202.1.1.6" # Status constants returned as value from SNMP STATUS_UP = 2 STATUS_DOWN = 0 # Status constants to set as value to SNMP STATUS_SET_ON = 2 STATUS_SET_OFF = 3 ### FUNCTIONS ### def get_power_status(conn, options): (_, status) = conn.get("%s.%s"% (STATUSES_OID, options["--plug"])) - return (status==str(STATUS_UP) and "on" or "off") + return status == str(STATUS_UP) and "on" or "off" def set_power_status(conn, options): conn.set("%s.%s" % (STATUSES_OID, options["--plug"]), (options["--action"]=="on" and STATUS_SET_ON or STATUS_SET_OFF)) def get_outlets_status(conn, options): result = {} res_blades = conn.walk(STATUSES_OID, 30) for x in res_blades: port_num = x[0].split('.')[-1] port_alias = "" port_status = (x[1]==str(STATUS_UP) and "on" or "off") result[port_num] = (port_alias, port_status) return result # Main agent method def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", "port", "snmp_version", "community" ] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for Intel Modular" docs["longdesc"] = "fence_intelmodular is an I/O Fencing agent \ which can be used with Intel Modular device (tested on Intel MFSYS25, should \ work with MFSYS35 as well). \ \n.P\n\ Note: Since firmware update version 2.7, SNMP v2 write support is \ removed, and replaced by SNMP v3 support. So agent now has default \ SNMP version 3. If you are using older firmware, please supply -d \ for command line and snmp_version option for your cluster.conf." docs["vendorurl"] = "http://www.intel.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ipdu/fence_ipdu.py b/fence/agents/ipdu/fence_ipdu.py index 913322d9..e17d837f 100644 --- a/fence/agents/ipdu/fence_ipdu.py +++ b/fence/agents/ipdu/fence_ipdu.py @@ -1,158 +1,158 @@ #!/usr/bin/python -tt # The Following agent has been tested on: # IBM iPDU model 46M4002 # Firmware release OPDP_sIBM_v01.2_1 # import sys import atexit sys.path.append("/usr/share/fence") from fencing import * from fencing import fail_usage from fencing_snmp import FencingSnmp #BEGIN_VERSION_GENERATION RELEASE_VERSION="IBM iPDU SNMP fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS ### # oid defining fence device OID_SYS_OBJECT_ID = '.1.3.6.1.2.1.1.2.0' ### GLOBAL VARIABLES ### # Device - see IBM iPDU device = None # Port ID port_id = None # Switch ID switch_id = None # Classes describing Device params class IBMiPDU(object): # iPDU status_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' control_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.11.%d' outlet_table_oid = '.1.3.6.1.4.1.2.6.223.8.2.2.1.2' ident_str = "IBM iPDU" state_on = 1 state_off = 0 turn_on = 1 turn_off = 0 has_switches = False ### FUNCTIONS ### def ipdu_set_device(conn, options): global device agents_dir = {'.1.3.6.1.4.1.2.6.223':IBMiPDU, None:IBMiPDU} # First resolve type of PDU device pdu_type = conn.walk(OID_SYS_OBJECT_ID) - if (not ((len(pdu_type)==1) and (agents_dir.has_key(pdu_type[0][1])))): + if not ((len(pdu_type)==1) and (agents_dir.has_key(pdu_type[0][1]))): pdu_type = [[None, None]] device = agents_dir[pdu_type[0][1]] conn.log_command("Trying %s"%(device.ident_str)) def ipdu_resolv_port_id(conn, options): global port_id, switch_id - if (device==None): + if device == None: ipdu_set_device(conn, options) # Now we resolv port_id/switch_id - if ((options["--plug"].isdigit()) and ((not device.has_switches) or (options["--switch"].isdigit()))): + if options["--plug"].isdigit() and ((not device.has_switches) or (options["--switch"].isdigit())): port_id = int(options["--plug"]) - if (device.has_switches): + if device.has_switches: switch_id = int(options["--switch"]) else: table = conn.walk(device.outlet_table_oid, 30) for x in table: - if (x[1].strip('"')==options["--plug"]): + if x[1].strip('"') == options["--plug"]: t = x[0].split('.') - if (device.has_switches): + if device.has_switches: port_id = int(t[len(t)-1]) switch_id = int(t[len(t)-3]) else: port_id = int(t[len(t)-1]) - if (port_id==None): + if port_id == None: fail_usage("Can't find port with name %s!"%(options["--plug"])) def get_power_status(conn, options): - if (port_id==None): + if port_id == None: ipdu_resolv_port_id(conn, options) oid = ((device.has_switches) and device.status_oid%(switch_id, port_id) or device.status_oid%(port_id)) (oid, status) = conn.get(oid) - return (status==str(device.state_on) and "on" or "off") + return status == str(device.state_on) and "on" or "off" def set_power_status(conn, options): - if (port_id==None): + if port_id == None: ipdu_resolv_port_id(conn, options) oid = ((device.has_switches) and device.control_oid%(switch_id, port_id) or device.control_oid%(port_id)) conn.set(oid,(options["--action"]=="on" and device.turn_on or device.turn_off)) def get_outlets_status(conn, options): result = {} - if (device == None): + if device == None: ipdu_set_device(conn, options) res_ports = conn.walk(device.outlet_table_oid, 30) for x in res_ports: t = x[0].split('.') port_num = ((device.has_switches) and "%s:%s"%(t[len(t)-3], t[len(t)-1]) or "%s"%(t[len(t)-1])) port_name = x[1].strip('"') port_status = "" result[port_num] = (port_name, port_status) return result # Main agent method def main(): global device device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "port", "snmp_version", "community" ] atexit.register(atexit_handler) all_opt["snmp_version"]["default"] = "3" all_opt["community"]["default"] = "private" all_opt["switch"]["default"] = "1" device = IBMiPDU options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for iPDU over SNMP" docs["longdesc"] = "fence_ipdu is an I/O Fencing agent \ which can be used with the IBM iPDU network power switch. It logs \ into a device via SNMP and reboots a specified outlet. It supports \ SNMP v3 with all combinations of authenticity/privacy settings." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) # Operate the fencing device result = fence_action(FencingSnmp(options), options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/ldom/fence_ldom.py b/fence/agents/ldom/fence_ldom.py index 65c810b0..5e046df2 100644 --- a/fence/agents/ldom/fence_ldom.py +++ b/fence/agents/ldom/fence_ldom.py @@ -1,119 +1,119 @@ #!/usr/bin/python -tt ## ## The Following Agent Has Been Tested On - LDOM 1.0.3 ## The interface is backward compatible so it will work ## with 1.0, 1.0.1 and .2 too. ## ##### import sys, re, pexpect, exceptions import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage #BEGIN_VERSION_GENERATION RELEASE_VERSION="Logical Domains (LDoms) fence Agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION COMMAND_PROMPT_REG = r"\[PEXPECT\]$" COMMAND_PROMPT_NEW = "[PEXPECT]" # Start comunicating after login. Prepare good environment. def start_communication(conn, options): conn.send_eol ("PS1='"+COMMAND_PROMPT_NEW+"'") res = conn.expect([pexpect.TIMEOUT, COMMAND_PROMPT_REG], int(options["--shell-timeout"])) if res == 0: #CSH stuff conn.send_eol("set prompt='"+COMMAND_PROMPT_NEW+"'") conn.log_expect(options, COMMAND_PROMPT_REG, int(options["--shell-timeout"])) def get_power_status(conn, options): start_communication(conn, options) conn.send_eol("ldm ls") conn.log_expect(options, COMMAND_PROMPT_REG, int(options["--shell-timeout"])) result = {} #This is status of mini finite automata. 0 = we didn't found NAME and STATE, 1 = we did fa_status = 0 for line in conn.before.splitlines(): domain = re.search(r"^(\S+)\s+(\S+)\s+.*$", line) - if (domain!=None): - if ((fa_status==0) and (domain.group(1)=="NAME") and (domain.group(2)=="STATE")): + if domain != None: + if fa_status == 0 and domain.group(1) == "NAME" and domain.group(2) == "STATE": fa_status = 1 - elif (fa_status==1): + elif fa_status == 1: result[domain.group(1)] = ("", (domain.group(2).lower()=="bound" and "off" or "on")) - if (not (options["--action"] in ['monitor','list'])): - if (not (options["--plug"] in result)): + if not options["--action"] in ['monitor','list']: + if not options["--plug"] in result: fail_usage("Failed: You have to enter existing logical domain!") else: return result[options["--plug"]][1] else: return result def set_power_status(conn, options): start_communication(conn, options) cmd_line = "ldm "+(options["--action"]=="on" and "start" or "stop -f")+" \""+options["--plug"]+"\"" conn.send_eol(cmd_line) conn.log_expect(options, COMMAND_PROMPT_REG, int(options["--power-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", "port" ] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [ r"\ $" ] options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for Sun LDOM" docs["longdesc"] = "fence_ldom is an I/O Fencing agent \ which can be used with LDoms virtual machines. This agent works \ so, that run ldm command on host machine. So ldm must be directly \ runnable.\ \n.P\n\ Very useful parameter is -c (or cmd_prompt in stdin mode). This \ must be set to something, what is displayed after successful login \ to host machine. Default string is space on end of string (default \ for root in bash). But (for example) csh use ], so in that case you \ must use parameter -c with argument ]. Very similar situation is, \ if you use bash and login to host machine with other user than \ root. Than prompt is $, so again, you must use parameter -c." docs["vendorurl"] = "http://www.sun.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) ## ## Logout from system ###### try: conn.send_eol("logout") conn.close() except exceptions.OSError: pass except pexpect.ExceptionPexpect: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/lib/fencing.py.py b/fence/agents/lib/fencing.py.py index a37cd0d8..56a8a1a0 100644 --- a/fence/agents/lib/fencing.py.py +++ b/fence/agents/lib/fencing.py.py @@ -1,1126 +1,1126 @@ #!/usr/bin/python -tt import sys, getopt, time, os, uuid, pycurl, stat import pexpect, re, atexit, syslog import logging import subprocess import threading import shlex import __main__ ## do not add code here. #BEGIN_VERSION_GENERATION RELEASE_VERSION = "New fence lib agent - test release on steroids" REDHAT_COPYRIGHT = "" BUILD_DATE = "March, 2008" #END_VERSION_GENERATION __all__ = [ 'atexit_handler', 'check_input', 'process_input', 'all_opt', 'show_docs', 'fence_login', 'fence_action' ] EC_GENERIC_ERROR = 1 EC_BAD_ARGS = 2 EC_LOGIN_DENIED = 3 EC_CONNECTION_LOST = 4 EC_TIMED_OUT = 5 EC_WAITING_ON = 6 EC_WAITING_OFF = 7 EC_STATUS = 8 EC_STATUS_HMC = 9 EC_PASSWORD_MISSING = 10 EC_INVALID_PRIVILEGES = 11 TELNET_PATH = "/usr/bin/telnet" SSH_PATH = "/usr/bin/ssh" SSL_PATH = "@GNUTLSCLI_PATH@" SUDO_PATH = "/usr/bin/sudo" all_opt = { "help" : { "getopt" : "h", "longopt" : "help", "help" : "-h, --help Display this help and exit", "required" : "0", "shortdesc" : "Display help and exit", "order" : 54 }, "version" : { "getopt" : "V", "longopt" : "version", "help" : "-V, --version Output version information and exit", "required" : "0", "shortdesc" : "Display version information and exit", "order" : 53 }, "verbose" : { "getopt" : "v", "longopt" : "verbose", "help" : "-v, --verbose Verbose mode", "required" : "0", "shortdesc" : "Verbose mode", "order" : 51 }, "debug" : { "getopt" : "D:", "longopt" : "debug-file", "help" : "-D, --debug-file=[debugfile] Debugging to output file", "required" : "0", "shortdesc" : "Write debug information to given file", "order" : 52 }, "delay" : { "getopt" : "f:", "longopt" : "delay", "help" : "--delay=[seconds] Wait X seconds before fencing is started", "required" : "0", "shortdesc" : "Wait X seconds before fencing is started", "default" : "0", "order" : 200 }, "agent" : { "getopt" : "", "help" : "", "order" : 1 }, "web" : { "getopt" : "", "help" : "", "order" : 1 }, "action" : { "getopt" : "o:", "longopt" : "action", "help" : "-o, --action=[action] Action: status, reboot (default), off or on", "required" : "1", "shortdesc" : "Fencing Action", "default" : "reboot", "order" : 1 }, "fabric_fencing" : { "getopt" : "", "help" : "", "order" : 1 }, "ipaddr" : { "getopt" : "a:", "longopt" : "ip", "help" : "-a, --ip=[ip] IP address or hostname of fencing device", "required" : "1", "shortdesc" : "IP Address or Hostname", "order" : 1 }, "ipport" : { "getopt" : "u:", "longopt" : "ipport", "help" : "-u, --ipport=[port] TCP/UDP port to use", "required" : "0", "shortdesc" : "TCP/UDP port to use for connection with device", "order" : 1 }, "login" : { "getopt" : "l:", "longopt" : "username", "help" : "-l, --username=[name] Login name", "required" : "?", "shortdesc" : "Login Name", "order" : 1 }, "no_login" : { "getopt" : "", "help" : "", "order" : 1 }, "no_password" : { "getopt" : "", "help" : "", "order" : 1 }, "no_port" : { "getopt" : "", "help" : "", "order" : 1 }, "passwd" : { "getopt" : "p:", "longopt" : "password", "help" : "-p, --password=[password] Login password or passphrase", "required" : "0", "shortdesc" : "Login password or passphrase", "order" : 1 }, "passwd_script" : { "getopt" : "S:", "longopt" : "password-script", "help" : "-S, --password-script=[script] Script to run to retrieve password", "required" : "0", "shortdesc" : "Script to retrieve password", "order" : 1 }, "identity_file" : { "getopt" : "k:", "longopt" : "identity-file", "help" : "-k, --identity-file=[filename] Identity file (private key) for ssh ", "required" : "0", "shortdesc" : "Identity file for ssh", "order" : 1 }, "cmd_prompt" : { "getopt" : "c:", "longopt" : "command-prompt", "help" : "-c, --command-prompt=[prompt] Force Python regex for command prompt", "shortdesc" : "Force Python regex for command prompt", "required" : "0", "order" : 1 }, "secure" : { "getopt" : "x", "longopt" : "ssh", "help" : "-x, --ssh Use ssh connection", "shortdesc" : "SSH connection", "required" : "0", "order" : 1 }, "ssh_options" : { "getopt" : "X:", "longopt" : "ssh-options", "help" : "--ssh-options=[options] SSH options to use", "shortdesc" : "SSH options to use", "required" : "0", "order" : 1 }, "ssl" : { "getopt" : "z", "longopt" : "ssl", "help" : "-z, --ssl Use ssl connection", "required" : "0", "shortdesc" : "SSL connection", "order" : 1 }, "notls" : { "getopt" : "t", "longopt" : "notls", "help" : "-t, --notls " "Disable TLS negotiation and force SSL3.0.\n" " " "This should only be used for devices that do not support TLS1.0 and up.", "required" : "0", "shortdesc" : "Disable TLS negotiation", "order" : 1 }, "port" : { "getopt" : "n:", "longopt" : "plug", "help" : "-n, --plug=[id] Physical plug number on device, UUID or\n" + " identification of machine", "required" : "1", "shortdesc" : "Physical plug number, name of virtual machine or UUID", "order" : 1 }, "switch" : { "getopt" : "s:", "longopt" : "switch", "help" : "-s, --switch=[id] Physical switch number on device", "required" : "0", "shortdesc" : "Physical switch number on device", "order" : 1 }, "exec" : { "getopt" : "e:", "longopt" : "exec", "help" : "-e, --exec=[command] Command to execute", "required" : "0", "shortdesc" : "Command to execute", "order" : 1 }, "vmware_type" : { "getopt" : "d:", "longopt" : "vmware_type", "help" : "-d, --vmware_type=[type] Type of VMware to connect", "required" : "0", "shortdesc" : "Type of VMware to connect", "order" : 1 }, "vmware_datacenter" : { "getopt" : "s:", "longopt" : "vmware-datacenter", "help" : "-s, --vmware-datacenter=[dc] VMWare datacenter filter", "required" : "0", "shortdesc" : "Show only machines in specified datacenter", "order" : 2 }, "snmp_version" : { "getopt" : "d:", "longopt" : "snmp-version", "help" : "-d, --snmp-version=[version] Specifies SNMP version to use", "required" : "0", "shortdesc" : "Specifies SNMP version to use (1,2c,3)", "choices" : [ "1", "2c", "3" ], "order" : 1 }, "community" : { "getopt" : "c:", "longopt" : "community", "help" : "-c, --community=[community] Set the community string", "required" : "0", "shortdesc" : "Set the community string", "order" : 1}, "snmp_auth_prot" : { "getopt" : "b:", "longopt" : "snmp-auth-prot", "help" : "-b, --snmp-auth-prot=[prot] Set authentication protocol (MD5|SHA)", "required" : "0", "shortdesc" : "Set authentication protocol (MD5|SHA)", "choices" : [ "MD5" , "SHA" ], "order" : 1}, "snmp_sec_level" : { "getopt" : "E:", "longopt" : "snmp-sec-level", "help" : "-E, --snmp-sec-level=[level] Set security level\n"+ " (noAuthNoPriv|authNoPriv|authPriv)", "required" : "0", "shortdesc" : "Set security level (noAuthNoPriv|authNoPriv|authPriv)", "choices" : [ "noAuthNoPriv", "authNoPriv", "authPriv" ], "order" : 1}, "snmp_priv_prot" : { "getopt" : "B:", "longopt" : "snmp-priv-prot", "help" : "-B, --snmp-priv-prot=[prot] Set privacy protocol (DES|AES)", "required" : "0", "shortdesc" : "Set privacy protocol (DES|AES)", "choices" : [ "DES", "AES" ], "order" : 1}, "snmp_priv_passwd" : { "getopt" : "P:", "longopt" : "snmp-priv-passwd", "help" : "-P, --snmp-priv-passwd=[pass] Set privacy protocol password", "required" : "0", "shortdesc" : "Set privacy protocol password", "order" : 1}, "snmp_priv_passwd_script" : { "getopt" : "R:", "longopt" : "snmp-priv-passwd-script", "help" : "-R, --snmp-priv-passwd-script Script to run to retrieve privacy password", "required" : "0", "shortdesc" : "Script to run to retrieve privacy password", "order" : 1}, "inet4_only" : { "getopt" : "4", "longopt" : "inet4-only", "help" : "-4, --inet4-only Forces agent to use IPv4 addresses only", "required" : "0", "shortdesc" : "Forces agent to use IPv4 addresses only", "order" : 1 }, "inet6_only" : { "getopt" : "6", "longopt" : "inet6-only", "help" : "-6, --inet6-only Forces agent to use IPv6 addresses only", "required" : "0", "shortdesc" : "Forces agent to use IPv6 addresses only", "order" : 1 }, "separator" : { "getopt" : "C:", "longopt" : "separator", "help" : "-C, --separator=[char] Separator for CSV created by 'list' operation", "default" : ",", "required" : "0", "shortdesc" : "Separator for CSV created by operation list", "order" : 100 }, "login_timeout" : { "getopt" : "y:", "longopt" : "login-timeout", "help" : "--login-timeout=[seconds] Wait X seconds for cmd prompt after login", "default" : "5", "required" : "0", "shortdesc" : "Wait X seconds for cmd prompt after login", "order" : 200 }, "shell_timeout" : { "getopt" : "Y:", "longopt" : "shell-timeout", "help" : "--shell-timeout=[seconds] Wait X seconds for cmd prompt after issuing command", "default" : "3", "required" : "0", "shortdesc" : "Wait X seconds for cmd prompt after issuing command", "order" : 200 }, "power_timeout" : { "getopt" : "g:", "longopt" : "power-timeout", "help" : "--power-timeout=[seconds] Test X seconds for status change after ON/OFF", "default" : "20", "required" : "0", "shortdesc" : "Test X seconds for status change after ON/OFF", "order" : 200 }, "power_wait" : { "getopt" : "G:", "longopt" : "power-wait", "help" : "--power-wait=[seconds] Wait X seconds after issuing ON/OFF", "default" : "0", "required" : "0", "shortdesc" : "Wait X seconds after issuing ON/OFF", "order" : 200 }, "missing_as_off" : { "getopt" : "M", "longopt" : "missing-as-off", "help" : "--missing-as-off Missing port returns OFF instead of failure", "required" : "0", "shortdesc" : "Missing port returns OFF instead of failure", "order" : 200 }, "retry_on" : { "getopt" : "F:", "longopt" : "retry-on", "help" : "--retry-on=[attempts] Count of attempts to retry power on", "default" : "1", "required" : "0", "shortdesc" : "Count of attempts to retry power on", "order" : 201 }, "session_url" : { "getopt" : "s:", "longopt" : "session-url", "help" : "-s, --session-url URL to connect to XenServer on", "required" : "1", "shortdesc" : "The URL of the XenServer host.", "order" : 1}, "sudo" : { "getopt" : "d", "longopt" : "use-sudo", "help" : "--use-sudo Use sudo (without password) when calling 3rd party software", "required" : "0", "shortdesc" : "Use sudo (without password) when calling 3rd party sotfware.", "order" : 205}, "method" : { "getopt" : "m:", "longopt" : "method", "help" : "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)", "required" : "0", "shortdesc" : "Method to fence (onoff|cycle)", "default" : "onoff", "choices" : [ "onoff", "cycle" ], "order" : 1} } # options which are added automatically if 'key' is encountered ("default" is always added) DEPENDENCY_OPT = { "default" : [ "help", "debug", "verbose", "version", "action", "agent", \ "power_timeout", "shell_timeout", "login_timeout", "power_wait", "retry_on", "delay" ], "passwd" : [ "passwd_script" ], "secure" : [ "identity_file", "ssh_options" ], "ipaddr" : [ "ipport", "inet4_only", "inet6_only" ], "port" : [ "separator" ], "community" : [ "snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ "snmp_priv_passwd", "snmp_priv_passwd_script" ] } class fspawn(pexpect.spawn): def __init__(self, options, command): logging.info("Running command: %s" % command) pexpect.spawn.__init__(self, command) self.opt = options def log_expect(self, options, pattern, timeout): result = self.expect(pattern, timeout) logging.debug("Received: %s" % (self.before + self.after)) return result def send(self, message): logging.debug("Sent: %s" % message) pexpect.spawn.send(self, message) # send EOL according to what was detected in login process (telnet) def send_eol(self, message): self.send(message + self.opt["eol"]) def atexit_handler(): try: sys.stdout.close() os.close(1) except IOError: logging.error("%s failed to close standard output\n" % (sys.argv[0])) syslog.syslog(syslog.LOG_ERR, "Failed to close standard output") sys.exit(EC_GENERIC_ERROR) def add_dependency_options(options): ## Add also options which are available for every fence agent added_opt = [] for opt in options + ["default"]: if DEPENDENCY_OPT.has_key(opt): added_opt.extend([y for y in DEPENDENCY_OPT[opt] if options.count(y) == 0]) return added_opt def fail_usage(message = ""): if len(message) > 0: logging.error("%s\n" % message) logging.error("Please use '-h' for usage\n") sys.exit(EC_GENERIC_ERROR) def fail(error_code): message = { EC_LOGIN_DENIED : "Unable to connect/login to fencing device", EC_CONNECTION_LOST : "Connection lost", EC_TIMED_OUT : "Connection timed out", EC_WAITING_ON : "Failed: Timed out waiting to power ON", EC_WAITING_OFF : "Failed: Timed out waiting to power OFF", EC_STATUS : "Failed: Unable to obtain correct plug status or plug is not available", EC_STATUS_HMC : "Failed: Either unable to obtain correct plug status, " "partition is not available or incorrect HMC version used", EC_PASSWORD_MISSING : "Failed: You have to set login password", EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action." }[error_code] + "\n" logging.error("%s\n" % message) syslog.syslog(syslog.LOG_ERR, message) sys.exit(EC_GENERIC_ERROR) def usage(avail_opt): print "Usage:" print "\t" + os.path.basename(sys.argv[0]) + " [options]" print "Options:" sorted_list = [ (key, all_opt[key]) for key in avail_opt ] sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) for key, value in sorted_list: if len(value["help"]) != 0: print " " + value["help"] def metadata(avail_opt, options, docs): # avail_opt has to be unique, if there are duplicities then they should be removed sorted_list = [ (key, all_opt[key]) for key in list(set(avail_opt)) ] sorted_list.sort(lambda x, y: cmp(x[1]["order"], y[1]["order"])) print "" print "" if "symlink" in docs: for (symlink, desc) in docs["symlink"]: print "" print "" + docs["longdesc"] + "" if docs.has_key("vendorurl"): print "" + docs["vendorurl"] + "" print "" for option, _ in sorted_list: if all_opt[option].has_key("shortdesc"): print "\t" default = "" if all_opt[option].has_key("default"): default = str(all_opt[option]["default"]) elif options.has_key("--" + all_opt[option]["longopt"]) and all_opt[option]["getopt"].endswith(":"): if options["--" + all_opt[option]["longopt"]]: try: default = options["--" + all_opt[option]["longopt"]] except TypeError: ## @todo/@note: Currently there is no clean way how to handle lists ## we can create a string from it but we can't set it on command line default = str(options["--" + all_opt[option]["longopt"]]) elif options.has_key("--" + all_opt[option]["longopt"]): default = "true" if default: default = default.replace("&", "&" ) default = default.replace('"', """ ) default = default.replace('<', "<" ) default = default.replace('>', ">" ) default = default.replace("'", "'" ) default = "default=\"" + default + "\" " mixed = all_opt[option]["help"] ## split it between option and help text res = re.compile(r"^(.*--\S+)\s+", re.IGNORECASE | re.S).search(mixed) - if (None != res): + if None != res: mixed = res.group(1) mixed = mixed.replace("<", "<").replace(">", ">") print "\t\t" if all_opt[option].has_key("choices"): print "\t\t" for choice in all_opt[option]["choices"]: print "\t\t\t" elif all_opt[option]["getopt"].count(":") > 0: print "\t\t" else: print "\t\t" print "\t\t" + all_opt[option]["shortdesc"] + "" print "\t" print "" print "" if avail_opt.count("fabric_fencing") == 1: ## do 'unfence' at the start print "\t" else: print "\t" print "\t" if avail_opt.count("fabric_fencing") == 0: print "\t" print "\t" print "\t" print "\t" print "\t" print "" print "" def process_input(avail_opt): avail_opt.extend(add_dependency_options(avail_opt)) ## ## Set standard environment ##### os.putenv("LANG", "C") os.putenv("LC_ALL", "C") ## ## Prepare list of options for getopt ##### getopt_string = "" longopt_list = [ ] for k in avail_opt: if all_opt.has_key(k): getopt_string += all_opt[k]["getopt"] else: fail_usage("Parse error: unknown option '"+k+"'") if all_opt.has_key(k) and all_opt[k].has_key("longopt"): if all_opt[k]["getopt"].endswith(":"): longopt_list.append(all_opt[k]["longopt"] + "=") else: longopt_list.append(all_opt[k]["longopt"]) ## ## Read options from command line or standard input ##### if len(sys.argv) > 1: try: opt, _args = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) except getopt.GetoptError, error: fail_usage("Parse error: " + error.msg) ## Transform short getopt to long one which are used in fencing agents ##### old_opt = opt opt = { } for o in dict(old_opt).keys(): if o.startswith("--"): for x in all_opt.keys(): if all_opt[x].has_key("longopt") and "--" + all_opt[x]["longopt"] == o: opt["--" + all_opt[x]["longopt"]] = dict(old_opt)[o] else: for x in all_opt.keys(): if x in avail_opt and all_opt[x].has_key("getopt") and all_opt[x].has_key("longopt") and \ ("-" + all_opt[x]["getopt"] == o or "-" + all_opt[x]["getopt"].rstrip(":") == o): opt["--" + all_opt[x]["longopt"]] = dict(old_opt)[o] opt[o] = dict(old_opt)[o] ## Compatibility Layer ##### z = dict(opt) if z.has_key("--plug") == 1: z["-m"] = z["--plug"] opt = z ## ##### else: opt = { } name = "" for line in sys.stdin.readlines(): line = line.strip() - if ((line.startswith("#")) or (len(line) == 0)): + if (line.startswith("#")) or (len(line) == 0): continue (name, value) = (line + "=").split("=", 1) value = value[:-1] if avail_opt.count(name) == 0: logging.warning("Parse error: Ignoring unknown option '%s'\n" % line) syslog.syslog(syslog.LOG_WARNING, "Parse error: Ignoring unknown option '"+line) continue if all_opt[name]["getopt"].endswith(":"): opt["--"+all_opt[name]["longopt"].rstrip(":")] = value elif value.lower() in [ "1", "yes", "on", "true" ]: opt["--"+all_opt[name]["longopt"]] = "1" return opt ## ## This function checks input and answers if we want to have same answers ## in each of the fencing agents. It looks for possible errors and run ## password script to set a correct password ###### def check_input(device_opt, opt): device_opt.extend(add_dependency_options(device_opt)) options = dict(opt) options["device_opt"] = device_opt ## Set requirements that should be included in metadata ##### if device_opt.count("login") and device_opt.count("no_login") == 0: all_opt["login"]["required"] = "1" else: all_opt["login"]["required"] = "0" if device_opt.count("fabric_fencing"): all_opt["action"]["default"] = "off" all_opt["action"]["help"] = "-o, --action=[action] Action: status, off (default) or on" ## Set default values ##### for opt in device_opt: if all_opt[opt].has_key("default"): getopt_long = "--" + all_opt[opt]["longopt"] if 0 == options.has_key(getopt_long): options[getopt_long] = all_opt[opt]["default"] if device_opt.count("ipport"): if options.has_key("--ipport"): all_opt["ipport"]["help"] = "-u, --ipport=[port] " + \ "TCP/UDP port to use (default " + options["--ipport"] +")" elif device_opt.count("snmp_version"): all_opt["ipport"]["default"] = "161" all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 161)" elif options.has_key("--ssh"): all_opt["ipport"]["default"] = 22 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 22)" elif options.has_key("--ssl"): all_opt["ipport"]["default"] = 443 all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 443)" elif device_opt.count("web"): all_opt["ipport"]["default"] = 80 if device_opt.count("ssl") == 0: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 80)" else: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\ (default 80, 443 if --ssl option is used)" else: all_opt["ipport"]["default"] = 23 if device_opt.count("secure") == 0: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use (default 23)" else: all_opt["ipport"]["help"] = "-u, --ipport=[port] TCP/UDP port to use\n\ (default 23, 22 if --ssh option is used)" ## In special cases (show help, metadata or version) we don't need to check anything ##### if options.has_key("--help") or options.has_key("--version") or \ (options.has_key("--action") and options["--action"].lower() == "metadata"): return options options["--action"] = options["--action"].lower() if options.has_key("--verbose"): logging.getLogger().setLevel(logging.DEBUG) acceptable_actions = [ "on", "off", "status", "list", "monitor" ] if 1 == device_opt.count("fabric_fencing"): ## Compatibility layer ##### acceptable_actions.extend(["enable", "disable"]) else: acceptable_actions.extend(["reboot"]) if 0 == acceptable_actions.count(options["--action"]): fail_usage("Failed: Unrecognised action '" + options["--action"] + "'") ## Compatibility layer ##### if options["--action"] == "enable": options["--action"] = "on" if options["--action"] == "disable": options["--action"] = "off" ## automatic detection and set of valid UUID from --plug if (0 == options.has_key("--username")) and \ device_opt.count("login") and (device_opt.count("no_login") == 0): fail_usage("Failed: You have to set login name") if device_opt.count("ipaddr") and 0 == options.has_key("--ip") and 0 == options.has_key("--managed"): fail_usage("Failed: You have to enter fence address") - if (device_opt.count("no_password") == 0): + if device_opt.count("no_password") == 0: if 0 == device_opt.count("identity_file"): if 0 == (options.has_key("--password") or options.has_key("--password-script")): fail_usage("Failed: You have to enter password or password script") else: if 0 == (options.has_key("--password") or \ options.has_key("--password-script") or options.has_key("--identity-file")): fail_usage("Failed: You have to enter password, password script or identity file") if 0 == options.has_key("--ssh") and 1 == options.has_key("--identity-file"): fail_usage("Failed: You have to use identity file together with ssh connection (-x)") if 1 == options.has_key("--identity-file"): if 0 == os.path.isfile(options["--identity-file"]): fail_usage("Failed: Identity file " + options["--identity-file"] + " does not exist") if (0 == ["list", "monitor"].count(options["--action"].lower())) and \ 0 == options.has_key("--plug") and device_opt.count("port") and device_opt.count("no_port") == 0: fail_usage("Failed: You have to enter plug number or machine identification") if options.has_key("--password-script"): options["--password"] = os.popen(options["--password-script"]).read().rstrip() if options.has_key("--debug-file"): try: fh = logging.FileHandler(options["--debug-file"]) fh.setLevel(logging.DEBUG) logging.getLogger().addHandler(fh) except IOError: logging.error("Unable to create file %s" % options["--debug-file"]) fail_usage("Failed: Unable to create file " + options["--debug-file"]) if options.has_key("--snmp-priv-passwd-script"): options["--snmp-priv-passwd"] = os.popen(options["--snmp-priv-passwd-script"]).read().rstrip() if options.has_key("--ipport") == False: if options.has_key("--ssh"): options["--ipport"] = 22 elif options.has_key("--ssl"): options["--ipport"] = 443 elif device_opt.count("web"): options["--ipport"] = 80 else: options["--ipport"] = 23 if options.has_key("--plug") and len(options["--plug"].split(",")) > 1 and \ options.has_key("--method") and options["--method"] == "cycle": fail_usage("Failed: Cannot use --method cycle for more than 1 plug") for opt in device_opt: if all_opt[opt].has_key("choices"): longopt = "--" + all_opt[opt]["longopt"] possible_values_upper = [y.upper() for y in all_opt[opt]["choices"]] if options.has_key(longopt): options[longopt] = options[longopt].upper() if not options["--" + all_opt[opt]["longopt"]] in possible_values_upper: fail_usage("Failed: You have to enter a valid choice " + \ "for %s from the valid values: %s" % \ ("--" + all_opt[opt]["longopt"] , str(all_opt[opt]["choices"]))) return options def wait_power_status(tn, options, get_power_fn): for dummy in xrange(int(options["--power-timeout"])): if get_multi_power_fn(tn, options, get_power_fn) != options["--action"]: time.sleep(1) else: return 1 return 0 ## Obtain a power status from possibly more than one plug ## "on" is returned if at least one plug is ON ###### def get_multi_power_fn(tn, options, get_power_fn): status = "off" if options.has_key("--plugs"): for plug in options["--plugs"]: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug plug_status = get_power_fn(tn, options) if plug_status != "off": status = plug_status else: status = get_power_fn(tn, options) return status def set_multi_power_fn(tn, options, set_power_fn): if options.has_key("--plugs"): for plug in options["--plugs"]: try: options["--uuid"] = str(uuid.UUID(plug)) except ValueError: pass except KeyError: pass options["--plug"] = plug set_power_fn(tn, options) else: set_power_fn(tn, options) def show_docs(options, docs = None): device_opt = options["device_opt"] if docs == None: docs = { } docs["shortdesc"] = "Fence agent" docs["longdesc"] = "" ## Process special options (and exit) ##### if options.has_key("--help"): usage(device_opt) sys.exit(0) if options.has_key("--action") and options["--action"].lower() == "metadata": metadata(device_opt, options, docs) sys.exit(0) if options.has_key("--version"): print __main__.RELEASE_VERSION, __main__.BUILD_DATE print __main__.REDHAT_COPYRIGHT sys.exit(0) def fence_action(tn, options, set_power_fn, get_power_fn, get_outlet_list = None, reboot_cycle_fn = None): result = 0 try: if options.has_key("--plug"): options["--plugs"] = options["--plug"].split(",") ## Process options that manipulate fencing device ##### - if (options["--action"] == "list") and 0 == options["device_opt"].count("port"): + if options["--action"] == "list" and 0 == options["device_opt"].count("port"): print "N/A" return - elif (options["--action"] == "list" and get_outlet_list == None): + elif options["--action"] == "list" and get_outlet_list == None: ## @todo: exception? ## This is just temporal solution, we will remove default value ## None as soon as all existing agent will support this operation print "NOTICE: List option is not working on this device yet" return elif (options["--action"] == "list") or \ ((options["--action"] == "monitor") and 1 == options["device_opt"].count("port")): outlets = get_outlet_list(tn, options) ## keys can be numbers (port numbers) or strings (names of VM) for outlet_id in outlets.keys(): (alias, status) = outlets[outlet_id] if options["--action"] != "monitor": print outlet_id + options["--separator"] + alias return status = get_multi_power_fn(tn, options, get_power_fn) if status != "on" and status != "off": fail(EC_STATUS) if options["--action"] == "on": if status == "on": print "Success: Already ON" else: power_on = False for _ in range(1, 1 + int(options["--retry-on"])): set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn): power_on = True break if power_on: print "Success: Powered ON" else: fail(EC_WAITING_ON) elif options["--action"] == "off": if status == "off": print "Success: Already OFF" else: set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn): print "Success: Powered OFF" else: fail(EC_WAITING_OFF) elif options["--action"] == "reboot": power_on = False if options.has_key("--method") and options["--method"].lower() == "cycle" and reboot_cycle_fn is not None: for _ in range(1, 1 + int(options["--retry-on"])): if reboot_cycle_fn(tn, options): power_on = True break if not power_on: fail(EC_TIMED_OUT) else: if status != "off": options["--action"] = "off" set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn) == 0: fail(EC_WAITING_OFF) options["--action"] = "on" try: for _ in range(1, 1 + int(options["--retry-on"])): set_multi_power_fn(tn, options, set_power_fn) time.sleep(int(options["--power-wait"])) if wait_power_status(tn, options, get_power_fn) == 1: power_on = True break except Exception, ex: # an error occured during power ON phase in reboot # fence action was completed succesfully even in that case logging.error("%s\n", str(ex)) syslog.syslog(syslog.LOG_NOTICE, str(ex)) if power_on == False: # this should not fail as node was fenced succesfully logging.error('Timed out waiting to power ON\n') syslog.syslog(syslog.LOG_NOTICE, "Timed out waiting to power ON") print "Success: Rebooted" elif options["--action"] == "status": print "Status: " + status.upper() if status.upper() == "OFF": result = 2 elif options["--action"] == "monitor": pass except pexpect.EOF: fail(EC_CONNECTION_LOST) except pexpect.TIMEOUT: fail(EC_TIMED_OUT) except pycurl.error, ex: logging.error("%s\n" % str(ex)) syslog.syslog(syslog.LOG_ERR, ex[1]) fail(EC_TIMED_OUT) return result def fence_login(options, re_login_string = r"(login\s*: )|(Login Name: )|(username: )|(User Name :)"): force_ipvx = "" - if (options.has_key("--inet6-only")): + if options.has_key("--inet6-only"): force_ipvx = "-6 " - if (options.has_key("--inet4-only")): + if options.has_key("--inet4-only"): force_ipvx = "-4 " - if (options.has_key("eol") == False): + if not options.has_key("eol"): options["eol"] = "\r\n" if options.has_key("--command-prompt") and type(options["--command-prompt"]) is not list: options["--command-prompt"] = [ options["--command-prompt"] ] ## Do the delay of the fence device before logging in ## Delay is important for two-node clusters fencing but we do not need to delay 'status' operations if options["--action"] in ["off", "reboot"]: logging.info("Delay %s second(s) before logging in to the fence device" % options["--delay"]) time.sleep(int(options["--delay"])) try: re_login = re.compile(re_login_string, re.IGNORECASE) re_pass = re.compile("(password)|(pass phrase)", re.IGNORECASE) if options.has_key("--ssl"): gnutls_opts = "" if options.has_key("--notls"): gnutls_opts = "--priority \"NORMAL:-VERS-TLS1.2:-VERS-TLS1.1:-VERS-TLS1.0:+VERS-SSL3.0\"" command = '%s %s --insecure --crlf -p %s %s' % \ (SSL_PATH, gnutls_opts, options["--ipport"], options["--ip"]) try: conn = fspawn(options, command) except pexpect.ExceptionPexpect, ex: logging.error("%s\n" % str(ex)) syslog.syslog(syslog.LOG_ERR, str(ex)) sys.exit(EC_GENERIC_ERROR) elif options.has_key("--ssh") and 0 == options.has_key("--identity-file"): command = '%s %s %s@%s -p %s -o PubkeyAuthentication=no' % \ (SSH_PATH, force_ipvx, options["--username"], options["--ip"], options["--ipport"]) if options.has_key("--ssh-options"): command += ' ' + options["--ssh-options"] conn = fspawn(options, command) if options.has_key("telnet_over_ssh"): # This is for stupid ssh servers (like ALOM) which behave more like telnet # (ignore name and display login prompt) result = conn.log_expect(options, \ [ re_login, "Are you sure you want to continue connecting (yes/no)?" ], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") # Host identity confirm conn.log_expect(options, re_login, int(options["--login-timeout"])) conn.sendline(options["--username"]) conn.log_expect(options, re_pass, int(options["--login-timeout"])) else: result = conn.log_expect(options, \ [ "ssword:", "Are you sure you want to continue connecting (yes/no)?" ], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") conn.log_expect(options, "ssword:", int(options["--login-timeout"])) conn.sendline(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) elif options.has_key("--ssh") and options.has_key("--identity-file"): command = '%s %s %s@%s -i %s -p %s' % \ (SSH_PATH, force_ipvx, options["--username"], options["--ip"], \ options["--identity-file"], options["--ipport"]) if options.has_key("--ssh-options"): command += ' ' + options["--ssh-options"] conn = fspawn(options, command) result = conn.log_expect(options, [ "Enter passphrase for key '" + options["--identity-file"] + "':", \ "Are you sure you want to continue connecting (yes/no)?" ] + \ options["--command-prompt"], int(options["--login-timeout"])) if result == 1: conn.sendline("yes") result = conn.log_expect(options, [ "Enter passphrase for key '" + options["--identity-file"]+"':"] + \ options["--command-prompt"], int(options["--login-timeout"])) if result == 0: if options.has_key("--password"): conn.sendline(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) else: fail_usage("Failed: You have to enter passphrase (-p) for identity file") else: conn = fspawn(options, TELNET_PATH) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) result = conn.log_expect(options, re_login, int(options["--login-timeout"])) conn.send_eol(options["--username"]) ## automatically change end of line separator screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) - if (re_login.search(screen) != None): + if re_login.search(screen) != None: options["eol"] = "\n" conn.send_eol(options["--username"]) result = conn.log_expect(options, re_pass, int(options["--login-timeout"])) - elif (re_pass.search(screen) == None): + elif re_pass.search(screen) != None: conn.log_expect(options, re_pass, int(options["--shell-timeout"])) try: conn.send_eol(options["--password"]) valid_password = conn.log_expect(options, [ re_login ] + \ options["--command-prompt"], int(options["--shell-timeout"])) if valid_password == 0: ## password is invalid or we have to change EOL separator options["eol"] = "\r" conn.send_eol("") screen = conn.read_nonblocking(size=100, timeout=int(options["--shell-timeout"])) ## after sending EOL the fence device can either show 'Login' or 'Password' - if (re_login.search(screen) != None): + if re_login.search(screen) != None: conn.send_eol("") conn.send_eol(options["--username"]) conn.log_expect(options, re_pass, int(options["--login-timeout"])) conn.send_eol(options["--password"]) conn.log_expect(options, options["--command-prompt"], int(options["--login-timeout"])) except KeyError: fail(EC_PASSWORD_MISSING) except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) return conn def is_executable(path): if os.path.exists(path): stats = os.stat(path) if stat.S_ISREG(stats.st_mode) and os.access(path, os.X_OK): return True return False def run_command(options, command, timeout = None, env = None): if timeout is None and "--power-timeout" in options: timeout = options["--power-timeout"] if timeout is not None: timeout = float(timeout) logging.info("Executing: %s\n" % command) try: process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) except OSError, ex: fail_usage("Unable to run %s\n" % command) thread = threading.Thread(target = process.wait) thread.start() thread.join(timeout) - if (thread.is_alive()): + if thread.is_alive(): process.kill() fail(EC_TIMED_OUT) status = process.wait() (pipe_stdout, pipe_stderr) = process.communicate() process.stdout.close() process.stderr.close() logging.debug("%s %s %s\n" % (str(status), str(pipe_stdout), str(pipe_stderr))) return (status, pipe_stdout, pipe_stderr) diff --git a/fence/agents/lib/fencing_snmp.py.py b/fence/agents/lib/fencing_snmp.py.py index 055c8f23..24ad1719 100644 --- a/fence/agents/lib/fencing_snmp.py.py +++ b/fence/agents/lib/fencing_snmp.py.py @@ -1,137 +1,137 @@ #!/usr/bin/python -tt # For example of use please see fence_cisco_mds import re, pexpect import logging from fencing import * from fencing import fail, fail_usage, EC_TIMED_OUT __all__ = [ 'FencingSnmp' ] ## do not add code here. #BEGIN_VERSION_GENERATION RELEASE_VERSION = "" REDHAT_COPYRIGHT = "" BUILD_DATE = "" #END_VERSION_GENERATION class FencingSnmp: def __init__(self, options): self.options = options # Log message if user set verbose option def log_command(self, message): logging.debug("%s\n" % message) def quote_for_run(self, string): return string.replace(r"'", "'\\''") def complete_missed_params(self): mapping = [[ ['snmp-priv-passwd','password','!snmp-sec-level'], 'self.options["--snmp-sec-level"]="authPriv"' ],[ ['!snmp-version','community','!username','!snmp-priv-passwd','!password'], 'self.options["--snmp-version"]="2c"' ]] for val in mapping: e = val[0] res = True for item in e: - if ((item[0]=='!') and (self.options.has_key("--"+item[1:]))): + if item[0] == '!' and self.options.has_key("--" + item[1:]): res = False break - if ((item[0]!='!') and (not self.options.has_key("--"+item[0:]))): + if item[0] != '!' and not self.options.has_key("--" + item[0:]): res = False break if res: exec(val[1]) def prepare_cmd(self, command): cmd = "@SNMPBIN@/%s -m '' -Oeqn "% (command) self.complete_missed_params() #mapping from our option to snmpcmd option mapping = (('snmp-version', 'v'),('community', 'c')) for item in mapping: - if (self.options.has_key("--" + item[0])): + if self.options.has_key("--" + item[0]): cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) # Some options make sense only for v3 (and for v1/2c can cause "problems") if (self.options.has_key("--snmp-version")) and (self.options["--snmp-version"] == "3"): # Mapping from our options to snmpcmd options for v3 mapping_v3 = (('snmp-auth-prot','a'), ('snmp-sec-level','l'), ('snmp-priv-prot','x'), \ ('snmp-priv-passwd','X'),('password','A'),('username','u')) for item in mapping_v3: - if (self.options.has_key("--"+item[0])): + if self.options.has_key("--"+item[0]): cmd += " -%s '%s'"% (item[1], self.quote_for_run(self.options["--" + item[0]])) force_ipvx = "" - if (self.options.has_key("--inet6-only")): + if self.options.has_key("--inet6-only"): force_ipvx = "udp6:" - if (self.options.has_key("--inet4-only")): + if self.options.has_key("--inet4-only"): force_ipvx = "udp:" cmd += " '%s%s%s'"% (force_ipvx, self.quote_for_run(self.options["--ip"]), self.options.has_key("--ipport") and self.quote_for_run(":" + str (self.options["--ipport"])) or "") return cmd def run_command(self, command, additional_timemout=0): try: self.log_command(command) (res_output, res_code) = pexpect.run(command, int(self.options["--shell-timeout"]) + int(self.options["--login-timeout"]) + additional_timemout, True) - if (res_code==None): + if res_code == None: fail(EC_TIMED_OUT) self.log_command(res_output) if (res_code!=0) or (re.search("^Error ", res_output, re.MULTILINE) != None): fail_usage("Returned %d: %s"% (res_code, res_output)) except pexpect.ExceptionPexpect: fail_usage("Cannot run command %s"%(command)) return res_output def get(self, oid, additional_timemout=0): cmd = "%s '%s'"% (self.prepare_cmd("snmpget"), self.quote_for_run(oid)) output = self.run_command(cmd, additional_timemout).splitlines() return output[len(output)-1].split(None, 1) def set(self, oid, value, additional_timemout=0): mapping = ((int, 'i'), (str, 's')) type_of_value = '' for item in mapping: - if (isinstance(value, item[0])): + if isinstance(value, item[0]): type_of_value = item[1] break cmd = "%s '%s' %s '%s'" % (self.prepare_cmd("snmpset"), self.quote_for_run(oid), type_of_value, self.quote_for_run(str(value))) self.run_command(cmd, additional_timemout) def walk(self, oid, additional_timemout=0): cmd = "%s '%s'"% (self.prepare_cmd("snmpwalk"), self.quote_for_run(oid)) output = self.run_command(cmd, additional_timemout).splitlines() return [ x.split(None,1) for x in output if x.startswith(".") ] diff --git a/fence/agents/ovh/fence_ovh.py b/fence/agents/ovh/fence_ovh.py index 24c3972e..f4e9caf4 100644 --- a/fence/agents/ovh/fence_ovh.py +++ b/fence/agents/ovh/fence_ovh.py @@ -1,148 +1,148 @@ #!/usr/bin/python -tt # Copyright 2013 Adrian Gibanel Lopez (bTactic) # Adrian Gibanel improved this script at 2013 to add verification of success and to output metadata # Based on: # This is a fence agent for use at OVH # As there are no other fence devices available, we must use OVH's SOAP API #Quick-and-dirty # assemled by Dennis Busch, secofor GmbH, Germany # This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. import sys, time import shutil, tempfile import logging import atexit from datetime import datetime from suds.client import Client from suds.xsd.doctor import ImportDoctor, Import sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_LOGIN_DENIED OVH_RESCUE_PRO_NETBOOT_ID = '28' OVH_HARD_DISK_NETBOOT_ID = '1' STATUS_HARD_DISK_SLEEP = 240 # Wait 4 minutes to SO to boot STATUS_RESCUE_PRO_SLEEP = 150 # Wait 2 minutes 30 seconds to Rescue-Pro to run def define_new_opts(): all_opt["email"] = { "getopt" : "Z:", "longopt" : "email", "help" : "-Z, --email= email for reboot message: admin@domain.com", "required" : "1", "shortdesc" : "Reboot email", "default" : "", "order" : 1 } def netboot_reboot(options, mode): conn = soap_login(options) # dedicatedNetbootModifyById changes the mode of the next reboot conn.service.dedicatedNetbootModifyById(options["session"], options["--plug"], mode, '', options["--email"]) - + # dedicatedHardRebootDo initiates a hard reboot on the given node conn.service.dedicatedHardRebootDo(options["session"], options["--plug"], 'Fencing initiated by cluster', '', 'en') conn.logout(options["session"]) def reboot_time(options): conn = soap_login(options) result = conn.service.dedicatedHardRebootStatus(options["session"], options["--plug"]) tmpstart = datetime.strptime(result.start,'%Y-%m-%d %H:%M:%S') tmpend = datetime.strptime(result.end,'%Y-%m-%d %H:%M:%S') result.start = tmpstart result.end = tmpend conn.logout(options["session"]) return result def soap_login(options): imp = Import('http://schemas.xmlsoap.org/soap/encoding/') url = 'https://www.ovh.com/soapi/soapi-re-1.59.wsdl' imp.filter.add('http://soapi.ovh.com/manager') d = ImportDoctor(imp) tmp_dir = tempfile.mkdtemp() tempfile.tempdir = tmp_dir atexit.register(remove_tmp_dir, tmp_dir) try: soap = Client(url, doctor=d) session = soap.service.login(options["--username"], options["--password"], 'en', 0) except Exception: fail(EC_LOGIN_DENIED) options["session"] = session return soap def remove_tmp_dir(tmp_dir): shutil.rmtree(tmp_dir) - + def main(): device_opt = [ "login", "passwd", "port", "email" ] atexit.register(atexit_handler) define_new_opts() options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for OVH" docs["longdesc"] = "fence_ovh is an Power Fencing agent \ which can be used within OVH datecentre. \ Poweroff is simulated with a reboot into rescue-pro mode." docs["vendorurl"] = "http://www.ovh.net" show_docs(options, docs) if options["--action"] in [ "list", "status"]: fail_usage("Action '" + options["--action"] + "' is not supported in this fence agent") if options["--plug"].endswith(".ovh.net") == False: options["--plug"] += ".ovh.net" if options.has_key("--email") == False: fail_usage("You have to enter e-mail address which is notified by fence agent") # Save datetime just before changing netboot before_netboot_reboot = datetime.now() if options["--action"] == 'off': # Reboot in Rescue-pro netboot_reboot(options, OVH_RESCUE_PRO_NETBOOT_ID) time.sleep(STATUS_RESCUE_PRO_SLEEP) elif options["--action"] in ['on', 'reboot' ]: # Reboot from HD netboot_reboot(options, OVH_HARD_DISK_NETBOOT_ID) time.sleep(STATUS_HARD_DISK_SLEEP) # Save datetime just after reboot after_netboot_reboot = datetime.now() # Verify that action was completed sucesfully reboot_t = reboot_time(options) logging.debug("reboot_start_end.start: %s\n" % reboot_t.start.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("before_netboot_reboot: %s\n" % before_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("reboot_start_end.end: %s\n" % reboot_t.end.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("after_netboot_reboot: %s\n" % after_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) - + if reboot_t.start < after_netboot_reboot < reboot_t.end: result = 0 logging.debug("Netboot reboot went OK.\n") else: result = 1 logging.debug("ERROR: Netboot reboot wasn't OK.\n") sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rhevm/fence_rhevm.py b/fence/agents/rhevm/fence_rhevm.py index 54af81b2..8ff5ee98 100644 --- a/fence/agents/rhevm/fence_rhevm.py +++ b/fence/agents/rhevm/fence_rhevm.py @@ -1,133 +1,133 @@ #!/usr/bin/python -tt import sys, re import pycurl, StringIO import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS #BEGIN_VERSION_GENERATION RELEASE_VERSION="New RHEV-M Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION RE_GET_ID = re.compile("(.*?)", re.IGNORECASE) RE_GET_NAME = re.compile("(.*?)", re.IGNORECASE) def get_power_status(conn, options): del conn ### Obtain real ID from name res = send_command(options, "vms/?search=name%3D" + options["--plug"]) result = RE_GET_ID.search(res) - if (result == None): + if result == None: # Unable to obtain ID needed to access virtual machine fail(EC_STATUS) options["id"] = result.group(2) result = RE_STATUS.search(res) - if (result == None): + if result == None: # We were able to parse ID so output is correct # in some cases it is possible that RHEV-M output does not # contain line. We can assume machine is OFF then return "off" else: status = result.group(1) - if (status.lower() == "down"): + if status.lower() == "down": return "off" else: return "on" def set_power_status(conn, options): del conn action = { 'on' : "start", 'off' : "stop" }[options["--action"]] url = "vms/" + options["id"] + "/" + action send_command(options, url, "POST") def get_list(conn, options): del conn outlets = { } try: res = send_command(options, "vms") lines = res.split("") conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) conn.perform() result = web_buffer.getvalue() logging.debug("%s\n" % command) logging.debug("%s\n" % result) return result def main(): device_opt = [ "ipaddr", "login", "passwd", "ssl", "notls", "web", "port" ] atexit.register(atexit_handler) all_opt["power_wait"]["default"] = "1" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for RHEV-M REST API" docs["longdesc"] = "fence_rhevm is an I/O Fencing agent which can be \ used with RHEV-M REST API to fence virtual machines." docs["vendorurl"] = "http://www.redhat.com" show_docs(options, docs) ## ## Fence operations #### result = fence_action(None, options, set_power_status, get_power_status, get_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rsa/fence_rsa.py b/fence/agents/rsa/fence_rsa.py index ba937092..e1633975 100644 --- a/fence/agents/rsa/fence_rsa.py +++ b/fence/agents/rsa/fence_rsa.py @@ -1,78 +1,78 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## Main GFEP25A & Boot GFBP25A ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="New RSA2 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send_eol("power state") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) match = re.compile("Power: (.*)", re.IGNORECASE).search(conn.before) - if (match != None): + if match != None: status = match.group(1) else: status = "undefined" return status.lower().strip() def set_power_status(conn, options): conn.send_eol("power " + options["--action"]) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure" ] atexit.register(atexit_handler) all_opt["login_timeout"]["default"] = 10 all_opt["cmd_prompt"]["default"] = [ ">" ] # This device will not allow us to login even with LANG=C all_opt["ssh_options"]["default"] = "-F /dev/null" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for IBM RSA" docs["longdesc"] = "fence_rsa is an I/O Fencing agent \ which can be used with the IBM RSA II management interface. It \ logs into an RSA II device via telnet and reboots the associated \ machine. Lengthy telnet connections to the RSA II device should \ be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) ## ## Operate the fencing device ###### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) ## ## Logout from system ###### try: conn.send_eol("exit") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/rsb/fence_rsb.py b/fence/agents/rsb/fence_rsb.py index b72d295a..e9e37de4 100755 --- a/fence/agents/rsb/fence_rsb.py +++ b/fence/agents/rsb/fence_rsb.py @@ -1,87 +1,87 @@ #!/usr/bin/python -tt import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_power_status(conn, options): conn.send("2") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) status = re.compile(r"Power Status[\s]*: (on|off)", re.IGNORECASE).search(conn.before).group(1) conn.send("0") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) - return (status.lower().strip()) + return status.lower().strip() def set_power_status(conn, options): action = { 'on' : "4", 'off': "1" }[options["--action"]] conn.send("2") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol(action) conn.log_expect(options, ["want to power off", "'yes' or 'no'"], int(options["--shell-timeout"])) conn.send_eol("yes") conn.log_expect(options, "any key to continue", int(options["--power-timeout"])) conn.send_eol("") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol("0") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "secure", "cmd_prompt" ] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [ "to quit:" ] opt = process_input(device_opt) # set default port for telnet only if 0 == opt.has_key("--ssh") and 0 == opt.has_key("--ipport"): opt["--ipport"] = "3172" options = check_input(device_opt, opt) docs = { } docs["shortdesc"] = "I/O Fencing agent for Fujitsu-Siemens RSB" docs["longdesc"] = "fence_rsb is an I/O Fencing agent \ which can be used with the Fujitsu-Siemens RSB management interface. It logs \ into device via telnet/ssh and reboots a specified outlet. Lengthy telnet/ssh \ connections should be avoided while a GFS cluster is running because the connection \ will block any necessary fencing actions." docs["vendorurl"] = "http://www.fujitsu.com" show_docs(options, docs) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, None) ## ## Logout from system ## ## In some special unspecified cases it is possible that ## connection will be closed before we run close(). This is not ## a problem because everything is checked before. ###### try: conn.send_eol("0") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/sanbox2/fence_sanbox2.py b/fence/agents/sanbox2/fence_sanbox2.py index 161e002f..c53f1eff 100644 --- a/fence/agents/sanbox2/fence_sanbox2.py +++ b/fence/agents/sanbox2/fence_sanbox2.py @@ -1,156 +1,156 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version Firmware ## +-----------------+---------------------------+ ##### import sys, re, pexpect, exceptions import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_TIMED_OUT, EC_GENERIC_ERROR #BEGIN_VERSION_GENERATION RELEASE_VERSION="New Sanbox2 Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_power_status(conn, options): status_trans = { 'online' : "on", 'offline' : "off" } try: conn.send_eol("show port " + options["--plug"]) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except: pass fail(EC_TIMED_OUT) status = re.compile(r".*AdminState\s+(online|offline)\s+", re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) try: return status_trans[status.lower().strip()] except KeyError: return "PROBLEM" def set_power_status(conn, options): action = { 'on' : "online", 'off' : "offline" }[options["--action"]] try: conn.send_eol("set port " + options["--plug"] + " state " + action) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except: pass fail(EC_TIMED_OUT) try: conn.send_eol("set port " + options["--plug"] + " state " + action) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except: pass fail(EC_TIMED_OUT) def get_list_devices(conn, options): outlets = { } try: conn.send_eol("show port") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) list_re = re.compile(r"^\s+(\d+?)\s+(Online|Offline)\s+", re.IGNORECASE) for line in conn.before.splitlines(): - if (list_re.search(line)): + if list_re.search(line): status = { 'online' : "ON", 'offline' : "OFF" }[list_re.search(line).group(2).lower()] outlets[list_re.search(line).group(1)] = ("", status) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() except: pass fail(EC_TIMED_OUT) return outlets def main(): device_opt = [ "fabric_fencing", "ipaddr", "login", "passwd", "cmd_prompt", "port" ] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [ " #> " ] options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for QLogic SANBox2 FC switches" docs["longdesc"] = "fence_sanbox2 is an I/O Fencing agent which can be used with \ QLogic SANBox2 FC switches. It logs into a SANBox2 switch via telnet and disables a specified \ port. Disabling the port which a machine is connected to effectively fences that machine. \ Lengthy telnet connections to the switch should be avoided while a GFS cluster is running \ because the connection will block any necessary fencing actions." docs["vendorurl"] = "http://www.qlogic.com" show_docs(options, docs) ## ## Operate the fencing device ## conn = fence_login(options) conn.send_eol("admin start") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) - if (re.search(r"\(admin\)", conn.before, re.MULTILINE) == None): + if re.search(r"\(admin\)", conn.before, re.MULTILINE) == None: ## Someone else is in admin section, we can't enable/disable ## ports so we will rather exit logging.error("Failed: Unable to switch to admin section\n") sys.exit(EC_GENERIC_ERROR) result = fence_action(conn, options, set_power_status, get_power_status, get_list_devices) ## ## Logout from system ###### try: conn.send_eol("admin end") conn.send_eol("exit\n") conn.close() except exceptions.OSError: pass except pexpect.ExceptionPexpect: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/virsh/fence_virsh.py b/fence/agents/virsh/fence_virsh.py index cbdb3998..9f94f58f 100644 --- a/fence/agents/virsh/fence_virsh.py +++ b/fence/agents/virsh/fence_virsh.py @@ -1,106 +1,106 @@ #!/usr/bin/python -tt # The Following Agent Has Been Tested On: # # Virsh 0.3.3 on RHEL 5.2 with xen-3.0.3-51 # import sys, re import time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail_usage, SUDO_PATH #BEGIN_VERSION_GENERATION RELEASE_VERSION="Virsh fence agent" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION def get_name_or_uuid(options): return options["--uuid"] if options.has_key("--uuid") else options["--plug"] def get_outlets_status(conn, options): if options.has_key("--use-sudo"): prefix = SUDO_PATH + " " else: prefix = "" conn.sendline(prefix + "virsh list --all") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) result = {} #This is status of mini finite automata. 0 = we didn't found Id and Name, 1 = we did fa_status = 0 for line in conn.before.splitlines(): domain = re.search(r"^\s*(\S+)\s+(\S+)\s+(\S+).*$", line) - if (domain!=None): - if ((fa_status==0) and (domain.group(1).lower()=="id") and (domain.group(2).lower()=="name")): + if domain != None: + if fa_status == 0 and domain.group(1).lower() == "id" and domain.group(2).lower() == "name": fa_status = 1 - elif (fa_status==1): + elif fa_status == 1: result[domain.group(2)] = ("", (domain.group(3).lower() in ["running", "blocked", "idle", "no state", "paused"] and "on" or "off")) return result def get_power_status(conn, options): prefix = SUDO_PATH + " " if options.has_key("--use-sudo") else "" conn.sendline(prefix + "virsh domstate %s" % (get_name_or_uuid(options))) conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) for line in conn.before.splitlines(): if line.strip() in ["running", "blocked", "idle", "no state", "paused"]: return "on" if "error:" in line.strip(): fail_usage("Failed: You have to enter existing name/UUID of virtual machine!") return "off" def set_power_status(conn, options): prefix = SUDO_PATH + " " if options.has_key("--use-sudo") else "" conn.sendline(prefix + "virsh %s " % (options["--action"] == "on" and "start" or "destroy") + get_name_or_uuid(options)) conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) time.sleep(int(options["--power-wait"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "cmd_prompt", "secure", "port", "sudo" ] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [ r"\[EXPECT\]#\ " ] all_opt["ssh_options"]["default"] = "-t '/bin/bash -c \"" + r"PS1=\[EXPECT\]#\ " + "/bin/bash --noprofile --norc\"'" options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for virsh" docs["longdesc"] = "fence_virsh is an I/O Fencing agent \ which can be used with the virtual machines managed by libvirt. \ It logs via ssh to a dom0 and there run virsh command, which does \ all work. \ \n.P\n\ By default, virsh needs root account to do properly work. So you \ must allow ssh login in your sshd_config." docs["vendorurl"] = "http://libvirt.org" show_docs(options, docs) ## Operate the fencing device conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_outlets_status) ## Logout from system try: conn.sendline("quit") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/vmware/fence_vmware.py b/fence/agents/vmware/fence_vmware.py index 80dc1223..4576f402 100644 --- a/fence/agents/vmware/fence_vmware.py +++ b/fence/agents/vmware/fence_vmware.py @@ -1,344 +1,344 @@ #!/usr/bin/python -tt # # The Following agent has been tested on: # vmrun 2.0.0 build-116503 (from VMware Server 2.0) against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # VMware ESX 3.5 # VMware Server 2.0.0 # VMware ESXi 3.5 update 2 # VMware Server 1.0.7 (works but list/status show only running VMs) # # VI Perl API 1.6 against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # VMware ESX 3.5 # VMware ESXi 3.5 update 2 # VMware Virtual Center 2.5 # # VMware vSphere SDK for Perl 4.0.0 against: # VMware ESX 4.0.0 # VMware vCenter 4.0.0 # import sys, re, pexpect import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_TIMED_OUT #BEGIN_VERSION_GENERATION RELEASE_VERSION="VMware Agent using VI Perl API and/or VIX vmrun command" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION ### CONSTANTS #### # VMware type is ESX/ESXi/VC VMWARE_TYPE_ESX = 0 # VMware type is Server 1.x VMWARE_TYPE_SERVER1 = 1 # VMware type is Server 2.x and/or ESX 3.5 up2, ESXi 3.5 up2, VC 2.5 up2 VMWARE_TYPE_SERVER2 = 2 # Minimum required version of vmrun command VMRUN_MINIMUM_REQUIRED_VERSION = 2 # Default path to vmhelper command VMHELPER_COMMAND = "fence_vmware_helper" # Default path to vmrun command VMRUN_COMMAND = "/usr/bin/vmrun" # Default type of vmware VMWARE_DEFAULT_TYPE = "esx" #### GLOBAL VARIABLES #### # Internal type. One of VMWARE_TYPE_, set by #vmware_check_vmware_type vmware_internal_type = VMWARE_TYPE_ESX # If ESX is disconnected, say, that VM is off (don't return previous state) vmware_disconnected_hack = False ### FUNCTIONS #### #Split string in simplified DSV format to array of items def dsv_split(dsv_str): delimiter_c = ':' escape_c = '\\' res = [] status = 0 tmp_str = "" for x in dsv_str: - if (status==0): - if (x==delimiter_c): + if status == 0: + if x == delimiter_c: res.append(tmp_str) tmp_str = "" - elif (x==escape_c): + elif x == escape_c: status = 1 else: tmp_str += x - elif (status==1): - if (x==delimiter_c): + elif status == 1: + if x == delimiter_c: tmp_str += delimiter_c - elif (x==escape_c): + elif x == escape_c: tmp_str += escape_c else: tmp_str += escape_c+x status = 0 - if (tmp_str != ""): + if tmp_str != "": res.append(tmp_str) return res # Quote string for proper existence in quoted string used for pexpect.run function # Ex. test'this will return test'\''this. So pexpect run will really pass ' to argument def quote_for_run(text): dstr = '' for c in text: if c == r"'": dstr += "'\\''" else: dstr += c return dstr # Return string with command and additional parameters (something like vmrun -h 'host' def vmware_prepare_command(options, add_login_params, additional_params): res = options["--exec"] - if (add_login_params): - if (vmware_internal_type==VMWARE_TYPE_ESX): + if add_login_params: + if vmware_internal_type==VMWARE_TYPE_ESX: res += " --server '%s' --username '%s' --password '%s' "% (quote_for_run(options["--ip"]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) - elif (vmware_internal_type==VMWARE_TYPE_SERVER2): + elif vmware_internal_type==VMWARE_TYPE_SERVER2: res += " -h 'https://%s/sdk' -u '%s' -p '%s' -T server "% (quote_for_run(options["--ip"]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) - elif (vmware_internal_type==VMWARE_TYPE_SERVER1): + elif vmware_internal_type==VMWARE_TYPE_SERVER1: host_name_array = options["--ip"].split(':') res += " -h '%s' -u '%s' -p '%s' -T server1 "% (quote_for_run(host_name_array[0]), quote_for_run(options["--username"]), quote_for_run(options["--password"])) - if (len(host_name_array)>1): + if len(host_name_array) > 1: res += "-P '%s' "% (quote_for_run(host_name_array[1])) - if ((options.has_key("--vmware-datacenter")) and (vmware_internal_type==VMWARE_TYPE_ESX)): + if options.has_key("--vmware-datacenter") and vmware_internal_type == VMWARE_TYPE_ESX: res += "--datacenter '%s' "% (quote_for_run(options["--vmware-datacenter"])) - if (additional_params != ""): + if additional_params != "": res += additional_params return res # Log message if user set verbose option def vmware_log(options, message): logging.debug("%s\n" % message) # Run command with timeout and parameters. Internaly uses vmware_prepare_command. Returns string # with output from vmrun command. If something fails (command not found, exit code is not 0), fail_usage # function is called (and never return). def vmware_run_command(options, add_login_params, additional_params, additional_timeout): command = vmware_prepare_command(options, add_login_params, additional_params) try: vmware_log(options, command) (res_output, res_code) = pexpect.run(command, int(options["--shell-timeout"]) + int(options["--login-timeout"]) + additional_timeout, True) - if (res_code==None): + if res_code == None: fail(EC_TIMED_OUT) - if ((res_code!=0) and (add_login_params)): + if res_code != 0 and add_login_params: vmware_log(options, res_output) fail_usage("%s returned %s"% (options["--exec"], res_output)) else: vmware_log(options, res_output) except pexpect.ExceptionPexpect: fail_usage("Cannot run command %s"% (options["--exec"])) return res_output # Get outlet list with status as hash table. If you will use add_vm_name, only VM with vmname is # returned. This is used in get_status function def vmware_get_outlets_vi(options, add_vm_name): outlets = {} - if (add_vm_name): + if add_vm_name: all_machines = vmware_run_command(options, True, ("--operation status --vmname '%s'"% (quote_for_run(options["--plug"]))), 0) else: all_machines = vmware_run_command(options, True, "--operation list", int(options["--power-timeout"])) all_machines_array = all_machines.splitlines() for machine in all_machines_array: machine_array = dsv_split(machine) - if (len(machine_array) == 4): - if (machine_array[0] in outlets): + if len(machine_array) == 4: + if machine_array[0] in outlets: fail_usage("Failed. More machines with same name %s found!"%(machine_array[0])) - if (vmware_disconnected_hack): + if vmware_disconnected_hack: outlets[machine_array[0]] = ("", ( ((machine_array[2].lower() in ["poweredon"]) and (machine_array[3].lower()=="connected")) and "on" or "off")) else: outlets[machine_array[0]] = ("", ((machine_array[2].lower() in ["poweredon"]) and "on" or "off")) return outlets # Get outlet list with status as hash table. def vmware_get_outlets_vix(options): outlets = {} running_machines = vmware_run_command(options, True, "list", 0) running_machines_array = running_machines.splitlines()[1:] - if (vmware_internal_type==VMWARE_TYPE_SERVER2): + if vmware_internal_type == VMWARE_TYPE_SERVER2: all_machines = vmware_run_command(options, True, "listRegisteredVM", 0) all_machines_array = all_machines.splitlines()[1:] - elif (vmware_internal_type==VMWARE_TYPE_SERVER1): + elif vmware_internal_type == VMWARE_TYPE_SERVER1: all_machines_array = running_machines_array for machine in all_machines_array: - if (machine!=""): + if machine != "": outlets[machine] = ("", ((machine in running_machines_array) and "on" or "off")) return outlets def get_outlets_status(conn, options): del conn - if (vmware_internal_type==VMWARE_TYPE_ESX): + if vmware_internal_type == VMWARE_TYPE_ESX: return vmware_get_outlets_vi(options, False) - if ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): + if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: return vmware_get_outlets_vix(options) def get_power_status(conn, options): - if (vmware_internal_type==VMWARE_TYPE_ESX): + if vmware_internal_type == VMWARE_TYPE_ESX: outlets = vmware_get_outlets_vi(options, True) else: outlets = get_outlets_status(conn, options) - if ((vmware_internal_type==VMWARE_TYPE_SERVER2) or (vmware_internal_type==VMWARE_TYPE_ESX)): - if (not (options["--plug"] in outlets)): + if vmware_internal_type == VMWARE_TYPE_SERVER2 or vmware_internal_type == VMWARE_TYPE_ESX: + if not options["--plug"] in outlets: fail_usage("Failed: You have to enter existing name of virtual machine!") else: return outlets[options["--plug"]][1] - elif (vmware_internal_type==VMWARE_TYPE_SERVER1): - return ((options["--plug"] in outlets) and "on" or "off") + elif vmware_internal_type == VMWARE_TYPE_SERVER1: + return (options["--plug"] in outlets) and "on" or "off" def set_power_status(conn, options): del conn - if (vmware_internal_type==VMWARE_TYPE_ESX): + if vmware_internal_type == VMWARE_TYPE_ESX: additional_params = "--operation %s --vmname '%s'" % \ ((options["--action"]=="on" and "on" or "off"), quote_for_run(options["--plug"])) - elif ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): + elif vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: additional_params = "%s '%s'" % \ ((options["--action"]=="on" and "start" or "stop"), quote_for_run(options["--plug"])) - if (options["--action"]=="off"): + if options["--action"] == "off": additional_params += " hard" vmware_run_command(options, True, additional_params, int(options["--power-timeout"])) # Returns True, if user uses supported vmrun version (currently >=2.0.0) otherwise False. def vmware_is_supported_vmrun_version(options): vmware_help_str = vmware_run_command(options, False, "", 0) version_re = re.search(r"vmrun version (\d\.(\d[\.]*)*)", vmware_help_str.lower()) - if (version_re==None): + if version_re == None: return False # Looks like this "vmrun" is not real vmrun version_array = version_re.group(1).split(".") try: - if (int(version_array[0]) < VMRUN_MINIMUM_REQUIRED_VERSION): + if int(version_array[0]) < VMRUN_MINIMUM_REQUIRED_VERSION: return False except Exception: return False return True # Check vmware type, set vmware_internal_type to one of VMWARE_TYPE_ value and # options["--exec"] to path (if not specified) def vmware_check_vmware_type(options): global vmware_internal_type options["--vmware_type"] = options["--vmware_type"].lower() - if (options["--vmware_type"]=="esx"): + if options["--vmware_type"] == "esx": vmware_internal_type = VMWARE_TYPE_ESX - if (not options.has_key("--exec")): + if not options.has_key("--exec"): options["--exec"] = VMHELPER_COMMAND - elif (options["--vmware_type"]=="server2"): + elif options["--vmware_type"] == "server2": vmware_internal_type = VMWARE_TYPE_SERVER2 - if (not options.has_key("--exec")): + if not options.has_key("--exec"): options["--exec"] = VMRUN_COMMAND - elif (options["--vmware_type"]=="server1"): + elif options["--vmware_type"] == "server1": vmware_internal_type = VMWARE_TYPE_SERVER1 - if (not options.has_key("--exec")): + if not options.has_key("--exec"): options["--exec"] = VMRUN_COMMAND else: fail_usage("vmware_type can be esx,server2 or server1!") # Main agent method def main(): device_opt = [ "ipaddr", "login", "passwd", "secure", "exec", "vmware_type", "vmware_datacenter"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["vmware_type"]["default"] = VMWARE_DEFAULT_TYPE options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for VMWare" docs["longdesc"] = "fence_vmware is an I/O Fencing agent \ which can be used with the VMware ESX, VMware ESXi or VMware Server \ to fence virtual machines.\ \n.P\n\ Before you can use this agent, it must be installed VI Perl Toolkit or \ vmrun command on every node you want to make fencing.\ \n.P\n\ VI Perl Toolkit is preferred for VMware ESX/ESXi and Virtual Center. Vmrun \ command is only solution for VMware Server 1/2 (this command will works against \ ESX/ESXi 3.5 up2 and VC up2 too, but not cluster aware!) and is available as part \ of VMware VIX API SDK package. VI Perl and VIX API SDK are both available from \ VMware web pages (not int RHEL repository!). \ \n.P\n\ You can specify type of VMware you are connecting to with \\fB-d\\fP switch \ (or \\fIvmware_type\\fR for stdin). Possible values are esx, server2 and server1.\ Default value is esx, which will use VI Perl. With server1 and server2, vmrun \ command is used.\ \n.P\n\ After you have successfully installed VI Perl Toolkit or VIX API, you should \ be able to run fence_vmware_helper (part of this agent) or vmrun command. \ This agent supports only vmrun from version 2.0.0 (VIX API 1.6.0)." docs["vendorurl"] = "http://www.vmware.com" show_docs(options, docs) # Check vmware type and set path vmware_check_vmware_type(options) # Test user vmrun command version - if ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): - if (not (vmware_is_supported_vmrun_version(options))): + if vmware_internal_type == VMWARE_TYPE_SERVER1 or vmware_internal_type == VMWARE_TYPE_SERVER2: + if not vmware_is_supported_vmrun_version(options): fail_usage("Unsupported version of vmrun command! You must use at least version %d!" % (VMRUN_MINIMUM_REQUIRED_VERSION)) # Operate the fencing device result = fence_action(None, options, set_power_status, get_power_status, get_outlets_status) sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/vmware_soap/fence_vmware_soap.py b/fence/agents/vmware_soap/fence_vmware_soap.py index ccdbac19..feba4479 100644 --- a/fence/agents/vmware_soap/fence_vmware_soap.py +++ b/fence/agents/vmware_soap/fence_vmware_soap.py @@ -1,227 +1,227 @@ #!/usr/bin/python -tt import sys, time import shutil, tempfile, suds import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from suds.client import Client from suds.sudsobject import Property from fencing import * from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF #BEGIN_VERSION_GENERATION RELEASE_VERSION="New VMWare Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="April, 2011" #END_VERSION_GENERATION def soap_login(options): if options["--action"] in ["off", "reboot"]: time.sleep(int(options["--delay"])) if options.has_key("--ssl"): url = "https://" else: url = "http://" url += options["--ip"] + ":" + str(options["--ipport"]) + "/sdk" tmp_dir = tempfile.mkdtemp() tempfile.tempdir = tmp_dir atexit.register(remove_tmp_dir, tmp_dir) try: conn = Client(url + "/vimService.wsdl") conn.set_options(location = url) mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' ServiceContent = conn.service.RetrieveServiceContent(mo_ServiceInstance) mo_SessionManager = Property(ServiceContent.sessionManager.value) mo_SessionManager._type = 'SessionManager' conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) except Exception: fail(EC_LOGIN_DENIED) options["ServiceContent"] = ServiceContent options["mo_SessionManager"] = mo_SessionManager return conn def process_results(results, machines, uuid, mappingToUUID): for m in results.objects: info = {} for i in m.propSet: info[i.name] = i.val # Prevent error KeyError: 'config.uuid' when reaching systems which P2V failed, # since these systems don't have a valid UUID if info.has_key("config.uuid"): machines[info["name"]] = (info["config.uuid"], info["summary.runtime.powerState"]) uuid[info["config.uuid"]] = info["summary.runtime.powerState"] mappingToUUID[m.obj.value] = info["config.uuid"] return (machines, uuid, mappingToUUID) def get_power_status(conn, options): mo_ViewManager = Property(options["ServiceContent"].viewManager.value) mo_ViewManager._type = "ViewManager" mo_RootFolder = Property(options["ServiceContent"].rootFolder.value) mo_RootFolder._type = "Folder" mo_PropertyCollector = Property(options["ServiceContent"].propertyCollector.value) mo_PropertyCollector._type = 'PropertyCollector' ContainerView = conn.service.CreateContainerView(mo_ViewManager, recursive = 1, container = mo_RootFolder, type = ['VirtualMachine']) mo_ContainerView = Property(ContainerView.value) mo_ContainerView._type = "ContainerView" FolderTraversalSpec = conn.factory.create('ns0:TraversalSpec') FolderTraversalSpec.name = "traverseEntities" FolderTraversalSpec.path = "view" FolderTraversalSpec.skip = False FolderTraversalSpec.type = "ContainerView" objSpec = conn.factory.create('ns0:ObjectSpec') objSpec.obj = mo_ContainerView objSpec.selectSet = [ FolderTraversalSpec ] objSpec.skip = True propSpec = conn.factory.create('ns0:PropertySpec') propSpec.all = False propSpec.pathSet = ["name", "summary.runtime.powerState", "config.uuid"] propSpec.type = "VirtualMachine" propFilterSpec = conn.factory.create('ns0:PropertyFilterSpec') propFilterSpec.propSet = [ propSpec ] propFilterSpec.objectSet = [ objSpec ] try: raw_machines = conn.service.RetrievePropertiesEx(mo_PropertyCollector, propFilterSpec) except Exception: fail(EC_STATUS) (machines, uuid, mappingToUUID) = process_results(raw_machines, {}, {}, {}) # Probably need to loop over the ContinueRetreive if there are more results after 1 iteration. - while (hasattr(raw_machines, 'token') == True): + while hasattr(raw_machines, 'token'): try: raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token) except Exception: fail(EC_STATUS) (more_machines, more_uuid, more_mappingToUUID) = process_results(raw_machines, {}, {}, {}) machines.update(more_machines) uuid.update(more_uuid) mappingToUUID.update(more_mappingToUUID) # Do not run unnecessary SOAP requests if options.has_key("--uuid") and options["--uuid"] in uuid: break if ["list", "monitor"].count(options["--action"]) == 1: return machines else: if options.has_key("--uuid") == False: if options["--plug"].startswith('/'): ## Transform InventoryPath to UUID mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) mo_SearchIndex._type = "SearchIndex" vm = conn.service.FindByInventoryPath(mo_SearchIndex, options["--plug"]) try: options["--uuid"] = mappingToUUID[vm.value] except KeyError: fail(EC_STATUS) except AttributeError: fail(EC_STATUS) else: ## Name of virtual machine instead of path ## warning: if you have same names of machines this won't work correctly try: (options["--uuid"], _) = machines[options["--plug"]] except KeyError: fail(EC_STATUS) except AttributeError: fail(EC_STATUS) try: if uuid[options["--uuid"]] == "poweredOn": return "on" else: return "off" except KeyError: fail(EC_STATUS) def set_power_status(conn, options): mo_SearchIndex = Property(options["ServiceContent"].searchIndex.value) mo_SearchIndex._type = "SearchIndex" vm = conn.service.FindByUuid(mo_SearchIndex, vmSearch = 1, uuid = options["--uuid"]) mo_machine = Property(vm.value) mo_machine._type = "VirtualMachine" try: if options["--action"] == "on": conn.service.PowerOnVM_Task(mo_machine) else: conn.service.PowerOffVM_Task(mo_machine) except suds.WebFault, ex: - if ((str(ex).find("Permission to perform this operation was denied")) >= 0): + if (str(ex).find("Permission to perform this operation was denied")) >= 0: fail(EC_INVALID_PRIVILEGES) else: if options["--action"] == "on": fail(EC_WAITING_ON) else: fail(EC_WAITING_OFF) def remove_tmp_dir(tmp_dir): shutil.rmtree(tmp_dir) def main(): device_opt = [ "ipaddr", "login", "passwd", "web", "ssl", "notls", "port" ] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) ## ## Fence agent specific defaults ##### docs = { } docs["shortdesc"] = "Fence agent for VMWare over SOAP API" docs["longdesc"] = "fence_vmware_soap is an I/O Fencing agent \ which can be used with the virtual machines managed by VMWare products \ that have SOAP API v4.1+. \ \n.P\n\ Name of virtual machine (-n / port) has to be used in inventory path \ format (e.g. /datacenter/vm/Discovered virtual machine/myMachine). \ In the cases when name of yours VM is unique you can use it instead. \ Alternatively you can always use UUID to access virtual machine." docs["vendorurl"] = "http://www.vmware.com" show_docs(options, docs) logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.CRITICAL) ## ## Operate the fencing device #### conn = soap_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) ## ## Logout from system ##### try: conn.service.Logout(options["mo_SessionManager"]) except Exception: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/wti/fence_wti.py b/fence/agents/wti/fence_wti.py index d502a0e5..a7e1c8f4 100644 --- a/fence/agents/wti/fence_wti.py +++ b/fence/agents/wti/fence_wti.py @@ -1,252 +1,252 @@ #!/usr/bin/python -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version Firmware ## +-----------------+---------------------------+ ## WTI RSM-8R4 ?? unable to find out ?? ## WTI MPC-??? ?? unable to find out ?? ## WTI IPS-800-CE v1.40h (no username) ('list' tested) ##### import sys, re, pexpect import atexit import time sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fspawn, fail, fail_usage, TELNET_PATH, EC_LOGIN_DENIED #BEGIN_VERSION_GENERATION RELEASE_VERSION="New WTI Agent - test release on steroids" REDHAT_COPYRIGHT="" BUILD_DATE="March, 2008" #END_VERSION_GENERATION def get_listing(conn, options, listing_command): listing = "" conn.send(listing_command + "\r\n") if isinstance(options["--command-prompt"], list): re_all = list(options["--command-prompt"]) else: re_all = [options["--command-prompt"]] re_next = re.compile("Enter: ", re.IGNORECASE) re_all.append(re_next) result = conn.log_expect(options, re_all, int(options["--shell-timeout"])) listing = conn.before if result == (len(re_all) - 1): conn.send("\r\n") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) listing += conn.before return listing def get_plug_status(conn, options): listing = get_listing(conn, options, "/S") plug_section = 0 plug_index = -1 name_index = -1 status_index = -1 plug_header = list() outlets = {} for line in listing.splitlines(): if (plug_section == 2) and line.find("|") >= 0 and line.startswith("PLUG") == False: plug_line = [x.strip().lower() for x in line.split("|")] if len(plug_line) < len(plug_header): plug_section = -1 if ["list", "monitor"].count(options["--action"]) == 0 and \ options["--plug"].lower() == plug_line[plug_index]: return plug_line[status_index] else: ## We already believe that first column contains plug number if len(plug_line[0]) != 0: outlets[plug_line[0]] = (plug_line[name_index], plug_line[status_index]) - elif (plug_section == 1): + elif plug_section == 1: plug_section = 2 - elif (line.upper().startswith("PLUG")): + elif line.upper().startswith("PLUG"): plug_section = 1 plug_header = [x.strip().lower() for x in line.split("|")] plug_index = plug_header.index("plug") name_index = plug_header.index("name") status_index = plug_header.index("status") if ["list", "monitor"].count(options["--action"]) == 1: return outlets else: return "PROBLEM" def get_plug_group_status_from_list(status_list): for status in status_list: if status == "on": return status return "off" def get_plug_group_status(conn, options): listing = get_listing(conn, options, "/SG") outlets = {} line_index = 0 status_index = -1 plug_index = -1 name_index = -1 lines = listing.splitlines() while line_index < len(lines) and line_index >= 0: line = lines[line_index] - if (line.find("|") >= 0 and line.lstrip().startswith("GROUP NAME") == False): + if line.find("|") >= 0 and line.lstrip().startswith("GROUP NAME") == False: plug_line = [x.strip().lower() for x in line.split("|")] if ["list", "monitor"].count(options["--action"]) == 0 and \ options["--plug"].lower() == plug_line[name_index]: plug_status = [] while line_index < len(lines) and line_index >= 0: plug_line = [x.strip().lower() for x in lines[line_index].split("|")] if len(plug_line) >= max(name_index, status_index) and \ len(plug_line[plug_index]) > 0 and \ (len(plug_line[name_index]) == 0 or options["--plug"].lower() == plug_line[name_index]): ## Firmware 1.43 does not have a valid value of plug on first line as only name is defined on that line if not "---" in plug_line[status_index]: plug_status.append(plug_line[status_index]) line_index += 1 else: line_index = -1 return get_plug_group_status_from_list(plug_status) else: ## We already believe that first column contains plug number if len(plug_line[0]) != 0: group_name = plug_line[0] plug_line_index = line_index + 1 plug_status = [] while plug_line_index < len(lines) and plug_line_index >= 0: plug_line = [x.strip().lower() for x in lines[plug_line_index].split("|")] if len(plug_line[name_index]) > 0: plug_line_index = -1 break if len(plug_line[plug_index]) > 0: plug_status.append(plug_line[status_index]) plug_line_index += 1 else: plug_line_index = -1 outlets[group_name] = (group_name, get_plug_group_status_from_list(plug_status)) line_index += 1 - elif (line.upper().lstrip().startswith("GROUP NAME")): + elif line.upper().lstrip().startswith("GROUP NAME"): plug_header = [x.strip().lower() for x in line.split("|")] name_index = plug_header.index("group name") plug_index = plug_header.index("plug") status_index = plug_header.index("status") line_index += 2 else: line_index += 1 if ["list", "monitor"].count(options["--action"]) == 1: results = {} for group, status in outlets.items(): results[group] = (group, status[0]) return results else: return "PROBLEM" def get_power_status(conn, options): if ["list"].count(options["--action"]) == 0: ret = get_plug_status(conn, options) if ret == "PROBLEM": ret = get_plug_group_status(conn, options) else: ret = dict(get_plug_status(conn, options).items() + \ get_plug_group_status(conn, options).items()) return ret def set_power_status(conn, options): action = { 'on' : "/on", 'off': "/off" }[options["--action"]] conn.send(action + " " + options["--plug"] + ",y\r\n") conn.log_expect(options, options["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = [ "ipaddr", "login", "passwd", "no_login", "no_password", \ "cmd_prompt", "secure", "port" ] atexit.register(atexit_handler) all_opt["cmd_prompt"]["default"] = [ "RSM>", "MPC>", "IPS>", "TPS>", "NBB>", "NPS>", "VMR>" ] options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "Fence agent for WTI" docs["longdesc"] = "fence_wti is an I/O Fencing agent \ which can be used with the WTI Network Power Switch (NPS). It logs \ into an NPS via telnet or ssh and boots a specified plug. \ Lengthy telnet connections to the NPS should be avoided while a GFS cluster \ is running because the connection will block any necessary fencing actions." docs["vendorurl"] = "http://www.wti.com" show_docs(options, docs) ## ## Operate the fencing device ## ## @note: if it possible that this device does not need either login, password or both of them ##### if 0 == options.has_key("--ssh"): try: if options["--action"] in ["off", "reboot"]: time.sleep(int(options["--delay"])) conn = fspawn(options, TELNET_PATH) conn.send("set binary\n") conn.send("open %s -%s\n"%(options["--ip"], options["--ipport"])) re_login = re.compile("(login: )|(Login Name: )|(username: )|(User Name :)", re.IGNORECASE) re_prompt = re.compile("|".join(["(" + x + ")" for x in options["--command-prompt"]]), re.IGNORECASE) result = conn.log_expect(options, [ re_login, "Password: ", re_prompt ], int(options["--shell-timeout"])) if result == 0: if options.has_key("--username"): conn.send(options["--username"]+"\r\n") result = conn.log_expect(options, [ re_login, "Password: ", re_prompt ], int(options["--shell-timeout"])) else: fail_usage("Failed: You have to set login name") if result == 1: if options.has_key("--password"): conn.send(options["--password"]+"\r\n") conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) else: fail_usage("Failed: You have to enter password or password script") except pexpect.EOF: fail(EC_LOGIN_DENIED) except pexpect.TIMEOUT: fail(EC_LOGIN_DENIED) else: conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) ## ## Logout from system ###### try: conn.send("/X"+"\r\n") conn.close() except: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/fence/agents/xenapi/fence_xenapi.py b/fence/agents/xenapi/fence_xenapi.py index 2a52c984..0a4f838e 100644 --- a/fence/agents/xenapi/fence_xenapi.py +++ b/fence/agents/xenapi/fence_xenapi.py @@ -1,228 +1,228 @@ #!/usr/bin/python -tt # ############################################################################# # Copyright 2011 Matthew Clark # This file is part of fence-xenserver # # fence-xenserver is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # fence-xenserver is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please let me know if you are using this script so that I can work out # whether I should continue support for it. mattjclark0407 at hotmail dot com ############################################################################# ############################################################################# # It's only just begun... # Current status: completely usable. This script is now working well and, # has a lot of functionality as a result of the fencing.py library and the # XenAPI libary. ############################################################################# # Please let me know if you are using this script so that I can work out # whether I should continue support for it. mattjclark0407 at hotmail dot com import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * import XenAPI #BEGIN_VERSION_GENERATION RELEASE_VERSION="" REDHAT_COPYRIGHT="" BUILD_DATE="" #END_VERSION_GENERATION EC_BAD_SESSION = 1 # Find the status of the port given in the -U flag of options. def get_power_fn(session, options): if options.has_key("--verbose"): verbose = True else: verbose = False try: # Get a reference to the vm specified in the UUID or vm_name/port parameter vm = return_vm_reference(session, options) # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. - if not(record["is_a_template"]) and not(record["is_control_domain"]): + if not record["is_a_template"] and not record["is_control_domain"]: status = record["power_state"] if verbose: print "UUID:", record["uuid"], "NAME:", record["name_label"], "POWER STATUS:", record["power_state"] # Note that the VM can be in the following states (from the XenAPI document) # Halted: VM is offline and not using any resources. # Paused: All resources have been allocated but the VM itself is paused and its vCPUs are not running # Running: Running # Paused: VM state has been saved to disk and it is nolonger running. Note that disks remain in-Use while # We want to make sure that we only return the status "off" if the machine is actually halted as the status # is checked before a fencing action. Only when the machine is Halted is it not consuming resources which # may include whatever you are trying to protect with this fencing action. - return (status=="Halted" and "off" or "on") + return status == "Halted" and "off" or "on" except Exception, exn: print str(exn) return "Error" # Set the state of the port given in the -U flag of options. def set_power_fn(session, options): action = options["--action"].lower() try: # Get a reference to the vm specified in the UUID or vm_name/port parameter vm = return_vm_reference(session, options) # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. - if not(record["is_a_template"]) and not(record["is_control_domain"]): - if( action == "on" ): + if not record["is_a_template"] and not record["is_control_domain"]: + if action == "on": # Start the VM session.xenapi.VM.start(vm, False, True) - elif( action == "off" ): + elif action == "off": # Force shutdown the VM session.xenapi.VM.hard_shutdown(vm) - elif( action == "reboot" ): + elif action == "reboot": # Force reboot the VM session.xenapi.VM.hard_reboot(vm) except Exception, exn: print str(exn) # Function to populate an array of virtual machines and their status def get_outlet_list(session, options): result = {} if options.has_key("--verbose"): verbose = True else: verbose = False try: # Return an array of all the VM's on the host vms = session.xenapi.VM.get_all() for vm in vms: # Query the VM for its' associated parameters record = session.xenapi.VM.get_record(vm) # Check that we are not trying to manipulate a template or a control # domain as they show up as VM's with specific properties. - if not(record["is_a_template"]) and not(record["is_control_domain"]): + if not record["is_a_template"] and not record["is_control_domain"]: name = record["name_label"] uuid = record["uuid"] status = record["power_state"] result[uuid] = (name, status) if verbose: print "UUID:", record["uuid"], "NAME:", name, "POWER STATUS:", record["power_state"] except Exception, exn: print str(exn) return result # Function to initiate the XenServer session via the XenAPI library. def connect_and_login(options): url = options["--session-url"] username = options["--username"] password = options["--password"] try: # Create the XML RPC session to the specified URL. session = XenAPI.Session(url) # Login using the supplied credentials. session.xenapi.login_with_password(username, password) except Exception, exn: print str(exn) # http://sources.redhat.com/cluster/wiki/FenceAgentAPI says that for no connectivity # the exit value should be 1. It doesn't say anything about failed logins, so # until I hear otherwise it is best to keep this exit the same to make sure that # anything calling this script (that uses the same information in the web page # above) knows that this is an error condition, not a msg signifying a down port. sys.exit(EC_BAD_SESSION) return session # return a reference to the VM by either using the UUID or the vm_name/port. If the UUID is set then # this is tried first as this is the only properly unique identifier. # Exceptions are not handled in this function, code that calls this must be ready to handle them. def return_vm_reference(session, options): if options.has_key("--verbose"): verbose = True else: verbose = False # Case where the UUID has been specified if options.has_key("--uuid"): uuid = options["--uuid"].lower() # When using the -n parameter for name, we get an error message (in verbose # mode) that tells us that we didn't find a VM. To immitate that here we # need to catch and re-raise the exception produced by get_by_uuid. try: return session.xenapi.VM.get_by_uuid(uuid) except Exception: if verbose: print "No VM's found with a UUID of \"%s\"" % uuid raise # Case where the vm_name/port has been specified if options.has_key("--plug"): vm_name = options["--plug"] vm_arr = session.xenapi.VM.get_by_name_label(vm_name) # Need to make sure that we only have one result as the vm_name may # not be unique. Average case, so do it first. if len(vm_arr) == 1: return vm_arr[0] else: if len(vm_arr) == 0: if verbose: print "No VM's found with a name of \"%s\"" % vm_name # NAME_INVALID used as the XenAPI throws a UUID_INVALID if it can't find # a VM with the specified UUID. This should make the output look fairly # consistent. raise Exception("NAME_INVALID") else: if verbose: print "Multiple VM's have the name \"%s\", use UUID instead" % vm_name raise Exception("MULTIPLE_VMS_FOUND") # We should never get to this case as the input processing checks that either the UUID or # the name parameter is set. Regardless of whether or not a VM is found the above if # statements will return to the calling function (either by exception or by a reference # to the VM). raise Exception("VM_LOGIC_ERROR") def main(): device_opt = [ "login", "passwd", "port", "no_login", "no_password", "session_url" ] atexit.register(atexit_handler) options = check_input(device_opt, process_input(device_opt)) docs = { } docs["shortdesc"] = "XenAPI based fencing for the Citrix XenServer virtual machines." docs["longdesc"] = "\ fence_cxs is an I/O Fencing agent used on Citrix XenServer hosts. \ It uses the XenAPI, supplied by Citrix, to establish an XML-RPC sesssion \ to a XenServer host. Once the session is established, further XML-RPC \ commands are issued in order to switch on, switch off, restart and query \ the status of virtual machines running on the host." docs["vendorurl"] = "http://www.xenproject.org" show_docs(options, docs) xen_session = connect_and_login(options) # Operate the fencing device result = fence_action(xen_session, options, set_power_fn, get_power_fn, get_outlet_list) sys.exit(result) if __name__ == "__main__": main()