diff --git a/agents/apc/fence_apc.py b/agents/apc/fence_apc.py index 24a5a423..dd0287f8 100644 --- a/agents/apc/fence_apc.py +++ b/agents/apc/fence_apc.py @@ -1,260 +1,262 @@ #!@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, time import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_STATUS # Fix for connection timed out issue in: # https://bugzilla.redhat.com/show_bug.cgi?id=1342584 TIMEDOUT_DELAY = 0.5 def get_power_status(conn, options): exp_result = 0 outlets = {} conn.send_eol("1") conn.log_expect(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): switch = 1 if None != re.compile('.* MasterSwitch plus 2', re.IGNORECASE | re.S).match(conn.before): if "--switch" not in options: fail_usage("Failed: You have to enter physical switch number") else: if "--switch" not in options: options["--switch"] = "1" 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): 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["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol("1") else: conn.send_eol(options["--switch"]) while True: exp_result = conn.log_expect( ["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: outlets[res.group(2)] = (res.group(3), res.group(4)) time.sleep(TIMEDOUT_DELAY) conn.send_eol("") if exp_result != 0: break conn.send(chr(0o3)) conn.log_expect("- Logout", int(options["--shell-timeout"])) conn.log_expect(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: + except KeyError as e: + logging.error("Failed: {}".format(str(e))) fail(EC_STATUS) def set_power_status(conn, options): action = { 'on' : "1", 'off': "2" }[options["--action"]] conn.send_eol("1") conn.log_expect(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): 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 "--switch" not in options: fail_usage("Failed: You have to enter physical switch number") else: if "--switch" not in options: options["--switch"] = 1 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): 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["--command-prompt"], int(options["--shell-timeout"])) 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( ["Press "] + options["--command-prompt"], int(options["--shell-timeout"])): time.sleep(TIMEDOUT_DELAY) conn.send_eol("") conn.send_eol(options["--plug"]+"") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if switch == 0: if admin2 == 1: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) if admin3 == 1: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) else: conn.send_eol("1") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) conn.send_eol(action) conn.log_expect("Enter 'YES' to continue or to cancel :", int(options["--shell-timeout"])) conn.send_eol("YES") conn.log_expect("Press to continue...", int(options["--power-timeout"])) time.sleep(TIMEDOUT_DELAY) conn.send_eol("") conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) conn.send(chr(0o3)) conn.log_expect("- Logout", int(options["--shell-timeout"])) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) def get_power_status5(conn, options): outlets = {} conn.send_eol("olStatus all") conn.log_expect(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: 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: + except KeyError as e: + logging.error("Failed: {}".format(str(e))) 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["--command-prompt"], int(options["--power-timeout"])) def main(): device_opt = ["ipaddr", "login", "passwd", "cmd_prompt", "secure", \ "port", "switch", "telnet"] 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 (("--plug" in options) == 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) in [ "5", "6" ]): 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) fence_logout(conn, "4") sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py index ec311754..2280dbbc 100644 --- a/agents/cisco_ucs/fence_cisco_ucs.py +++ b/agents/cisco_ucs/fence_cisco_ucs.py @@ -1,196 +1,197 @@ #!@PYTHON@ -tt import sys, re import pycurl, io import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS, EC_LOGIN_DENIED, run_delay RE_COOKIE = re.compile("", int(options["--shell-timeout"])) result = RE_GET_PNDN.search(res) if result == None: pndn = "" else: pndn = result.group(1) if pndn.strip() == "": if "--missing-as-off" in options: return "off" else: fail(EC_STATUS) res = send_command(options, "", int(options["--shell-timeout"])) result = RE_GET_PRESENCE.search(res) if result == None: fail(EC_STATUS) else: presence_status = result.group(1) if presence_status in ["missing", "mismatch"]: return "off" else: result = RE_GET_OPERPOWER.search(res) if result == None: fail(EC_STATUS) else: power_status = result.group(1) if power_status == "on": return "on" else: return "off" def set_power_status(conn, options): del conn action = { 'on' : "admin-up", 'off' : "admin-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_global["--shell-timeout"])) except Exception: pass def main(): global options_global device_opt = ["ipaddr", "login", "passwd", "ssl", "notls", "port", "web", "suborg", "missing_as_off"] atexit.register(atexit_handler) atexit.register(logout) define_new_opts() options_global = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for Cisco UCS" docs["longdesc"] = "fence_cisco_ucs is an I/O Fencing agent which can be \ used with Cisco UCS to fence machines." docs["vendorurl"] = "http://www.cisco.com" show_docs(options_global, docs) run_delay(options_global) ### Login try: res = send_command(options_global, "", int(options_global["--login-timeout"])) result = RE_COOKIE.search(res) if result == None: ## Cookie is absenting in response fail(EC_LOGIN_DENIED) - except Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) fail(EC_LOGIN_DENIED) options_global["cookie"] = result.group(1) ## ## Modify suborg to format /suborg if options_global["--suborg"] != "": options_global["--suborg"] = "/" + options_global["--suborg"].lstrip("/").rstrip("/") ## ## Fence operations #### result = fence_action(None, options_global, set_power_status, get_power_status, get_list) ## Logout is done every time at atexit phase sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/eps/fence_eps.py b/agents/eps/fence_eps.py index 74c89b95..f0df8623 100644 --- a/agents/eps/fence_eps.py +++ b/agents/eps/fence_eps.py @@ -1,128 +1,129 @@ #!@PYTHON@ -tt # The Following Agent Has Been Tested On: # ePowerSwitch 8M+ version 1.0.0.4 import sys, re import 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, run_delay if sys.version_info[0] > 2: import http.client as httplib else: import httplib # 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 != "": request_str += "?"+params logging.debug("GET %s\n", request_str) conn.putrequest('GET', request_str) if "--username" in options: if "--password" not in options: 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: fail(EC_LOGIN_DENIED) result = response.read() logging.debug("%s \n", result) conn.close() except socket.timeout: fail(EC_TIMED_OUT) - except socket.error: + except socket.error as e: + logging.error("Failed: {}".format(str(e))) 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: 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", "web"] 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_delay(options) #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/agents/ilo_moonshot/fence_ilo_moonshot.py b/agents/ilo_moonshot/fence_ilo_moonshot.py index a066a9c9..6f5cca32 100644 --- a/agents/ilo_moonshot/fence_ilo_moonshot.py +++ b/agents/ilo_moonshot/fence_ilo_moonshot.py @@ -1,63 +1,64 @@ #!@PYTHON@ -tt import sys import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_STATUS def get_power_status(conn, options): conn.send_eol("show node list") conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) nodes = {} for line in conn.before.splitlines(): if len(line.split()) == 10: nodes[line.split()[1]] = ("", line.split()[8].lower().strip()) if ["list", "monitor"].count(options["--action"]) == 1: return nodes else: try: (_, status) = nodes[options["--plug"]] return status.lower() - except KeyError: + except KeyError as e: + logging.error("Failed: {}".format(str(e))) fail(EC_STATUS) def set_power_status(conn, options): if options["--action"] == "on": conn.send_eol("set node power on %s" % (options["--plug"])) else: conn.send_eol("set node power off force %s" % (options["--plug"])) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) return def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", "port"] atexit.register(atexit_handler) all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = ["MP>", "hpiLO->"] options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for HP Moonshot iLO" docs["longdesc"] = "" docs["vendorurl"] = "http://www.hp.com" show_docs(options, docs) conn = fence_login(options) ## ## Fence operations #### result = fence_action(conn, options, set_power_status, get_power_status, get_power_status) fence_logout(conn, "exit") sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py index a1610373..66cb65e4 100644 --- a/agents/lpar/fence_lpar.py +++ b/agents/lpar/fence_lpar.py @@ -1,179 +1,181 @@ #!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version ## +---------------------------------------------+ ## Tested on HMC ## ##### import sys, re import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_STATUS_HMC ## ## Transformation to standard ON/OFF status if possible def _normalize_status(status): if status in ["Running", "Open Firmware", "Shutting Down", "Starting"]: status = "on" else: status = "off" return status def get_power_status(conn, options): if options["--hmc-version"] == "3": conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") # First line (command) may cause parsing issues if long conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) try: status = re.compile("^" + options["--plug"] + ",(.*?),.*$", re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) - except AttributeError: + except AttributeError as e: + logging.error("Failed: {}".format(str(e))) fail(EC_STATUS_HMC) elif options["--hmc-version"] in ["4", "IVM"]: conn.send("lssyscfg -r lpar -m "+ options["--managed"] + " --filter 'lpar_names=" + options["--plug"] + "'\n") # First line (command) may cause parsing issues if long conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) try: status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) - except AttributeError: + except AttributeError as e: + logging.error("Failed: {}".format(str(e))) fail(EC_STATUS_HMC) return _normalize_status(status) def set_power_status(conn, options): if options["--hmc-version"] == "3": conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + "\n") # First line (command) may cause parsing issues if long conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) elif options["--hmc-version"] in ["4", "IVM"]: if options["--action"] == "on": conn.send("chsysstate -o on -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -f `lssyscfg -r lpar -F curr_profile " + " -m " + options["--managed"] + " --filter \"lpar_names=" + options["--plug"] + "\"`\n") else: conn.send("chsysstate -o shutdown -r lpar --immed" + " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") # First line (command) may cause parsing issues if long conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) def get_lpar_list(conn, options): outlets = {} if options["--hmc-version"] == "3": conn.send("query_partition_names -m " + options["--managed"] + "\n") ## We have to remove first line (command) conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) ## We have to remove next 2 lines (header) and last line (part of new prompt) #### res = re.search("^(.+?\n){2}(.*)\n.*$", conn.before, re.S) if res == None: fail_usage("Unable to parse output of list command") lines = res.group(2).split("\n") for outlet_line in lines: outlets[outlet_line.rstrip()] = ("", "") elif options["--hmc-version"] in ["4", "IVM"]: sep = ":" if options["--hmc-version"] == "4" else "," conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -F name" + sep + "state\n") ## We have to remove first line (command) conn.readline() conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) ## We have to remove last line (part of new prompt) #### res = re.search("^(.*)\n.*$", conn.before, re.S) if res == None: fail_usage("Unable to parse output of list command") lines = res.group(1).split("\n") for outlet_line in lines: try: (port, status) = outlet_line.rstrip().split(sep) except ValueError: fail_usage('Output does not match expected HMC version, try different one'); outlets[port] = ("", _normalize_status(status)) return outlets def define_new_opts(): all_opt["managed"] = { "getopt" : "s:", "longopt" : "managed", "help" : "-s, --managed=[id] Name of the managed system", "required" : "1", "shortdesc" : "Managed system name", "order" : 1} all_opt["hmc_version"] = { "getopt" : "H:", "longopt" : "hmc-version", "help" : "-H, --hmc-version=[version] Force HMC version to use: (3|4|ivm) (default: 4)", "required" : "0", "shortdesc" : "Force HMC version to use", "default" : "4", "choices" : ["3", "4", "ivm"], "order" : 1} def main(): device_opt = ["ipaddr", "login", "passwd", "secure", "cmd_prompt", \ "port", "managed", "hmc_version"] atexit.register(atexit_handler) define_new_opts() all_opt["login_timeout"]["default"] = "15" all_opt["secure"]["default"] = "1" all_opt["cmd_prompt"]["default"] = [r":~>", r"]\$", r"\$ "] options = check_input(device_opt, process_input(device_opt), other_conditions = True) docs = {} docs["shortdesc"] = "Fence agent for IBM LPAR" docs["longdesc"] = "" docs["vendorurl"] = "http://www.ibm.com" show_docs(options, docs) if "--managed" not in options: fail_usage("Failed: You have to enter name of managed system") if options["--action"] == "validate-all": sys.exit(0) ## ## Operate the fencing device #### conn = fence_login(options) result = fence_action(conn, options, set_power_status, get_power_status, get_lpar_list) fence_logout(conn, "quit\r\n") sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/ovh/fence_ovh.py b/agents/ovh/fence_ovh.py index f5403c54..2b7eb864 100644 --- a/agents/ovh/fence_ovh.py +++ b/agents/ovh/fence_ovh.py @@ -1,163 +1,164 @@ #!@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, run_delay 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] email for reboot message: admin@domain.com", "required" : "1", "shortdesc" : "Reboot email", "order" : 1} def netboot_reboot(conn, options, mode): # 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(conn, 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 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: + except Exception as e: + logging.error("Failed: {}".format(str(e))) 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", "no_status", "web"] atexit.register(atexit_handler) define_new_opts() options = check_input(device_opt, process_input(device_opt), other_conditions=True) 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"] == "list": fail_usage("Action 'list' is not supported in this fence agent") if options["--action"] == "list-status": fail_usage("Action 'list-status' is not supported in this fence agent") if "--email" not in options: fail_usage("You have to enter e-mail address which is notified by fence agent") if options["--action"] == "validate-all": sys.exit(0) if options["--action"] != "monitor" and not options["--plug"].endswith(".ovh.net"): options["--plug"] += ".ovh.net" run_delay(options) conn = soap_login(options) if options["--action"] == 'monitor': try: conn.service.logout(options["session"]) except Exception: pass sys.exit(0) # Save datetime just before changing netboot before_netboot_reboot = datetime.now() if options["--action"] == 'off': # Reboot in Rescue-pro netboot_reboot(conn, options, OVH_RESCUE_PRO_NETBOOT_ID) time.sleep(STATUS_RESCUE_PRO_SLEEP) elif options["--action"] in ['on', 'reboot']: # Reboot from HD netboot_reboot(conn, 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(conn, 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") try: conn.service.logout(options["session"]) except Exception: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/sanbox2/fence_sanbox2.py b/agents/sanbox2/fence_sanbox2.py index 679d1d98..179fe0e8 100644 --- a/agents/sanbox2/fence_sanbox2.py +++ b/agents/sanbox2/fence_sanbox2.py @@ -1,151 +1,155 @@ #!@PYTHON@ -tt ##### ## ## The Following Agent Has Been Tested On: ## ## Version Firmware ## +-----------------+---------------------------+ ##### import sys, re, pexpect import logging import atexit sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, EC_TIMED_OUT, EC_GENERIC_ERROR def get_power_status(conn, options): status_trans = { 'online' : "on", 'offline' : "off" } try: conn.send_eol("show port " + options["--plug"]) conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() - except Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) 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["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() - except Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) pass fail(EC_TIMED_OUT) try: conn.send_eol("set port " + options["--plug"] + " state " + action) conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) except pexpect.TIMEOUT: try: conn.send_eol("admin end") conn.send_eol("exit") conn.close() - except Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) pass fail(EC_TIMED_OUT) def get_list_devices(conn, options): outlets = {} try: conn.send_eol("show port") conn.log_expect(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): 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 Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) pass fail(EC_TIMED_OUT) return outlets def main(): device_opt = ["fabric_fencing", "ipaddr", "login", "passwd", "cmd_prompt", \ "port", "telnet"] 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["--command-prompt"], int(options["--shell-timeout"])) 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 OSError: pass except pexpect.ExceptionPexpect: pass sys.exit(result) if __name__ == "__main__": main() diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py index f2ab68b0..a7f08b3d 100644 --- a/agents/vmware_soap/fence_vmware_soap.py +++ b/agents/vmware_soap/fence_vmware_soap.py @@ -1,261 +1,264 @@ #!@PYTHON@ -tt import sys import shutil, tempfile, suds import logging, requests import atexit, signal sys.path.append("@FENCEAGENTSLIBDIR@") from suds.client import Client from suds.sudsobject import Property from suds.transport.http import HttpAuthenticated from suds.transport import Reply, TransportError from fencing import * from fencing import fail, fail_usage, EC_STATUS, EC_LOGIN_DENIED, EC_INVALID_PRIVILEGES, EC_WAITING_ON, EC_WAITING_OFF from fencing import run_delay options_global = None conn_global = None class RequestsTransport(HttpAuthenticated): def __init__(self, **kwargs): self.cert = kwargs.pop('cert', None) self.verify = kwargs.pop('verify', True) self.session = requests.Session() # super won't work because not using new style class HttpAuthenticated.__init__(self, **kwargs) def send(self, request): self.addcredentials(request) resp = self.session.post(request.url, data=request.message, headers=request.headers, cert=self.cert, verify=self.verify) result = Reply(resp.status_code, resp.headers, resp.content) return result def soap_login(options): run_delay(options) if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options: if "--ssl-insecure" in options: import ssl import urllib3 if hasattr(ssl, '_create_unverified_context'): ssl._create_default_https_context = ssl._create_unverified_context urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) verify = False else: verify = True url = "https://" else: verify = False 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: headers = {"Content-Type" : "text/xml;charset=UTF-8", "SOAPAction" : "vim25"} conn = Client(url + "/vimService.wsdl", location=url, transport=RequestsTransport(verify=verify), headers=headers) 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 requests.exceptions.SSLError as ex: fail_usage("Server side certificate verification failed: %s" % ex) - except Exception: + except Exception as e: + logging.error("Server side certificate verification failed: {}".format(str(e))) 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 "config.uuid" in info: 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: + except Exception as e: + logging.error("Failed: {}".format(str(e))) 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'): try: raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token) - except Exception: + except Exception as e: + logging.error("Failed: {}".format(str(e))) 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 "--uuid" in options and options["--uuid"] in uuid: break if ["list", "monitor"].count(options["--action"]) == 1: return machines else: if "--uuid" not in options: 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 as ex: 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 logout(): try: conn_global.service.Logout(options_global["mo_SessionManager"]) except Exception: pass def signal_handler(signum, frame): raise Exception("Signal \"%d\" received which has triggered an exit of the process." % signum) def main(): global options_global global conn_global device_opt = ["ipaddr", "login", "passwd", "web", "ssl", "notls", "port"] atexit.register(atexit_handler) atexit.register(logout) signal.signal(signal.SIGTERM, signal_handler) options_global = 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_global, docs) logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.CRITICAL) logging.getLogger("requests").setLevel(logging.CRITICAL) logging.getLogger("urllib3").setLevel(logging.CRITICAL) ## ## Operate the fencing device #### conn_global = soap_login(options_global) result = fence_action(conn_global, options_global, set_power_status, get_power_status, get_power_status) ## Logout from system is done automatically via atexit() sys.exit(result) if __name__ == "__main__": main()