diff --git a/SOURCES/bz1350908-fence_vmware_soap-cleanup-sigterm.patch b/SOURCES/bz1350908-fence_vmware_soap-cleanup-sigterm.patch new file mode 100644 index 0000000..8d27ea4 --- /dev/null +++ b/SOURCES/bz1350908-fence_vmware_soap-cleanup-sigterm.patch @@ -0,0 +1,41 @@ +From 116fb7d1253ac31a8f174187dfe9f4a0c6546ade Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 7 Sep 2018 15:56:56 +0200 +Subject: [PATCH] fence_vmware_soap: cleanup when receiving SIGTERM + +--- + agents/vmware_soap/fence_vmware_soap.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py +index b90edc9b..dd1a4ed6 100644 +--- a/agents/vmware_soap/fence_vmware_soap.py ++++ b/agents/vmware_soap/fence_vmware_soap.py +@@ -3,7 +3,7 @@ + import sys + import shutil, tempfile, suds + import logging, requests +-import atexit ++import atexit, signal + sys.path.append("@FENCEAGENTSLIBDIR@") + + from suds.client import Client +@@ -211,6 +211,9 @@ def logout(): + 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 +@@ -219,6 +222,8 @@ def main(): + atexit.register(atexit_handler) + atexit.register(logout) + ++ signal.signal(signal.SIGTERM, signal_handler) ++ + options_global = check_input(device_opt, process_input(device_opt)) + + ## diff --git a/SOURCES/bz1402862-fence_rhevm-RHEV-v4-API-support.patch b/SOURCES/bz1402862-fence_rhevm-RHEV-v4-API-support.patch new file mode 100644 index 0000000..6f115e8 --- /dev/null +++ b/SOURCES/bz1402862-fence_rhevm-RHEV-v4-API-support.patch @@ -0,0 +1,164 @@ +From a4e8b77ac51a0e4a6de489823ee1be47cbc7eb18 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 9 May 2019 12:09:48 +0200 +Subject: [PATCH] fence_rhevm: add RHEV v4 API support and auto-detection + +--- + agents/rhevm/fence_rhevm.py | 44 +++++++++++++++++++++++------ + tests/data/metadata/fence_rhevm.xml | 7 ++++- + 2 files changed, 41 insertions(+), 10 deletions(-) + +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index a1cdaf605..6012c4239 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -9,7 +9,8 @@ + from fencing import fail, EC_FETCH_VM_UUID, run_delay + + RE_GET_ID = re.compile("(.*?)", re.IGNORECASE) ++RE_STATUS = re.compile("(.*?)", re.IGNORECASE) ++RE_STATE = re.compile("(.*?)", re.IGNORECASE) + RE_GET_NAME = re.compile("(.*?)", re.IGNORECASE) + + def get_power_status(conn, options): +@@ -25,7 +26,10 @@ def get_power_status(conn, options): + + options["id"] = result.group(2) + +- result = RE_STATUS.search(res) ++ if tuple(map(int, options["--api-version"].split(".")))[0] > 3: ++ result = RE_STATUS.search(res) ++ else: ++ result = RE_STATE.search(res) + 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 +@@ -59,7 +63,10 @@ def get_list(conn, options): + lines = res.split(" 3: ++ status = RE_STATUS.search(lines[i]).group(1) ++ else: ++ status = RE_STATE.search(lines[i]).group(1) + outlets[name] = ("", status) + except AttributeError: + return {} +@@ -69,6 +76,13 @@ def get_list(conn, options): + return outlets + + def send_command(opt, command, method="GET"): ++ if opt["--api-version"] == "auto": ++ opt["--api-version"] = "4" ++ res = send_command(opt, "") ++ if re.search("Error", res): ++ opt["--api-version"] = "3" ++ logging.debug("auto-detected API version: " + opt["--api-version"]) ++ + ## setup correct URL + if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: + url = "https:" +@@ -90,7 +104,7 @@ def send_command(opt, command, method="GET"): + web_buffer = io.BytesIO() + conn.setopt(pycurl.URL, url.encode("UTF-8")) + conn.setopt(pycurl.HTTPHEADER, [ +- "Version: 3", ++ "Version: {}".format(opt["--api-version"]), + "Content-type: application/xml", + "Accept: application/xml", + "Prefer: persistent-auth", +@@ -130,8 +144,9 @@ def send_command(opt, command, method="GET"): + + result = web_buffer.getvalue().decode("UTF-8") + +- logging.debug("%s\n", command) +- logging.debug("%s\n", result) ++ logging.debug("url: %s\n", url) ++ logging.debug("command: %s\n", command) ++ logging.debug("result: %s\n", result) + + return result + +@@ -151,6 +166,15 @@ def define_new_opts(): + "required" : "0", + "shortdesc" : "Reuse cookies for authentication", + "order" : 1} ++ all_opt["api_version"] = { ++ "getopt" : ":", ++ "longopt" : "api-version", ++ "help" : "--api-version " ++ "Version of RHEV API (default: auto)", ++ "required" : "0", ++ "order" : 2, ++ "default" : "auto", ++ } + all_opt["api_path"] = { + "getopt" : ":", + "longopt" : "api-path", +@@ -158,20 +182,19 @@ def define_new_opts(): + "default" : "/ovirt-engine/api", + "required" : "0", + "shortdesc" : "The path part of the API URL", +- "order" : 2} ++ "order" : 3} + all_opt["disable_http_filter"] = { + "getopt" : "", + "longopt" : "disable-http-filter", + "help" : "--disable-http-filter Set HTTP Filter header to false", + "required" : "0", + "shortdesc" : "Set HTTP Filter header to false", +- "order" : 3} ++ "order" : 4} + + + def main(): + device_opt = [ + "ipaddr", +- "api_path", + "login", + "passwd", + "ssl", +@@ -179,6 +202,8 @@ def main(): + "web", + "port", + "use_cookies", ++ "api_version", ++ "api_path", + "disable_http_filter", + ] + +@@ -186,6 +211,7 @@ def main(): + define_new_opts() + + all_opt["power_wait"]["default"] = "1" ++ all_opt["shell_timeout"]["default"] = "5" + + options = check_input(device_opt, process_input(device_opt)) + +diff --git a/tests/data/metadata/fence_rhevm.xml b/tests/data/metadata/fence_rhevm.xml +index 6344db79f..c56cf64b6 100644 +--- a/tests/data/metadata/fence_rhevm.xml ++++ b/tests/data/metadata/fence_rhevm.xml +@@ -98,6 +98,11 @@ + + Login name + ++ ++ ++ ++ Version of RHEV API (default: auto) ++ + + + The path part of the API URL +@@ -164,7 +169,7 @@ + + + +- ++ + Wait X seconds for cmd prompt after issuing command + + diff --git a/SOURCES/bz1464933-1-fence_redfish.patch b/SOURCES/bz1464933-1-fence_redfish.patch new file mode 100644 index 0000000..c6f5dfd --- /dev/null +++ b/SOURCES/bz1464933-1-fence_redfish.patch @@ -0,0 +1,812 @@ +From 64e3f3ef4d0abefd2836fe015c87173310b1e130 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Mon, 3 Dec 2018 10:11:15 -0600 +Subject: [PATCH 1/8] Add new fence agent for Redfish + +- Agent works on all fence devices that implement the Redfish API specification +- Agent programatically finds the Systems Resouce URI if it's not provided +--- + agents/redfish/fence_redfish.py | 151 +++++++++++++++++++++ + tests/data/metadata/fence_redfish.xml | 181 ++++++++++++++++++++++++++ + 2 files changed, 332 insertions(+) + create mode 100644 agents/redfish/fence_redfish.py + create mode 100644 tests/data/metadata/fence_redfish.xml + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +new file mode 100644 +index 00000000..df7cf8c2 +--- /dev/null ++++ b/agents/redfish/fence_redfish.py +@@ -0,0 +1,151 @@ ++#!@PYTHON@ -tt ++ ++# Copyright (c) 2018 Dell Inc. or its subsidiaries. All Rights Reserved. ++ ++# Fence agent for devices that support the Redfish API Specification. ++ ++import sys ++import re ++import json ++import requests ++import atexit ++sys.path.append("@FENCEAGENTSLIBDIR@") ++ ++from requests.packages.urllib3.exceptions import InsecureRequestWarning ++from fencing import * ++from fencing import fail_usage ++ ++def get_power_status(conn, options): ++ uri = options["--systems-uri"] ++ response = send_get_request(options, uri) ++ if response['ret'] is False: ++ fail_usage("Couldn't get power information") ++ data = response['data'] ++ if data[u'PowerState'].strip() == "On": ++ return "on" ++ else: ++ return "off" ++ ++def set_power_status(conn, options): ++ action = { ++ 'on' : "On", ++ 'off': "ForceOff", ++ 'reboot': "GracefulRestart" ++ }[options["--action"]] ++ ++ payload = {'ResetType': action} ++ headers = {'content-type': 'application/json'} ++ ++ # Search for 'Actions' key and extract URI from it ++ uri = options["--systems-uri"] ++ response = send_get_request(options, uri) ++ if response['ret'] is False: ++ return {'ret': False} ++ data = response['data'] ++ uri = data["Actions"]["#ComputerSystem.Reset"]["target"] ++ ++ response = send_post_request(options, uri, payload, headers) ++ if response['ret'] is False: ++ fail_usage("Error sending power command") ++ return ++ ++def send_get_request(options, uri): ++ full_uri = "https://" + options["--ip"] + uri ++ try: ++ resp = requests.get(full_uri, verify=False, ++ auth=(options["--username"], options["--password"])) ++ data = resp.json() ++ except: ++ return {'ret': False} ++ return {'ret': True, 'data': data} ++ ++def send_post_request(options, uri, payload, headers): ++ full_uri = "https://" + options["--ip"] + uri ++ try: ++ requests.post(full_uri, data=json.dumps(payload), ++ headers=headers, verify=False, ++ auth=(options["--username"], options["--password"])) ++ except: ++ return {'ret': False} ++ return {'ret': True} ++ ++def find_systems_resource(options): ++ uri = options["--redfish-uri"] ++ response = send_get_request(options, uri) ++ if response['ret'] is False: ++ return {'ret': False} ++ data = response['data'] ++ ++ if 'Systems' not in data: ++ # Systems resource not found" ++ return {'ret': False} ++ else: ++ uri = data["Systems"]["@odata.id"] ++ response = send_get_request(options, uri) ++ if response['ret'] is False: ++ return {'ret': False} ++ data = response['data'] ++ ++ # need to be able to handle more than one entry ++ for member in data[u'Members']: ++ system_uri = member[u'@odata.id'] ++ return {'ret': True, 'uri': system_uri} ++ ++def define_new_opts(): ++ all_opt["redfish-uri"] = { ++ "getopt" : ":", ++ "longopt" : "redfish-uri", ++ "help" : "--redfish-uri=[uri] Base or starting Redifsh URI", ++ "required" : "0", ++ "default" : "/redfish/v1", ++ "shortdesc" : "Base or starting Redfish URI", ++ "order": 1 ++ } ++ all_opt["systems-uri"] = { ++ "getopt" : ":", ++ "longopt" : "systems-uri", ++ "help" : "--systems-uri=[uri] Redfish Systems resource URI", ++ "required" : "0", ++ "shortdesc" : "Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1", ++ "order": 1 ++ } ++ ++def main(): ++ atexit.register(atexit_handler) ++ device_opt = ["ipaddr", "login", "passwd", "redfish-uri", "systems-uri", "ssl"] ++ define_new_opts() ++ ++ opt = process_input(device_opt) ++ ++ all_opt["ipport"]["default"] = "443" ++ options = check_input(device_opt, opt) ++ ++ docs = {} ++ docs["shortdesc"] = "I/O Fencing agent for Redfish" ++ docs["longdesc"] = "fence_redfish is an I/O Fencing agent which can be used with \ ++Out-of-Band controllers that support Redfish APIs. These controllers provide remote \ ++access to control power on a server." ++ docs["vendorurl"] = "http://www.dmtf.org" ++ show_docs(options, docs) ++ ++ ## ++ ## Operate the fencing device ++ #### ++ ++ # Disable insecure-certificate-warning message ++ if "--ssl-insecure" in opt: ++ requests.packages.urllib3.disable_warnings(InsecureRequestWarning) ++ ++ if "--systems-uri" not in opt: ++ # Systems URI not provided, find it ++ sysresult = find_systems_resource(options) ++ if sysresult['ret'] is False: ++ sys.exit(1) ++ else: ++ options["--systems-uri"] = sysresult["uri"] ++ ++ result = fence_action(None, options, set_power_status, get_power_status, None) ++ sys.exit(result) ++ ++if __name__ == "__main__": ++ main() +diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml +new file mode 100644 +index 00000000..43d447d0 +--- /dev/null ++++ b/tests/data/metadata/fence_redfish.xml +@@ -0,0 +1,181 @@ ++ ++ ++fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server. ++http://www.dmtf.org ++ ++ ++ ++ ++ TCP/UDP port to use for connection with device ++ ++ ++ ++ ++ SSL connection with verifying fence device's certificate ++ ++ ++ ++ ++ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 ++ ++ ++ ++ ++ Fencing Action ++ ++ ++ ++ ++ Forces agent to use IPv6 addresses only ++ ++ ++ ++ ++ IP Address or Hostname ++ ++ ++ ++ ++ IP address or hostname of fencing device (together with --port-as-ip) ++ ++ ++ ++ ++ Script to retrieve password ++ ++ ++ ++ ++ Forces agent to use IPv4 addresses only ++ ++ ++ ++ ++ Login password or passphrase ++ ++ ++ ++ ++ SSL connection ++ ++ ++ ++ ++ Base or starting Redfish URI ++ ++ ++ ++ ++ SSL connection without verifying fence device's certificate ++ ++ ++ ++ ++ Login Name ++ ++ ++ ++ ++ IP address or hostname of fencing device (together with --port-as-ip) ++ ++ ++ ++ ++ Login Name ++ ++ ++ ++ ++ Base or starting Redfish URI ++ ++ ++ ++ ++ IP Address or Hostname ++ ++ ++ ++ ++ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 ++ ++ ++ ++ ++ Login password or passphrase ++ ++ ++ ++ ++ Script to retrieve password ++ ++ ++ ++ ++ Verbose mode ++ ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ ++ Display version information and exit ++ ++ ++ ++ ++ Display help and exit ++ ++ ++ ++ ++ Wait X seconds after issuing ON/OFF ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after login ++ ++ ++ ++ ++ Test X seconds for status change after ON/OFF ++ ++ ++ ++ ++ Wait X seconds before fencing is started ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after issuing command ++ ++ ++ ++ ++ Make "port/plug" to be an alias to IP address ++ ++ ++ ++ ++ Count of attempts to retry power on ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +From 6921a34d64d098a7b1f32205e0be434438c36898 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Mon, 3 Dec 2018 10:46:52 -0600 +Subject: [PATCH 2/8] Updated fence_redfish.xml with make xml-upload + +--- + tests/data/metadata/fence_redfish.xml | 148 ++++++++++++++------------ + 1 file changed, 79 insertions(+), 69 deletions(-) + +diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml +index 43d447d0..a39541e6 100644 +--- a/tests/data/metadata/fence_redfish.xml ++++ b/tests/data/metadata/fence_redfish.xml +@@ -3,110 +3,115 @@ + fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server. + http://www.dmtf.org + +- +- +- +- TCP/UDP port to use for connection with device +- +- +- +- +- SSL connection with verifying fence device's certificate +- +- +- +- +- Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 +- + + + +- Fencing Action ++ Fencing action ++ ++ ++ ++ ++ Forces agent to use IPv4 addresses only + + + + + Forces agent to use IPv6 addresses only + +- ++ + + +- IP Address or Hostname ++ IP address or hostname of fencing device + +- +- ++ ++ + +- IP address or hostname of fencing device (together with --port-as-ip) ++ IP address or hostname of fencing device + +- +- +- +- Script to retrieve password ++ ++ ++ ++ TCP/UDP port to use for connection with device + +- +- +- +- Forces agent to use IPv4 addresses only ++ ++ ++ ++ Login name + + + + + Login password or passphrase + +- +- +- +- SSL connection +- +- +- +- +- Base or starting Redfish URI ++ ++ ++ ++ Script to run to retrieve password + +- +- +- +- SSL connection without verifying fence device's certificate ++ ++ ++ ++ Login password or passphrase + +- +- ++ ++ + +- Login Name ++ Script to run to retrieve password + + + + + IP address or hostname of fencing device (together with --port-as-ip) + +- +- ++ ++ + +- Login Name ++ IP address or hostname of fencing device (together with --port-as-ip) ++ ++ ++ ++ ++ Base or starting Redfish URI + + + + + Base or starting Redfish URI + +- +- ++ ++ ++ ++ Use SSL connection with verifying certificate ++ ++ ++ ++ ++ Use SSL connection without verifying certificate ++ ++ ++ ++ ++ Use SSL connection with verifying certificate ++ ++ ++ + +- IP Address or Hostname ++ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 + + + + + Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 + +- +- ++ ++ + +- Login password or passphrase ++ Login name + +- +- +- +- Script to retrieve password ++ ++ ++ ++ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. + + + +@@ -133,41 +138,45 @@ + + Display help and exit + +- +- ++ ++ + +- Wait X seconds after issuing ON/OFF ++ Wait X seconds before fencing is started + + + + + Wait X seconds for cmd prompt after login + ++ ++ ++ ++ Make "port/plug" to be an alias to IP address ++ + + + + Test X seconds for status change after ON/OFF + +- +- ++ ++ + +- Wait X seconds before fencing is started ++ Wait X seconds after issuing ON/OFF + + + + + Wait X seconds for cmd prompt after issuing command + +- +- +- +- Make "port/plug" to be an alias to IP address +- + + + + Count of attempts to retry power on + ++ ++ ++ Path to gnutls-cli binary ++ + + + +@@ -176,6 +185,7 @@ + + + ++ + + + + +From 755627fadd711848ea256d72f5e75f36f83b4d31 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Mon, 3 Dec 2018 11:55:23 -0600 +Subject: [PATCH 3/8] Added run_delay() + +--- + agents/redfish/fence_redfish.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index df7cf8c2..0e4a4f68 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -13,7 +13,7 @@ + + from requests.packages.urllib3.exceptions import InsecureRequestWarning + from fencing import * +-from fencing import fail_usage ++from fencing import fail_usage, run_delay + + def get_power_status(conn, options): + uri = options["--systems-uri"] +@@ -127,6 +127,7 @@ def main(): + access to control power on a server." + docs["vendorurl"] = "http://www.dmtf.org" + show_docs(options, docs) ++ run_delay(options) + + ## + ## Operate the fencing device + +From 15fef4c47f391a3f03c714d86c9670ea209dec99 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Tue, 4 Dec 2018 10:56:58 -0600 +Subject: [PATCH 4/8] Modify power status check + +- Only returns off if PowerState = Off +- Otherwise returns on +--- + agents/redfish/fence_redfish.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 0e4a4f68..7998fb1c 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -21,10 +21,10 @@ def get_power_status(conn, options): + if response['ret'] is False: + fail_usage("Couldn't get power information") + data = response['data'] +- if data[u'PowerState'].strip() == "On": +- return "on" +- else: ++ if data[u'PowerState'].strip() == "Off": + return "off" ++ else: ++ return "on" + + def set_power_status(conn, options): + action = { + +From acf70f4672be65562841227ab0b4cacb87965f44 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Wed, 5 Dec 2018 10:39:32 -0600 +Subject: [PATCH 5/8] Changed reboot type to ForceRestart + +--- + agents/redfish/fence_redfish.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 7998fb1c..3fe2bfc0 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -30,7 +30,7 @@ def set_power_status(conn, options): + action = { + 'on' : "On", + 'off': "ForceOff", +- 'reboot': "GracefulRestart" ++ 'reboot': "ForceRestart" + }[options["--action"]] + + payload = {'ResetType': action} + +From 56e3358d45050ac669c099c56873feefa1ecda38 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Wed, 5 Dec 2018 10:54:44 -0600 +Subject: [PATCH 6/8] Replaced default port 443 with default ssl enabled option + +--- + agents/redfish/fence_redfish.py | 2 +- + tests/data/metadata/fence_redfish.xml | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 3fe2bfc0..6a2dbb76 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -117,7 +117,7 @@ def main(): + + opt = process_input(device_opt) + +- all_opt["ipport"]["default"] = "443" ++ all_opt["ssl"]["default"] = "1" + options = check_input(device_opt, opt) + + docs = {} +diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml +index a39541e6..e1c18584 100644 +--- a/tests/data/metadata/fence_redfish.xml ++++ b/tests/data/metadata/fence_redfish.xml +@@ -80,7 +80,7 @@ + + + +- ++ + Use SSL connection with verifying certificate + + + +From 5c25a85b22a17d6bbc3dcb47c99b76e3a99a5857 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Wed, 5 Dec 2018 13:29:42 -0600 +Subject: [PATCH 7/8] Renamed variable to avoid reusing variable name + +--- + agents/redfish/fence_redfish.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 6a2dbb76..1ea25cd8 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -42,9 +42,9 @@ def set_power_status(conn, options): + if response['ret'] is False: + return {'ret': False} + data = response['data'] +- uri = data["Actions"]["#ComputerSystem.Reset"]["target"] ++ action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"] + +- response = send_post_request(options, uri, payload, headers) ++ response = send_post_request(options, action_uri, payload, headers) + if response['ret'] is False: + fail_usage("Error sending power command") + return + +From 7dce8b1e22d57fec0d34e91a99fab9d8a06f1303 Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Thu, 6 Dec 2018 10:33:06 -0600 +Subject: [PATCH 8/8] Removed unnecessary variable assignments to simplify code + +--- + agents/redfish/fence_redfish.py | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 1ea25cd8..67ef67ab 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -16,8 +16,7 @@ + from fencing import fail_usage, run_delay + + def get_power_status(conn, options): +- uri = options["--systems-uri"] +- response = send_get_request(options, uri) ++ response = send_get_request(options, options["--systems-uri"]) + if response['ret'] is False: + fail_usage("Couldn't get power information") + data = response['data'] +@@ -37,8 +36,7 @@ def set_power_status(conn, options): + headers = {'content-type': 'application/json'} + + # Search for 'Actions' key and extract URI from it +- uri = options["--systems-uri"] +- response = send_get_request(options, uri) ++ response = send_get_request(options, options["--systems-uri"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] +@@ -70,8 +68,7 @@ def send_post_request(options, uri, payload, headers): + return {'ret': True} + + def find_systems_resource(options): +- uri = options["--redfish-uri"] +- response = send_get_request(options, uri) ++ response = send_get_request(options, options["--redfish-uri"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] +@@ -80,8 +77,7 @@ def find_systems_resource(options): + # Systems resource not found" + return {'ret': False} + else: +- uri = data["Systems"]["@odata.id"] +- response = send_get_request(options, uri) ++ response = send_get_request(options, data["Systems"]["@odata.id"]) + if response['ret'] is False: + return {'ret': False} + data = response['data'] diff --git a/SOURCES/bz1464933-2-fence_redfish-fail-invalid-cert.patch b/SOURCES/bz1464933-2-fence_redfish-fail-invalid-cert.patch new file mode 100644 index 0000000..a834644 --- /dev/null +++ b/SOURCES/bz1464933-2-fence_redfish-fail-invalid-cert.patch @@ -0,0 +1,60 @@ +From 7aa3c50d1d02dd26bdeac99c49ada72f842d88e8 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 17 Jan 2019 16:52:52 +0100 +Subject: [PATCH] fence_redfish: fail when using invalid cert without + --ssl-insecure + +--- + agents/redfish/fence_redfish.py | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 67ef67ab..5b719d4b 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -6,6 +6,7 @@ + + import sys + import re ++import logging + import json + import requests + import atexit +@@ -20,6 +21,9 @@ def get_power_status(conn, options): + if response['ret'] is False: + fail_usage("Couldn't get power information") + data = response['data'] ++ ++ logging.debug("PowerState is: " + data[u'PowerState']) ++ + if data[u'PowerState'].strip() == "Off": + return "off" + else: +@@ -50,21 +54,21 @@ def set_power_status(conn, options): + def send_get_request(options, uri): + full_uri = "https://" + options["--ip"] + uri + try: +- resp = requests.get(full_uri, verify=False, ++ resp = requests.get(full_uri, verify=not "--ssl-insecure" in options, + auth=(options["--username"], options["--password"])) + data = resp.json() +- except: +- return {'ret': False} ++ except Exception as e: ++ fail_usage("Failed: send_get_request: " + str(e)) + return {'ret': True, 'data': data} + + def send_post_request(options, uri, payload, headers): + full_uri = "https://" + options["--ip"] + uri + try: + requests.post(full_uri, data=json.dumps(payload), +- headers=headers, verify=False, ++ headers=headers, verify=not "--ssl-insecure" in options, + auth=(options["--username"], options["--password"])) +- except: +- return {'ret': False} ++ except Exception as e: ++ fail_usage("Failed: send_post_request: " + str(e)) + return {'ret': True} + + def find_systems_resource(options): diff --git a/SOURCES/bz1608550-fence_dump-validate-all.patch b/SOURCES/bz1608550-fence_dump-validate-all.patch new file mode 100644 index 0000000..69143e8 --- /dev/null +++ b/SOURCES/bz1608550-fence_dump-validate-all.patch @@ -0,0 +1,62 @@ +From 0dc5bcf0ee82f6d6dc42a92e6564b93740b3c7ee Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 3 Sep 2018 15:29:19 +0200 +Subject: [PATCH] fence_kdump: add validate-all action + +--- + agents/kdump/fence_kdump.c | 6 +++++- + agents/kdump/options.h | 3 +++ + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/agents/kdump/fence_kdump.c b/agents/kdump/fence_kdump.c +index 768a9344..4ab2dd9b 100644 +--- a/agents/kdump/fence_kdump.c ++++ b/agents/kdump/fence_kdump.c +@@ -295,6 +295,7 @@ do_action_metadata (const char *self) + fprintf (stdout, "\t\n"); + fprintf (stdout, "\t\n"); + fprintf (stdout, "\t\n"); ++ fprintf (stdout, "\t\n"); + fprintf (stdout, "\n"); + + fprintf (stdout, "\n"); +@@ -316,7 +317,7 @@ print_usage (const char *self) + fprintf (stdout, "%s\n", + " -f, --family=FAMILY Network family: ([auto], ipv4, ipv6)"); + fprintf (stdout, "%s\n", +- " -o, --action=ACTION Fencing action: ([off], monitor, metadata)"); ++ " -o, --action=ACTION Fencing action: ([off], monitor, metadata, validate-all)"); + fprintf (stdout, "%s\n", + " -t, --timeout=TIMEOUT Timeout in seconds (default: 60)"); + fprintf (stdout, "%s\n", +@@ -556,6 +557,9 @@ main (int argc, char **argv) + case FENCE_KDUMP_ACTION_MONITOR: + error = do_action_monitor (); + break; ++ case FENCE_KDUMP_ACTION_VALIDATE: ++ error = 0; ++ break; + default: + break; + } +diff --git a/agents/kdump/options.h b/agents/kdump/options.h +index 22731d7c..6d774e5a 100644 +--- a/agents/kdump/options.h ++++ b/agents/kdump/options.h +@@ -36,6 +36,7 @@ enum { + FENCE_KDUMP_ACTION_LIST = 4, + FENCE_KDUMP_ACTION_MONITOR = 5, + FENCE_KDUMP_ACTION_METADATA = 6, ++ FENCE_KDUMP_ACTION_VALIDATE = 7, + }; + + enum { +@@ -191,6 +192,8 @@ set_option_action (fence_kdump_opts_t *opts, const char *arg) + opts->action = FENCE_KDUMP_ACTION_METADATA; + } else if (!strcasecmp (arg, "monitor")) { + opts->action = FENCE_KDUMP_ACTION_MONITOR; ++ } else if (!strcasecmp (arg, "validate-all")) { ++ opts->action = FENCE_KDUMP_ACTION_VALIDATE; + } else { + fprintf (stderr, "[error]: unsupported action '%s'\n", arg); + exit (1); diff --git a/SOURCES/bz1645170-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch b/SOURCES/bz1645170-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch new file mode 100644 index 0000000..9560368 --- /dev/null +++ b/SOURCES/bz1645170-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch @@ -0,0 +1,24 @@ +From f77297b654586bf539e78957f26cae1d22c6f081 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 2 Nov 2018 09:24:56 +0100 +Subject: [PATCH] fence_scsi: fix incorrect SCSI key when node ID is 10 or + higher + + The last four digits of the SCSI key will be zero padded digit between 0000-0009. +--- + agents/scsi/fence_scsi.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 2180d0c9..79ada4fa 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -191,7 +191,7 @@ def get_cluster_id(options): + def get_node_id(options): + cmd = options["--corosync-cmap-path"] + " nodelist" + +- match = re.search(r".(\d).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"]) ++ match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"]) + return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist") + + diff --git a/SOURCES/bz1647522-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch b/SOURCES/bz1647522-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch deleted file mode 100644 index 9560368..0000000 --- a/SOURCES/bz1647522-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch +++ /dev/null @@ -1,24 +0,0 @@ -From f77297b654586bf539e78957f26cae1d22c6f081 Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Fri, 2 Nov 2018 09:24:56 +0100 -Subject: [PATCH] fence_scsi: fix incorrect SCSI key when node ID is 10 or - higher - - The last four digits of the SCSI key will be zero padded digit between 0000-0009. ---- - agents/scsi/fence_scsi.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py -index 2180d0c9..79ada4fa 100644 ---- a/agents/scsi/fence_scsi.py -+++ b/agents/scsi/fence_scsi.py -@@ -191,7 +191,7 @@ def get_cluster_id(options): - def get_node_id(options): - cmd = options["--corosync-cmap-path"] + " nodelist" - -- match = re.search(r".(\d).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"]) -+ match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"]) - return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist") - - diff --git a/SOURCES/bz1650526-fence_hpblade-fix-log_expect_syntax.patch b/SOURCES/bz1650526-fence_hpblade-fix-log_expect_syntax.patch new file mode 100644 index 0000000..bb239b1 --- /dev/null +++ b/SOURCES/bz1650526-fence_hpblade-fix-log_expect_syntax.patch @@ -0,0 +1,50 @@ +From 342570c5a5af4c277be283507ef7898a078e2df9 Mon Sep 17 00:00:00 2001 +From: mmartinv <32071463+mmartinv@users.noreply.github.com> +Date: Fri, 16 Nov 2018 12:55:58 +0100 +Subject: [PATCH] Fix 'log_expect' in fence_hpblade.py + +Update the 'log_expect' call to the new method definition. +--- + agents/hpblade/fence_hpblade.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/hpblade/fence_hpblade.py b/agents/hpblade/fence_hpblade.py +index b2cc94a3..fbc89f61 100644 +--- a/agents/hpblade/fence_hpblade.py ++++ b/agents/hpblade/fence_hpblade.py +@@ -16,7 +16,7 @@ + + def get_enclosure_type(conn, options): + conn.send_eol("show enclosure info") +- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) ++ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$") + enclosure="unknown" +@@ -39,7 +39,7 @@ def get_power_status(conn, options): + powrestr = "^\\s*Power: (.*?)\\s*$" + + conn.send_eol(cmd_send) +- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) ++ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + power_re = re.compile(powrestr) + status = "unknown" +@@ -72,7 +72,7 @@ def set_power_status(conn, options): + conn.send_eol("poweron " + dev + options["--plug"]) + elif options["--action"] == "off": + conn.send_eol("poweroff " + dev + options["--plug"] + " force") +- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) ++ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + def get_instances_list(conn, options): + outlets = {} +@@ -84,7 +84,7 @@ def get_instances_list(conn, options): + listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$" + + conn.send_eol(cmd_send) +- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) ++ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) + + list_re = re.compile(listrestr) + for line in conn.before.splitlines(): diff --git a/SOURCES/bz1652115-fence_hpblade-fix-log_expect-syntax.patch b/SOURCES/bz1652115-fence_hpblade-fix-log_expect-syntax.patch deleted file mode 100644 index bb239b1..0000000 --- a/SOURCES/bz1652115-fence_hpblade-fix-log_expect-syntax.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 342570c5a5af4c277be283507ef7898a078e2df9 Mon Sep 17 00:00:00 2001 -From: mmartinv <32071463+mmartinv@users.noreply.github.com> -Date: Fri, 16 Nov 2018 12:55:58 +0100 -Subject: [PATCH] Fix 'log_expect' in fence_hpblade.py - -Update the 'log_expect' call to the new method definition. ---- - agents/hpblade/fence_hpblade.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/agents/hpblade/fence_hpblade.py b/agents/hpblade/fence_hpblade.py -index b2cc94a3..fbc89f61 100644 ---- a/agents/hpblade/fence_hpblade.py -+++ b/agents/hpblade/fence_hpblade.py -@@ -16,7 +16,7 @@ - - def get_enclosure_type(conn, options): - conn.send_eol("show enclosure info") -- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) -+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) - - type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$") - enclosure="unknown" -@@ -39,7 +39,7 @@ def get_power_status(conn, options): - powrestr = "^\\s*Power: (.*?)\\s*$" - - conn.send_eol(cmd_send) -- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) -+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) - - power_re = re.compile(powrestr) - status = "unknown" -@@ -72,7 +72,7 @@ def set_power_status(conn, options): - conn.send_eol("poweron " + dev + options["--plug"]) - elif options["--action"] == "off": - conn.send_eol("poweroff " + dev + options["--plug"] + " force") -- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) -+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) - - def get_instances_list(conn, options): - outlets = {} -@@ -84,7 +84,7 @@ def get_instances_list(conn, options): - listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$" - - conn.send_eol(cmd_send) -- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"])) -+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"])) - - list_re = re.compile(listrestr) - for line in conn.before.splitlines(): diff --git a/SOURCES/bz1653700-1-fence_scsi-watchdog-retry-support.patch b/SOURCES/bz1653700-1-fence_scsi-watchdog-retry-support.patch new file mode 100644 index 0000000..276c439 --- /dev/null +++ b/SOURCES/bz1653700-1-fence_scsi-watchdog-retry-support.patch @@ -0,0 +1,146 @@ +From 11a63822fbdc0a9ebe1b668b26a59f1cc9649f6c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 24 Oct 2018 14:51:27 +0200 +Subject: [PATCH] fence_scsi: watchdog retries support + +--- + agents/scsi/fence_scsi.py | 60 ++++++++++++++++++++---------- + tests/data/metadata/fence_scsi.xml | 4 +- + 2 files changed, 43 insertions(+), 21 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 79ada4fa..8a1e4c77 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -158,13 +158,15 @@ def get_reservation_key(options, dev): + return match.group(1) if match else None + + +-def get_registration_keys(options, dev): ++def get_registration_keys(options, dev, fail=True): + reset_dev(options,dev) + keys = [] + cmd = options["--sg_persist-path"] + " -n -i -k -d " + dev + out = run_cmd(options, cmd) + if out["err"]: +- fail_usage("Cannot get registration keys") ++ fail_usage("Cannot get registration keys", fail) ++ if not fail: ++ return [] + for line in out["out"].split("\n"): + match = re.search(r"\s+0x(\S+)\s*", line) + if match: +@@ -218,9 +220,8 @@ def get_key(fail=True): + try: + f = open(file_path, "r") + except IOError: +- if fail: +- fail_usage("Failed: Cannot open file \""+ file_path + "\"") +- else: ++ fail_usage("Failed: Cannot open file \""+ file_path + "\"", fail) ++ if not fail: + return None + return f.readline().strip().lower() + +@@ -244,9 +245,8 @@ def dev_read(fail=True): + try: + f = open(file_path, "r") + except IOError: +- if fail: +- fail_usage("Failed: Cannot open file \"" + file_path + "\"") +- else: ++ fail_usage("Failed: Cannot open file \"" + file_path + "\"", fail) ++ if not fail: + return None + # get not empty lines from file + devs = [line.strip() for line in f if line.strip()] +@@ -371,14 +371,20 @@ def define_new_opts(): + } + + +-def scsi_check_get_verbose(): ++def scsi_check_get_options(options): + try: +- f = open("/etc/sysconfig/watchdog", "r") ++ f = open("/etc/sysconfig/stonith", "r") + except IOError: +- return False +- match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE) ++ return options ++ ++ match = re.findall(r"^\s*(\S*)\s*=\s*(\S*)\s*", "".join(f.readlines()), re.MULTILINE) ++ ++ for m in match: ++ options[m[0].lower()] = m[1].lower() ++ + f.close() +- return bool(match) ++ ++ return options + + + def scsi_check(hardreboot=False): +@@ -388,7 +394,10 @@ def scsi_check(hardreboot=False): + options["--sg_turs-path"] = "@SG_TURS_PATH@" + options["--sg_persist-path"] = "@SG_PERSIST_PATH@" + options["--power-timeout"] = "5" +- if scsi_check_get_verbose(): ++ options["retry"] = "0" ++ options["retry-sleep"] = "1" ++ options = scsi_check_get_options(options) ++ if "verbose" in options and options["verbose"] == "yes": + logging.getLogger().setLevel(logging.DEBUG) + devs = dev_read(fail=False) + if not devs: +@@ -399,11 +408,18 @@ def scsi_check(hardreboot=False): + logging.error("Key not found") + return 0 + for dev in devs: +- if key in get_registration_keys(options, dev): +- logging.debug("key " + key + " registered with device " + dev) +- return 0 +- else: +- logging.debug("key " + key + " not registered with device " + dev) ++ for n in range(int(options["retry"]) + 1): ++ if n > 0: ++ logging.debug("retry: " + str(n) + " of " + options["retry"]) ++ if key in get_registration_keys(options, dev, fail=False): ++ logging.debug("key " + key + " registered with device " + dev) ++ return 0 ++ else: ++ logging.debug("key " + key + " not registered with device " + dev) ++ ++ if n < int(options["retry"]): ++ time.sleep(float(options["retry-sleep"])) ++ + logging.debug("key " + key + " registered with any devices") + + if hardreboot == True: +@@ -452,7 +468,11 @@ def main(): + device(s). The result is that only registered nodes may write to the \ + device(s). When a node failure occurs, the fence_scsi agent will remove the \ + key belonging to the failed node from the device(s). The failed node will no \ +-longer be able to write to the device(s). A manual reboot is required." ++longer be able to write to the device(s). A manual reboot is required.\ ++\n.P\n\ ++When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and \ ++verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it \ ++failing." + docs["vendorurl"] = "" + show_docs(options, docs) + +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index 45a84168..b8cdabd1 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -1,7 +1,9 @@ + + + fence_scsi is an I/O fencing agent that uses SCSI-3 persistent reservations to control access to shared storage devices. These devices must support SCSI-3 persistent reservations (SPC-3 or greater) as well as the "preempt-and-abort" subcommand. +-The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required. ++The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required. ++ ++When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it failing. + + + diff --git a/SOURCES/bz1653700-2-build-fix-check_used_options.patch b/SOURCES/bz1653700-2-build-fix-check_used_options.patch new file mode 100644 index 0000000..068375d --- /dev/null +++ b/SOURCES/bz1653700-2-build-fix-check_used_options.patch @@ -0,0 +1,23 @@ +From 267afc5caa0580cc483220e671cda094413a4e16 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 28 Nov 2018 09:54:16 +0100 +Subject: [PATCH] build: fix if-redirection to make check_used_options run for + the agents as intended + +--- + make/fencebuild.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/make/fencebuild.mk b/make/fencebuild.mk +index 9e8bd692..143082f0 100644 +--- a/make/fencebuild.mk ++++ b/make/fencebuild.mk +@@ -33,7 +33,7 @@ define gen_agent_from_py + -e 's#@''PING4_CMD@#${PING4_CMD}#g' \ + > $@ + +- if [ 0 -eq `echo "$(@)" | grep fence_ 2>&1 /dev/null; echo $$?` ]; then \ ++ if [ 0 -eq `echo "$(@)" | grep fence_ > /dev/null 2>&1; echo $$?` ]; then \ + PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \ + else true ; fi + diff --git a/SOURCES/bz1653700-3-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch b/SOURCES/bz1653700-3-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch new file mode 100644 index 0000000..010fc00 --- /dev/null +++ b/SOURCES/bz1653700-3-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch @@ -0,0 +1,42 @@ +From 418b3a36c8a7de0e984a0cd4707f2b90f279c4ce Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 13 Jun 2019 11:29:25 +0200 +Subject: [PATCH] fence_scsi watchdog: dont exit when command fails using retry + parameter + +--- + lib/fencing.py.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/lib/fencing.py.py b/lib/fencing.py.py +index 8cd0a813..6f2526a9 100644 +--- a/lib/fencing.py.py ++++ b/lib/fencing.py.py +@@ -530,7 +530,7 @@ def fail_usage(message="", stop=True): + logging.error("Please use '-h' for usage\n") + sys.exit(EC_GENERIC_ERROR) + +-def fail(error_code): ++def fail(error_code, stop=True): + message = { + EC_LOGIN_DENIED : "Unable to connect/login to fencing device", + EC_CONNECTION_LOST : "Connection lost", +@@ -546,7 +546,8 @@ def fail(error_code): + + }[error_code] + "\n" + logging.error("%s\n", message) +- sys.exit(EC_GENERIC_ERROR) ++ if stop: ++ sys.exit(EC_GENERIC_ERROR) + + def usage(avail_opt): + print("Usage:") +@@ -1009,7 +1010,7 @@ def run_command(options, command, timeout=None, env=None, log_command=None): + thread.join(timeout) + if thread.is_alive(): + process.kill() +- fail(EC_TIMED_OUT) ++ fail(EC_TIMED_OUT, stop=(int(options.get("retry", 0)) < 1)) + + status = process.wait() + diff --git a/SOURCES/bz1654172-1-fence_scsi-watchdog-retry-support.patch b/SOURCES/bz1654172-1-fence_scsi-watchdog-retry-support.patch deleted file mode 100644 index 276c439..0000000 --- a/SOURCES/bz1654172-1-fence_scsi-watchdog-retry-support.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 11a63822fbdc0a9ebe1b668b26a59f1cc9649f6c Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Wed, 24 Oct 2018 14:51:27 +0200 -Subject: [PATCH] fence_scsi: watchdog retries support - ---- - agents/scsi/fence_scsi.py | 60 ++++++++++++++++++++---------- - tests/data/metadata/fence_scsi.xml | 4 +- - 2 files changed, 43 insertions(+), 21 deletions(-) - -diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py -index 79ada4fa..8a1e4c77 100644 ---- a/agents/scsi/fence_scsi.py -+++ b/agents/scsi/fence_scsi.py -@@ -158,13 +158,15 @@ def get_reservation_key(options, dev): - return match.group(1) if match else None - - --def get_registration_keys(options, dev): -+def get_registration_keys(options, dev, fail=True): - reset_dev(options,dev) - keys = [] - cmd = options["--sg_persist-path"] + " -n -i -k -d " + dev - out = run_cmd(options, cmd) - if out["err"]: -- fail_usage("Cannot get registration keys") -+ fail_usage("Cannot get registration keys", fail) -+ if not fail: -+ return [] - for line in out["out"].split("\n"): - match = re.search(r"\s+0x(\S+)\s*", line) - if match: -@@ -218,9 +220,8 @@ def get_key(fail=True): - try: - f = open(file_path, "r") - except IOError: -- if fail: -- fail_usage("Failed: Cannot open file \""+ file_path + "\"") -- else: -+ fail_usage("Failed: Cannot open file \""+ file_path + "\"", fail) -+ if not fail: - return None - return f.readline().strip().lower() - -@@ -244,9 +245,8 @@ def dev_read(fail=True): - try: - f = open(file_path, "r") - except IOError: -- if fail: -- fail_usage("Failed: Cannot open file \"" + file_path + "\"") -- else: -+ fail_usage("Failed: Cannot open file \"" + file_path + "\"", fail) -+ if not fail: - return None - # get not empty lines from file - devs = [line.strip() for line in f if line.strip()] -@@ -371,14 +371,20 @@ def define_new_opts(): - } - - --def scsi_check_get_verbose(): -+def scsi_check_get_options(options): - try: -- f = open("/etc/sysconfig/watchdog", "r") -+ f = open("/etc/sysconfig/stonith", "r") - except IOError: -- return False -- match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE) -+ return options -+ -+ match = re.findall(r"^\s*(\S*)\s*=\s*(\S*)\s*", "".join(f.readlines()), re.MULTILINE) -+ -+ for m in match: -+ options[m[0].lower()] = m[1].lower() -+ - f.close() -- return bool(match) -+ -+ return options - - - def scsi_check(hardreboot=False): -@@ -388,7 +394,10 @@ def scsi_check(hardreboot=False): - options["--sg_turs-path"] = "@SG_TURS_PATH@" - options["--sg_persist-path"] = "@SG_PERSIST_PATH@" - options["--power-timeout"] = "5" -- if scsi_check_get_verbose(): -+ options["retry"] = "0" -+ options["retry-sleep"] = "1" -+ options = scsi_check_get_options(options) -+ if "verbose" in options and options["verbose"] == "yes": - logging.getLogger().setLevel(logging.DEBUG) - devs = dev_read(fail=False) - if not devs: -@@ -399,11 +408,18 @@ def scsi_check(hardreboot=False): - logging.error("Key not found") - return 0 - for dev in devs: -- if key in get_registration_keys(options, dev): -- logging.debug("key " + key + " registered with device " + dev) -- return 0 -- else: -- logging.debug("key " + key + " not registered with device " + dev) -+ for n in range(int(options["retry"]) + 1): -+ if n > 0: -+ logging.debug("retry: " + str(n) + " of " + options["retry"]) -+ if key in get_registration_keys(options, dev, fail=False): -+ logging.debug("key " + key + " registered with device " + dev) -+ return 0 -+ else: -+ logging.debug("key " + key + " not registered with device " + dev) -+ -+ if n < int(options["retry"]): -+ time.sleep(float(options["retry-sleep"])) -+ - logging.debug("key " + key + " registered with any devices") - - if hardreboot == True: -@@ -452,7 +468,11 @@ def main(): - device(s). The result is that only registered nodes may write to the \ - device(s). When a node failure occurs, the fence_scsi agent will remove the \ - key belonging to the failed node from the device(s). The failed node will no \ --longer be able to write to the device(s). A manual reboot is required." -+longer be able to write to the device(s). A manual reboot is required.\ -+\n.P\n\ -+When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and \ -+verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it \ -+failing." - docs["vendorurl"] = "" - show_docs(options, docs) - -diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml -index 45a84168..b8cdabd1 100644 ---- a/tests/data/metadata/fence_scsi.xml -+++ b/tests/data/metadata/fence_scsi.xml -@@ -1,7 +1,9 @@ - - - fence_scsi is an I/O fencing agent that uses SCSI-3 persistent reservations to control access to shared storage devices. These devices must support SCSI-3 persistent reservations (SPC-3 or greater) as well as the "preempt-and-abort" subcommand. --The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required. -+The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required. -+ -+When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it failing. - - - diff --git a/SOURCES/bz1654172-2-build-fix-check_used_options.patch b/SOURCES/bz1654172-2-build-fix-check_used_options.patch deleted file mode 100644 index 068375d..0000000 --- a/SOURCES/bz1654172-2-build-fix-check_used_options.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 267afc5caa0580cc483220e671cda094413a4e16 Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Wed, 28 Nov 2018 09:54:16 +0100 -Subject: [PATCH] build: fix if-redirection to make check_used_options run for - the agents as intended - ---- - make/fencebuild.mk | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/make/fencebuild.mk b/make/fencebuild.mk -index 9e8bd692..143082f0 100644 ---- a/make/fencebuild.mk -+++ b/make/fencebuild.mk -@@ -33,7 +33,7 @@ define gen_agent_from_py - -e 's#@''PING4_CMD@#${PING4_CMD}#g' \ - > $@ - -- if [ 0 -eq `echo "$(@)" | grep fence_ 2>&1 /dev/null; echo $$?` ]; then \ -+ if [ 0 -eq `echo "$(@)" | grep fence_ > /dev/null 2>&1; echo $$?` ]; then \ - PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \ - else true ; fi - diff --git a/SOURCES/bz1666848-1-fence_redfish.patch b/SOURCES/bz1666848-1-fence_redfish.patch deleted file mode 100644 index c6f5dfd..0000000 --- a/SOURCES/bz1666848-1-fence_redfish.patch +++ /dev/null @@ -1,812 +0,0 @@ -From 64e3f3ef4d0abefd2836fe015c87173310b1e130 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Mon, 3 Dec 2018 10:11:15 -0600 -Subject: [PATCH 1/8] Add new fence agent for Redfish - -- Agent works on all fence devices that implement the Redfish API specification -- Agent programatically finds the Systems Resouce URI if it's not provided ---- - agents/redfish/fence_redfish.py | 151 +++++++++++++++++++++ - tests/data/metadata/fence_redfish.xml | 181 ++++++++++++++++++++++++++ - 2 files changed, 332 insertions(+) - create mode 100644 agents/redfish/fence_redfish.py - create mode 100644 tests/data/metadata/fence_redfish.xml - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -new file mode 100644 -index 00000000..df7cf8c2 ---- /dev/null -+++ b/agents/redfish/fence_redfish.py -@@ -0,0 +1,151 @@ -+#!@PYTHON@ -tt -+ -+# Copyright (c) 2018 Dell Inc. or its subsidiaries. All Rights Reserved. -+ -+# Fence agent for devices that support the Redfish API Specification. -+ -+import sys -+import re -+import json -+import requests -+import atexit -+sys.path.append("@FENCEAGENTSLIBDIR@") -+ -+from requests.packages.urllib3.exceptions import InsecureRequestWarning -+from fencing import * -+from fencing import fail_usage -+ -+def get_power_status(conn, options): -+ uri = options["--systems-uri"] -+ response = send_get_request(options, uri) -+ if response['ret'] is False: -+ fail_usage("Couldn't get power information") -+ data = response['data'] -+ if data[u'PowerState'].strip() == "On": -+ return "on" -+ else: -+ return "off" -+ -+def set_power_status(conn, options): -+ action = { -+ 'on' : "On", -+ 'off': "ForceOff", -+ 'reboot': "GracefulRestart" -+ }[options["--action"]] -+ -+ payload = {'ResetType': action} -+ headers = {'content-type': 'application/json'} -+ -+ # Search for 'Actions' key and extract URI from it -+ uri = options["--systems-uri"] -+ response = send_get_request(options, uri) -+ if response['ret'] is False: -+ return {'ret': False} -+ data = response['data'] -+ uri = data["Actions"]["#ComputerSystem.Reset"]["target"] -+ -+ response = send_post_request(options, uri, payload, headers) -+ if response['ret'] is False: -+ fail_usage("Error sending power command") -+ return -+ -+def send_get_request(options, uri): -+ full_uri = "https://" + options["--ip"] + uri -+ try: -+ resp = requests.get(full_uri, verify=False, -+ auth=(options["--username"], options["--password"])) -+ data = resp.json() -+ except: -+ return {'ret': False} -+ return {'ret': True, 'data': data} -+ -+def send_post_request(options, uri, payload, headers): -+ full_uri = "https://" + options["--ip"] + uri -+ try: -+ requests.post(full_uri, data=json.dumps(payload), -+ headers=headers, verify=False, -+ auth=(options["--username"], options["--password"])) -+ except: -+ return {'ret': False} -+ return {'ret': True} -+ -+def find_systems_resource(options): -+ uri = options["--redfish-uri"] -+ response = send_get_request(options, uri) -+ if response['ret'] is False: -+ return {'ret': False} -+ data = response['data'] -+ -+ if 'Systems' not in data: -+ # Systems resource not found" -+ return {'ret': False} -+ else: -+ uri = data["Systems"]["@odata.id"] -+ response = send_get_request(options, uri) -+ if response['ret'] is False: -+ return {'ret': False} -+ data = response['data'] -+ -+ # need to be able to handle more than one entry -+ for member in data[u'Members']: -+ system_uri = member[u'@odata.id'] -+ return {'ret': True, 'uri': system_uri} -+ -+def define_new_opts(): -+ all_opt["redfish-uri"] = { -+ "getopt" : ":", -+ "longopt" : "redfish-uri", -+ "help" : "--redfish-uri=[uri] Base or starting Redifsh URI", -+ "required" : "0", -+ "default" : "/redfish/v1", -+ "shortdesc" : "Base or starting Redfish URI", -+ "order": 1 -+ } -+ all_opt["systems-uri"] = { -+ "getopt" : ":", -+ "longopt" : "systems-uri", -+ "help" : "--systems-uri=[uri] Redfish Systems resource URI", -+ "required" : "0", -+ "shortdesc" : "Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1", -+ "order": 1 -+ } -+ -+def main(): -+ atexit.register(atexit_handler) -+ device_opt = ["ipaddr", "login", "passwd", "redfish-uri", "systems-uri", "ssl"] -+ define_new_opts() -+ -+ opt = process_input(device_opt) -+ -+ all_opt["ipport"]["default"] = "443" -+ options = check_input(device_opt, opt) -+ -+ docs = {} -+ docs["shortdesc"] = "I/O Fencing agent for Redfish" -+ docs["longdesc"] = "fence_redfish is an I/O Fencing agent which can be used with \ -+Out-of-Band controllers that support Redfish APIs. These controllers provide remote \ -+access to control power on a server." -+ docs["vendorurl"] = "http://www.dmtf.org" -+ show_docs(options, docs) -+ -+ ## -+ ## Operate the fencing device -+ #### -+ -+ # Disable insecure-certificate-warning message -+ if "--ssl-insecure" in opt: -+ requests.packages.urllib3.disable_warnings(InsecureRequestWarning) -+ -+ if "--systems-uri" not in opt: -+ # Systems URI not provided, find it -+ sysresult = find_systems_resource(options) -+ if sysresult['ret'] is False: -+ sys.exit(1) -+ else: -+ options["--systems-uri"] = sysresult["uri"] -+ -+ result = fence_action(None, options, set_power_status, get_power_status, None) -+ sys.exit(result) -+ -+if __name__ == "__main__": -+ main() -diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml -new file mode 100644 -index 00000000..43d447d0 ---- /dev/null -+++ b/tests/data/metadata/fence_redfish.xml -@@ -0,0 +1,181 @@ -+ -+ -+fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server. -+http://www.dmtf.org -+ -+ -+ -+ -+ TCP/UDP port to use for connection with device -+ -+ -+ -+ -+ SSL connection with verifying fence device's certificate -+ -+ -+ -+ -+ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 -+ -+ -+ -+ -+ Fencing Action -+ -+ -+ -+ -+ Forces agent to use IPv6 addresses only -+ -+ -+ -+ -+ IP Address or Hostname -+ -+ -+ -+ -+ IP address or hostname of fencing device (together with --port-as-ip) -+ -+ -+ -+ -+ Script to retrieve password -+ -+ -+ -+ -+ Forces agent to use IPv4 addresses only -+ -+ -+ -+ -+ Login password or passphrase -+ -+ -+ -+ -+ SSL connection -+ -+ -+ -+ -+ Base or starting Redfish URI -+ -+ -+ -+ -+ SSL connection without verifying fence device's certificate -+ -+ -+ -+ -+ Login Name -+ -+ -+ -+ -+ IP address or hostname of fencing device (together with --port-as-ip) -+ -+ -+ -+ -+ Login Name -+ -+ -+ -+ -+ Base or starting Redfish URI -+ -+ -+ -+ -+ IP Address or Hostname -+ -+ -+ -+ -+ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 -+ -+ -+ -+ -+ Login password or passphrase -+ -+ -+ -+ -+ Script to retrieve password -+ -+ -+ -+ -+ Verbose mode -+ -+ -+ -+ -+ Write debug information to given file -+ -+ -+ -+ -+ Write debug information to given file -+ -+ -+ -+ -+ Display version information and exit -+ -+ -+ -+ -+ Display help and exit -+ -+ -+ -+ -+ Wait X seconds after issuing ON/OFF -+ -+ -+ -+ -+ Wait X seconds for cmd prompt after login -+ -+ -+ -+ -+ Test X seconds for status change after ON/OFF -+ -+ -+ -+ -+ Wait X seconds before fencing is started -+ -+ -+ -+ -+ Wait X seconds for cmd prompt after issuing command -+ -+ -+ -+ -+ Make "port/plug" to be an alias to IP address -+ -+ -+ -+ -+ Count of attempts to retry power on -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - -From 6921a34d64d098a7b1f32205e0be434438c36898 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Mon, 3 Dec 2018 10:46:52 -0600 -Subject: [PATCH 2/8] Updated fence_redfish.xml with make xml-upload - ---- - tests/data/metadata/fence_redfish.xml | 148 ++++++++++++++------------ - 1 file changed, 79 insertions(+), 69 deletions(-) - -diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml -index 43d447d0..a39541e6 100644 ---- a/tests/data/metadata/fence_redfish.xml -+++ b/tests/data/metadata/fence_redfish.xml -@@ -3,110 +3,115 @@ - fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server. - http://www.dmtf.org - -- -- -- -- TCP/UDP port to use for connection with device -- -- -- -- -- SSL connection with verifying fence device's certificate -- -- -- -- -- Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 -- - - - -- Fencing Action -+ Fencing action -+ -+ -+ -+ -+ Forces agent to use IPv4 addresses only - - - - - Forces agent to use IPv6 addresses only - -- -+ - - -- IP Address or Hostname -+ IP address or hostname of fencing device - -- -- -+ -+ - -- IP address or hostname of fencing device (together with --port-as-ip) -+ IP address or hostname of fencing device - -- -- -- -- Script to retrieve password -+ -+ -+ -+ TCP/UDP port to use for connection with device - -- -- -- -- Forces agent to use IPv4 addresses only -+ -+ -+ -+ Login name - - - - - Login password or passphrase - -- -- -- -- SSL connection -- -- -- -- -- Base or starting Redfish URI -+ -+ -+ -+ Script to run to retrieve password - -- -- -- -- SSL connection without verifying fence device's certificate -+ -+ -+ -+ Login password or passphrase - -- -- -+ -+ - -- Login Name -+ Script to run to retrieve password - - - - - IP address or hostname of fencing device (together with --port-as-ip) - -- -- -+ -+ - -- Login Name -+ IP address or hostname of fencing device (together with --port-as-ip) -+ -+ -+ -+ -+ Base or starting Redfish URI - - - - - Base or starting Redfish URI - -- -- -+ -+ -+ -+ Use SSL connection with verifying certificate -+ -+ -+ -+ -+ Use SSL connection without verifying certificate -+ -+ -+ -+ -+ Use SSL connection with verifying certificate -+ -+ -+ - -- IP Address or Hostname -+ Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 - - - - - Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1 - -- -- -+ -+ - -- Login password or passphrase -+ Login name - -- -- -- -- Script to retrieve password -+ -+ -+ -+ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. - - - -@@ -133,41 +138,45 @@ - - Display help and exit - -- -- -+ -+ - -- Wait X seconds after issuing ON/OFF -+ Wait X seconds before fencing is started - - - - - Wait X seconds for cmd prompt after login - -+ -+ -+ -+ Make "port/plug" to be an alias to IP address -+ - - - - Test X seconds for status change after ON/OFF - -- -- -+ -+ - -- Wait X seconds before fencing is started -+ Wait X seconds after issuing ON/OFF - - - - - Wait X seconds for cmd prompt after issuing command - -- -- -- -- Make "port/plug" to be an alias to IP address -- - - - - Count of attempts to retry power on - -+ -+ -+ Path to gnutls-cli binary -+ - - - -@@ -176,6 +185,7 @@ - - - -+ - - - - -From 755627fadd711848ea256d72f5e75f36f83b4d31 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Mon, 3 Dec 2018 11:55:23 -0600 -Subject: [PATCH 3/8] Added run_delay() - ---- - agents/redfish/fence_redfish.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index df7cf8c2..0e4a4f68 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -13,7 +13,7 @@ - - from requests.packages.urllib3.exceptions import InsecureRequestWarning - from fencing import * --from fencing import fail_usage -+from fencing import fail_usage, run_delay - - def get_power_status(conn, options): - uri = options["--systems-uri"] -@@ -127,6 +127,7 @@ def main(): - access to control power on a server." - docs["vendorurl"] = "http://www.dmtf.org" - show_docs(options, docs) -+ run_delay(options) - - ## - ## Operate the fencing device - -From 15fef4c47f391a3f03c714d86c9670ea209dec99 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Tue, 4 Dec 2018 10:56:58 -0600 -Subject: [PATCH 4/8] Modify power status check - -- Only returns off if PowerState = Off -- Otherwise returns on ---- - agents/redfish/fence_redfish.py | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 0e4a4f68..7998fb1c 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -21,10 +21,10 @@ def get_power_status(conn, options): - if response['ret'] is False: - fail_usage("Couldn't get power information") - data = response['data'] -- if data[u'PowerState'].strip() == "On": -- return "on" -- else: -+ if data[u'PowerState'].strip() == "Off": - return "off" -+ else: -+ return "on" - - def set_power_status(conn, options): - action = { - -From acf70f4672be65562841227ab0b4cacb87965f44 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Wed, 5 Dec 2018 10:39:32 -0600 -Subject: [PATCH 5/8] Changed reboot type to ForceRestart - ---- - agents/redfish/fence_redfish.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 7998fb1c..3fe2bfc0 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -30,7 +30,7 @@ def set_power_status(conn, options): - action = { - 'on' : "On", - 'off': "ForceOff", -- 'reboot': "GracefulRestart" -+ 'reboot': "ForceRestart" - }[options["--action"]] - - payload = {'ResetType': action} - -From 56e3358d45050ac669c099c56873feefa1ecda38 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Wed, 5 Dec 2018 10:54:44 -0600 -Subject: [PATCH 6/8] Replaced default port 443 with default ssl enabled option - ---- - agents/redfish/fence_redfish.py | 2 +- - tests/data/metadata/fence_redfish.xml | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 3fe2bfc0..6a2dbb76 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -117,7 +117,7 @@ def main(): - - opt = process_input(device_opt) - -- all_opt["ipport"]["default"] = "443" -+ all_opt["ssl"]["default"] = "1" - options = check_input(device_opt, opt) - - docs = {} -diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml -index a39541e6..e1c18584 100644 ---- a/tests/data/metadata/fence_redfish.xml -+++ b/tests/data/metadata/fence_redfish.xml -@@ -80,7 +80,7 @@ - - - -- -+ - Use SSL connection with verifying certificate - - - -From 5c25a85b22a17d6bbc3dcb47c99b76e3a99a5857 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Wed, 5 Dec 2018 13:29:42 -0600 -Subject: [PATCH 7/8] Renamed variable to avoid reusing variable name - ---- - agents/redfish/fence_redfish.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 6a2dbb76..1ea25cd8 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -42,9 +42,9 @@ def set_power_status(conn, options): - if response['ret'] is False: - return {'ret': False} - data = response['data'] -- uri = data["Actions"]["#ComputerSystem.Reset"]["target"] -+ action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"] - -- response = send_post_request(options, uri, payload, headers) -+ response = send_post_request(options, action_uri, payload, headers) - if response['ret'] is False: - fail_usage("Error sending power command") - return - -From 7dce8b1e22d57fec0d34e91a99fab9d8a06f1303 Mon Sep 17 00:00:00 2001 -From: Jose Delarosa -Date: Thu, 6 Dec 2018 10:33:06 -0600 -Subject: [PATCH 8/8] Removed unnecessary variable assignments to simplify code - ---- - agents/redfish/fence_redfish.py | 12 ++++-------- - 1 file changed, 4 insertions(+), 8 deletions(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 1ea25cd8..67ef67ab 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -16,8 +16,7 @@ - from fencing import fail_usage, run_delay - - def get_power_status(conn, options): -- uri = options["--systems-uri"] -- response = send_get_request(options, uri) -+ response = send_get_request(options, options["--systems-uri"]) - if response['ret'] is False: - fail_usage("Couldn't get power information") - data = response['data'] -@@ -37,8 +36,7 @@ def set_power_status(conn, options): - headers = {'content-type': 'application/json'} - - # Search for 'Actions' key and extract URI from it -- uri = options["--systems-uri"] -- response = send_get_request(options, uri) -+ response = send_get_request(options, options["--systems-uri"]) - if response['ret'] is False: - return {'ret': False} - data = response['data'] -@@ -70,8 +68,7 @@ def send_post_request(options, uri, payload, headers): - return {'ret': True} - - def find_systems_resource(options): -- uri = options["--redfish-uri"] -- response = send_get_request(options, uri) -+ response = send_get_request(options, options["--redfish-uri"]) - if response['ret'] is False: - return {'ret': False} - data = response['data'] -@@ -80,8 +77,7 @@ def find_systems_resource(options): - # Systems resource not found" - return {'ret': False} - else: -- uri = data["Systems"]["@odata.id"] -- response = send_get_request(options, uri) -+ response = send_get_request(options, data["Systems"]["@odata.id"]) - if response['ret'] is False: - return {'ret': False} - data = response['data'] diff --git a/SOURCES/bz1666848-2-fence_redfish-fail-invalid-cert.patch b/SOURCES/bz1666848-2-fence_redfish-fail-invalid-cert.patch deleted file mode 100644 index a834644..0000000 --- a/SOURCES/bz1666848-2-fence_redfish-fail-invalid-cert.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 7aa3c50d1d02dd26bdeac99c49ada72f842d88e8 Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Thu, 17 Jan 2019 16:52:52 +0100 -Subject: [PATCH] fence_redfish: fail when using invalid cert without - --ssl-insecure - ---- - agents/redfish/fence_redfish.py | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py -index 67ef67ab..5b719d4b 100644 ---- a/agents/redfish/fence_redfish.py -+++ b/agents/redfish/fence_redfish.py -@@ -6,6 +6,7 @@ - - import sys - import re -+import logging - import json - import requests - import atexit -@@ -20,6 +21,9 @@ def get_power_status(conn, options): - if response['ret'] is False: - fail_usage("Couldn't get power information") - data = response['data'] -+ -+ logging.debug("PowerState is: " + data[u'PowerState']) -+ - if data[u'PowerState'].strip() == "Off": - return "off" - else: -@@ -50,21 +54,21 @@ def set_power_status(conn, options): - def send_get_request(options, uri): - full_uri = "https://" + options["--ip"] + uri - try: -- resp = requests.get(full_uri, verify=False, -+ resp = requests.get(full_uri, verify=not "--ssl-insecure" in options, - auth=(options["--username"], options["--password"])) - data = resp.json() -- except: -- return {'ret': False} -+ except Exception as e: -+ fail_usage("Failed: send_get_request: " + str(e)) - return {'ret': True, 'data': data} - - def send_post_request(options, uri, payload, headers): - full_uri = "https://" + options["--ip"] + uri - try: - requests.post(full_uri, data=json.dumps(payload), -- headers=headers, verify=False, -+ headers=headers, verify=not "--ssl-insecure" in options, - auth=(options["--username"], options["--password"])) -- except: -- return {'ret': False} -+ except Exception as e: -+ fail_usage("Failed: send_post_request: " + str(e)) - return {'ret': True} - - def find_systems_resource(options): diff --git a/SOURCES/bz1670460-fence_rhevm-1-use-UTF8-encoding.patch b/SOURCES/bz1670460-fence_rhevm-1-use-UTF8-encoding.patch new file mode 100644 index 0000000..281e006 --- /dev/null +++ b/SOURCES/bz1670460-fence_rhevm-1-use-UTF8-encoding.patch @@ -0,0 +1,32 @@ +From a77165d7c8caadf514462d359c6d564048c2c33a Mon Sep 17 00:00:00 2001 +From: Sandro <42254081+Numblesix@users.noreply.github.com> +Date: Tue, 29 Jan 2019 13:29:52 +0100 +Subject: [PATCH] Changed Encoding to UTF-8 + +Starting from RHV/Ovirt 4.2 we saw issues with the agent(unable to fence) after switching to UTF-8 all worked again. +--- + agents/rhevm/fence_rhevm.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index 2a5107cc6..a1cdaf605 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -88,7 +88,7 @@ def send_command(opt, command, method="GET"): + ## send command through pycurl + conn = pycurl.Curl() + web_buffer = io.BytesIO() +- conn.setopt(pycurl.URL, url.encode("ascii")) ++ conn.setopt(pycurl.URL, url.encode("UTF-8")) + conn.setopt(pycurl.HTTPHEADER, [ + "Version: 3", + "Content-type: application/xml", +@@ -128,7 +128,7 @@ def send_command(opt, command, method="GET"): + + opt["cookie"] = cookie + +- result = web_buffer.getvalue().decode() ++ result = web_buffer.getvalue().decode("UTF-8") + + logging.debug("%s\n", command) + logging.debug("%s\n", result) diff --git a/SOURCES/bz1670460-fence_rhevm-2-fix-debug-encoding-issues.patch b/SOURCES/bz1670460-fence_rhevm-2-fix-debug-encoding-issues.patch new file mode 100644 index 0000000..9603498 --- /dev/null +++ b/SOURCES/bz1670460-fence_rhevm-2-fix-debug-encoding-issues.patch @@ -0,0 +1,31 @@ +From 965924fe8bf7dcd0bc15fb0e9265ab49bb8a5dd8 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 20 May 2019 15:49:39 +0200 +Subject: [PATCH] fence_rhevm: fix debug encoding issues + +Tested with UTF-8 encoded comment in result, which caused this issue, +and added to command and url in case they are in UTF-8 decoded state. +--- + agents/rhevm/fence_rhevm.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index 6012c423..9e4650cd 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -144,9 +144,9 @@ def send_command(opt, command, method="GET"): + + result = web_buffer.getvalue().decode("UTF-8") + +- logging.debug("url: %s\n", url) +- logging.debug("command: %s\n", command) +- logging.debug("result: %s\n", result) ++ logging.debug("url: %s\n", url.encode("UTF-8")) ++ logging.debug("command: %s\n", command.encode("UTF-8")) ++ logging.debug("result: %s\n", result.encode("UTF-8")) + + return result + +-- +2.21.0 + diff --git a/SOURCES/bz1677023-1-fence_redfish-use-ipport-parameter.patch b/SOURCES/bz1677023-1-fence_redfish-use-ipport-parameter.patch new file mode 100644 index 0000000..e2514f1 --- /dev/null +++ b/SOURCES/bz1677023-1-fence_redfish-use-ipport-parameter.patch @@ -0,0 +1,43 @@ +From 9ebd2e2e36ae0de5c9164f4ac3fd29bdac0cab61 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 14 Feb 2019 10:03:33 +0100 +Subject: [PATCH] fence_redfish: use "ipport" parameter and improve logging + +--- + agents/redfish/fence_redfish.py | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 5b719d4b..28840058 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -22,7 +22,10 @@ def get_power_status(conn, options): + fail_usage("Couldn't get power information") + data = response['data'] + +- logging.debug("PowerState is: " + data[u'PowerState']) ++ try: ++ logging.debug("PowerState is: " + data[u'PowerState']) ++ except Exception: ++ fail_usage("Unable to get PowerState: " + "https://" + options["--ip"] + ":" + str(options["--ipport"]) + options["--systems-uri"]) + + if data[u'PowerState'].strip() == "Off": + return "off" +@@ -52,7 +55,7 @@ def set_power_status(conn, options): + return + + def send_get_request(options, uri): +- full_uri = "https://" + options["--ip"] + uri ++ full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + resp = requests.get(full_uri, verify=not "--ssl-insecure" in options, + auth=(options["--username"], options["--password"])) +@@ -62,7 +65,7 @@ def send_get_request(options, uri): + return {'ret': True, 'data': data} + + def send_post_request(options, uri, payload, headers): +- full_uri = "https://" + options["--ip"] + uri ++ full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + requests.post(full_uri, data=json.dumps(payload), + headers=headers, verify=not "--ssl-insecure" in options, diff --git a/SOURCES/bz1677023-2-fence_redfish-ip-parameter-backward-compatibility.patch b/SOURCES/bz1677023-2-fence_redfish-ip-parameter-backward-compatibility.patch new file mode 100644 index 0000000..3d97c4e --- /dev/null +++ b/SOURCES/bz1677023-2-fence_redfish-ip-parameter-backward-compatibility.patch @@ -0,0 +1,24 @@ +From 21898e45ca2624546de99086a27a14dd1ff86a2b Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 21 Feb 2019 09:08:03 +0100 +Subject: [PATCH] fence_redfish: backwards compatibility for : + +--- + agents/redfish/fence_redfish.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 28840058..f1424232 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -140,6 +140,10 @@ def main(): + if "--ssl-insecure" in opt: + requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + ++ # backwards compatibility for : ++ if options["--ip"].count(":") == 1: ++ (options["--ip"], options["--ipport"]) = options["--ip"].split(":") ++ + if "--systems-uri" not in opt: + # Systems URI not provided, find it + sysresult = find_systems_resource(options) diff --git a/SOURCES/bz1700544-fence_azure_arm-skip_shutdown.patch b/SOURCES/bz1700544-fence_azure_arm-skip_shutdown.patch new file mode 100644 index 0000000..708eb84 --- /dev/null +++ b/SOURCES/bz1700544-fence_azure_arm-skip_shutdown.patch @@ -0,0 +1,48 @@ +From 1b3e548fcc0bd427dade178fa260567047ff3a0e Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 6 May 2019 13:24:18 +0200 +Subject: [PATCH] fence_azure_arm: use skip_shutdown feature when available + +The "skip_shutdown" parameter is ignored in older Azure SDK, so there's +no need for a fallback option. +--- + agents/azure_arm/fence_azure_arm.py | 6 +++--- + tests/data/metadata/fence_azure_arm.xml | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py +index 58b9eeb13..be0d40345 100755 +--- a/agents/azure_arm/fence_azure_arm.py ++++ b/agents/azure_arm/fence_azure_arm.py +@@ -114,8 +114,8 @@ def set_power_status(clients, options): + azure_fence.set_network_state(compute_client, network_client, rgName, vmName, "unblock") + + if (options["--action"]=="off"): +- logging.info("Deallocating " + vmName + " in resource group " + rgName) +- compute_client.virtual_machines.deallocate(rgName, vmName) ++ logging.info("Poweroff " + vmName + " in resource group " + rgName) ++ compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=True) + elif (options["--action"]=="on"): + logging.info("Starting " + vmName + " in resource group " + rgName) + compute_client.virtual_machines.start(rgName, vmName) +@@ -199,7 +199,7 @@ def main(): + + docs = {} + docs["shortdesc"] = "Fence agent for Azure Resource Manager" +- docs["longdesc"] = "Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure.\ ++ docs["longdesc"] = "fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure.\ + \n.P\n\ + For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal\ + \n.P\n\ +diff --git a/tests/data/metadata/fence_azure_arm.xml b/tests/data/metadata/fence_azure_arm.xml +index 1c0b6cc6b..97ecfdba4 100644 +--- a/tests/data/metadata/fence_azure_arm.xml ++++ b/tests/data/metadata/fence_azure_arm.xml +@@ -1,6 +1,6 @@ + + +-Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure. ++fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure. + + For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal + diff --git a/SOURCES/bz1708547-fence_rhevm-RHEV-v4-API-support.patch b/SOURCES/bz1708547-fence_rhevm-RHEV-v4-API-support.patch deleted file mode 100644 index 6f115e8..0000000 --- a/SOURCES/bz1708547-fence_rhevm-RHEV-v4-API-support.patch +++ /dev/null @@ -1,164 +0,0 @@ -From a4e8b77ac51a0e4a6de489823ee1be47cbc7eb18 Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Thu, 9 May 2019 12:09:48 +0200 -Subject: [PATCH] fence_rhevm: add RHEV v4 API support and auto-detection - ---- - agents/rhevm/fence_rhevm.py | 44 +++++++++++++++++++++++------ - tests/data/metadata/fence_rhevm.xml | 7 ++++- - 2 files changed, 41 insertions(+), 10 deletions(-) - -diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py -index a1cdaf605..6012c4239 100644 ---- a/agents/rhevm/fence_rhevm.py -+++ b/agents/rhevm/fence_rhevm.py -@@ -9,7 +9,8 @@ - from fencing import fail, EC_FETCH_VM_UUID, run_delay - - RE_GET_ID = re.compile("(.*?)", re.IGNORECASE) -+RE_STATUS = re.compile("(.*?)", re.IGNORECASE) -+RE_STATE = re.compile("(.*?)", re.IGNORECASE) - RE_GET_NAME = re.compile("(.*?)", re.IGNORECASE) - - def get_power_status(conn, options): -@@ -25,7 +26,10 @@ def get_power_status(conn, options): - - options["id"] = result.group(2) - -- result = RE_STATUS.search(res) -+ if tuple(map(int, options["--api-version"].split(".")))[0] > 3: -+ result = RE_STATUS.search(res) -+ else: -+ result = RE_STATE.search(res) - 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 -@@ -59,7 +63,10 @@ def get_list(conn, options): - lines = res.split(" 3: -+ status = RE_STATUS.search(lines[i]).group(1) -+ else: -+ status = RE_STATE.search(lines[i]).group(1) - outlets[name] = ("", status) - except AttributeError: - return {} -@@ -69,6 +76,13 @@ def get_list(conn, options): - return outlets - - def send_command(opt, command, method="GET"): -+ if opt["--api-version"] == "auto": -+ opt["--api-version"] = "4" -+ res = send_command(opt, "") -+ if re.search("Error", res): -+ opt["--api-version"] = "3" -+ logging.debug("auto-detected API version: " + opt["--api-version"]) -+ - ## setup correct URL - if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt: - url = "https:" -@@ -90,7 +104,7 @@ def send_command(opt, command, method="GET"): - web_buffer = io.BytesIO() - conn.setopt(pycurl.URL, url.encode("UTF-8")) - conn.setopt(pycurl.HTTPHEADER, [ -- "Version: 3", -+ "Version: {}".format(opt["--api-version"]), - "Content-type: application/xml", - "Accept: application/xml", - "Prefer: persistent-auth", -@@ -130,8 +144,9 @@ def send_command(opt, command, method="GET"): - - result = web_buffer.getvalue().decode("UTF-8") - -- logging.debug("%s\n", command) -- logging.debug("%s\n", result) -+ logging.debug("url: %s\n", url) -+ logging.debug("command: %s\n", command) -+ logging.debug("result: %s\n", result) - - return result - -@@ -151,6 +166,15 @@ def define_new_opts(): - "required" : "0", - "shortdesc" : "Reuse cookies for authentication", - "order" : 1} -+ all_opt["api_version"] = { -+ "getopt" : ":", -+ "longopt" : "api-version", -+ "help" : "--api-version " -+ "Version of RHEV API (default: auto)", -+ "required" : "0", -+ "order" : 2, -+ "default" : "auto", -+ } - all_opt["api_path"] = { - "getopt" : ":", - "longopt" : "api-path", -@@ -158,20 +182,19 @@ def define_new_opts(): - "default" : "/ovirt-engine/api", - "required" : "0", - "shortdesc" : "The path part of the API URL", -- "order" : 2} -+ "order" : 3} - all_opt["disable_http_filter"] = { - "getopt" : "", - "longopt" : "disable-http-filter", - "help" : "--disable-http-filter Set HTTP Filter header to false", - "required" : "0", - "shortdesc" : "Set HTTP Filter header to false", -- "order" : 3} -+ "order" : 4} - - - def main(): - device_opt = [ - "ipaddr", -- "api_path", - "login", - "passwd", - "ssl", -@@ -179,6 +202,8 @@ def main(): - "web", - "port", - "use_cookies", -+ "api_version", -+ "api_path", - "disable_http_filter", - ] - -@@ -186,6 +211,7 @@ def main(): - define_new_opts() - - all_opt["power_wait"]["default"] = "1" -+ all_opt["shell_timeout"]["default"] = "5" - - options = check_input(device_opt, process_input(device_opt)) - -diff --git a/tests/data/metadata/fence_rhevm.xml b/tests/data/metadata/fence_rhevm.xml -index 6344db79f..c56cf64b6 100644 ---- a/tests/data/metadata/fence_rhevm.xml -+++ b/tests/data/metadata/fence_rhevm.xml -@@ -98,6 +98,11 @@ - - Login name - -+ -+ -+ -+ Version of RHEV API (default: auto) -+ - - - The path part of the API URL -@@ -164,7 +169,7 @@ - - - -- -+ - Wait X seconds for cmd prompt after issuing command - - diff --git a/SOURCES/bz1709110-fence_azure_arm-skip_shutdown.patch b/SOURCES/bz1709110-fence_azure_arm-skip_shutdown.patch deleted file mode 100644 index 708eb84..0000000 --- a/SOURCES/bz1709110-fence_azure_arm-skip_shutdown.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 1b3e548fcc0bd427dade178fa260567047ff3a0e Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Mon, 6 May 2019 13:24:18 +0200 -Subject: [PATCH] fence_azure_arm: use skip_shutdown feature when available - -The "skip_shutdown" parameter is ignored in older Azure SDK, so there's -no need for a fallback option. ---- - agents/azure_arm/fence_azure_arm.py | 6 +++--- - tests/data/metadata/fence_azure_arm.xml | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py -index 58b9eeb13..be0d40345 100755 ---- a/agents/azure_arm/fence_azure_arm.py -+++ b/agents/azure_arm/fence_azure_arm.py -@@ -114,8 +114,8 @@ def set_power_status(clients, options): - azure_fence.set_network_state(compute_client, network_client, rgName, vmName, "unblock") - - if (options["--action"]=="off"): -- logging.info("Deallocating " + vmName + " in resource group " + rgName) -- compute_client.virtual_machines.deallocate(rgName, vmName) -+ logging.info("Poweroff " + vmName + " in resource group " + rgName) -+ compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=True) - elif (options["--action"]=="on"): - logging.info("Starting " + vmName + " in resource group " + rgName) - compute_client.virtual_machines.start(rgName, vmName) -@@ -199,7 +199,7 @@ def main(): - - docs = {} - docs["shortdesc"] = "Fence agent for Azure Resource Manager" -- docs["longdesc"] = "Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure.\ -+ docs["longdesc"] = "fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure.\ - \n.P\n\ - For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal\ - \n.P\n\ -diff --git a/tests/data/metadata/fence_azure_arm.xml b/tests/data/metadata/fence_azure_arm.xml -index 1c0b6cc6b..97ecfdba4 100644 ---- a/tests/data/metadata/fence_azure_arm.xml -+++ b/tests/data/metadata/fence_azure_arm.xml -@@ -1,6 +1,6 @@ - - --Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure. -+fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure. - - For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal - diff --git a/SOURCES/bz1709879-fence_mpath-fix-watchdog-hardreboot.patch b/SOURCES/bz1709879-fence_mpath-fix-watchdog-hardreboot.patch new file mode 100644 index 0000000..2b187c2 --- /dev/null +++ b/SOURCES/bz1709879-fence_mpath-fix-watchdog-hardreboot.patch @@ -0,0 +1,21 @@ +From e5c6c2e134fd397ffe3319adc7afb8b633a251b2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 14 May 2019 16:44:59 +0200 +Subject: [PATCH] fence_mpath: import ctypes to fix watchdog hardreboot + +--- + agents/mpath/fence_mpath.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index d9ac2ef54..e4f598361 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -6,6 +6,7 @@ + import os + import logging + import atexit ++import ctypes + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs + from fencing import fence_action, all_opt, run_delay diff --git a/SOURCES/bz1713665-fence_redfish-full-redfish-spec-compliance.patch b/SOURCES/bz1713665-fence_redfish-full-redfish-spec-compliance.patch new file mode 100644 index 0000000..3b8ba13 --- /dev/null +++ b/SOURCES/bz1713665-fence_redfish-full-redfish-spec-compliance.patch @@ -0,0 +1,65 @@ +From 75a74debba2205547d8eefae221221c2c71d99ce Mon Sep 17 00:00:00 2001 +From: Jose Delarosa +Date: Mon, 15 Apr 2019 12:46:42 -0500 +Subject: [PATCH] fence_redfish: add headers to HTTP methods + +* Needed for full compliance with Redfish spec. +* May cause errors in some devices if not sent. +--- + agents/redfish/fence_redfish.py | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index f1424232..390a4827 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -16,6 +16,11 @@ + from fencing import * + from fencing import fail_usage, run_delay + ++GET_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'} ++POST_HEADERS = {'content-type': 'application/json', 'accept': 'application/json', ++ 'OData-Version': '4.0'} ++ ++ + def get_power_status(conn, options): + response = send_get_request(options, options["--systems-uri"]) + if response['ret'] is False: +@@ -40,7 +45,6 @@ def set_power_status(conn, options): + }[options["--action"]] + + payload = {'ResetType': action} +- headers = {'content-type': 'application/json'} + + # Search for 'Actions' key and extract URI from it + response = send_get_request(options, options["--systems-uri"]) +@@ -49,7 +53,7 @@ def set_power_status(conn, options): + data = response['data'] + action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"] + +- response = send_post_request(options, action_uri, payload, headers) ++ response = send_post_request(options, action_uri, payload) + if response['ret'] is False: + fail_usage("Error sending power command") + return +@@ -58,17 +62,18 @@ def send_get_request(options, uri): + full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + resp = requests.get(full_uri, verify=not "--ssl-insecure" in options, ++ headers=GET_HEADERS, + auth=(options["--username"], options["--password"])) + data = resp.json() + except Exception as e: + fail_usage("Failed: send_get_request: " + str(e)) + return {'ret': True, 'data': data} + +-def send_post_request(options, uri, payload, headers): ++def send_post_request(options, uri, payload): + full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri + try: + requests.post(full_uri, data=json.dumps(payload), +- headers=headers, verify=not "--ssl-insecure" in options, ++ headers=POST_HEADERS, verify=not "--ssl-insecure" in options, + auth=(options["--username"], options["--password"])) + except Exception as e: + fail_usage("Failed: send_post_request: " + str(e)) diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index 2879b4c..346ffe1 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -66,7 +66,7 @@ Name: fence-agents Summary: Fence Agents for Red Hat Cluster Version: 4.2.1 -Release: 11%{?alphatag:.%{alphatag}}%{?dist}.8 +Release: 24%{?alphatag:.%{alphatag}}%{?dist} License: GPLv2+ and LGPLv2+ Group: System Environment/Base URL: https://github.com/ClusterLabs/fence-agents @@ -99,14 +99,23 @@ Patch13: bz1236395-3-fix-version.patch Patch14: bz1622229-1-fence_aliyun-list-instance-names.patch Patch15: bz1622229-2-fence_aliyun-correct-help-indentation.patch Patch16: bz1625164-fence_cisco_ucs-encode-POSTFIELDS.patch -Patch17: bz1647522-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch -Patch18: bz1654172-1-fence_scsi-watchdog-retry-support.patch -Patch19: bz1654172-2-build-fix-check_used_options.patch -Patch20: bz1652115-fence_hpblade-fix-log_expect-syntax.patch -Patch21: bz1666848-1-fence_redfish.patch -Patch22: bz1666848-2-fence_redfish-fail-invalid-cert.patch -Patch23: bz1708547-fence_rhevm-RHEV-v4-API-support.patch -Patch24: bz1709110-fence_azure_arm-skip_shutdown.patch +Patch17: bz1645170-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch +Patch18: bz1653700-1-fence_scsi-watchdog-retry-support.patch +Patch19: bz1653700-2-build-fix-check_used_options.patch +Patch20: bz1650526-fence_hpblade-fix-log_expect_syntax.patch +Patch21: bz1350908-fence_vmware_soap-cleanup-sigterm.patch +Patch22: bz1464933-1-fence_redfish.patch +Patch23: bz1464933-2-fence_redfish-fail-invalid-cert.patch +Patch24: bz1608550-fence_dump-validate-all.patch +Patch25: bz1677023-1-fence_redfish-use-ipport-parameter.patch +Patch26: bz1677023-2-fence_redfish-ip-parameter-backward-compatibility.patch +Patch27: bz1670460-fence_rhevm-1-use-UTF8-encoding.patch +Patch28: bz1402862-fence_rhevm-RHEV-v4-API-support.patch +Patch29: bz1700544-fence_azure_arm-skip_shutdown.patch +Patch30: bz1670460-fence_rhevm-2-fix-debug-encoding-issues.patch +Patch31: bz1709879-fence_mpath-fix-watchdog-hardreboot.patch +Patch32: bz1713665-fence_redfish-full-redfish-spec-compliance.patch +Patch33: bz1653700-3-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch # bundle patches Patch1000: bz1568753-4-fence_gce-bundled-libs.patch Patch1001: bz1568753-5-%{oauth2client}-docs-build-fix.patch @@ -179,8 +188,17 @@ BuildRequires: python-six >= 1.6.1 %patch20 -p1 %patch21 -p1 %patch22 -p1 -%patch23 -p1 -F2 +%patch23 -p1 %patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 -F1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 -F1 %ifarch x86_64 # bundles @@ -930,7 +948,7 @@ Requires: fence-agents-common >= %{version}-%{release} Requires: device-mapper-multipath Obsoletes: fence-agents %description mpath -The fence-agents-mpath package contains fence agent for SCSI persisent reservation over Device Mapper Multipath +The fence-agents-mpath package contains fence agent for SCSI persistent reservation over Device Mapper Multipath %files mpath %defattr(-,root,root,-) %{_sbindir}/fence_mpath @@ -1055,11 +1073,11 @@ The fence-agents-sbd package contains fence agent for SBD (storage-based death) %package scsi License: GPLv2+ and LGPLv2+ Group: System Environment/Base -Summary: Fence agent for SCSI persisent reservations +Summary: Fence agent for SCSI persistent reservations Requires: sg3_utils fence-agents-common >= %{version}-%{release} Obsoletes: fence-agents %description scsi -The fence-agents-scsi package contains fence agent for SCSI persisent reservations +The fence-agents-scsi package contains fence agent for SCSI persistent reservations %files scsi %defattr(-,root,root,-) %{_sbindir}/fence_scsi @@ -1142,27 +1160,51 @@ The fence-agents-zvm package contains a fence agent for z/VM hypervisors %endif %changelog -* Thu May 16 2019 Oyvind Albrigtsen - 4.2.1-11.8 +* Thu Jun 13 2019 Oyvind Albrigtsen - 4.2.1-24 +- fence_scsi watchdog: fix failing on first try when using retry + Resolves: rhbz#1653700 + +* Tue May 28 2019 Oyvind Albrigtsen - 4.2.1-22 +- fence_redfish: add header for full Redfish spec compliance + Resolves: rhbz#1713665 + +* Tue May 21 2019 Oyvind Albrigtsen - 4.2.1-21 +- fence_rhevm: fix encoding issues + Resolves: rhbz#1670460 + +* Mon May 20 2019 Oyvind Albrigtsen - 4.2.1-20 +- fence_mpath: fix watchdog hardreboot + Resolves: rhbz#1709879 + +* Tue May 14 2019 Oyvind Albrigtsen - 4.2.1-18 - fence_rhevm: add RHEV v4 API support and auto-detection - Resolves: rhbz#1708547 + Resolves: rhbz#1402862 - fence_azure_arm: use skip_shutdown feature - Resolves: rhbz#1709110 + Resolves: rhbz#1700544 + +* Thu Feb 21 2019 Oyvind Albrigtsen - 4.2.1-16 +- fence_redfish: use ipport parameter + Resolves: rhbz#1677023 -* Thu Jan 17 2019 Oyvind Albrigtsen - 4.2.1-11.7 +* Tue Feb 5 2019 Oyvind Albrigtsen - 4.2.1-15 +- fence_dump: add validate-all action + Resolves: rhbz#1608550 + +* Fri Jan 18 2019 Oyvind Albrigtsen - 4.2.1-14 - fence_redfish: new fence agent - Resolves: rhbz#1666848 + Resolves: rhbz#1464933, rhbz#1631492 -* Thu Dec 6 2018 Oyvind Albrigtsen - 4.2.1-11.5 +* Tue Jan 8 2019 Oyvind Albrigtsen - 4.2.1-13 - fence_scsi: add watchdog retry support - Resolves: rhbz#1654172 - -* Wed Nov 28 2018 Oyvind Albrigtsen - 4.2.1-11.4 -- fence_hpblade: fix log_expect syntax - Resolves: rhbz#1652115 + Resolves: rhbz#1653700 -* Thu Nov 8 2018 Oyvind Albrigtsen - 4.2.1-11.1 +* Thu Nov 29 2018 Oyvind Albrigtsen - 4.2.1-12 - fence_scsi: fix incorrect SCSI-key when node ID is 10 or higher - Resolves: rhbz#1647522 + Resolves: rhbz#1645170 +- fence_hpblade: fix log_expect syntax + Resolves: rhbz#1650526 +- fence_vmware_soap: cleanup when receiving SIGTERM + Resolves: rhbz#1350908 * Tue Sep 4 2018 Oyvind Albrigtsen - 4.2.1-11 - fence_cisco_ucs: fix missing encode for POSTFIELDS