diff --git a/SOURCES/bz1750596-fence_scsi-add-readonly-parameter.patch b/SOURCES/bz1750596-fence_scsi-add-readonly-parameter.patch new file mode 100644 index 0000000..dea7876 --- /dev/null +++ b/SOURCES/bz1750596-fence_scsi-add-readonly-parameter.patch @@ -0,0 +1,79 @@ +From f1f8fe7791d0bf439f7caf1365c371153f9819ff Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 14 May 2020 15:41:52 +0200 +Subject: [PATCH] fence_scsi: add readonly parameter + +--- + agents/scsi/fence_scsi.py | 21 ++++++++++++++++++--- + tests/data/metadata/fence_scsi.xml | 5 +++++ + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 9b6af556..77817f35 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -150,7 +150,10 @@ def reserve_dev(options, dev): + + def get_reservation_key(options, dev): + reset_dev(options,dev) +- cmd = options["--sg_persist-path"] + " -n -i -r -d " + dev ++ opts = "" ++ if "--readonly" in options: ++ opts = "-y " ++ cmd = options["--sg_persist-path"] + " -n -i " + opts + "-r -d " + dev + out = run_cmd(options, cmd) + if out["err"]: + fail_usage("Cannot get reservation key") +@@ -161,7 +164,10 @@ def get_reservation_key(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 ++ opts = "" ++ if "--readonly" in options: ++ opts = "-y " ++ cmd = options["--sg_persist-path"] + " -n -i " + opts + "-k -d " + dev + out = run_cmd(options, cmd) + if out["err"]: + fail_usage("Cannot get registration keys", fail) +@@ -342,6 +348,14 @@ def define_new_opts(): + "shortdesc" : "Use the APTPL flag for registrations. This option is only used for the 'on' action.", + "order": 1 + } ++ all_opt["readonly"] = { ++ "getopt" : "", ++ "longopt" : "readonly", ++ "help" : "--readonly Open DEVICE read-only. May be useful with PRIN commands if there are unwanted side effects with the default read-write open.", ++ "required" : "0", ++ "shortdesc" : "Open DEVICE read-only.", ++ "order": 4 ++ } + all_opt["logfile"] = { + "getopt" : ":", + "longopt" : "logfile", +@@ -464,7 +478,8 @@ def main(): + + device_opt = ["no_login", "no_password", "devices", "nodename", "port",\ + "no_port", "key", "aptpl", "fabric_fencing", "on_target", "corosync_cmap_path",\ +- "sg_persist_path", "sg_turs_path", "logfile", "vgs_path", "force_on", "key_value"] ++ "sg_persist_path", "sg_turs_path", "readonly", "logfile", "vgs_path",\ ++ "force_on", "key_value"] + + define_new_opts() + +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index b840f3cf..d0818b0d 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -36,6 +36,11 @@ When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and ve + + Name of the node to be fenced. The node name is used to generate the key value used for the current operation. This option will be ignored when used with the -k option. + ++ ++ ++ ++ Open DEVICE read-only. ++ + + + diff --git a/SOURCES/bz1793739-fence_vmware_rest-1-fix-encoding.patch b/SOURCES/bz1793739-fence_vmware_rest-1-fix-encoding.patch new file mode 100644 index 0000000..c215ab1 --- /dev/null +++ b/SOURCES/bz1793739-fence_vmware_rest-1-fix-encoding.patch @@ -0,0 +1,23 @@ +From 06cba4aa30322f410b0b2fec5785be39d0953433 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 12 Feb 2020 14:21:54 +0100 +Subject: [PATCH] fence_vmware_rest: fix encoding to avoid issues with UTF-8 + encoded comments + +--- + agents/vmware_rest/fence_vmware_rest.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index cd99b4ac..d07bc10d 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -127,7 +127,7 @@ def send_command(conn, command, method="GET"): + raise Exception(e[1]) + + rc = conn.getinfo(pycurl.HTTP_CODE) +- result = web_buffer.getvalue().decode() ++ result = web_buffer.getvalue().decode("UTF-8") + + web_buffer.close() + diff --git a/SOURCES/bz1793739-fence_vmware_rest-2-support-utf-8-vm-names.patch b/SOURCES/bz1793739-fence_vmware_rest-2-support-utf-8-vm-names.patch new file mode 100644 index 0000000..ce113af --- /dev/null +++ b/SOURCES/bz1793739-fence_vmware_rest-2-support-utf-8-vm-names.patch @@ -0,0 +1,38 @@ +From 80aea3942aaca881349230a32b5dcc06c57de98a Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 19 May 2020 15:10:16 +0200 +Subject: [PATCH] fence_vmware_rest: support UTF-8 VM names + +--- + agents/vmware_rest/fence_vmware_rest.py | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index 675de246..a038a096 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -8,11 +8,14 @@ + from fencing import * + from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + ++if sys.version_info[0] > 2: import urllib.parse as urllib ++else: import urllib ++ + state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"} + + def get_power_status(conn, options): + try: +- res = send_command(conn, "vcenter/vm?filter.names={}".format(options["--plug"]))["value"] ++ res = send_command(conn, "vcenter/vm?filter.names={}".format(urllib.quote(options["--plug"])))["value"] + except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) +@@ -58,7 +61,7 @@ def get_list(conn, options): + fail(EC_STATUS) + + for r in res["value"]: +- outlets[r["name"]] = ("", state[r["power_state"]]) ++ outlets[r["name"].encode("UTF-8")] = ("", state[r["power_state"]]) + + return outlets + diff --git a/SOURCES/bz1793739-fence_vmware_rest-3-fix-encode-issue.patch b/SOURCES/bz1793739-fence_vmware_rest-3-fix-encode-issue.patch new file mode 100644 index 0000000..55b7f17 --- /dev/null +++ b/SOURCES/bz1793739-fence_vmware_rest-3-fix-encode-issue.patch @@ -0,0 +1,23 @@ +From 2ac3b05200477f3f04ce73de439e84c10a269552 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 2 Jul 2020 12:05:33 +0200 +Subject: [PATCH] fence_vmware_rest: remove .encode() that made the list action + fail on Python 3. It works fine with/without this on Python 2.x + +--- + agents/vmware_rest/fence_vmware_rest.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index a038a096..e49fd566 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -61,7 +61,7 @@ def get_list(conn, options): + fail(EC_STATUS) + + for r in res["value"]: +- outlets[r["name"].encode("UTF-8")] = ("", state[r["power_state"]]) ++ outlets[r["name"]] = ("", state[r["power_state"]]) + + return outlets + diff --git a/SOURCES/bz1796654-fence_vmware_soap-log-exception-message-for-SSLError.patch b/SOURCES/bz1796654-fence_vmware_soap-log-exception-message-for-SSLError.patch new file mode 100644 index 0000000..c362210 --- /dev/null +++ b/SOURCES/bz1796654-fence_vmware_soap-log-exception-message-for-SSLError.patch @@ -0,0 +1,23 @@ +From 39e96371ab9ab1318db004c0ddbb1049d1c0f474 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 11 Jun 2020 10:25:34 +0200 +Subject: [PATCH] fence_vmware_soap: log exception message for SSLError + exception + +--- + agents/vmware_soap/fence_vmware_soap.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py +index 53e8d8f4..f2ab68b0 100644 +--- a/agents/vmware_soap/fence_vmware_soap.py ++++ b/agents/vmware_soap/fence_vmware_soap.py +@@ -67,7 +67,7 @@ def soap_login(options): + + conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) + except requests.exceptions.SSLError as ex: +- fail_usage("Server side certificate verification failed") ++ fail_usage("Server side certificate verification failed: %s" % ex) + except Exception: + fail(EC_LOGIN_DENIED) + diff --git a/SOURCES/bz1810457-fence_aws-improve-parameter-logic.patch b/SOURCES/bz1810457-fence_aws-improve-parameter-logic.patch new file mode 100644 index 0000000..29c1f8c --- /dev/null +++ b/SOURCES/bz1810457-fence_aws-improve-parameter-logic.patch @@ -0,0 +1,48 @@ +From 1c2f791b6b2be13bcceaa096df52654164b1f6cb Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 5 Mar 2020 14:10:29 +0100 +Subject: [PATCH] fence_aws: improve connect parameter logic, so region can be + specified as parameter, while using role or keys from ~/.aws/config + +--- + agents/aws/fence_aws.py | 27 +++++++++------------------ + 1 file changed, 9 insertions(+), 18 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 74321e8e..4a4d9de2 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -107,24 +107,15 @@ def main(): + + run_delay(options) + +- if "--region" in options and "--access-key" in options and "--secret-key" in options: +- region = options["--region"] +- access_key = options["--access-key"] +- secret_key = options["--secret-key"] +- try: +- conn = boto3.resource('ec2', region_name=region, +- aws_access_key_id=access_key, +- aws_secret_access_key=secret_key) +- except Exception as e: +- fail_usage("Failed: Unable to connect to AWS: " + str(e)) +- else: +- # If setup with "aws configure" or manually in +- # ~/.aws/credentials +- try: +- conn = boto3.resource('ec2') +- except Exception as e: +- # If any of region/access/secret are missing +- fail_usage("Failed: Unable to connect to AWS: " + str(e)) ++ region = options.get("--region") ++ access_key = options.get("--access-key") ++ secret_key = options.get("--secret-key") ++ try: ++ conn = boto3.resource('ec2', region_name=region, ++ aws_access_key_id=access_key, ++ aws_secret_access_key=secret_key) ++ except Exception as e: ++ fail_usage("Failed: Unable to connect to AWS: " + str(e)) + + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) diff --git a/SOURCES/bz1816203-fence_aws-1-fix-race-condition.patch b/SOURCES/bz1816203-fence_aws-1-fix-race-condition.patch new file mode 100644 index 0000000..ce17980 --- /dev/null +++ b/SOURCES/bz1816203-fence_aws-1-fix-race-condition.patch @@ -0,0 +1,421 @@ +From 1742baf17954c58a84b9c668a617bac78303ce95 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Tue, 17 Mar 2020 13:18:38 +0000 +Subject: [PATCH 1/9] fence_aws: Fix fence race condition by checking local + instance status + +--- + agents/aws/fence_aws.py | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 4a4d9de2..f37f68d6 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -3,6 +3,7 @@ + import sys, re + import logging + import atexit ++import requests + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * + from fencing import fail, fail_usage, run_delay, EC_STATUS +@@ -10,6 +11,17 @@ + import boto3 + from botocore.exceptions import ClientError, EndpointConnectionError, NoRegionError + ++def get_instance_id(): ++ try: ++ r = requests.get('http://169.254.169.254/latest/meta-data/instance-id') ++ return r.content ++ except HTTPError as http_err: ++ logging.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err) ++ except Exception as err: ++ logging.error('A fatal error occurred while trying to access EC2 metadata server: %s', err) ++ return None ++ ++ + def get_nodes_list(conn, options): + result = {} + try: +@@ -45,10 +57,33 @@ def get_power_status(conn, options): + logging.error("Failed to get power status: %s", e) + fail(EC_STATUS) + ++def get_self_power_status(conn, options): ++ try: ++ instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [instance_id]}]) ++ state = list(instance)[0].state["Name"] ++ if state == "running": ++ logging.debug("Captured my (%s) state and it %s - returning OK - Proceeding with fencing",instance_id,state.upper()) ++ return "ok" ++ else: ++ logging.debug("Captured my (%s) state it is %s - returning Alert - Unable to fence other nodes",instance_id,state.upper()) ++ return "alert" ++ ++ except ClientError: ++ fail_usage("Failed: Incorrect Access Key or Secret Key.") ++ except EndpointConnectionError: ++ fail_usage("Failed: Incorrect Region.") ++ except IndexError: ++ return "fail" ++ + def set_power_status(conn, options): ++ my_instance = get_instance_id() + try: + if (options["--action"]=="off"): +- conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) ++ if (get_self_power_status(conn,myinstance) == "ok"): ++ logging.info("Called StopInstance API call for %s", options["--plug"]) ++ conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) ++ else: ++ logging.info("Skipping fencing as instance is not in running status") + elif (options["--action"]=="on"): + conn.instances.filter(InstanceIds=[options["--plug"]]).start() + except Exception as e: + +From 45e429b3132ebc9e78121c3fbb15f0bf46845a59 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Tue, 17 Mar 2020 13:28:34 +0000 +Subject: [PATCH 2/9] fence_aws: Use local logger and improve logging + experience + +--- + agents/aws/fence_aws.py | 34 ++++++++++++++++++++++++++-------- + 1 file changed, 26 insertions(+), 8 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index f37f68d6..b0b6685a 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -6,7 +6,7 @@ + import requests + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * +-from fencing import fail, fail_usage, run_delay, EC_STATUS ++from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler + + import boto3 + from botocore.exceptions import ClientError, EndpointConnectionError, NoRegionError +@@ -16,13 +16,14 @@ def get_instance_id(): + r = requests.get('http://169.254.169.254/latest/meta-data/instance-id') + return r.content + except HTTPError as http_err: +- logging.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err) ++ logger.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err) + except Exception as err: +- logging.error('A fatal error occurred while trying to access EC2 metadata server: %s', err) ++ logger.error('A fatal error occurred while trying to access EC2 metadata server: %s', err) + return None + + + def get_nodes_list(conn, options): ++ logger.info("Starting monitor operation") + result = {} + try: + for instance in conn.instances.all(): +@@ -32,14 +33,16 @@ def get_nodes_list(conn, options): + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") + except Exception as e: +- logging.error("Failed to get node list: %s", e) +- ++ logger.error("Failed to get node list: %s", e) ++ logger.debug("Monitor operation OK: %s",result) + return result + + def get_power_status(conn, options): ++ logger.debug("Starting status operation") + try: + instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [options["--plug"]]}]) + state = list(instance)[0].state["Name"] ++ logger.info("Status operation for EC2 instance %s returned state: %s",options["--plug"],state.upper()) + if state == "running": + return "on" + elif state == "stopped": +@@ -80,14 +83,14 @@ def set_power_status(conn, options): + try: + if (options["--action"]=="off"): + if (get_self_power_status(conn,myinstance) == "ok"): +- logging.info("Called StopInstance API call for %s", options["--plug"]) + conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) ++ logger.info("Called StopInstance API call for %s", options["--plug"]) + else: +- logging.info("Skipping fencing as instance is not in running status") ++ logger.info("Skipping fencing as instance is not in running status") + elif (options["--action"]=="on"): + conn.instances.filter(InstanceIds=[options["--plug"]]).start() + except Exception as e: +- logging.error("Failed to power %s %s: %s", \ ++ logger.error("Failed to power %s %s: %s", \ + options["--action"], options["--plug"], e) + + def define_new_opts(): +@@ -142,6 +145,13 @@ def main(): + + run_delay(options) + ++ if options.get("--verbose") is not None: ++ lh = logging.FileHandler('/var/log/fence_aws_debug.log') ++ logger.addHandler(lh) ++ lhf = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ++ lh.setFormatter(lhf) ++ logger.setLevel(logging.DEBUG) ++ + region = options.get("--region") + access_key = options.get("--access-key") + secret_key = options.get("--secret-key") +@@ -157,4 +167,12 @@ def main(): + sys.exit(result) + + if __name__ == "__main__": ++ ++ logger = logging.getLogger("fence_aws") ++ logger.propagate = False ++ logger.setLevel(logging.INFO) ++ logger.addHandler(SyslogLibHandler()) ++ logger.getLogger('botocore.vendored').propagate = False ++ ++ + main() + +From 00569921597b8007c67296ab8332747baf1e6fae Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Tue, 17 Mar 2020 13:33:02 +0000 +Subject: [PATCH 3/9] fence_aws: Decouple boto3 and botocore debug logging from + local logging + +--- + agents/aws/fence_aws.py | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index b0b6685a..11714315 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -118,18 +118,27 @@ def define_new_opts(): + "required" : "0", + "order" : 4 + } ++ all_opt["boto3_debug"] = { ++ "getopt" : "b:", ++ "longopt" : "boto3_debug", ++ "help" : "-b, --boto3_debug=on|off Boto3 and Botocore library debug logging", ++ "shortdesc": "Boto Lib debug", ++ "required": "0", ++ "order": 5 ++ } + + # Main agent method + def main(): + conn = None + +- device_opt = ["port", "no_password", "region", "access_key", "secret_key"] ++ device_opt = ["port", "no_password", "region", "access_key", "secret_key", "boto3_debug"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" ++ all_opt["boto3_debug"]["default"] = "off" + + options = check_input(device_opt, process_input(device_opt)) + +@@ -151,6 +160,21 @@ def main(): + lhf = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + lh.setFormatter(lhf) + logger.setLevel(logging.DEBUG) ++ ++ if options["--boto3_debug"] != "on": ++ boto3.set_stream_logger('boto3',logging.INFO) ++ boto3.set_stream_logger('botocore',logging.INFO) ++ logging.getLogger('botocore').propagate = False ++ logging.getLogger('boto3').propagate = False ++ else: ++ log_format = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s') ++ logging.getLogger('botocore').propagate = False ++ logging.getLogger('boto3').propagate = False ++ fdh = logging.FileHandler('/var/log/fence_aws_boto3.log') ++ fdh.setFormatter(log_format) ++ logging.getLogger('boto3').addHandler(fdh) ++ logging.getLogger('botocore').addHandler(fdh) ++ logging.debug("Boto debug level is %s and sending debug info to /var/log/fence_aws_boto3.log", options["--boto3_debug"]) + + region = options.get("--region") + access_key = options.get("--access-key") + +From ed309bd51dfd5e0fed30156e7a312d5b5a8f4bd4 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Thu, 19 Mar 2020 16:02:47 +0000 +Subject: [PATCH 4/9] fence_aws: Fix typos and variable names + +--- + agents/aws/fence_aws.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 11714315..207631e8 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -60,7 +60,7 @@ def get_power_status(conn, options): + logging.error("Failed to get power status: %s", e) + fail(EC_STATUS) + +-def get_self_power_status(conn, options): ++def get_self_power_status(conn, instance_id): + try: + instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [instance_id]}]) + state = list(instance)[0].state["Name"] +@@ -82,7 +82,7 @@ def set_power_status(conn, options): + my_instance = get_instance_id() + try: + if (options["--action"]=="off"): +- if (get_self_power_status(conn,myinstance) == "ok"): ++ if (get_self_power_status(conn,my_instance) == "ok"): + conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) + logger.info("Called StopInstance API call for %s", options["--plug"]) + else: +@@ -196,7 +196,7 @@ def main(): + logger.propagate = False + logger.setLevel(logging.INFO) + logger.addHandler(SyslogLibHandler()) +- logger.getLogger('botocore.vendored').propagate = False ++ logging.getLogger('botocore.vendored').propagate = False + + + main() + +From 624c652a95a676286af408898186186b7d7fcf55 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Thu, 19 Mar 2020 16:58:45 +0000 +Subject: [PATCH 5/9] fence_aws: Missing brackets on boto3_debug metadata + +--- + agents/aws/fence_aws.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 207631e8..8916f4a0 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -121,7 +121,7 @@ def define_new_opts(): + all_opt["boto3_debug"] = { + "getopt" : "b:", + "longopt" : "boto3_debug", +- "help" : "-b, --boto3_debug=on|off Boto3 and Botocore library debug logging", ++ "help" : "-b, --boto3_debug=[on|off] Boto3 and Botocore library debug logging", + "shortdesc": "Boto Lib debug", + "required": "0", + "order": 5 + +From 7c641a6885c4ab67b7739a43892d92d95a6f566c Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Thu, 19 Mar 2020 17:04:31 +0000 +Subject: [PATCH 6/9] fence_aws: Fix travis build #1 + +--- + agents/aws/fence_aws.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 8916f4a0..f41a47e4 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -121,7 +121,7 @@ def define_new_opts(): + all_opt["boto3_debug"] = { + "getopt" : "b:", + "longopt" : "boto3_debug", +- "help" : "-b, --boto3_debug=[on|off] Boto3 and Botocore library debug logging", ++ "help" : "-b, --boto3_debug=[option] Boto3 and Botocore library debug logging", + "shortdesc": "Boto Lib debug", + "required": "0", + "order": 5 + +From 257af7ccc9789646adc7abf1e7dbac744b756071 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Fri, 20 Mar 2020 10:59:56 +0000 +Subject: [PATCH 7/9] fence_aws: Updated metadata XML file + +--- + tests/data/metadata/fence_aws.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/data/metadata/fence_aws.xml b/tests/data/metadata/fence_aws.xml +index 5e5d5d99..acfebb61 100644 +--- a/tests/data/metadata/fence_aws.xml ++++ b/tests/data/metadata/fence_aws.xml +@@ -36,6 +36,11 @@ For instructions see: https://boto3.readthedocs.io/en/latest/guide/quickstart.ht + + Secret Key. + ++ ++ ++ ++ Boto Lib debug ++ + + + + +From 8f78bc19356b5e07d0021aaf7da3fc4e712e00f0 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Fri, 20 Mar 2020 12:13:16 +0000 +Subject: [PATCH 8/9] fence_aws: Moving logger config next to import statements + for visibility + +--- + agents/aws/fence_aws.py | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index f41a47e4..72fb8843 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -11,6 +11,12 @@ + import boto3 + from botocore.exceptions import ClientError, EndpointConnectionError, NoRegionError + ++logger = logging.getLogger("fence_aws") ++logger.propagate = False ++logger.setLevel(logging.INFO) ++logger.addHandler(SyslogLibHandler()) ++logging.getLogger('botocore.vendored').propagate = False ++ + def get_instance_id(): + try: + r = requests.get('http://169.254.169.254/latest/meta-data/instance-id') +@@ -192,11 +198,4 @@ def main(): + + if __name__ == "__main__": + +- logger = logging.getLogger("fence_aws") +- logger.propagate = False +- logger.setLevel(logging.INFO) +- logger.addHandler(SyslogLibHandler()) +- logging.getLogger('botocore.vendored').propagate = False +- +- + main() + +From 570a05c425fe55008c8892ebaad8a73d36143909 Mon Sep 17 00:00:00 2001 +From: Guilherme Felix +Date: Fri, 20 Mar 2020 14:17:55 +0000 +Subject: [PATCH 9/9] fence_aws: Remove empty line + +--- + agents/aws/fence_aws.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 72fb8843..ed55f390 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -197,5 +197,4 @@ def main(): + sys.exit(result) + + if __name__ == "__main__": +- +- main() ++ main() +\ No newline at end of file diff --git a/SOURCES/bz1816203-fence_aws-2-fix-python3-encoding.patch b/SOURCES/bz1816203-fence_aws-2-fix-python3-encoding.patch new file mode 100644 index 0000000..2751b79 --- /dev/null +++ b/SOURCES/bz1816203-fence_aws-2-fix-python3-encoding.patch @@ -0,0 +1,22 @@ +From 9758f8c83c44ad6949d4411042c59bcf9365f67e Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 24 Mar 2020 15:31:13 +0100 +Subject: [PATCH] fence_aws: fix Python 3 encoding issue + +--- + agents/aws/fence_aws.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index ed55f390..17c2fedb 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -20,7 +20,7 @@ + def get_instance_id(): + try: + r = requests.get('http://169.254.169.254/latest/meta-data/instance-id') +- return r.content ++ return r.content.decode("UTF-8") + except HTTPError as http_err: + logger.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err) + except Exception as err: diff --git a/SOURCES/bz1827559-fence_vmware_rest-improve-exception-handling.patch b/SOURCES/bz1827559-fence_vmware_rest-improve-exception-handling.patch new file mode 100644 index 0000000..1c61b35 --- /dev/null +++ b/SOURCES/bz1827559-fence_vmware_rest-improve-exception-handling.patch @@ -0,0 +1,44 @@ +From 020f48a309bcad659dc493960d2b39e8e1243085 Mon Sep 17 00:00:00 2001 +From: Thomas Abraham +Date: Mon, 20 Apr 2020 20:28:43 -0400 +Subject: [PATCH] fence_vmware_rest: improve exception handling in + send_command() + +If an exception occurs, simply raise it. pycurl's perform() method can +generate a pycurl.error object, which does not support indexing and +attempting to do so will generate an exception that hides the original +exception. + +Also, don't assume that the remote will return a JSON formatted response. +If it doesn't, a exception will occur accessing result which will not +raise the intended exception. +--- + agents/vmware_rest/fence_vmware_rest.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index d07bc10d..1505ffe6 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -124,7 +124,7 @@ def send_command(conn, command, method="GET"): + try: + conn.perform() + except Exception as e: +- raise Exception(e[1]) ++ raise(e) + + rc = conn.getinfo(pycurl.HTTP_CODE) + result = web_buffer.getvalue().decode("UTF-8") +@@ -135,7 +135,11 @@ def send_command(conn, command, method="GET"): + result = json.loads(result) + + if rc != 200: +- raise Exception("{}: {}".format(rc, result["value"]["messages"][0]["default_message"])) ++ if len(result) > 0: ++ raise Exception("{}: {}".format(rc, ++ result["value"]["messages"][0]["default_message"])) ++ else: ++ raise Exception("Remote returned {} for request to {}".format(rc, url)) + + logging.debug("url: {}".format(url)) + logging.debug("method: {}".format(method)) diff --git a/SOURCES/bz1827652-fence_vmware_rest-1-add-filter-parameter.patch b/SOURCES/bz1827652-fence_vmware_rest-1-add-filter-parameter.patch new file mode 100644 index 0000000..2e17f7f --- /dev/null +++ b/SOURCES/bz1827652-fence_vmware_rest-1-add-filter-parameter.patch @@ -0,0 +1,92 @@ +From ab193580dcdd810b7bef69cc04cebef315f4781d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 23 Apr 2020 15:55:11 +0200 +Subject: [PATCH] fence_vmware_rest: add filter parameter + +--- + agents/vmware_rest/fence_vmware_rest.py | 24 ++++++++++++++++++++--- + tests/data/metadata/fence_vmware_rest.xml | 9 ++++++++- + 2 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index 1505ffe6..6daff121 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -42,7 +42,10 @@ def get_list(conn, options): + outlets = {} + + try: +- res = send_command(conn, "vcenter/vm") ++ command = "vcenter/vm" ++ if "--filter" in options: ++ command = command + "?" + options["--filter"] ++ res = send_command(conn, command) + except: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) +@@ -157,6 +160,16 @@ def define_new_opts(): + "required" : "0", + "shortdesc" : "The path part of the API URL", + "order" : 2} ++ all_opt["filter"] = { ++ "getopt" : ":", ++ "longopt" : "filter", ++ "help" : "--filter=[filter] Filter to only return relevant VMs" ++ " (e.g. \"filter.names=node1&filter.names=node2\").", ++ "default" : "", ++ "required" : "0", ++ "shortdesc" : "Filter to only return relevant VMs. It can be used to avoid " ++ "the agent failing when more than 1000 VMs should be returned.", ++ "order" : 2} + + + def main(): +@@ -169,6 +182,7 @@ def main(): + "notls", + "web", + "port", ++ "filter", + ] + + atexit.register(atexit_handler) +@@ -181,8 +195,12 @@ def main(): + + docs = {} + docs["shortdesc"] = "Fence agent for VMware REST API" +- docs["longdesc"] = "fence_vmware_rest is an I/O Fencing agent which can be \ +-used with VMware API to fence virtual machines." ++ docs["longdesc"] = """fence_vmware_rest is an I/O Fencing agent which can be \ ++used with VMware API to fence virtual machines. ++ ++NOTE: If there's more than 1000 VMs there is a filter parameter to work around \ ++the API limit. See https://code.vmware.com/apis/62/vcenter-management#/VM%20/get_vcenter_vm \ ++for full list of filters.""" + docs["vendorurl"] = "https://www.vmware.com" + show_docs(options, docs) + +diff --git a/tests/data/metadata/fence_vmware_rest.xml b/tests/data/metadata/fence_vmware_rest.xml +index 5b497a6a..d60c8775 100644 +--- a/tests/data/metadata/fence_vmware_rest.xml ++++ b/tests/data/metadata/fence_vmware_rest.xml +@@ -1,6 +1,8 @@ + + +-fence_vmware_rest is an I/O Fencing agent which can be used with VMware API to fence virtual machines. ++fence_vmware_rest is an I/O Fencing agent which can be used with VMware API to fence virtual machines. ++ ++NOTE: If there's more than 1000 VMs there is a filter parameter to work around the API limit. See https://code.vmware.com/apis/62/vcenter-management#/VM%20/get_vcenter_vm for full list of filters. + https://www.vmware.com + + +@@ -87,6 +89,11 @@ + + The path part of the API URL + ++ ++ ++ ++ Filter to only return relevant VMs. It can be used to avoid the agent failing when more than 1000 VMs should be returned. ++ + + + diff --git a/SOURCES/bz1827652-fence_vmware_rest-2-fix-1000-VM-monitor-error.patch b/SOURCES/bz1827652-fence_vmware_rest-2-fix-1000-VM-monitor-error.patch new file mode 100644 index 0000000..0f83fa7 --- /dev/null +++ b/SOURCES/bz1827652-fence_vmware_rest-2-fix-1000-VM-monitor-error.patch @@ -0,0 +1,76 @@ +From 0296bc8512e37b8b935bc342b6493ed4fa8aa001 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 14 May 2020 13:17:04 +0200 +Subject: [PATCH 1/2] fence_vmware_rest: fix exception and remove default value + for filter parameter (which was shown in the manpage) + +--- + agents/vmware_rest/fence_vmware_rest.py | 3 +-- + tests/data/metadata/fence_vmware_rest.xml | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index 6daff121..2635ae07 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -46,7 +46,7 @@ def get_list(conn, options): + if "--filter" in options: + command = command + "?" + options["--filter"] + res = send_command(conn, command) +- except: ++ except Exception as e: + logging.debug("Failed: {}".format(e)) + fail(EC_STATUS) + +@@ -165,7 +165,6 @@ def define_new_opts(): + "longopt" : "filter", + "help" : "--filter=[filter] Filter to only return relevant VMs" + " (e.g. \"filter.names=node1&filter.names=node2\").", +- "default" : "", + "required" : "0", + "shortdesc" : "Filter to only return relevant VMs. It can be used to avoid " + "the agent failing when more than 1000 VMs should be returned.", +diff --git a/tests/data/metadata/fence_vmware_rest.xml b/tests/data/metadata/fence_vmware_rest.xml +index d60c8775..830b6a21 100644 +--- a/tests/data/metadata/fence_vmware_rest.xml ++++ b/tests/data/metadata/fence_vmware_rest.xml +@@ -91,7 +91,7 @@ NOTE: If there's more than 1000 VMs there is a filter parameter to work around t + + + +- ++ + Filter to only return relevant VMs. It can be used to avoid the agent failing when more than 1000 VMs should be returned. + + + +From 7420cf9f11568be7239956bed4631cdbaa6fb87c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 14 May 2020 14:17:03 +0200 +Subject: [PATCH 2/2] fence_vmware_rest: dont fail when receiving more than + 1000 VM error during monitor-action + +--- + agents/vmware_rest/fence_vmware_rest.py | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index 2635ae07..675de246 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -48,7 +48,14 @@ def get_list(conn, options): + res = send_command(conn, command) + except Exception as e: + logging.debug("Failed: {}".format(e)) +- fail(EC_STATUS) ++ if str(e).startswith("400"): ++ if options.get("--original-action") == "monitor": ++ return outlets ++ else: ++ logging.error("More than 1000 VMs returned. Use --filter parameter to limit which VMs to list.") ++ fail(EC_STATUS) ++ else: ++ fail(EC_STATUS) + + for r in res["value"]: + outlets[r["name"]] = ("", state[r["power_state"]]) diff --git a/SOURCES/bz1830776-fence_compute-fence_evacuate-fix-insecure-parameter.patch b/SOURCES/bz1830776-fence_compute-fence_evacuate-fix-insecure-parameter.patch new file mode 100644 index 0000000..914b7e3 --- /dev/null +++ b/SOURCES/bz1830776-fence_compute-fence_evacuate-fix-insecure-parameter.patch @@ -0,0 +1,122 @@ +From 8920d2fc7993453e7ad05f807f6ec51745b408a5 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 4 May 2020 16:53:55 +0200 +Subject: [PATCH] fence_compute/fence_evacuate: fix --insecure parameter + +--- + agents/compute/fence_compute.py | 10 +++++++--- + agents/evacuate/fence_evacuate.py | 10 +++++++--- + tests/data/metadata/fence_compute.xml | 2 +- + tests/data/metadata/fence_evacuate.xml | 2 +- + 4 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index d0e012e6..f53b97da 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -281,7 +281,7 @@ def create_nova_connection(options): + + loader = loading.get_plugin_loader('password') + keystone_auth = loader.load_from_options(**kwargs) +- keystone_session = session.Session(auth=keystone_auth, verify=(not options["--insecure"])) ++ keystone_session = session.Session(auth=keystone_auth, verify=not "--insecure" in options) + + nova_versions = [ "2.11", "2" ] + for version in nova_versions: +@@ -307,7 +307,7 @@ def create_nova_connection(options): + None, # Password + None, # Tenant + None, # Auth URL +- insecure=options["--insecure"], ++ insecure="--insecure" in options, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +@@ -395,7 +395,6 @@ def define_new_opts(): + "help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests", + "required" : "0", + "shortdesc" : "Allow Insecure TLS Requests", +- "default" : "False", + "order": 2, + } + all_opt["domain"] = { +@@ -484,6 +483,11 @@ def main(): + options["--domain"] = options["--compute-domain"] + del options["--domain"] + ++ # Disable insecure-certificate-warning message ++ if "--insecure" in options: ++ import urllib3 ++ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ++ + logging.debug("Running "+options["--action"]) + connection = create_nova_connection(options) + +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 60bb130e..88837dd8 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -217,7 +217,7 @@ def create_nova_connection(options): + + loader = loading.get_plugin_loader('password') + keystone_auth = loader.load_from_options(**kwargs) +- keystone_session = session.Session(auth=keystone_auth, verify=(not options["--insecure"])) ++ keystone_session = session.Session(auth=keystone_auth, verify=not "--insecure" in options) + + versions = [ "2.11", "2" ] + for version in versions: +@@ -244,7 +244,7 @@ def create_nova_connection(options): + None, # Password + None, # Tenant + None, # Auth URL +- insecure=options["--insecure"], ++ insecure="--insecure" in options, + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +@@ -332,7 +332,6 @@ def define_new_opts(): + "help" : "--insecure Explicitly allow agent to perform \"insecure\" TLS (https) requests", + "required" : "0", + "shortdesc" : "Allow Insecure TLS Requests", +- "default" : "False", + "order": 2, + } + all_opt["domain"] = { +@@ -397,6 +396,11 @@ def main(): + del options["--domain"] + + ++ # Disable insecure-certificate-warning message ++ if "--insecure" in options: ++ import urllib3 ++ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ++ + connection = create_nova_connection(options) + + # Un-evacuating a server doesn't make sense +diff --git a/tests/data/metadata/fence_compute.xml b/tests/data/metadata/fence_compute.xml +index 99d56af0..2f183268 100644 +--- a/tests/data/metadata/fence_compute.xml ++++ b/tests/data/metadata/fence_compute.xml +@@ -70,7 +70,7 @@ + + + +- ++ + Allow Insecure TLS Requests + + +diff --git a/tests/data/metadata/fence_evacuate.xml b/tests/data/metadata/fence_evacuate.xml +index 8c720b80..95da0e1b 100644 +--- a/tests/data/metadata/fence_evacuate.xml ++++ b/tests/data/metadata/fence_evacuate.xml +@@ -70,7 +70,7 @@ + + + +- ++ + Allow Insecure TLS Requests + + diff --git a/SOURCES/bz1839776-fence_aws-catch-connectionerror.patch b/SOURCES/bz1839776-fence_aws-catch-connectionerror.patch new file mode 100644 index 0000000..674586e --- /dev/null +++ b/SOURCES/bz1839776-fence_aws-catch-connectionerror.patch @@ -0,0 +1,95 @@ +From be20615859c518b3161b08ee63f5da5213eba91d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 25 May 2020 14:03:53 +0200 +Subject: [PATCH 1/2] fence_aws: catch ConnectionError and suppress traceback + for caught exceptions + +--- + agents/aws/fence_aws.py | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 17c2fedb..191f5de1 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -9,14 +9,14 @@ + from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler + + import boto3 +-from botocore.exceptions import ClientError, EndpointConnectionError, NoRegionError ++from botocore.exceptions import ConnectionError, ClientError, EndpointConnectionError, NoRegionError + + logger = logging.getLogger("fence_aws") + logger.propagate = False + logger.setLevel(logging.INFO) + logger.addHandler(SyslogLibHandler()) + logging.getLogger('botocore.vendored').propagate = False +- ++ + def get_instance_id(): + try: + r = requests.get('http://169.254.169.254/latest/meta-data/instance-id') +@@ -38,6 +38,8 @@ def get_nodes_list(conn, options): + fail_usage("Failed: Incorrect Access Key or Secret Key.") + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") ++ except ConnectionError as e: ++ fail_usage("Failed: Unable to connect to AWS: " + str(e)) + except Exception as e: + logger.error("Failed to get node list: %s", e) + logger.debug("Monitor operation OK: %s",result) +@@ -169,7 +171,7 @@ def main(): + + if options["--boto3_debug"] != "on": + boto3.set_stream_logger('boto3',logging.INFO) +- boto3.set_stream_logger('botocore',logging.INFO) ++ boto3.set_stream_logger('botocore',logging.CRITICAL) + logging.getLogger('botocore').propagate = False + logging.getLogger('boto3').propagate = False + else: +@@ -197,4 +199,4 @@ def main(): + sys.exit(result) + + if __name__ == "__main__": +- main() +\ No newline at end of file ++ main() + +From 50772024cffa60d05938d328bbd5cffd930f6b42 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 25 May 2020 14:07:14 +0200 +Subject: [PATCH 2/2] fence_aws: improve boto3_debug boolean handling + +--- + agents/aws/fence_aws.py | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 191f5de1..483a2991 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -132,6 +132,7 @@ def define_new_opts(): + "help" : "-b, --boto3_debug=[option] Boto3 and Botocore library debug logging", + "shortdesc": "Boto Lib debug", + "required": "0", ++ "default": "False", + "order": 5 + } + +@@ -146,7 +147,6 @@ def main(): + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" +- all_opt["boto3_debug"]["default"] = "off" + + options = check_input(device_opt, process_input(device_opt)) + +@@ -169,7 +169,7 @@ def main(): + lh.setFormatter(lhf) + logger.setLevel(logging.DEBUG) + +- if options["--boto3_debug"] != "on": ++ if options["--boto3_debug"].lower() not in ["1", "yes", "on", "true"]: + boto3.set_stream_logger('boto3',logging.INFO) + boto3.set_stream_logger('botocore',logging.CRITICAL) + logging.getLogger('botocore').propagate = False diff --git a/SOURCES/bz1859932-fence_evacuate-support-private-flavors.patch b/SOURCES/bz1859932-fence_evacuate-support-private-flavors.patch new file mode 100644 index 0000000..60eddd2 --- /dev/null +++ b/SOURCES/bz1859932-fence_evacuate-support-private-flavors.patch @@ -0,0 +1,26 @@ +From 18ef1622475db947aef70042523f4a176c4155bd Mon Sep 17 00:00:00 2001 +From: Luca Miccini +Date: Thu, 23 Jul 2020 14:33:38 +0200 +Subject: [PATCH] [fence_evacuate] Enable evacuation of instances using private + flavors + +This commit extends the flavor.list() api call in the fence_evacuate +agent to fetch private flavors that could be tagged with the 'evacuable' +attribute, allowing instance-ha to be enabled on a per tenant basis. +--- + agents/evacuate/fence_evacuate.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 88837dd8..53d6fd15 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -87,7 +87,7 @@ def _is_server_evacuable(server, evac_flavors, evac_images): + + def _get_evacuable_flavors(connection): + result = [] +- flavors = connection.flavors.list() ++ flavors = connection.flavors.list(is_public=None) + # Since the detailed view for all flavors doesn't provide the extra specs, + # we need to call each of the flavor to get them. + for flavor in flavors: diff --git a/SOURCES/bz1860544-fence_lpar-fix-long-user-host-issue.patch b/SOURCES/bz1860544-fence_lpar-fix-long-user-host-issue.patch new file mode 100644 index 0000000..f65f6ba --- /dev/null +++ b/SOURCES/bz1860544-fence_lpar-fix-long-user-host-issue.patch @@ -0,0 +1,127 @@ +From 3424464d3e447308f171399302cf76eb573a618f Mon Sep 17 00:00:00 2001 +From: Reid wahl +Date: Fri, 24 Jul 2020 18:22:24 -0700 +Subject: [PATCH] fence_lpar: Fix parse error from long command line + +When Pacemaker executes `fence_lpar` and the HMC command line is greater +than 80 characters, a parse error causes agent failure. This can happen +with a long user name and/or long managed system name. It happens only +when Pacemaker spawns the `fence_lpar` process; it does not happen when +`fence_lpar` is run from the CLI. + +A long command line gets a carriage return ('\r') added at the 80 +character mark and wraps back to the beginning of the line with no line +feed ('\n'), overwriting the displayed characters. `fence_lpar`'s regex +matches handle this fine when it's run from the command line. + +The problem is that when Pacemaker spawns fence_lpar, **for some +reason** there are backspace characters in the buffer when we hit the +'\r' character. This seems to overwrite some of the `conn.before` +string. As a result, the regex doesn't match `conn.before`, and the +agent fails. + +This patch works around the `conn.before` weirdness by reading and +discarding the first received line **before** any regex processing. + +Resolves: RHBZ#1860544 +Resolves: RHBZ#1860545 + +Signed-off-by: Reid Wahl +--- + agents/lpar/fence_lpar.py | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py +index 270bbe3b..9dfabc43 100644 +--- a/agents/lpar/fence_lpar.py ++++ b/agents/lpar/fence_lpar.py +@@ -19,6 +19,9 @@ + def get_power_status(conn, options): + if options["--hmc-version"] == "3": + conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") ++ ++ # First line (command) may cause parsing issues if long ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: +@@ -29,6 +32,9 @@ def get_power_status(conn, options): + elif options["--hmc-version"] in ["4", "IVM"]: + conn.send("lssyscfg -r lpar -m "+ options["--managed"] + + " --filter 'lpar_names=" + options["--plug"] + "'\n") ++ ++ # First line (command) may cause parsing issues if long ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + try: +@@ -49,6 +55,9 @@ def set_power_status(conn, options): + if options["--hmc-version"] == "3": + conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] + + " -n " + options["--plug"] + "\n") ++ ++ # First line (command) may cause parsing issues if long ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + elif options["--hmc-version"] in ["4", "IVM"]: + if options["--action"] == "on": +@@ -60,17 +69,23 @@ def set_power_status(conn, options): + else: + conn.send("chsysstate -o shutdown -r lpar --immed" + + " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") ++ ++ # First line (command) may cause parsing issues if long ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + + def get_lpar_list(conn, options): + outlets = {} + if options["--hmc-version"] == "3": + conn.send("query_partition_names -m " + options["--managed"] + "\n") ++ ++ ## We have to remove first line (command) ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +- ## We have to remove first 3 lines (command + header) and last line (part of new prompt) ++ ## We have to remove next 2 lines (header) and last line (part of new prompt) + #### +- res = re.search("^.+?\n(.+?\n){2}(.*)\n.*$", conn.before, re.S) ++ res = re.search("^(.+?\n){2}(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") +@@ -81,11 +96,14 @@ def get_lpar_list(conn, options): + elif options["--hmc-version"] == "4": + conn.send("lssyscfg -r lpar -m " + options["--managed"] + + " -F name:state\n") ++ ++ ## We have to remove first line (command) ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +- ## We have to remove first line (command) and last line (part of new prompt) ++ ## We have to remove last line (part of new prompt) + #### +- res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) ++ res = re.search("^(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") +@@ -100,11 +118,14 @@ def get_lpar_list(conn, options): + elif options["--hmc-version"] == "IVM": + conn.send("lssyscfg -r lpar -m " + options["--managed"] + + " -F name,state\n") ++ ++ ## We have to remove first line (command) ++ conn.readline() + conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) + +- ## We have to remove first line (command) and last line (part of new prompt) ++ ## We have to remove last line (part of new prompt) + #### +- res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) ++ res = re.search("^(.*)\n.*$", conn.before, re.S) + + if res == None: + fail_usage("Unable to parse output of list command") diff --git a/SOURCES/bz1861139-fence_lpar-fix-long-user-host-issue.patch b/SOURCES/bz1861139-fence_lpar-fix-long-user-host-issue.patch deleted file mode 100644 index f65f6ba..0000000 --- a/SOURCES/bz1861139-fence_lpar-fix-long-user-host-issue.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 3424464d3e447308f171399302cf76eb573a618f Mon Sep 17 00:00:00 2001 -From: Reid wahl -Date: Fri, 24 Jul 2020 18:22:24 -0700 -Subject: [PATCH] fence_lpar: Fix parse error from long command line - -When Pacemaker executes `fence_lpar` and the HMC command line is greater -than 80 characters, a parse error causes agent failure. This can happen -with a long user name and/or long managed system name. It happens only -when Pacemaker spawns the `fence_lpar` process; it does not happen when -`fence_lpar` is run from the CLI. - -A long command line gets a carriage return ('\r') added at the 80 -character mark and wraps back to the beginning of the line with no line -feed ('\n'), overwriting the displayed characters. `fence_lpar`'s regex -matches handle this fine when it's run from the command line. - -The problem is that when Pacemaker spawns fence_lpar, **for some -reason** there are backspace characters in the buffer when we hit the -'\r' character. This seems to overwrite some of the `conn.before` -string. As a result, the regex doesn't match `conn.before`, and the -agent fails. - -This patch works around the `conn.before` weirdness by reading and -discarding the first received line **before** any regex processing. - -Resolves: RHBZ#1860544 -Resolves: RHBZ#1860545 - -Signed-off-by: Reid Wahl ---- - agents/lpar/fence_lpar.py | 33 +++++++++++++++++++++++++++------ - 1 file changed, 27 insertions(+), 6 deletions(-) - -diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py -index 270bbe3b..9dfabc43 100644 ---- a/agents/lpar/fence_lpar.py -+++ b/agents/lpar/fence_lpar.py -@@ -19,6 +19,9 @@ - def get_power_status(conn, options): - if options["--hmc-version"] == "3": - conn.send("lssyscfg -r lpar -m " + options["--managed"] + " -n " + options["--plug"] + " -F name,state\n") -+ -+ # First line (command) may cause parsing issues if long -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - - try: -@@ -29,6 +32,9 @@ def get_power_status(conn, options): - elif options["--hmc-version"] in ["4", "IVM"]: - conn.send("lssyscfg -r lpar -m "+ options["--managed"] + - " --filter 'lpar_names=" + options["--plug"] + "'\n") -+ -+ # First line (command) may cause parsing issues if long -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - - try: -@@ -49,6 +55,9 @@ def set_power_status(conn, options): - if options["--hmc-version"] == "3": - conn.send("chsysstate -o " + options["--action"] + " -r lpar -m " + options["--managed"] - + " -n " + options["--plug"] + "\n") -+ -+ # First line (command) may cause parsing issues if long -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - elif options["--hmc-version"] in ["4", "IVM"]: - if options["--action"] == "on": -@@ -60,17 +69,23 @@ def set_power_status(conn, options): - else: - conn.send("chsysstate -o shutdown -r lpar --immed" + - " -m " + options["--managed"] + " -n " + options["--plug"] + "\n") -+ -+ # First line (command) may cause parsing issues if long -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - - def get_lpar_list(conn, options): - outlets = {} - if options["--hmc-version"] == "3": - conn.send("query_partition_names -m " + options["--managed"] + "\n") -+ -+ ## We have to remove first line (command) -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - -- ## We have to remove first 3 lines (command + header) and last line (part of new prompt) -+ ## We have to remove next 2 lines (header) and last line (part of new prompt) - #### -- res = re.search("^.+?\n(.+?\n){2}(.*)\n.*$", conn.before, re.S) -+ res = re.search("^(.+?\n){2}(.*)\n.*$", conn.before, re.S) - - if res == None: - fail_usage("Unable to parse output of list command") -@@ -81,11 +96,14 @@ def get_lpar_list(conn, options): - elif options["--hmc-version"] == "4": - conn.send("lssyscfg -r lpar -m " + options["--managed"] + - " -F name:state\n") -+ -+ ## We have to remove first line (command) -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - -- ## We have to remove first line (command) and last line (part of new prompt) -+ ## We have to remove last line (part of new prompt) - #### -- res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) -+ res = re.search("^(.*)\n.*$", conn.before, re.S) - - if res == None: - fail_usage("Unable to parse output of list command") -@@ -100,11 +118,14 @@ def get_lpar_list(conn, options): - elif options["--hmc-version"] == "IVM": - conn.send("lssyscfg -r lpar -m " + options["--managed"] + - " -F name,state\n") -+ -+ ## We have to remove first line (command) -+ conn.readline() - conn.log_expect(options["--command-prompt"], int(options["--power-timeout"])) - -- ## We have to remove first line (command) and last line (part of new prompt) -+ ## We have to remove last line (part of new prompt) - #### -- res = re.search("^.+?\n(.*)\n.*$", conn.before, re.S) -+ res = re.search("^(.*)\n.*$", conn.before, re.S) - - if res == None: - fail_usage("Unable to parse output of list command") diff --git a/SOURCES/bz1867156-fence_evacuate-support-private-flavors.patch b/SOURCES/bz1867156-fence_evacuate-support-private-flavors.patch deleted file mode 100644 index 60eddd2..0000000 --- a/SOURCES/bz1867156-fence_evacuate-support-private-flavors.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 18ef1622475db947aef70042523f4a176c4155bd Mon Sep 17 00:00:00 2001 -From: Luca Miccini -Date: Thu, 23 Jul 2020 14:33:38 +0200 -Subject: [PATCH] [fence_evacuate] Enable evacuation of instances using private - flavors - -This commit extends the flavor.list() api call in the fence_evacuate -agent to fetch private flavors that could be tagged with the 'evacuable' -attribute, allowing instance-ha to be enabled on a per tenant basis. ---- - agents/evacuate/fence_evacuate.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py -index 88837dd8..53d6fd15 100644 ---- a/agents/evacuate/fence_evacuate.py -+++ b/agents/evacuate/fence_evacuate.py -@@ -87,7 +87,7 @@ def _is_server_evacuable(server, evac_flavors, evac_images): - - def _get_evacuable_flavors(connection): - result = [] -- flavors = connection.flavors.list() -+ flavors = connection.flavors.list(is_public=None) - # Since the detailed view for all flavors doesn't provide the extra specs, - # we need to call each of the flavor to get them. - for flavor in flavors: diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index 190e73d..799fb15 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -29,7 +29,7 @@ Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.2.1 -Release: 41%{?alphatag:.%{alphatag}}%{?dist}.2 +Release: 53%{?alphatag:.%{alphatag}}%{?dist} License: GPLv2+ and LGPLv2+ Group: System Environment/Base URL: https://github.com/ClusterLabs/fence-agents @@ -95,16 +95,29 @@ Patch53: bz1781357-fence_aws-improve-logging-and-metadata-usage-text.patch Patch54: bz1753228-fence_mpath-1-add-plug-parameter-support.patch Patch55: bz1753228-fence_mpath-2-fix-plug-parameter-issues.patch Patch56: bz1798641-fence_mpath-fix-reserve-parameter-typo.patch -Patch57: bz1861139-fence_lpar-fix-long-user-host-issue.patch -Patch58: bz1867156-fence_evacuate-support-private-flavors.patch +Patch57: bz1810457-fence_aws-improve-parameter-logic.patch +Patch58: bz1816203-fence_aws-1-fix-race-condition.patch +Patch59: bz1816203-fence_aws-2-fix-python3-encoding.patch +Patch60: bz1827559-fence_vmware_rest-improve-exception-handling.patch +Patch61: bz1827652-fence_vmware_rest-1-add-filter-parameter.patch +Patch62: bz1827652-fence_vmware_rest-2-fix-1000-VM-monitor-error.patch +Patch63: bz1830776-fence_compute-fence_evacuate-fix-insecure-parameter.patch +Patch64: bz1750596-fence_scsi-add-readonly-parameter.patch +Patch65: bz1793739-fence_vmware_rest-1-fix-encoding.patch +Patch66: bz1793739-fence_vmware_rest-2-support-utf-8-vm-names.patch +Patch67: bz1839776-fence_aws-catch-connectionerror.patch +Patch68: bz1796654-fence_vmware_soap-log-exception-message-for-SSLError.patch +Patch69: bz1793739-fence_vmware_rest-3-fix-encode-issue.patch +Patch70: bz1860544-fence_lpar-fix-long-user-host-issue.patch +Patch71: bz1859932-fence_evacuate-support-private-flavors.patch %if 0%{?fedora} || 0%{?rhel} > 7 -%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan mpath kdump redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti +%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti %ifarch x86_64 %global testagents virsh heuristics_ping aliyun aws azure_arm gce %endif %ifarch ppc64le -%global testagents virsh lpar heuristics_ping +%global testagents virsh heuristics_ping %endif %ifarch s390x %global testagents virsh zvm heuristics_ping @@ -233,6 +246,19 @@ BuildRequires: python3-google-api-client %patch56 -p1 %patch57 -p1 %patch58 -p1 +%patch59 -p1 +%patch60 -p1 -F1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 -F1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 +%patch70 -p1 +%patch71 -p1 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -831,7 +857,6 @@ Fence agent for use with kdump crash recovery service. %{_mandir}/man8/fence_kdump.8* %{_mandir}/man8/fence_kdump_send.8* -%ifarch ppc64le %package lpar License: GPLv2+ and LGPLv2+ Group: System Environment/Base @@ -845,7 +870,6 @@ Fence agent for IBM LPAR devices that are accessed via telnet or SSH. %files lpar %{_sbindir}/fence_lpar %{_mandir}/man8/fence_lpar.8* -%endif %package mpath License: GPLv2+ and LGPLv2+ @@ -1026,16 +1050,53 @@ Fence agent for IBM z/VM over IP. %endif %changelog -* Tue Jul 28 2020 Oyvind Albrigtsen - 4.2.1-41.2 +* Fri Aug 7 2020 Oyvind Albrigtsen - 4.2.1-53 - fence_evacuate: enable evacuation of instances using private flavors - Resolves: rhbz#1867156 + Resolves: rhbz#1859932 -* Tue Jul 28 2020 Oyvind Albrigtsen - 4.2.1-41.1 +* Tue Jul 28 2020 Oyvind Albrigtsen - 4.2.1-52 - fence_lpar: fix issue with long username, hostname, etc not working when the command run by the agent exceeds 80 characters - Resolves: rhbz#1861139 + Resolves: rhbz#1860544 + +* Thu Jul 2 2020 Oyvind Albrigtsen - 4.2.1-51 +- fence_vmware_rest: fix encoding issues + Resolves: rhbz#1793739 + +* Thu Jun 11 2020 Oyvind Albrigtsen - 4.2.1-50 +- fence_vmware_soap: log exception message for SSLError exception + Resolves: rhbz#1796654 + +* Wed May 27 2020 Oyvind Albrigtsen - 4.2.1-49 +- fence_aws: improve logging by catching ConnectionError exception + Resolves: rhbz#1839776 + +* Fri May 15 2020 Oyvind Albrigtsen - 4.2.1-47 +- fence_vmware_rest: add filter parameter to avoid 1000 VM API limit + and avoid failing when hitting it during the monitor-action + Resolves: rhbz#1827652 +- fence_compute/fence_evacuate: fix --insecure parameter + Resolves: rhbz#1830776 +- fence_scsi: add readonly parameter + Resolves: rhbz#1750596 + +* Tue Apr 28 2020 Oyvind Albrigtsen - 4.2.1-45 +- fence_vmware_rest: improve exception handling + Resolves: rhbz#1827559 + +* Tue Mar 24 2020 Oyvind Albrigtsen - 4.2.1-44 +- fence_aws: fix possible race condition + + Resolves: rhbz#1816203 + +* Fri Mar 13 2020 Oyvind Albrigtsen - 4.2.1-42 +- fence-agents-lpar: build on non-ppc64le arch's + Resolves: rhbz#1804907 +- fence_aws: improve parameter logic to allow setting region parameter + while using credentials from ~/.aws/config + Resolves: rhbz#1810457 * Thu Feb 13 2020 Oyvind Albrigtsen - 4.2.1-41 - fence_mpath: add plug parameter support to be able to use pcmk_host_map