diff --git a/.fence-agents.metadata b/.fence-agents.metadata new file mode 100644 index 0000000..ee9f972 --- /dev/null +++ b/.fence-agents.metadata @@ -0,0 +1,5 @@ +0a56f6d9ed2014a363486d33b63eca094379be06 SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz +c2a98b9a1562d223a76514f05028488ca000c395 SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz +f14647a4d37a9a254c4e711b95a7654fc418e41e SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz +e2561df8e7ff9113dab118a651371dd88dab0142 SOURCES/fence-agents-4.2.1.tar.gz +326a73f58a62ebee00c11a12cfdd838b196e0e8e SOURCES/pycryptodome-3.6.4.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b2651e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz +SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz +SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz +SOURCES/fence-agents-4.2.1.tar.gz +SOURCES/pycryptodome-3.6.4.tar.gz diff --git a/SOURCES/bz1650214-fence_azure_arm-bundled.patch b/SOURCES/bz1650214-fence_azure_arm-bundled.patch new file mode 100644 index 0000000..747c151 --- /dev/null +++ b/SOURCES/bz1650214-fence_azure_arm-bundled.patch @@ -0,0 +1,12 @@ +diff -uNr a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py +--- a/agents/azure_arm/fence_azure_arm.py 2018-06-28 14:24:54.000000000 +0200 ++++ b/agents/azure_arm/fence_azure_arm.py 2019-01-15 10:24:16.030092206 +0100 +@@ -7,6 +7,8 @@ + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * + from fencing import fail_usage, run_command, run_delay ++ ++sys.path.insert(0, '/usr/lib/fence-agents/bundled/azure') + import azure_fence + + def get_nodes_list(clients, options): diff --git a/SOURCES/bz1654616-fence_hpblade-fix-log_expect_syntax.patch b/SOURCES/bz1654616-fence_hpblade-fix-log_expect_syntax.patch new file mode 100644 index 0000000..bb239b1 --- /dev/null +++ b/SOURCES/bz1654616-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/bz1654968-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch b/SOURCES/bz1654968-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch new file mode 100644 index 0000000..9560368 --- /dev/null +++ b/SOURCES/bz1654968-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/bz1654973-fence_vmware_soap-cleanup-sigterm.patch b/SOURCES/bz1654973-fence_vmware_soap-cleanup-sigterm.patch new file mode 100644 index 0000000..8d27ea4 --- /dev/null +++ b/SOURCES/bz1654973-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/bz1654976-1-fence_scsi-watchdog-retry-support.patch b/SOURCES/bz1654976-1-fence_scsi-watchdog-retry-support.patch new file mode 100644 index 0000000..276c439 --- /dev/null +++ b/SOURCES/bz1654976-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/bz1654976-2-build-fix-check_used_options.patch b/SOURCES/bz1654976-2-build-fix-check_used_options.patch new file mode 100644 index 0000000..068375d --- /dev/null +++ b/SOURCES/bz1654976-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/bz1666914-1-fence_redfish.patch b/SOURCES/bz1666914-1-fence_redfish.patch new file mode 100644 index 0000000..c6f5dfd --- /dev/null +++ b/SOURCES/bz1666914-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/bz1666914-2-fence_redfish-fail-invalid-cert.patch b/SOURCES/bz1666914-2-fence_redfish-fail-invalid-cert.patch new file mode 100644 index 0000000..a834644 --- /dev/null +++ b/SOURCES/bz1666914-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/bz1677327-1-fence_redfish-use-ipport-parameter.patch b/SOURCES/bz1677327-1-fence_redfish-use-ipport-parameter.patch new file mode 100644 index 0000000..e2514f1 --- /dev/null +++ b/SOURCES/bz1677327-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/bz1677327-2-fence_redfish-ip-parameter-backward-compatibility.patch b/SOURCES/bz1677327-2-fence_redfish-ip-parameter-backward-compatibility.patch new file mode 100644 index 0000000..3d97c4e --- /dev/null +++ b/SOURCES/bz1677327-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/bz1696584-fence_gce-fix-python3-encoding-issue.patch b/SOURCES/bz1696584-fence_gce-fix-python3-encoding-issue.patch new file mode 100644 index 0000000..9e9f7ad --- /dev/null +++ b/SOURCES/bz1696584-fence_gce-fix-python3-encoding-issue.patch @@ -0,0 +1,22 @@ +From 64ac6207152508392690b7c1dfcac3fe0a76adfd Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 5 Apr 2019 09:48:52 +0200 +Subject: [PATCH] fence_gce: fix Python 3 encoding issue + +--- + agents/gce/fence_gce.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 93cd11801..b171710d9 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -146,7 +146,7 @@ def get_metadata(metadata_key, params=None, timeout=None): + url = '%s?%s' % (metadata_url, params) + request = urlrequest.Request(url, headers=METADATA_HEADERS) + request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({})) +- return request_opener.open(request, timeout=timeout * 1.1).read() ++ return request_opener.open(request, timeout=timeout * 1.1).read().decode("utf-8") + + + def define_new_opts(): diff --git a/SOURCES/bz1700546-fence_azure_arm-skip_shutdown.patch b/SOURCES/bz1700546-fence_azure_arm-skip_shutdown.patch new file mode 100644 index 0000000..708eb84 --- /dev/null +++ b/SOURCES/bz1700546-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/bz1704228-fence_redfish-full-redfish-spec-compliance.patch b/SOURCES/bz1704228-fence_redfish-full-redfish-spec-compliance.patch new file mode 100644 index 0000000..3b8ba13 --- /dev/null +++ b/SOURCES/bz1704228-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/SOURCES/bz1709780-fence_rhevm-RHEV-v4-API-support.patch b/SOURCES/bz1709780-fence_rhevm-RHEV-v4-API-support.patch new file mode 100644 index 0000000..6f115e8 --- /dev/null +++ b/SOURCES/bz1709780-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/bz1709926-fence_mpath-fix-watchdog-hardreboot.patch b/SOURCES/bz1709926-fence_mpath-fix-watchdog-hardreboot.patch new file mode 100644 index 0000000..2b187c2 --- /dev/null +++ b/SOURCES/bz1709926-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/bz1712263-fence_rhevm-1-use-UTF8-encoding.patch b/SOURCES/bz1712263-fence_rhevm-1-use-UTF8-encoding.patch new file mode 100644 index 0000000..281e006 --- /dev/null +++ b/SOURCES/bz1712263-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/bz1712263-fence_rhevm-2-fix-debug-encoding-issues.patch b/SOURCES/bz1712263-fence_rhevm-2-fix-debug-encoding-issues.patch new file mode 100644 index 0000000..9603498 --- /dev/null +++ b/SOURCES/bz1712263-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/bz1714458-fence_scsi-node-id-new-format.patch b/SOURCES/bz1714458-fence_scsi-node-id-new-format.patch new file mode 100644 index 0000000..0364930 --- /dev/null +++ b/SOURCES/bz1714458-fence_scsi-node-id-new-format.patch @@ -0,0 +1,30 @@ +From 1c4a64ca803831b44c96c75022abe5bb8713cd1a Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 22 May 2019 10:13:34 +0200 +Subject: [PATCH] fence_scsi: detect node ID using new format, and fallback to + old format before failing + +--- + agents/scsi/fence_scsi.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 8a1e4c77..5580e08b 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -192,8 +192,14 @@ def get_cluster_id(options): + + def get_node_id(options): + cmd = options["--corosync-cmap-path"] + " nodelist" ++ out = run_cmd(options, cmd)["out"] ++ ++ match = re.search(r".(\d+).name \(str\) = " + options["--plug"] + "\n", out) ++ ++ # try old format before failing ++ if not match: ++ match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", 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/bz1720198-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch b/SOURCES/bz1720198-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch new file mode 100644 index 0000000..010fc00 --- /dev/null +++ b/SOURCES/bz1720198-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/bz1732766-fence_aliyun-1-add-RAM-role.patch b/SOURCES/bz1732766-fence_aliyun-1-add-RAM-role.patch new file mode 100644 index 0000000..fd636fa --- /dev/null +++ b/SOURCES/bz1732766-fence_aliyun-1-add-RAM-role.patch @@ -0,0 +1,152 @@ +From 31548d184c977521dad5e6320c7a74ed732c19bb Mon Sep 17 00:00:00 2001 +From: dongchen126 <51401223+dongchen126@users.noreply.github.com> +Date: Thu, 11 Jul 2019 14:05:58 +0800 +Subject: [PATCH 1/4] Update fence_aliyun.py + +1.Import region provider to enable Alibaba cloud private zone functionality which support API endpoint access from intranet +2.Add ram role functionality to improve security which disable AccessKey ID and Access Key Secret +--- + agents/aliyun/fence_aliyun.py | 28 +++++++++++++++++++++------- + 1 file changed, 21 insertions(+), 7 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index d780e2ab..aea1ea8f 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -15,6 +15,7 @@ + from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest + from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest + from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest ++ from aliyunsdkcore.profile import region_provider + except ImportError: + pass + +@@ -121,12 +122,20 @@ def define_new_opts(): + "required" : "0", + "order" : 4 + } ++ all_opt["ram_role"] = { ++ "getopt": "m:", ++ "longopt": "ram-role", ++ "help": "-m, --ram-role=[name] Ram Role", ++ "shortdesc": "Ram Role.", ++ "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", "ram_role"] + + atexit.register(atexit_handler) + +@@ -144,13 +153,18 @@ def main(): + + run_delay(options) + +- if "--region" in options and "--access-key" in options and "--secret-key" in options: ++ if "--region" in options: + region = options["--region"] +- access_key = options["--access-key"] +- secret_key = options["--secret-key"] +- conn = client.AcsClient(access_key, secret_key, region) +- +- ++ if "--access-key" in options and "--secret-key" in options: ++ access_key = options["--access-key"] ++ secret_key = options["--secret-key"] ++ conn = client.AcsClient(access_key, secret_key, region) ++ elif "--ram-role" in options: ++ ram_role = options["--ram-role"] ++ role = EcsRamRoleCredential(ram_role) ++ conn = client.AcsClient(region_id=region, credential=role) ++ region_provider.modify_point('Ecs', region, 'ecs.%s.aliyuncs.com' % region) ++ + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) + +From 285d29d398bbf8f87da7acfde3f89f83b32fa586 Mon Sep 17 00:00:00 2001 +From: chen dong <51401223+dongchen126@users.noreply.github.com> +Date: Thu, 11 Jul 2019 15:30:10 +0800 +Subject: [PATCH 2/4] Update fence_aliyun.xml + +Add ram role for security +Add region provider for private zone functionality +--- + tests/data/metadata/fence_aliyun.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml +index b41d82bf..eecd6f4e 100644 +--- a/tests/data/metadata/fence_aliyun.xml ++++ b/tests/data/metadata/fence_aliyun.xml +@@ -33,6 +33,11 @@ + + Secret Key. + ++ ++ ++ ++ Ram Role. ++ + + + + +From d4de57fdb94eeee483988584086c5690c8967f76 Mon Sep 17 00:00:00 2001 +From: chen dong <51401223+dongchen126@users.noreply.github.com> +Date: Wed, 24 Jul 2019 17:23:48 +0800 +Subject: [PATCH 3/4] Update fence_aliyun.py +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +delet paramater “m” +--- + agents/aliyun/fence_aliyun.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index aea1ea8f..3bc825fe 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -123,9 +123,9 @@ def define_new_opts(): + "order" : 4 + } + all_opt["ram_role"] = { +- "getopt": "m:", ++ "getopt": ":", + "longopt": "ram-role", +- "help": "-m, --ram-role=[name] Ram Role", ++ "help": "--ram-role=[name] Ram Role", + "shortdesc": "Ram Role.", + "required": "0", + "order": 5 + +From 367c17ef4f44b6cce2d10f0a220b55b02d0d631e Mon Sep 17 00:00:00 2001 +From: chen dong <51401223+dongchen126@users.noreply.github.com> +Date: Wed, 24 Jul 2019 17:25:39 +0800 +Subject: [PATCH 4/4] Update fence_aliyun.xml + +delete "m" parameter +--- + tests/data/metadata/fence_aliyun.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml +index eecd6f4e..2de3a8aa 100644 +--- a/tests/data/metadata/fence_aliyun.xml ++++ b/tests/data/metadata/fence_aliyun.xml +@@ -34,7 +34,7 @@ + Secret Key. + + +- ++ + + Ram Role. + diff --git a/SOURCES/bz1732766-fence_aliyun-2-import-EcsRamRoleCredential.patch b/SOURCES/bz1732766-fence_aliyun-2-import-EcsRamRoleCredential.patch new file mode 100644 index 0000000..db4416d --- /dev/null +++ b/SOURCES/bz1732766-fence_aliyun-2-import-EcsRamRoleCredential.patch @@ -0,0 +1,39 @@ +From b5f1bd2a257ce868b6845d77abdfc741c19d4d3e Mon Sep 17 00:00:00 2001 +From: chen dong <51401223+dongchen126@users.noreply.github.com> +Date: Thu, 11 Jul 2019 15:30:10 +0800 +Subject: [PATCH] Update fence_aliyun.xml +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add ram role for security +Add region provider for private zone functionality + +Update fence_aliyun.py + +delet paramater “m” + +Update fence_aliyun.xml + +delete "m" parameter + +Update fence_aliyun.py + +add "EcsRamRoleCredential" class from aliyun SDK +--- + agents/aliyun/fence_aliyun.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index 3bc825fe..aa0b741d 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -10,7 +10,7 @@ + + try: + from aliyunsdkcore import client +- ++ from aliyunsdkcore.auth.credentials import EcsRamRoleCredential + from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest + from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest + from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest diff --git a/SOURCES/bz1732773-fence_vmware_rest-fix-keyerror-suspended-vms.patch b/SOURCES/bz1732773-fence_vmware_rest-fix-keyerror-suspended-vms.patch new file mode 100644 index 0000000..3c9af83 --- /dev/null +++ b/SOURCES/bz1732773-fence_vmware_rest-fix-keyerror-suspended-vms.patch @@ -0,0 +1,23 @@ +From 33a638ff624839d7fa2d409479c348abee57763e Mon Sep 17 00:00:00 2001 +From: dwannamaker-onr +Date: Tue, 25 Jun 2019 15:28:00 -0400 +Subject: [PATCH] Fixed issue with SUSPENDED VMs + +If any VMs in the vCenter are suspended, you get a KeyError because that state is not expected. This breaks list and monitor actions. +--- + 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 b544d385..53b4066d 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -8,7 +8,7 @@ + from fencing import * + from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS + +-state = {"POWERED_ON": "on", 'POWERED_OFF': "off"} ++state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"} + + def get_power_status(conn, options): + res = send_command(conn, "vcenter/vm?filter.names={}".format(options["--plug"]))["value"] diff --git a/SOURCES/bz1734811-fence_iloX_ssh-monitor-timeout-warning.patch b/SOURCES/bz1734811-fence_iloX_ssh-monitor-timeout-warning.patch new file mode 100644 index 0000000..ba26ed3 --- /dev/null +++ b/SOURCES/bz1734811-fence_iloX_ssh-monitor-timeout-warning.patch @@ -0,0 +1,25 @@ +From 7c1348d53aa8080f2fcfc344a2f4a2372739a62c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 6 Aug 2019 13:06:13 +0200 +Subject: [PATCH] fence_ilo_ssh*: add timeout warning in metadata/manpage + +--- + agents/ilo_ssh/fence_ilo_ssh.py | 5 ++++- + 5 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/agents/ilo_ssh/fence_ilo_ssh.py b/agents/ilo_ssh/fence_ilo_ssh.py +index 88f13d17..a27e3418 100644 +--- a/agents/ilo_ssh/fence_ilo_ssh.py ++++ b/agents/ilo_ssh/fence_ilo_ssh.py +@@ -51,7 +51,10 @@ def main(): + docs = {} + docs["shortdesc"] = "Fence agent for HP iLO over SSH" + docs["longdesc"] = "fence_ilo_ssh is a fence agent that connects to iLO device. It logs into \ +-device via ssh and reboot a specified outlet. " ++device via ssh and reboot a specified outlet.\ ++\n.P\n\ ++WARNING: The monitor-action is prone to timeouts. Use the fence_ilo-equivalent \ ++to avoid this issue." + docs["vendorurl"] = "http://www.hp.com" + docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"), + ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH"), diff --git a/SOURCES/bz1748443-fence_zvmip-python3-fixes.patch b/SOURCES/bz1748443-fence_zvmip-python3-fixes.patch new file mode 100644 index 0000000..90586aa --- /dev/null +++ b/SOURCES/bz1748443-fence_zvmip-python3-fixes.patch @@ -0,0 +1,43 @@ +From 2735a4ee096f87fda2e94029db7f059d7be28464 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 5 Sep 2019 10:28:18 +0200 +Subject: [PATCH] fence_zvmip: fix Python 3 issues + +--- + agents/zvm/fence_zvmip.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py +index 5fbe53e4..e6bb01d1 100644 +--- a/agents/zvm/fence_zvmip.py ++++ b/agents/zvm/fence_zvmip.py +@@ -37,7 +37,7 @@ def open_socket(options): + return conn + + def smapi_pack_string(string): +- return struct.pack("!i%ds" % (len(string)), len(string), string) ++ return struct.pack("!i%ds" % (len(string)), len(string), string.encode("UTF-8")) + + def prepare_smapi_command(options, smapi_function, additional_args): + packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"]) +@@ -126,7 +126,7 @@ def get_list_of_images(options, command, data_as_plug): + data = "" + + while True: +- read_data = conn.recv(1024, socket.MSG_WAITALL) ++ read_data = conn.recv(1024, socket.MSG_WAITALL).decode("UTF-8") + data += read_data + if array_len == len(data): + break +@@ -136,9 +136,9 @@ def get_list_of_images(options, command, data_as_plug): + + parsed_len = 0 + while parsed_len < array_len: +- string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4])[0] ++ string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4].encode("UTF-8"))[0] + parsed_len += INT4 +- image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len])[0] ++ image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len].encode("UTF-8"))[0].decode("UTF-8") + parsed_len += string_len + images.add(image_name) + diff --git a/SOURCES/bz1751704-fence_mpath-fix-watchdog-trigger-multipath-disconnect.patch b/SOURCES/bz1751704-fence_mpath-fix-watchdog-trigger-multipath-disconnect.patch new file mode 100644 index 0000000..8c804c2 --- /dev/null +++ b/SOURCES/bz1751704-fence_mpath-fix-watchdog-trigger-multipath-disconnect.patch @@ -0,0 +1,40 @@ +From 2df8abf25eddc8da71c193ca29f6be51e66b02f0 Mon Sep 17 00:00:00 2001 +From: Hideo Yamauchi +Date: Thu, 12 Sep 2019 08:44:49 +0900 +Subject: [PATCH] High: mpath: Correction of failure detection behavior from + watchdog service. + +--- + agents/mpath/fence_mpath.py | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index e4f59836..b17388eb 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -117,12 +117,14 @@ def get_reservation_key(options, dev): + match = re.search(r"\s+key\s*=\s*0x(\S+)\s+", out["out"], re.IGNORECASE) + return match.group(1) if match else None + +-def get_registration_keys(options, dev): ++def get_registration_keys(options, dev, fail=True): + keys = [] + cmd = options["--mpathpersist-path"] + " -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: +@@ -183,7 +185,7 @@ def mpath_check(hardreboot=False): + logging.error("No devices found") + return 0 + for dev, key in list(devs.items()): +- if key in get_registration_keys(options, dev): ++ if key in get_registration_keys(options, dev, fail=False): + logging.debug("key " + key + " registered with device " + dev) + return 0 + else: diff --git a/SOURCES/bz1753228-fence_mpath-1-add-plug-parameter-support.patch b/SOURCES/bz1753228-fence_mpath-1-add-plug-parameter-support.patch new file mode 100644 index 0000000..216f48c --- /dev/null +++ b/SOURCES/bz1753228-fence_mpath-1-add-plug-parameter-support.patch @@ -0,0 +1,197 @@ +From d866e11213ebeab8da280b41371a968ae12410bd Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 13 Sep 2019 12:48:46 +0200 +Subject: [PATCH] fence_mpath: use -n/--plug/port parameter to be able to use + pcmk_host_map + +--- + agents/mpath/fence_mpath.py | 63 +++++++++++++++++------------ + tests/data/metadata/fence_mpath.xml | 12 +++++- + 2 files changed, 49 insertions(+), 26 deletions(-) + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index e4f59836..dfc5657b 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -16,11 +16,11 @@ def get_status(conn, options): + status = "off" + for dev in options["devices"]: + is_block_device(dev) +- if options["--key"] in get_registration_keys(options, dev): ++ if options["--plug"] in get_registration_keys(options, dev): + status = "on" + else: + logging.debug("No registration for key "\ +- + options["--key"] + " on device " + dev + "\n") ++ + options["--plug"] + " on device " + dev + "\n") + + if options["--action"] == "monitor": + dev_read(options) +@@ -36,10 +36,10 @@ def set_status(conn, options): + is_block_device(dev) + + register_dev(options, dev) +- if options["--key"] not in get_registration_keys(options, dev): ++ if options["--plug"] not in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to register key "\ +- + options["--key"] + "on device " + dev + "\n") ++ + options["--plug"] + "on device " + dev + "\n") + continue + dev_write(options, dev) + +@@ -48,7 +48,7 @@ def set_status(conn, options): + and get_reservation_key(options, dev) is None: + count += 1 + logging.debug("Failed to create reservation (key="\ +- + options["--key"] + ", device=" + dev + ")\n") ++ + options["--plug"] + ", device=" + dev + ")\n") + + else: + dev_keys = dev_read(options) +@@ -56,14 +56,14 @@ def set_status(conn, options): + for dev in options["devices"]: + is_block_device(dev) + +- if options["--key"] in get_registration_keys(options, dev): ++ if options["--plug"] in get_registration_keys(options, dev): + preempt_abort(options, dev_keys[dev], dev) + + for dev in options["devices"]: +- if options["--key"] in get_registration_keys(options, dev): ++ if options["--plug"] in get_registration_keys(options, dev): + count += 1 + logging.debug("Failed to remove key "\ +- + options["--key"] + " on device " + dev + "\n") ++ + options["--plug"] + " on device " + dev + "\n") + continue + + if not get_reservation_key(options, dev): +@@ -97,16 +97,16 @@ def is_block_device(dev): + + # cancel registration + def preempt_abort(options, host, dev): +- cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--key"] +" -d " + dev ++ cmd = options["--mpathpersist-path"] + " -o --preempt-abort --prout-type=5 --param-rk=" + host +" --param-sark=" + options["--plug"] +" -d " + dev + return not bool(run_cmd(options, cmd)["err"]) + + def register_dev(options, dev): +- cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--key"] + " -d " + dev ++ cmd = options["--mpathpersist-path"] + " -o --register --param-sark=" + options["--plug"] + " -d " + dev + #cmd return code != 0 but registration can be successful + return not bool(run_cmd(options, cmd)["err"]) + + def reserve_dev(options, dev): +- cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--key"] + " -d " + dev ++ cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--plug"] + " -d " + dev + return not bool(run_cmd(options, cmd)["err"]) + + def get_reservation_key(options, dev): +@@ -141,7 +141,7 @@ def dev_write(options, dev): + fail_usage("Failed: Cannot open file \""+ file_path + "\"") + out = store_fh.read() + if not re.search(r"^" + dev + r"\s+", out): +- store_fh.write(dev + "\t" + options["--key"] + "\n") ++ store_fh.write(dev + "\t" + options["--plug"] + "\n") + store_fh.close() + + def dev_read(options, fail=True): +@@ -209,12 +209,9 @@ def define_new_opts(): + all_opt["key"] = { + "getopt" : "k:", + "longopt" : "key", +- "help" : "-k, --key=[key] Key to use for the current operation", +- "required" : "1", +- "shortdesc" : "Key to use for the current operation. This key should be \ +-unique to a node and have to be written in /etc/multipath.conf. For the \"on\" action, the key specifies the key use to \ +-register the local node. For the \"off\" action, this key specifies the key to \ +-be removed from the device(s).", ++ "help" : "-k, --key=[key] Replaced by -n, --plug", ++ "required" : "0", ++ "shortdesc" : "Replaced by -n, --plug", + "order": 1 + } + all_opt["mpathpersist_path"] = { +@@ -240,10 +237,18 @@ def main(): + atexit.register(atexit_handler) + + device_opt = ["no_login", "no_password", "devices", "key", "sudo", \ +- "fabric_fencing", "on_target", "store_path", "mpathpersist_path", "force_on"] ++ "fabric_fencing", "on_target", "store_path", \ ++ "mpathpersist_path", "force_on", "port", "no_port"] + + define_new_opts() + ++ all_opt["port"]["help"] = "Key to use for the current operation" ++ all_opt["port"]["shortdesc"] = "Key to use for the current operation. \ ++This key should be unique to a node and have to be written in \ ++/etc/multipath.conf. For the \"on\" action, the key specifies the key use to \ ++register the local node. For the \"off\" action, this key specifies the key to \ ++be removed from the device(s)." ++ + # fence_mpath_check + if os.path.basename(sys.argv[0]) == "fence_mpath_check": + sys.exit(mpath_check()) +@@ -252,6 +257,17 @@ def main(): + + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + ++ # hack to remove list/list-status actions which are not supported ++ options["device_opt"] = [ o for o in options["device_opt"] if o != "separator" ] ++ ++ # workaround to avoid regressions ++ if "--key" in options: ++ options["--plug"] = options["--key"] ++ del options["--key"] ++ elif options["--action"] in ["off", "on", "reboot", "status"] \ ++ and "--plug" not in options: ++ fail_usage("Failed: You have to enter plug number or machine identification", stop) ++ + docs = {} + docs["shortdesc"] = "Fence agent for multipath persistent reservation" + docs["longdesc"] = "fence_mpath is an I/O fencing agent that uses SCSI-3 \ +@@ -271,16 +287,13 @@ def main(): + run_delay(options) + + # Input control BEGIN +- if not "--key" in options: +- fail_usage("Failed: key is required") +- + if options["--action"] == "validate-all": + sys.exit(0) + +- options["devices"] = options["--devices"].split(",") +- +- if not options["devices"]: ++ if not ("--devices" in options and options["--devices"]): + fail_usage("Failed: No devices found") ++ ++ options["devices"] = options["--devices"].split(",") + # Input control END + + result = fence_action(None, options, set_status, get_status) +diff --git a/tests/data/metadata/fence_mpath.xml b/tests/data/metadata/fence_mpath.xml +index bbe9ad2b..fe9378df 100644 +--- a/tests/data/metadata/fence_mpath.xml ++++ b/tests/data/metadata/fence_mpath.xml +@@ -14,9 +14,19 @@ The fence_mpath agent works by having a unique key for each node that has to be + + List of devices to use for current operation. Devices can be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). Each device must support SCSI-3 persistent reservations. + +- ++ + + ++ Replaced by -n, --plug ++ ++ ++ ++ ++ Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s). ++ ++ ++ ++ + Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s). + + diff --git a/SOURCES/bz1753228-fence_mpath-2-fix-plug-parameter-issues.patch b/SOURCES/bz1753228-fence_mpath-2-fix-plug-parameter-issues.patch new file mode 100644 index 0000000..d668e27 --- /dev/null +++ b/SOURCES/bz1753228-fence_mpath-2-fix-plug-parameter-issues.patch @@ -0,0 +1,73 @@ +From 868c494d17952eecc6736683c6df04aa9d3a3199 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 20 Sep 2019 12:06:55 +0200 +Subject: [PATCH] fence_mpath: fix fail_usage() issue and a couple of other + minor issues w/the newly added plug/port parameter + +--- + agents/mpath/fence_mpath.py | 12 +++++++----- + tests/data/metadata/fence_mpath.xml | 10 +++++----- + 2 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index 25aeb052..73517851 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -213,7 +213,7 @@ def define_new_opts(): + "longopt" : "key", + "help" : "-k, --key=[key] Replaced by -n, --plug", + "required" : "0", +- "shortdesc" : "Replaced by -n, --plug", ++ "shortdesc" : "Replaced by port/-n/--plug", + "order": 1 + } + all_opt["mpathpersist_path"] = { +@@ -244,7 +244,8 @@ def main(): + + define_new_opts() + +- all_opt["port"]["help"] = "Key to use for the current operation" ++ all_opt["port"]["required"] = "0" ++ all_opt["port"]["help"] = "-n, --plug=[key] Key to use for the current operation" + all_opt["port"]["shortdesc"] = "Key to use for the current operation. \ + This key should be unique to a node and have to be written in \ + /etc/multipath.conf. For the \"on\" action, the key specifies the key use to \ +@@ -266,9 +267,10 @@ def main(): + if "--key" in options: + options["--plug"] = options["--key"] + del options["--key"] +- elif options["--action"] in ["off", "on", "reboot", "status"] \ +- and "--plug" not in options: +- fail_usage("Failed: You have to enter plug number or machine identification", stop) ++ elif "--help" not in options and options["--action"] in ["off", "on", \ ++ "reboot", "status", "validate-all"] and "--plug" not in options: ++ stop_after_error = False if options["--action"] == "validate-all" else True ++ fail_usage("Failed: You have to enter plug number or machine identification", stop_after_error) + + docs = {} + docs["shortdesc"] = "Fence agent for multipath persistent reservation" +diff --git a/tests/data/metadata/fence_mpath.xml b/tests/data/metadata/fence_mpath.xml +index fe9378df..f5e60823 100644 +--- a/tests/data/metadata/fence_mpath.xml ++++ b/tests/data/metadata/fence_mpath.xml +@@ -17,15 +17,15 @@ The fence_mpath agent works by having a unique key for each node that has to be + + + +- Replaced by -n, --plug ++ Replaced by port/-n/--plug + +- +- ++ ++ + + Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s). + +- +- ++ ++ + + Key to use for the current operation. This key should be unique to a node and have to be written in /etc/multipath.conf. For the "on" action, the key specifies the key use to register the local node. For the "off" action, this key specifies the key to be removed from the device(s). + diff --git a/SOURCES/bz1760201-fence_compute-fence_evacuate-1-fix-region_name-type.patch b/SOURCES/bz1760201-fence_compute-fence_evacuate-1-fix-region_name-type.patch new file mode 100644 index 0000000..2d8ba1c --- /dev/null +++ b/SOURCES/bz1760201-fence_compute-fence_evacuate-1-fix-region_name-type.patch @@ -0,0 +1,66 @@ +From 32d2aa2cea22bb38fc3eeded1f6682daad097908 Mon Sep 17 00:00:00 2001 +From: Gauvain Pocentek +Date: Tue, 13 Aug 2019 20:11:21 +0200 +Subject: [PATCH] Fix argument parsing for region_name + +The region_name attribute for fence_compute and fence_evacuate is not a boolean +and should expect a string argument. +--- + agents/compute/fence_compute.py | 2 +- + agents/evacuate/fence_evacuate.py | 2 +- + tests/data/metadata/fence_compute.xml | 2 +- + tests/data/metadata/fence_evacuate.xml | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index 0e6c8044..a94bdc46 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -381,7 +381,7 @@ def define_new_opts(): + "order": 1, + } + all_opt["region_name"] = { +- "getopt" : "", ++ "getopt" : ":", + "longopt" : "region-name", + "help" : "--region-name=[region] Region Name", + "required" : "0", +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 2b9af273..76e78b87 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -318,7 +318,7 @@ def define_new_opts(): + "order": 1, + } + all_opt["region_name"] = { +- "getopt" : "", ++ "getopt" : ":", + "longopt" : "region-name", + "help" : "--region-name=[region] Region Name", + "required" : "0", +diff --git a/tests/data/metadata/fence_compute.xml b/tests/data/metadata/fence_compute.xml +index 1dcbfc54..abc276ca 100644 +--- a/tests/data/metadata/fence_compute.xml ++++ b/tests/data/metadata/fence_compute.xml +@@ -55,7 +55,7 @@ + + + +- ++ + Region Name + + +diff --git a/tests/data/metadata/fence_evacuate.xml b/tests/data/metadata/fence_evacuate.xml +index 4f1f6a58..7decb05c 100644 +--- a/tests/data/metadata/fence_evacuate.xml ++++ b/tests/data/metadata/fence_evacuate.xml +@@ -55,7 +55,7 @@ + + + +- ++ + Region Name + + diff --git a/SOURCES/bz1760201-fence_compute-fence_evacuate-2-fix-project-shortopt.patch b/SOURCES/bz1760201-fence_compute-fence_evacuate-2-fix-project-shortopt.patch new file mode 100644 index 0000000..1458956 --- /dev/null +++ b/SOURCES/bz1760201-fence_compute-fence_evacuate-2-fix-project-shortopt.patch @@ -0,0 +1,77 @@ +From 708d0a8e4e45d4f4a6bee67f0a9ebc0ff573e1ff Mon Sep 17 00:00:00 2001 +From: Kumabuchi Kenji +Date: Fri, 25 Oct 2019 16:34:40 +0900 +Subject: [PATCH] fix shortopt in fence-compute / fence_evacuate help messages + +Signed-off-by: Kumabuchi Kenji +--- + agents/compute/fence_compute.py | 2 +- + agents/evacuate/fence_evacuate.py | 2 +- + tests/data/metadata/fence_compute.xml | 4 ++-- + tests/data/metadata/fence_evacuate.xml | 4 ++-- + 4 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index c08a9dbe..d0e012e6 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -365,7 +365,7 @@ def define_new_opts(): + all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", +- "help" : "-d, --project-domain=[name] Keystone v3 Project Domain", ++ "help" : "-P, --project-domain=[name] Keystone v3 Project Domain", + "required" : "0", + "shortdesc" : "Keystone v3 Project Domain", + "default" : "Default", +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 76e78b87..60bb130e 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -302,7 +302,7 @@ def define_new_opts(): + all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", +- "help" : "-d, --project-domain=[name] Keystone v3 Project Domain", ++ "help" : "-P, --project-domain=[name] Keystone v3 Project Domain", + "required" : "0", + "shortdesc" : "Keystone v3 Project Domain", + "default" : "Default", +diff --git a/tests/data/metadata/fence_compute.xml b/tests/data/metadata/fence_compute.xml +index abc276ca..99d56af0 100644 +--- a/tests/data/metadata/fence_compute.xml ++++ b/tests/data/metadata/fence_compute.xml +@@ -74,12 +74,12 @@ + Allow Insecure TLS Requests + + +- ++ + + Keystone v3 Project Domain + + +- ++ + + Keystone v3 Project Domain + +diff --git a/tests/data/metadata/fence_evacuate.xml b/tests/data/metadata/fence_evacuate.xml +index 7decb05c..8c720b80 100644 +--- a/tests/data/metadata/fence_evacuate.xml ++++ b/tests/data/metadata/fence_evacuate.xml +@@ -74,12 +74,12 @@ + Allow Insecure TLS Requests + + +- ++ + + Keystone v3 Project Domain + + +- ++ + + Keystone v3 Project Domain + diff --git a/SOURCES/bz1760213-fence_compute-disable-service-after-force-down.patch b/SOURCES/bz1760213-fence_compute-disable-service-after-force-down.patch new file mode 100644 index 0000000..a8161d1 --- /dev/null +++ b/SOURCES/bz1760213-fence_compute-disable-service-after-force-down.patch @@ -0,0 +1,42 @@ +From 099758a41bbb153c4a13a89de57cdcb72e1f1ea7 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Fri, 11 Oct 2019 10:39:53 +0200 +Subject: [PATCH] fence_compute: Invert the force-down/service disable order + +In OpenStack Train we first observed that IHA was not working via +https://bugzilla.redhat.com/show_bug.cgi?id=1760213 + +The reason for this is that nova has made the disabling of the compute +service depend on the compute node being up via: +https://review.opendev.org/#/c/654596/ + +By first calling force-down, the subsequence service-disable API +call won't wait for the reachability of the compute node any +longer and the whole operation has the same outcome. + +Tested this on an OSP Train environment and we correctly +got Instance HA working again and we observed the VMs being +restarted on the available compute nodes. + +Co-Authored-By: Luca Miccini +--- + agents/compute/fence_compute.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index a94bdc46..c08a9dbe 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -117,11 +117,11 @@ def set_power_status_off(connection, options): + if status in [ "off" ]: + return + +- connection.services.disable(options["--plug"], 'nova-compute') + try: + # Until 2.53 + connection.services.force_down( + options["--plug"], "nova-compute", force_down=True) ++ connection.services.disable(options["--plug"], 'nova-compute') + except Exception as e: + # Something went wrong when we tried to force the host down. + # That could come from either an incompatible API version diff --git a/SOURCES/bz1760224-fence_vmware_rest-improve-logging.patch b/SOURCES/bz1760224-fence_vmware_rest-improve-logging.patch new file mode 100644 index 0000000..9b39fa6 --- /dev/null +++ b/SOURCES/bz1760224-fence_vmware_rest-improve-logging.patch @@ -0,0 +1,61 @@ +From a128c296c18faa1b58c3f067370bde64e7c49dae Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 9 Oct 2019 14:35:48 +0200 +Subject: [PATCH] fence_vmware_rest: improve logging + +--- + agents/vmware_rest/fence_vmware_rest.py | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py +index 53b4066d..cd99b4ac 100644 +--- a/agents/vmware_rest/fence_vmware_rest.py ++++ b/agents/vmware_rest/fence_vmware_rest.py +@@ -11,7 +11,11 @@ + state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"} + + def get_power_status(conn, options): +- res = send_command(conn, "vcenter/vm?filter.names={}".format(options["--plug"]))["value"] ++ try: ++ res = send_command(conn, "vcenter/vm?filter.names={}".format(options["--plug"]))["value"] ++ except Exception as e: ++ logging.debug("Failed: {}".format(e)) ++ fail(EC_STATUS) + + if len(res) == 0: + fail(EC_STATUS) +@@ -28,12 +32,20 @@ def set_power_status(conn, options): + "off" : "stop" + }[options["--action"]] + +- send_command(conn, "vcenter/vm/{}/power/{}".format(options["id"], action), "POST") ++ try: ++ send_command(conn, "vcenter/vm/{}/power/{}".format(options["id"], action), "POST") ++ except Exception as e: ++ logging.debug("Failed: {}".format(e)) ++ fail(EC_STATUS) + + def get_list(conn, options): + outlets = {} + +- res = send_command(conn, "vcenter/vm") ++ try: ++ res = send_command(conn, "vcenter/vm") ++ except: ++ logging.debug("Failed: {}".format(e)) ++ fail(EC_STATUS) + + for r in res["value"]: + outlets[r["name"]] = ("", state[r["power_state"]]) +@@ -87,7 +99,10 @@ def connect(opt): + return conn + + def disconnect(conn): +- send_command(conn, "com/vmware/cis/session", "DELETE") ++ try: ++ send_command(conn, "com/vmware/cis/session", "DELETE") ++ except Exception as e: ++ logging.debug("Failed: {}".format(e)) + conn.close() + + def send_command(conn, command, method="GET"): diff --git a/SOURCES/bz1763674-fence_rhevm-add-cookie-support.patch b/SOURCES/bz1763674-fence_rhevm-add-cookie-support.patch new file mode 100644 index 0000000..d4f7be9 --- /dev/null +++ b/SOURCES/bz1763674-fence_rhevm-add-cookie-support.patch @@ -0,0 +1,109 @@ +From b885e0f65af626154096a49554e9765e18bfbbd9 Mon Sep 17 00:00:00 2001 +From: Frank Toth +Date: Wed, 16 Oct 2019 13:58:50 +0800 +Subject: [PATCH 1/3] Added cookie file management to properly reuse session + and do not create new one every time. + +--- + agents/rhevm/fence_rhevm.py | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index 9e4650cd..defa35e6 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -117,7 +117,12 @@ def send_command(opt, command, method="GET"): + conn.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) + conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"]) + if "--use-cookies" in opt: +- conn.setopt(pycurl.COOKIEFILE, "") ++ if "--cookie-file" in opt: ++ cookie_file = opt["--cookie-file"] ++ else: ++ cookie_file = "/tmp/fence_rhevm_" + opt["--ip"] + "_" + opt["--username"] + "_cookie.dat" ++ conn.setopt(pycurl.COOKIEFILE, cookie_file) ++ conn.setopt(pycurl.COOKIEJAR, cookie_file) + + conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) + if "--ssl" in opt or "--ssl-secure" in opt: +@@ -166,6 +171,14 @@ def define_new_opts(): + "required" : "0", + "shortdesc" : "Reuse cookies for authentication", + "order" : 1} ++ all_opt["cookie_file"] = { ++ "getopt" : ":", ++ "longopt" : "cookie-file", ++ "help" : "--cookie-file Path to cookie file for authentication\n" ++ "\t\t\t\t (Default: /tmp/fence_rhevm_ip_username_cookie.dat)", ++ "required" : "0", ++ "shortdesc" : "Path to cookie file for authentication", ++ "order" : 2} + all_opt["api_version"] = { + "getopt" : ":", + "longopt" : "api-version", + +From 874344acbfee5f774b320e384a46e1ce953a34ce Mon Sep 17 00:00:00 2001 +From: Frank Toth +Date: Wed, 16 Oct 2019 23:41:50 +0800 +Subject: [PATCH 2/3] Added cookie_file to device_opt array. Use + tempfile.gettempdir() to get the TMP dir instead of hardcoded /tmp + +--- + agents/rhevm/fence_rhevm.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index defa35e6..25aecbe5 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -4,6 +4,7 @@ + import pycurl, io + import logging + import atexit ++import tempfile + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * + from fencing import fail, EC_FETCH_VM_UUID, run_delay +@@ -120,7 +121,7 @@ def send_command(opt, command, method="GET"): + if "--cookie-file" in opt: + cookie_file = opt["--cookie-file"] + else: +- cookie_file = "/tmp/fence_rhevm_" + opt["--ip"] + "_" + opt["--username"] + "_cookie.dat" ++ cookie_file = tempfile.gettempdir() + "/fence_rhevm_" + opt["--ip"] + "_" + opt["--username"] + "_cookie.dat" + conn.setopt(pycurl.COOKIEFILE, cookie_file) + conn.setopt(pycurl.COOKIEJAR, cookie_file) + +@@ -215,6 +216,7 @@ def main(): + "web", + "port", + "use_cookies", ++ "cookie_file", + "api_version", + "api_path", + "disable_http_filter", + +From 196513cfc0edfd28f483a00b4adfa230b666a47d Mon Sep 17 00:00:00 2001 +From: Frank Toth +Date: Fri, 18 Oct 2019 05:16:18 +0200 +Subject: [PATCH 3/3] After 'make xml-upload' + +--- + tests/data/metadata/fence_rhevm.xml | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/tests/data/metadata/fence_rhevm.xml b/tests/data/metadata/fence_rhevm.xml +index c56cf64b..2b6b02b2 100644 +--- a/tests/data/metadata/fence_rhevm.xml ++++ b/tests/data/metadata/fence_rhevm.xml +@@ -103,6 +103,11 @@ + + Version of RHEV API (default: auto) + ++ ++ ++ ++ Path to cookie file for authentication ++ + + + The path part of the API URL diff --git a/SOURCES/bz1769783-fencing-improve-stdin-quote-parsing.patch b/SOURCES/bz1769783-fencing-improve-stdin-quote-parsing.patch new file mode 100644 index 0000000..adf0754 --- /dev/null +++ b/SOURCES/bz1769783-fencing-improve-stdin-quote-parsing.patch @@ -0,0 +1,23 @@ +From 82626dbdb12519e95a5df70ae6ae21bc17112f43 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 13 Feb 2019 13:28:25 +0100 +Subject: [PATCH] fencing: improve stdin parse function + +- Remove quotes around stdin parameters for consistency with CLI +parameters and to be able to quote number and time parameters +--- + lib/fencing.py.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/fencing.py.py b/lib/fencing.py.py +index 287cd01f..8cd0a813 100644 +--- a/lib/fencing.py.py ++++ b/lib/fencing.py.py +@@ -1389,6 +1389,7 @@ def _parse_input_stdin(avail_opt): + + (name, value) = (line + "=").split("=", 1) + value = value[:-1] ++ value = re.sub("^\"(.*)\"$", "\\1", value) + + if name.replace("-", "_") in mapping_longopt_names: + name = mapping_longopt_names[name.replace("-", "_")] diff --git a/SOURCES/bz1771594-1-fencing-inetX_only-SSH-fence_zvmip.patch b/SOURCES/bz1771594-1-fencing-inetX_only-SSH-fence_zvmip.patch new file mode 100644 index 0000000..6ee722d --- /dev/null +++ b/SOURCES/bz1771594-1-fencing-inetX_only-SSH-fence_zvmip.patch @@ -0,0 +1,756 @@ +From cecf3b3edeccbac6293b95073b0c0ad4f02a8652 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 12 Nov 2019 17:25:57 +0100 +Subject: [PATCH] fencing: only use inetX_only parameters for SSH based agents + and fence_zvmip, and fixed syntax issue for Gawk v5+ + +--- + agents/zvm/fence_zvmip.py | 2 +- + lib/fencing.py.py | 4 ++-- + make/agentpycheck.mk | 2 +- + tests/data/metadata/fence_amt.xml | 10 ---------- + tests/data/metadata/fence_amt_ws.xml | 10 ---------- + tests/data/metadata/fence_apc_snmp.xml | 10 ---------- + tests/data/metadata/fence_cisco_mds.xml | 10 ---------- + tests/data/metadata/fence_cisco_ucs.xml | 10 ---------- + tests/data/metadata/fence_docker.xml | 10 ---------- + tests/data/metadata/fence_drac.xml | 10 ---------- + tests/data/metadata/fence_eaton_snmp.xml | 10 ---------- + tests/data/metadata/fence_emerson.xml | 10 ---------- + tests/data/metadata/fence_eps.xml | 10 ---------- + tests/data/metadata/fence_ibmblade.xml | 10 ---------- + tests/data/metadata/fence_idrac.xml | 10 ---------- + tests/data/metadata/fence_ifmib.xml | 10 ---------- + tests/data/metadata/fence_ilo.xml | 10 ---------- + tests/data/metadata/fence_ilo2.xml | 10 ---------- + tests/data/metadata/fence_ilo3.xml | 10 ---------- + tests/data/metadata/fence_ilo4.xml | 10 ---------- + tests/data/metadata/fence_imm.xml | 10 ---------- + tests/data/metadata/fence_intelmodular.xml | 10 ---------- + tests/data/metadata/fence_ipdu.xml | 10 ---------- + tests/data/metadata/fence_ipmilan.xml | 10 ---------- + tests/data/metadata/fence_netio.xml | 10 ---------- + tests/data/metadata/fence_powerman.xml | 10 ---------- + tests/data/metadata/fence_pve.xml | 10 ---------- + tests/data/metadata/fence_raritan.xml | 10 ---------- + tests/data/metadata/fence_redfish.xml | 10 ---------- + tests/data/metadata/fence_rhevm.xml | 10 ---------- + tests/data/metadata/fence_sanbox2.xml | 10 ---------- + tests/data/metadata/fence_tripplite_snmp.xml | 10 ---------- + tests/data/metadata/fence_vmware_rest.xml | 10 ---------- + tests/data/metadata/fence_vmware_soap.xml | 10 ---------- + tests/data/metadata/fence_vmware_vcloud.xml | 10 ---------- + 36 files changed, 4 insertions(+), 334 deletions(-) + +diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py +index e6bb01d1..5b272bb9 100644 +--- a/agents/zvm/fence_zvmip.py ++++ b/agents/zvm/fence_zvmip.py +@@ -146,7 +146,7 @@ def get_list_of_images(options, command, data_as_plug): + return (return_code, reason_code, images) + + def main(): +- device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off"] ++ device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off", "inet4_only", "inet6_only"] + + atexit.register(atexit_handler) + +diff --git a/lib/fencing.py.py b/lib/fencing.py.py +index 2a0b0b91..4b54aa7c 100644 +--- a/lib/fencing.py.py ++++ b/lib/fencing.py.py +@@ -459,9 +459,9 @@ + "delay", "quiet"], + "passwd" : ["passwd_script"], + "sudo" : ["sudo_path"], +- "secure" : ["identity_file", "ssh_options", "ssh_path"], ++ "secure" : ["identity_file", "ssh_options", "ssh_path", "inet4_only", "inet6_only"], + "telnet" : ["telnet_path"], +- "ipaddr" : ["ipport", "inet4_only", "inet6_only"], ++ "ipaddr" : ["ipport"], + "port" : ["separator"], + "ssl" : ["ssl_secure", "ssl_insecure", "gnutlscli_path"], + "snmp" : ["snmp_auth_prot", "snmp_sec_level", "snmp_priv_prot", \ +diff --git a/make/agentpycheck.mk b/make/agentpycheck.mk +index 58122c65..13482bf2 100644 +--- a/make/agentpycheck.mk ++++ b/make/agentpycheck.mk +@@ -1,5 +1,5 @@ + DATADIR:=$(abs_top_srcdir)/tests/data/metadata +-AWK_VAL='BEGIN {store=-1} /name=\".*_path\"/ {store=2} {if (store!=0) {print}; store--}' ++AWK_VAL='BEGIN {store=-1} /name=".*_path"/ {store=2} {if (store!=0) {print}; store--}' + + TEST_TARGET=$(filter-out $(TEST_TARGET_SKIP),$(TARGET)) + +diff --git a/tests/data/metadata/fence_amt.xml b/tests/data/metadata/fence_amt.xml +index c1e24db9..5f0adc98 100644 +--- a/tests/data/metadata/fence_amt.xml ++++ b/tests/data/metadata/fence_amt.xml +@@ -19,16 +19,6 @@ + + Change the default boot behavior of the machine. + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_amt_ws.xml b/tests/data/metadata/fence_amt_ws.xml +index 07c22db3..86f36f6c 100644 +--- a/tests/data/metadata/fence_amt_ws.xml ++++ b/tests/data/metadata/fence_amt_ws.xml +@@ -19,16 +19,6 @@ + + Change the default boot behavior of the machine. + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_apc_snmp.xml b/tests/data/metadata/fence_apc_snmp.xml +index 26661d6a..7f1c616c 100644 +--- a/tests/data/metadata/fence_apc_snmp.xml ++++ b/tests/data/metadata/fence_apc_snmp.xml +@@ -14,16 +14,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_cisco_mds.xml b/tests/data/metadata/fence_cisco_mds.xml +index 1917595e..15d7798c 100644 +--- a/tests/data/metadata/fence_cisco_mds.xml ++++ b/tests/data/metadata/fence_cisco_mds.xml +@@ -13,16 +13,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_cisco_ucs.xml b/tests/data/metadata/fence_cisco_ucs.xml +index 40581da7..848e72f8 100644 +--- a/tests/data/metadata/fence_cisco_ucs.xml ++++ b/tests/data/metadata/fence_cisco_ucs.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_docker.xml b/tests/data/metadata/fence_docker.xml +index fdd6324c..3285314c 100644 +--- a/tests/data/metadata/fence_docker.xml ++++ b/tests/data/metadata/fence_docker.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_drac.xml b/tests/data/metadata/fence_drac.xml +index 405d660a..2184ee0c 100644 +--- a/tests/data/metadata/fence_drac.xml ++++ b/tests/data/metadata/fence_drac.xml +@@ -18,16 +18,6 @@ + + Force Python regex for command prompt + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_eaton_snmp.xml b/tests/data/metadata/fence_eaton_snmp.xml +index 33957ed1..3dd92dd2 100644 +--- a/tests/data/metadata/fence_eaton_snmp.xml ++++ b/tests/data/metadata/fence_eaton_snmp.xml +@@ -13,16 +13,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_emerson.xml b/tests/data/metadata/fence_emerson.xml +index 87205c1b..f6886469 100644 +--- a/tests/data/metadata/fence_emerson.xml ++++ b/tests/data/metadata/fence_emerson.xml +@@ -13,16 +13,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_eps.xml b/tests/data/metadata/fence_eps.xml +index 68d8fb69..26e75477 100644 +--- a/tests/data/metadata/fence_eps.xml ++++ b/tests/data/metadata/fence_eps.xml +@@ -15,16 +15,6 @@ Agent basically works by connecting to hidden page and pass appropriate argument + + Name of hidden page + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ibmblade.xml b/tests/data/metadata/fence_ibmblade.xml +index eff551f6..5084b3a0 100644 +--- a/tests/data/metadata/fence_ibmblade.xml ++++ b/tests/data/metadata/fence_ibmblade.xml +@@ -13,16 +13,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_idrac.xml b/tests/data/metadata/fence_idrac.xml +index f4588b35..55d9ced3 100644 +--- a/tests/data/metadata/fence_idrac.xml ++++ b/tests/data/metadata/fence_idrac.xml +@@ -32,16 +32,6 @@ + + Hexadecimal-encoded Kg key for IPMIv2 authentication + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ifmib.xml b/tests/data/metadata/fence_ifmib.xml +index b5f3b1d4..c07a6e1f 100644 +--- a/tests/data/metadata/fence_ifmib.xml ++++ b/tests/data/metadata/fence_ifmib.xml +@@ -15,16 +15,6 @@ It was written with managed ethernet switches in mind, in order to fence iSCSI S + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ilo.xml b/tests/data/metadata/fence_ilo.xml +index eb2e7a72..44b3c43a 100644 +--- a/tests/data/metadata/fence_ilo.xml ++++ b/tests/data/metadata/fence_ilo.xml +@@ -9,16 +9,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ilo2.xml b/tests/data/metadata/fence_ilo2.xml +index b14aa2fb..e9cae6d2 100644 +--- a/tests/data/metadata/fence_ilo2.xml ++++ b/tests/data/metadata/fence_ilo2.xml +@@ -9,16 +9,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ilo3.xml b/tests/data/metadata/fence_ilo3.xml +index deaeaaf0..2a99e0a4 100644 +--- a/tests/data/metadata/fence_ilo3.xml ++++ b/tests/data/metadata/fence_ilo3.xml +@@ -32,16 +32,6 @@ + + Hexadecimal-encoded Kg key for IPMIv2 authentication + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ilo4.xml b/tests/data/metadata/fence_ilo4.xml +index bbf0833b..68790266 100644 +--- a/tests/data/metadata/fence_ilo4.xml ++++ b/tests/data/metadata/fence_ilo4.xml +@@ -32,16 +32,6 @@ + + Hexadecimal-encoded Kg key for IPMIv2 authentication + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_imm.xml b/tests/data/metadata/fence_imm.xml +index 22cb54e7..e22e4723 100644 +--- a/tests/data/metadata/fence_imm.xml ++++ b/tests/data/metadata/fence_imm.xml +@@ -32,16 +32,6 @@ + + Hexadecimal-encoded Kg key for IPMIv2 authentication + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_intelmodular.xml b/tests/data/metadata/fence_intelmodular.xml +index 4f2e8c49..5e0d3b19 100644 +--- a/tests/data/metadata/fence_intelmodular.xml ++++ b/tests/data/metadata/fence_intelmodular.xml +@@ -15,16 +15,6 @@ Note: Since firmware update version 2.7, SNMP v2 write support is removed, and r + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ipdu.xml b/tests/data/metadata/fence_ipdu.xml +index 0b615852..546e372c 100644 +--- a/tests/data/metadata/fence_ipdu.xml ++++ b/tests/data/metadata/fence_ipdu.xml +@@ -13,16 +13,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_ipmilan.xml b/tests/data/metadata/fence_ipmilan.xml +index b9ce66f8..3e13d288 100644 +--- a/tests/data/metadata/fence_ipmilan.xml ++++ b/tests/data/metadata/fence_ipmilan.xml +@@ -32,16 +32,6 @@ + + Hexadecimal-encoded Kg key for IPMIv2 authentication + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_netio.xml b/tests/data/metadata/fence_netio.xml +index e6350ed4..79d27af3 100644 +--- a/tests/data/metadata/fence_netio.xml ++++ b/tests/data/metadata/fence_netio.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_powerman.xml b/tests/data/metadata/fence_powerman.xml +index f0499d86..ce72e002 100644 +--- a/tests/data/metadata/fence_powerman.xml ++++ b/tests/data/metadata/fence_powerman.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_pve.xml b/tests/data/metadata/fence_pve.xml +index b727a7e8..5d744903 100644 +--- a/tests/data/metadata/fence_pve.xml ++++ b/tests/data/metadata/fence_pve.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_raritan.xml b/tests/data/metadata/fence_raritan.xml +index c75783fd..565eebc7 100644 +--- a/tests/data/metadata/fence_raritan.xml ++++ b/tests/data/metadata/fence_raritan.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml +index e1c18584..91b483b7 100644 +--- a/tests/data/metadata/fence_redfish.xml ++++ b/tests/data/metadata/fence_redfish.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_rhevm.xml b/tests/data/metadata/fence_rhevm.xml +index 2b6b02b2..73c9906f 100644 +--- a/tests/data/metadata/fence_rhevm.xml ++++ b/tests/data/metadata/fence_rhevm.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_sanbox2.xml b/tests/data/metadata/fence_sanbox2.xml +index 9832841e..7e20c8ce 100644 +--- a/tests/data/metadata/fence_sanbox2.xml ++++ b/tests/data/metadata/fence_sanbox2.xml +@@ -18,16 +18,6 @@ + + Force Python regex for command prompt + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_tripplite_snmp.xml b/tests/data/metadata/fence_tripplite_snmp.xml +index 22d3db5d..d3769133 100644 +--- a/tests/data/metadata/fence_tripplite_snmp.xml ++++ b/tests/data/metadata/fence_tripplite_snmp.xml +@@ -14,16 +14,6 @@ + + Set the community string + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_vmware_rest.xml b/tests/data/metadata/fence_vmware_rest.xml +index 1e1f790f..5b497a6a 100644 +--- a/tests/data/metadata/fence_vmware_rest.xml ++++ b/tests/data/metadata/fence_vmware_rest.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_vmware_soap.xml b/tests/data/metadata/fence_vmware_soap.xml +index 46d29116..da6a1002 100644 +--- a/tests/data/metadata/fence_vmware_soap.xml ++++ b/tests/data/metadata/fence_vmware_soap.xml +@@ -10,16 +10,6 @@ Name of virtual machine (-n / port) has to be used in inventory path format (e.g + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + +diff --git a/tests/data/metadata/fence_vmware_vcloud.xml b/tests/data/metadata/fence_vmware_vcloud.xml +index 69269a2d..505eaf2b 100644 +--- a/tests/data/metadata/fence_vmware_vcloud.xml ++++ b/tests/data/metadata/fence_vmware_vcloud.xml +@@ -8,16 +8,6 @@ + + Fencing action + +- +- +- +- Forces agent to use IPv4 addresses only +- +- +- +- +- Forces agent to use IPv6 addresses only +- + + + diff --git a/SOURCES/bz1771594-2-fence_redfish-fence_vmware_soap-suppress-warning.patch b/SOURCES/bz1771594-2-fence_redfish-fence_vmware_soap-suppress-warning.patch new file mode 100644 index 0000000..889c6f9 --- /dev/null +++ b/SOURCES/bz1771594-2-fence_redfish-fence_vmware_soap-suppress-warning.patch @@ -0,0 +1,51 @@ +From 559771f2c5a638f7e14ec9c0ef1068c86ee9d40e Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 26 Nov 2019 14:09:14 +0100 +Subject: [PATCH] fence_redfish/fence_vmware_soap: suppress warnings correctly + with new python-requests + +python-requests doesnt suppress warnings anymore, so it needs to be done in urllib3: https://stackoverflow.com/questions/27981545/suppress-insecurerequestwarning-unverified-https-request-is-being-made-in-pytho/28002687#28002687 +--- + agents/redfish/fence_redfish.py | 4 ++-- + agents/vmware_soap/fence_vmware_soap.py | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py +index 390a4827..c7c6492c 100644 +--- a/agents/redfish/fence_redfish.py ++++ b/agents/redfish/fence_redfish.py +@@ -12,7 +12,6 @@ + import atexit + sys.path.append("@FENCEAGENTSLIBDIR@") + +-from requests.packages.urllib3.exceptions import InsecureRequestWarning + from fencing import * + from fencing import fail_usage, run_delay + +@@ -143,7 +142,8 @@ def main(): + + # Disable insecure-certificate-warning message + if "--ssl-insecure" in opt: +- requests.packages.urllib3.disable_warnings(InsecureRequestWarning) ++ import urllib3 ++ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + # backwards compatibility for : + if options["--ip"].count(":") == 1: +diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py +index dd1a4ed6..53e8d8f4 100644 +--- a/agents/vmware_soap/fence_vmware_soap.py ++++ b/agents/vmware_soap/fence_vmware_soap.py +@@ -37,10 +37,10 @@ def soap_login(options): + if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options: + if "--ssl-insecure" in options: + import ssl +- from requests.packages.urllib3.exceptions import InsecureRequestWarning ++ import urllib3 + if hasattr(ssl, '_create_unverified_context'): + ssl._create_default_https_context = ssl._create_unverified_context +- requests.packages.urllib3.disable_warnings(InsecureRequestWarning) ++ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + verify = False + else: + verify = True diff --git a/SOURCES/bz1773890-fence_scsi-add-hash-key-value-support.patch b/SOURCES/bz1773890-fence_scsi-add-hash-key-value-support.patch new file mode 100644 index 0000000..b8cf248 --- /dev/null +++ b/SOURCES/bz1773890-fence_scsi-add-hash-key-value-support.patch @@ -0,0 +1,237 @@ +From baf8d524e89d7f6c716e8241a12d8135debadfcc Mon Sep 17 00:00:00 2001 +From: Ondrej Famera +Date: Sun, 20 Oct 2019 20:13:40 +0900 +Subject: [PATCH 1/4] add new method for autogenerating SCSI key + +this methos generates second part of SCSI key based on hash of cluster +node name instead of currently used ID based approach which can brake if +the nodes get removed from cluster but whole cluster is not restarted +because the IDs changes. With hash approach hashes stays same. +Note that there is theoretical risk that hashes could colide. +--- + agents/scsi/fence_scsi.py | 32 ++++++++++++++++++++++++++++-- + tests/data/metadata/fence_scsi.xml | 5 +++++ + 2 files changed, 35 insertions(+), 2 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 5580e08b..4cc9b66c 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -202,9 +202,20 @@ def get_node_id(options): + + return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist") + ++def get_node_hash(options): ++ try: ++ return hashlib.md5(options["--plug"].encode('ascii')).hexdigest() ++ except ValueError: ++ # FIPS requires usedforsecurity=False and might not be ++ # available on all distros: https://bugs.python.org/issue9216 ++ return hashlib.md5(options["--plug"].encode('ascii'), usedforsecurity=False).hexdigest() ++ + + def generate_key(options): +- return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options))) ++ if options["--key_value"] == "hash": ++ return "%.4s%.4s" % (get_cluster_id(options), get_node_hash(options)) ++ else: ++ return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options))) + + + # save node key to file +@@ -375,6 +386,19 @@ def define_new_opts(): + "default" : "@VGS_PATH@", + "order": 300 + } ++ all_opt["key_value"] = { ++ "getopt" : ":", ++ "longopt" : "key_value", ++ "help" : "--key_value= SCSI key node generation method", ++ "required" : "0", ++ "shortdesc" : "Method used to generate the SCSI key. \"id\" (default) \ ++uses the positional ID from \"corosync-cmactl nodelist\" output which can get inconsistent \ ++when nodes are removed from cluster without full cluster restart. \"hash\" uses part of hash \ ++made out of node names which is not affected over time but there is theoretical chance that \ ++hashes can collide as size of SCSI key is quite limited.", ++ "default" : "id", ++ "order": 300 ++ } + + + def scsi_check_get_options(options): +@@ -440,7 +464,7 @@ 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"] ++ "sg_persist_path", "sg_turs_path", "logfile", "vgs_path", "force_on", "key_value"] + + define_new_opts() + +@@ -517,6 +541,10 @@ def main(): + if options["--key"] == "0" or not options["--key"]: + fail_usage("Failed: key cannot be 0", stop_after_error) + ++ if "--key_value" in options\ ++ and (options["--key_value"] != "id" and options["--key_value"] != "hash"): ++ fail_usage("Failed: key_value has to be 'id' or 'hash'", stop_after_error) ++ + if options["--action"] == "validate-all": + sys.exit(0) + +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index b8cdabd1..56c6224d 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -105,6 +105,11 @@ When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and ve + + Path to corosync-cmapctl binary + ++ ++ ++ ++ Method used to generate the SCSI key. "id" (default) uses the positional ID from "corosync-cmactl nodelist" output which can get inconsistent when nodes are removed from cluster without full cluster restart. "hash" uses part of hash made out of node names which is not affected over time but there is theoretical chance that hashes can collide as size of SCSI key is quite limited. ++ + + + Path to sg_persist binary + +From ee7a5ea238b4b3312384e4cfd9edd392c311d17a Mon Sep 17 00:00:00 2001 +From: Ondrej Famera +Date: Fri, 1 Nov 2019 13:16:58 +0900 +Subject: [PATCH 2/4] rename 'key_value' to 'key-value' for manual invokation + +--- + agents/scsi/fence_scsi.py | 12 ++++++------ + tests/data/metadata/fence_scsi.xml | 2 +- + 2 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 4cc9b66c..7d515e16 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -212,7 +212,7 @@ def get_node_hash(options): + + + def generate_key(options): +- if options["--key_value"] == "hash": ++ if options["--key-value"] == "hash": + return "%.4s%.4s" % (get_cluster_id(options), get_node_hash(options)) + else: + return "%.4s%.4d" % (get_cluster_id(options), int(get_node_id(options))) +@@ -388,8 +388,8 @@ def define_new_opts(): + } + all_opt["key_value"] = { + "getopt" : ":", +- "longopt" : "key_value", +- "help" : "--key_value= SCSI key node generation method", ++ "longopt" : "key-value", ++ "help" : "--key-value= SCSI key node generation method", + "required" : "0", + "shortdesc" : "Method used to generate the SCSI key. \"id\" (default) \ + uses the positional ID from \"corosync-cmactl nodelist\" output which can get inconsistent \ +@@ -541,9 +541,9 @@ def main(): + if options["--key"] == "0" or not options["--key"]: + fail_usage("Failed: key cannot be 0", stop_after_error) + +- if "--key_value" in options\ +- and (options["--key_value"] != "id" and options["--key_value"] != "hash"): +- fail_usage("Failed: key_value has to be 'id' or 'hash'", stop_after_error) ++ if "--key-value" in options\ ++ and (options["--key-value"] != "id" and options["--key-value"] != "hash"): ++ fail_usage("Failed: key-value has to be 'id' or 'hash'", stop_after_error) + + if options["--action"] == "validate-all": + sys.exit(0) +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index 56c6224d..72800688 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -106,7 +106,7 @@ When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and ve + Path to corosync-cmapctl binary + + +- ++ + + Method used to generate the SCSI key. "id" (default) uses the positional ID from "corosync-cmactl nodelist" output which can get inconsistent when nodes are removed from cluster without full cluster restart. "hash" uses part of hash made out of node names which is not affected over time but there is theoretical chance that hashes can collide as size of SCSI key is quite limited. + + +From 58105710876bd6a2220f92ea37d621991d68bf4b Mon Sep 17 00:00:00 2001 +From: Ondrej Famera +Date: Fri, 1 Nov 2019 13:20:17 +0900 +Subject: [PATCH 3/4] expand longdesc of fence_scsi to describe the impact of + key_value option + +--- + agents/scsi/fence_scsi.py | 6 +++++- + tests/data/metadata/fence_scsi.xml | 2 +- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 7d515e16..4b2bfe20 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -493,7 +493,11 @@ def main(): + devices must support SCSI-3 persistent reservations (SPC-3 or greater) as \ + well as the \"preempt-and-abort\" subcommand.\nThe 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 \ ++device(s). Reservation key is generated from \"node id\" (default) or from \ ++\"node name hash\" (recommended) by adjusting \"key_value\" option. \ ++Using hash is recommended to prevent issues when removing nodes \ ++from cluster without full cluster restart. \ ++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 \ +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index 72800688..6f914823 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -1,7 +1,7 @@ + + + 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). Reservation key is generated from "node id" (default) or from "node name hash" (recommended) by adjusting "key_value" option. Using hash is recommended to prevent issues when removing nodes from cluster without full cluster restart. 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. + + +From 6a73919ab70d76fcf4ce19b4fd00e182e41f33b5 Mon Sep 17 00:00:00 2001 +From: Ondrej Famera +Date: Sat, 16 Nov 2019 17:03:42 +0900 +Subject: [PATCH 4/4] emphasize the recommendation to use 'hash' over 'id' + +--- + agents/scsi/fence_scsi.py | 2 +- + tests/data/metadata/fence_scsi.xml | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py +index 4b2bfe20..9b6af556 100644 +--- a/agents/scsi/fence_scsi.py ++++ b/agents/scsi/fence_scsi.py +@@ -494,7 +494,7 @@ def main(): + well as the \"preempt-and-abort\" subcommand.\nThe fence_scsi agent works by \ + having each node in the cluster register a unique key with the SCSI \ + device(s). Reservation key is generated from \"node id\" (default) or from \ +-\"node name hash\" (recommended) by adjusting \"key_value\" option. \ ++\"node name hash\" (RECOMMENDED) by adjusting \"key_value\" option. \ + Using hash is recommended to prevent issues when removing nodes \ + from cluster without full cluster restart. \ + Once registered, a single node will become the reservation holder \ +diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml +index 6f914823..b840f3cf 100644 +--- a/tests/data/metadata/fence_scsi.xml ++++ b/tests/data/metadata/fence_scsi.xml +@@ -1,7 +1,7 @@ + + + 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). Reservation key is generated from "node id" (default) or from "node name hash" (recommended) by adjusting "key_value" option. Using hash is recommended to prevent issues when removing nodes from cluster without full cluster restart. 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). Reservation key is generated from "node id" (default) or from "node name hash" (RECOMMENDED) by adjusting "key_value" option. Using hash is recommended to prevent issues when removing nodes from cluster without full cluster restart. 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/bz1774458-fence_sbd-stderr-support.patch b/SOURCES/bz1774458-fence_sbd-stderr-support.patch new file mode 100644 index 0000000..59a6794 --- /dev/null +++ b/SOURCES/bz1774458-fence_sbd-stderr-support.patch @@ -0,0 +1,39 @@ +From f37e5ba0b6c8dab527f947bfc602d50b953a7d08 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 17 Sep 2019 15:15:06 +0200 +Subject: [PATCH] fence_sbd: support errors on stderr + +--- + agents/sbd/fence_sbd.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/agents/sbd/fence_sbd.py b/agents/sbd/fence_sbd.py +index b1df70ac..3ae8df6e 100644 +--- a/agents/sbd/fence_sbd.py ++++ b/agents/sbd/fence_sbd.py +@@ -8,6 +8,7 @@ + from fencing import fail_usage, run_command, fence_action, all_opt + from fencing import atexit_handler, check_input, process_input, show_docs + from fencing import run_delay ++import itertools + + DEVICE_INIT = 1 + DEVICE_NOT_INIT = -3 +@@ -82,7 +83,7 @@ def check_sbd_device(options, device_path): + + (return_code, out, err) = run_command(options, cmd) + +- for line in out.split("\n"): ++ for line in itertools.chain(out.split("\n"), err.split("\n")): + if len(line) == 0: + continue + +@@ -148,7 +149,7 @@ def get_msg_timeout(options): + + (return_code, out, err) = run_command(options, cmd) + +- for line in out.split("\n"): ++ for line in itertools.chain(out.split("\n"), err.split("\n")): + if len(line) == 0: + continue + diff --git a/SOURCES/bz1781357-fence_aws-improve-logging-and-metadata-usage-text.patch b/SOURCES/bz1781357-fence_aws-improve-logging-and-metadata-usage-text.patch new file mode 100644 index 0000000..e81dce6 --- /dev/null +++ b/SOURCES/bz1781357-fence_aws-improve-logging-and-metadata-usage-text.patch @@ -0,0 +1,130 @@ +From 7ac16fb281fa8cfc51a31f672014c614c81aec82 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 31 Jan 2020 15:53:47 +0100 +Subject: [PATCH] fence_aws: improve logging and metadata/usage text + +--- + agents/aws/fence_aws.py | 36 +++++++++++++++++++------------ + tests/data/metadata/fence_aws.xml | 6 +++--- + 2 files changed, 25 insertions(+), 17 deletions(-) + +diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py +index 647b66fc..74321e8e 100644 +--- a/agents/aws/fence_aws.py ++++ b/agents/aws/fence_aws.py +@@ -5,7 +5,7 @@ + import atexit + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * +-from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay ++from fencing import fail, fail_usage, run_delay, EC_STATUS + + import boto3 + from botocore.exceptions import ClientError, EndpointConnectionError, NoRegionError +@@ -19,6 +19,8 @@ def get_nodes_list(conn, options): + fail_usage("Failed: Incorrect Access Key or Secret Key.") + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") ++ except Exception as e: ++ logging.error("Failed to get node list: %s", e) + + return result + +@@ -38,20 +40,26 @@ def get_power_status(conn, options): + except EndpointConnectionError: + fail_usage("Failed: Incorrect Region.") + except IndexError: +- return "fail" ++ fail(EC_STATUS) ++ except Exception as e: ++ logging.error("Failed to get power status: %s", e) ++ fail(EC_STATUS) + + def set_power_status(conn, options): +- if (options["--action"]=="off"): +- conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) +- elif (options["--action"]=="on"): +- conn.instances.filter(InstanceIds=[options["--plug"]]).start() +- ++ try: ++ if (options["--action"]=="off"): ++ conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True) ++ elif (options["--action"]=="on"): ++ conn.instances.filter(InstanceIds=[options["--plug"]]).start() ++ except Exception as e: ++ logging.error("Failed to power %s %s: %s", \ ++ options["--action"], options["--plug"], e) + + def define_new_opts(): + all_opt["region"] = { + "getopt" : "r:", + "longopt" : "region", +- "help" : "-r, --region=[name] Region, e.g. us-east-1", ++ "help" : "-r, --region=[region] Region, e.g. us-east-1", + "shortdesc" : "Region.", + "required" : "0", + "order" : 2 +@@ -59,7 +67,7 @@ def define_new_opts(): + all_opt["access_key"] = { + "getopt" : "a:", + "longopt" : "access-key", +- "help" : "-a, --access-key=[name] Access Key", ++ "help" : "-a, --access-key=[key] Access Key", + "shortdesc" : "Access Key.", + "required" : "0", + "order" : 3 +@@ -67,7 +75,7 @@ def define_new_opts(): + all_opt["secret_key"] = { + "getopt" : "s:", + "longopt" : "secret-key", +- "help" : "-s, --secret-key=[name] Secret Key", ++ "help" : "-s, --secret-key=[key] Secret Key", + "shortdesc" : "Secret Key.", + "required" : "0", + "order" : 4 +@@ -107,16 +115,16 @@ def main(): + conn = boto3.resource('ec2', region_name=region, + aws_access_key_id=access_key, + aws_secret_access_key=secret_key) +- except: +- fail_usage("Failed: Unable to connect to AWS. Check your configuration.") ++ 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: ++ except Exception as e: + # If any of region/access/secret are missing +- fail_usage("Failed: Unable to connect to AWS. Check your configuration.") ++ 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/tests/data/metadata/fence_aws.xml b/tests/data/metadata/fence_aws.xml +index 4dea4418..5e5d5d99 100644 +--- a/tests/data/metadata/fence_aws.xml ++++ b/tests/data/metadata/fence_aws.xml +@@ -22,17 +22,17 @@ For instructions see: https://boto3.readthedocs.io/en/latest/guide/quickstart.ht + Physical plug number on device, UUID or identification of machine + + +- ++ + + Region. + + +- ++ + + Access Key. + + +- ++ + + Secret Key. + diff --git a/SOURCES/bz1798641-fence_mpath-fix-reserve-parameter-typo.patch b/SOURCES/bz1798641-fence_mpath-fix-reserve-parameter-typo.patch new file mode 100644 index 0000000..03d7c5e --- /dev/null +++ b/SOURCES/bz1798641-fence_mpath-fix-reserve-parameter-typo.patch @@ -0,0 +1,22 @@ +From 0d3ff341c5dcff7ded0274ae20460895f35c13d6 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 13 Feb 2020 15:40:24 +0100 +Subject: [PATCH] fence_mpath: fix --reserve parameter typo + +--- + agents/mpath/fence_mpath.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index 73517851..a3d9fe23 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -106,7 +106,7 @@ def register_dev(options, dev): + return not bool(run_cmd(options, cmd)["err"]) + + def reserve_dev(options, dev): +- cmd = options["--mpathpersist-path"] + " -o --reserv --prout-type=5 --param-rk=" + options["--plug"] + " -d " + dev ++ cmd = options["--mpathpersist-path"] + " -o --reserve --prout-type=5 --param-rk=" + options["--plug"] + " -d " + dev + return not bool(run_cmd(options, cmd)["err"]) + + def get_reservation_key(options, dev): diff --git a/SOURCES/fence_aliyun-1.patch b/SOURCES/fence_aliyun-1.patch new file mode 100644 index 0000000..c5f656b --- /dev/null +++ b/SOURCES/fence_aliyun-1.patch @@ -0,0 +1,344 @@ +From 418df5845d1781e18e300cf17b2de714e4ff09d1 Mon Sep 17 00:00:00 2001 +From: "feng.changf1" +Date: Tue, 24 Jul 2018 15:56:50 +0800 +Subject: [PATCH 1/3] Add Aliyun fence agent. + +--- + agents/aliyun/fence_aliyun.py | 146 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 146 insertions(+) + create mode 100644 agents/aliyun/fence_aliyun.py + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +new file mode 100644 +index 00000000..ec7d2316 +--- /dev/null ++++ b/agents/aliyun/fence_aliyun.py +@@ -0,0 +1,146 @@ ++#!/usr/bin/python -tt ++ ++import sys, re ++import logging ++import atexit ++import json ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay ++ ++from aliyunsdkcore import client ++ ++from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest ++from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest ++from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest ++from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest ++ ++def _send_request(conn, request): ++ request.set_accept_format('json') ++ try: ++ response_str = conn.do_action_with_exception(request) ++ response_detail = json.loads(response_str) ++ return response_detail ++ except Exception as e: ++ fail_usage("Failed: _send_request failed") ++ ++def start_instance(conn, instance_id): ++ request = StartInstanceRequest() ++ request.set_InstanceId(instance_id) ++ _send_request(conn, request) ++ ++def stop_instance(conn, instance_id): ++ request = StopInstanceRequest() ++ request.set_InstanceId(instance_id) ++ request.set_ForceStop('true') ++ _send_request(conn, request) ++ ++def reboot_instance(conn, instance_id): ++ request = RebootInstanceRequest() ++ request.set_InstanceId(instance_id) ++ request.set_ForceStop('true') ++ _send_request(conn, request) ++ ++def get_status(conn, instance_id): ++ request = DescribeInstancesRequest() ++ request.set_InstanceIds(json.dumps([instance_id])) ++ response = _send_request(conn, request) ++ instance_status = None ++ if response is not None: ++ instance_list = response.get('Instances').get('Instance') ++ for item in instance_list: ++ instance_status = item.get('Status') ++ return instance_status ++ ++def get_nodes_list(conn, options): ++ result = {} ++ request = DescribeInstancesRequest() ++ response = _send_request(conn, request) ++ instance_status = None ++ if response is not None: ++ instance_list = response.get('Instances').get('Instance') ++ for item in instance_list: ++ instance_id = item.get('InstanceId') ++ result[instance_id] = ("", None) ++ return result ++ ++def get_power_status(conn, options): ++ state = get_status(conn, options["--plug"]) ++ if state == "Running": ++ return "on" ++ elif state == "Stopped": ++ return "off" ++ else: ++ return "unknown" ++ ++ ++def set_power_status(conn, options): ++ if (options["--action"]=="off"): ++ stop_instance(conn, options["--plug"]) ++ elif (options["--action"]=="on"): ++ start_instance(conn, options["--plug"]) ++ elif (options["--action"]=="reboot"): ++ reboot_instance(conn, options["--plug"]) ++ ++ ++def define_new_opts(): ++ all_opt["region"] = { ++ "getopt" : "r:", ++ "longopt" : "region", ++ "help" : "-r, --region=[name] Region, e.g. cn-hangzhou", ++ "shortdesc" : "Region.", ++ "required" : "0", ++ "order" : 2 ++ } ++ all_opt["access_key"] = { ++ "getopt" : "a:", ++ "longopt" : "access-key", ++ "help" : "-a, --access-key=[name] Access Key", ++ "shortdesc" : "Access Key.", ++ "required" : "0", ++ "order" : 3 ++ } ++ all_opt["secret_key"] = { ++ "getopt" : "s:", ++ "longopt" : "secret-key", ++ "help" : "-s, --secret-key=[name] Secret Key", ++ "shortdesc" : "Secret Key.", ++ "required" : "0", ++ "order" : 4 ++ } ++ ++# Main agent method ++def main(): ++ conn = None ++ ++ device_opt = ["port", "no_password", "region", "access_key", "secret_key"] ++ ++ atexit.register(atexit_handler) ++ ++ define_new_opts() ++ ++ all_opt["power_timeout"]["default"] = "60" ++ ++ options = check_input(device_opt, process_input(device_opt)) ++ ++ docs = {} ++ docs["shortdesc"] = "Fence agent for Aliyun (Aliyun Web Services)" ++ docs["longdesc"] = "fence_aliyun is an I/O Fencing agent for Aliyun" ++ docs["vendorurl"] = "http://www.aliyun.com" ++ show_docs(options, docs) ++ ++ 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"] ++ conn = client.AcsClient(access_key, secret_key, region) ++ ++ ++ # Operate the fencing device ++ result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) ++ sys.exit(result) ++ ++if __name__ == "__main__": ++ main() + +From 28b55555abda9b6c278a7f082bb22c4f6f1e2474 Mon Sep 17 00:00:00 2001 +From: "feng.changf1" +Date: Tue, 24 Jul 2018 17:18:53 +0800 +Subject: [PATCH 2/3] Add Aliyun fence agent. + +--- + tests/data/metadata/fence_aliyun.xml | 113 +++++++++++++++++++++++++++++++++++ + 1 file changed, 113 insertions(+) + create mode 100644 tests/data/metadata/fence_aliyun.xml + +diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml +new file mode 100644 +index 00000000..1db692ee +--- /dev/null ++++ b/tests/data/metadata/fence_aliyun.xml +@@ -0,0 +1,113 @@ ++ ++ ++fence_aliyun is an I/O Fencing agent for Aliyun ++http://www.aliyun.com ++ ++ ++ ++ ++ Fencing action ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Region. ++ ++ ++ ++ ++ Access Key. ++ ++ ++ ++ ++ Secret Key. ++ ++ ++ ++ ++ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. ++ ++ ++ ++ ++ Verbose mode ++ ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ ++ Display version information and exit ++ ++ ++ ++ ++ Display help and exit ++ ++ ++ ++ ++ Separator for CSV created by 'list' operation ++ ++ ++ ++ ++ Wait X seconds before fencing is started ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after login ++ ++ ++ ++ ++ Test X seconds for status change after ON/OFF ++ ++ ++ ++ ++ Wait X seconds after issuing ON/OFF ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after issuing command ++ ++ ++ ++ ++ Count of attempts to retry power on ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +From 53bbd91e91c231c89ae8981238bb15d85d02207b Mon Sep 17 00:00:00 2001 +From: "feng.changf1" +Date: Tue, 24 Jul 2018 17:26:45 +0800 +Subject: [PATCH 3/3] Fix CI error. + +--- + agents/aliyun/fence_aliyun.py | 32 +++++++++++++++++--------------- + 1 file changed, 17 insertions(+), 15 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index ec7d2316..0f24b83e 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -1,20 +1,22 @@ + #!/usr/bin/python -tt + +-import sys, re +-import logging +-import atexit +-import json +-sys.path.append("@FENCEAGENTSLIBDIR@") +-from fencing import * +-from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay +- +-from aliyunsdkcore import client +- +-from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest +-from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest +-from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest +-from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest +- ++try: ++ import sys, re ++ import logging ++ import atexit ++ import json ++ sys.path.append("@FENCEAGENTSLIBDIR@") ++ from fencing import * ++ from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay ++ ++ from aliyunsdkcore import client ++ ++ from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest ++ from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest ++ from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest ++ from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest ++except ImportError: ++ pass + def _send_request(conn, request): + request.set_accept_format('json') + try: diff --git a/SOURCES/fence_aliyun-2.patch b/SOURCES/fence_aliyun-2.patch new file mode 100644 index 0000000..eb4c735 --- /dev/null +++ b/SOURCES/fence_aliyun-2.patch @@ -0,0 +1,58 @@ +From 8db45537fb470624a754ea1243cc4f349a9b413d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 24 Jul 2018 13:10:41 +0200 +Subject: [PATCH] fence_aliyun: fix CI and add Python detection + +--- + agents/aliyun/fence_aliyun.py | 19 ++++++++++--------- + tests/data/metadata/fence_aliyun.xml | 1 + + 2 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index 0f24b83e..aa6c0acf 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -1,14 +1,14 @@ +-#!/usr/bin/python -tt ++#!@PYTHON@ -tt + +-try: +- import sys, re +- import logging +- import atexit +- import json +- sys.path.append("@FENCEAGENTSLIBDIR@") +- from fencing import * +- from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay ++import sys, re ++import logging ++import atexit ++import json ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay + ++try: + from aliyunsdkcore import client + + from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest +@@ -17,6 +17,7 @@ + from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest + except ImportError: + pass ++ + def _send_request(conn, request): + request.set_accept_format('json') + try: +diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml +index 1db692ee..b41d82bf 100644 +--- a/tests/data/metadata/fence_aliyun.xml ++++ b/tests/data/metadata/fence_aliyun.xml +@@ -108,6 +108,7 @@ + + + ++ + + + diff --git a/SOURCES/fence_aliyun-3-logging.patch b/SOURCES/fence_aliyun-3-logging.patch new file mode 100644 index 0000000..52c2dca --- /dev/null +++ b/SOURCES/fence_aliyun-3-logging.patch @@ -0,0 +1,51 @@ +From 790cbaa66f3927a84739af4a1f0e8bba295cdc36 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 30 Jul 2018 10:43:04 +0200 +Subject: [PATCH] fence_aliyun: add logging + +--- + agents/aliyun/fence_aliyun.py | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index aa6c0acf..2cda6b7f 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -23,9 +23,10 @@ def _send_request(conn, request): + try: + response_str = conn.do_action_with_exception(request) + response_detail = json.loads(response_str) ++ logging.debug("_send_request reponse: %s" % response_detail) + return response_detail + except Exception as e: +- fail_usage("Failed: _send_request failed") ++ fail_usage("Failed: _send_request failed: %s" % e) + + def start_instance(conn, instance_id): + request = StartInstanceRequest() +@@ -69,15 +70,22 @@ def get_nodes_list(conn, options): + + def get_power_status(conn, options): + state = get_status(conn, options["--plug"]) ++ + if state == "Running": +- return "on" ++ status = "on" + elif state == "Stopped": +- return "off" ++ status = "off" + else: +- return "unknown" ++ status = "unknown" ++ ++ logging.info("get_power_status: %s" % status) ++ ++ return status + + + def set_power_status(conn, options): ++ logging.info("set_power_status: %s" % options["--action"]) ++ + if (options["--action"]=="off"): + stop_instance(conn, options["--plug"]) + elif (options["--action"]=="on"): diff --git a/SOURCES/fence_aliyun-4-bundled.patch b/SOURCES/fence_aliyun-4-bundled.patch new file mode 100644 index 0000000..99a0b50 --- /dev/null +++ b/SOURCES/fence_aliyun-4-bundled.patch @@ -0,0 +1,11 @@ +diff -uNr a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +--- a/agents/aliyun/fence_aliyun.py 2018-07-24 14:30:29.030311806 +0200 ++++ b/agents/aliyun/fence_aliyun.py 2018-07-24 14:31:10.023884949 +0200 +@@ -9,6 +9,7 @@ + from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay + + try: ++ sys.path.insert(0, '/usr/lib/fence-agents/bundled/aliyun') + from aliyunsdkcore import client + + from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest diff --git a/SOURCES/fence_aliyun-5-list-instance-names.patch b/SOURCES/fence_aliyun-5-list-instance-names.patch new file mode 100644 index 0000000..40bebac --- /dev/null +++ b/SOURCES/fence_aliyun-5-list-instance-names.patch @@ -0,0 +1,31 @@ +From c21d60fbcf0b11dcbf4f70006c8ffaeac4ca7dbd Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 28 Aug 2018 15:20:10 +0200 +Subject: [PATCH] fence_aliyun: list instance names and show up to 100 + instances + +--- + agents/aliyun/fence_aliyun.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index 2cda6b7f..b3aca12f 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -59,13 +59,15 @@ def get_status(conn, instance_id): + def get_nodes_list(conn, options): + result = {} + request = DescribeInstancesRequest() ++ request.set_PageSize(100) + response = _send_request(conn, request) + instance_status = None + if response is not None: + instance_list = response.get('Instances').get('Instance') + for item in instance_list: + instance_id = item.get('InstanceId') +- result[instance_id] = ("", None) ++ instance_name = item.get('InstanceName') ++ result[instance_id] = (instance_name, None) + return result + + def get_power_status(conn, options): diff --git a/SOURCES/fence_aliyun-6-correct-help-indentation.patch b/SOURCES/fence_aliyun-6-correct-help-indentation.patch new file mode 100644 index 0000000..39b1551 --- /dev/null +++ b/SOURCES/fence_aliyun-6-correct-help-indentation.patch @@ -0,0 +1,31 @@ +From 588f935b1f79c8355d461fe9f8597151fbcd7fa2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 30 Aug 2018 09:11:58 +0200 +Subject: [PATCH] fence_aliyun: correct indentation for *key in help + +--- + agents/aliyun/fence_aliyun.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py +index 2cda6b7f..7d04c5bb 100644 +--- a/agents/aliyun/fence_aliyun.py ++++ b/agents/aliyun/fence_aliyun.py +@@ -106,7 +106,7 @@ def define_new_opts(): + all_opt["access_key"] = { + "getopt" : "a:", + "longopt" : "access-key", +- "help" : "-a, --access-key=[name] Access Key", ++ "help" : "-a, --access-key=[name] Access Key", + "shortdesc" : "Access Key.", + "required" : "0", + "order" : 3 +@@ -114,7 +114,7 @@ def define_new_opts(): + all_opt["secret_key"] = { + "getopt" : "s:", + "longopt" : "secret-key", +- "help" : "-s, --secret-key=[name] Secret Key", ++ "help" : "-s, --secret-key=[name] Secret Key", + "shortdesc" : "Secret Key.", + "required" : "0", + "order" : 4 diff --git a/SOURCES/fence_cisco_ucs-encode-POSTFIELDS.patch b/SOURCES/fence_cisco_ucs-encode-POSTFIELDS.patch new file mode 100644 index 0000000..6515deb --- /dev/null +++ b/SOURCES/fence_cisco_ucs-encode-POSTFIELDS.patch @@ -0,0 +1,22 @@ +From 70bd4ffa245ef7e8b7698228bab3b41c240d50d2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 4 Sep 2018 12:35:07 +0200 +Subject: [PATCH] fence_cisco_ucs: encode POSTFIELDS + +--- + agents/cisco_ucs/fence_cisco_ucs.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py +index d509b3e0..ec311754 100644 +--- a/agents/cisco_ucs/fence_cisco_ucs.py ++++ b/agents/cisco_ucs/fence_cisco_ucs.py +@@ -111,7 +111,7 @@ def send_command(opt, command, timeout): + web_buffer = io.BytesIO() + conn.setopt(pycurl.URL, url.encode("ascii")) + conn.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"]) +- conn.setopt(pycurl.POSTFIELDS, command) ++ conn.setopt(pycurl.POSTFIELDS, command.encode("ascii")) + conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) + conn.setopt(pycurl.TIMEOUT, timeout) + if "--ssl" in opt or "--ssl-secure" in opt: diff --git a/SOURCES/fence_compute-fence_evacuate-fix-compute-domain.patch b/SOURCES/fence_compute-fence_evacuate-fix-compute-domain.patch new file mode 100644 index 0000000..3ae0ae8 --- /dev/null +++ b/SOURCES/fence_compute-fence_evacuate-fix-compute-domain.patch @@ -0,0 +1,232 @@ +From 15635df9d12ce693f473d5ebcd5b7cacb81e2295 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 16 Jul 2018 11:14:16 +0200 +Subject: [PATCH] fence_compute/fence_evacuate: workaround for compute-domain + regression + +--- + agents/compute/fence_compute.py | 24 +++++++++++++++++++----- + agents/evacuate/fence_evacuate.py | 24 +++++++++++++++++++----- + tests/data/metadata/fence_compute.xml | 24 ++++++++++++++++++++++-- + tests/data/metadata/fence_evacuate.xml | 24 ++++++++++++++++++++++-- + 4 files changed, 82 insertions(+), 14 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index ec2d093c..aac9b296 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -353,7 +353,7 @@ def define_new_opts(): + "default" : "", + "order": 1, + } +- all_opt["user_domain"] = { ++ all_opt["user-domain"] = { + "getopt" : "u:", + "longopt" : "user-domain", + "help" : "-u, --user-domain=[name] Keystone v3 User Domain", +@@ -362,7 +362,7 @@ def define_new_opts(): + "default" : "Default", + "order": 2, + } +- all_opt["project_domain"] = { ++ all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", + "help" : "-d, --project-domain=[name] Keystone v3 Project Domain", +@@ -433,6 +433,14 @@ def define_new_opts(): + "default" : "False", + "order": 5, + } ++ all_opt["compute-domain"] = { ++ "getopt" : ":", ++ "longopt" : "compute-domain", ++ "help" : "--compute-domain=[string] Replaced by --domain", ++ "required" : "0", ++ "shortdesc" : "Replaced by domain", ++ "order": 6, ++ } + + def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1): + for _ in range(retry_attempts): +@@ -450,9 +458,10 @@ def main(): + global override_status + atexit.register(atexit_handler) + +- device_opt = ["login", "passwd", "tenant_name", "auth_url", "fabric_fencing", +- "no_login", "no_password", "port", "domain", "project_domain", "user_domain", +- "no_shared_storage", "endpoint_type", "record_only", "instance_filtering", "insecure", "region_name"] ++ device_opt = ["login", "passwd", "tenant_name", "auth_url", "fabric_fencing", "no_login", ++ "no_password", "port", "domain", "compute-domain", "project-domain", ++ "user-domain", "no_shared_storage", "endpoint_type", "record_only", ++ "instance_filtering", "insecure", "region_name"] + define_new_opts() + all_opt["shell_timeout"]["default"] = "180" + +@@ -470,6 +479,11 @@ def main(): + + run_delay(options) + ++ # workaround to avoid regressions ++ if "--compute-domain" in options and options["--compute-domain"]: ++ options["--domain"] = options["--compute-domain"] ++ del options["--domain"] ++ + 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 615dede7..529a60dd 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -287,7 +287,7 @@ def define_new_opts(): + "default" : "", + "order": 1, + } +- all_opt["user_domain"] = { ++ all_opt["user-domain"] = { + "getopt" : "u:", + "longopt" : "user-domain", + "help" : "-u, --user-domain=[name] Keystone v3 User Domain", +@@ -296,7 +296,7 @@ def define_new_opts(): + "default" : "Default", + "order": 2, + } +- all_opt["project_domain"] = { ++ all_opt["project-domain"] = { + "getopt" : "P:", + "longopt" : "project-domain", + "help" : "-d, --project-domain=[name] Keystone v3 Project Domain", +@@ -358,14 +358,22 @@ def define_new_opts(): + "default" : "False", + "order": 5, + } ++ all_opt["compute-domain"] = { ++ "getopt" : ":", ++ "longopt" : "compute-domain", ++ "help" : "--compute-domain=[string] Replaced by --domain", ++ "required" : "0", ++ "shortdesc" : "Replaced by domain", ++ "order": 6, ++ } + + def main(): + atexit.register(atexit_handler) + + device_opt = ["login", "passwd", "tenant_name", "auth_url", +- "no_login", "no_password", "port", "domain", "project_domain", +- "user_domain", "no_shared_storage", "endpoint_type", +- "instance_filtering", "insecure", "region_name"] ++ "no_login", "no_password", "port", "domain", "compute-domain", ++ "project-domain", "user-domain", "no_shared_storage", ++ "endpoint_type", "instance_filtering", "insecure", "region_name"] + define_new_opts() + all_opt["shell_timeout"]["default"] = "180" + +@@ -380,6 +388,12 @@ def main(): + + run_delay(options) + ++ # workaround to avoid regressions ++ if "--compute-domain" in options and options["--compute-domain"]: ++ options["--domain"] = options["--compute-domain"] ++ del options["--domain"] ++ ++ + 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 e1dac97c..1dcbfc54 100644 +--- a/tests/data/metadata/fence_compute.xml ++++ b/tests/data/metadata/fence_compute.xml +@@ -73,12 +73,22 @@ + + Allow Insecure TLS Requests + +- ++ + + + Keystone v3 Project Domain + +- ++ ++ ++ ++ Keystone v3 Project Domain ++ ++ ++ ++ ++ Keystone v3 User Domain ++ ++ + + + Keystone v3 User Domain +@@ -103,6 +113,16 @@ + + Only record the target as needing evacuation + ++ ++ ++ ++ Replaced by domain ++ ++ ++ ++ ++ Replaced by domain ++ + + + +diff --git a/tests/data/metadata/fence_evacuate.xml b/tests/data/metadata/fence_evacuate.xml +index 6f8bd0a4..4f1f6a58 100644 +--- a/tests/data/metadata/fence_evacuate.xml ++++ b/tests/data/metadata/fence_evacuate.xml +@@ -73,12 +73,22 @@ + + Allow Insecure TLS Requests + +- ++ + + + Keystone v3 Project Domain + +- ++ ++ ++ ++ Keystone v3 Project Domain ++ ++ ++ ++ ++ Keystone v3 User Domain ++ ++ + + + Keystone v3 User Domain +@@ -98,6 +108,16 @@ + + Disable functionality for dealing with shared storage + ++ ++ ++ ++ Replaced by domain ++ ++ ++ ++ ++ Replaced by domain ++ + + + +-- +2.17.1 + diff --git a/SOURCES/fence_evacuate-fix-evacuable-tag-mix-issue.patch b/SOURCES/fence_evacuate-fix-evacuable-tag-mix-issue.patch new file mode 100644 index 0000000..a83ff74 --- /dev/null +++ b/SOURCES/fence_evacuate-fix-evacuable-tag-mix-issue.patch @@ -0,0 +1,20 @@ +diff -uNr a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +--- a/agents/evacuate/fence_evacuate.py 2018-06-28 14:24:54.000000000 +0200 ++++ b/agents/evacuate/fence_evacuate.py 2018-07-11 09:08:56.975072003 +0200 +@@ -74,12 +74,15 @@ + } + + def _is_server_evacuable(server, evac_flavors, evac_images): ++ reason = "flavor "+server.flavor.get('id') + if server.flavor.get('id') in evac_flavors: + return True + if hasattr(server.image, 'get'): + if server.image.get('id') in evac_images: + return True +- logging.debug("Instance %s is not evacuable" % server.image.get('id')) ++ reason = reason +" and image "+server.image.get('id') ++ ++ logging.debug("Instance is not evacuable: no match for %s" % reason) + return False + + def _get_evacuable_flavors(connection): diff --git a/SOURCES/fence_gce-1-stackdriver-logging-default-method-cycle.patch b/SOURCES/fence_gce-1-stackdriver-logging-default-method-cycle.patch new file mode 100644 index 0000000..bafa753 --- /dev/null +++ b/SOURCES/fence_gce-1-stackdriver-logging-default-method-cycle.patch @@ -0,0 +1,674 @@ +From 59ae9d00060da5329d7ca538974498292bbe1d91 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Tue, 26 Jun 2018 10:18:29 -0300 +Subject: [PATCH 1/7] fence_gce: add support for stackdriver logging + +Add --logging option to enable sending logs to google stackdriver +--- + agents/gce/fence_gce.py | 65 +++++++++++++++++++++++++++++++++++++-- + tests/data/metadata/fence_gce.xml | 5 +++ + 2 files changed, 67 insertions(+), 3 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 3abb5207..3af5bfc8 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -1,12 +1,19 @@ + #!@PYTHON@ -tt + + import atexit ++import logging ++import platform + import sys ++import time + sys.path.append("@FENCEAGENTSLIBDIR@") + + import googleapiclient.discovery + from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action + ++ ++LOGGER = logging ++ ++ + def translate_status(instance_status): + "Returns on | off | unknown." + if instance_status == "RUNNING": +@@ -27,6 +34,7 @@ def get_nodes_list(conn, options): + + return result + ++ + def get_power_status(conn, options): + try: + instance = conn.instances().get( +@@ -38,18 +46,37 @@ def get_power_status(conn, options): + fail_usage("Failed: get_power_status: {}".format(str(err))) + + ++def wait_for_operation(conn, project, zone, operation): ++ while True: ++ result = conn.zoneOperations().get( ++ project=project, ++ zone=zone, ++ operation=operation['name']).execute() ++ if result['status'] == 'DONE': ++ if 'error' in result: ++ raise Exception(result['error']) ++ return ++ time.sleep(1) ++ ++ + def set_power_status(conn, options): + try: + if options["--action"] == "off": +- conn.instances().stop( ++ LOGGER.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"])) ++ operation = conn.instances().stop( + project=options["--project"], + zone=options["--zone"], + instance=options["--plug"]).execute() ++ wait_for_operation(conn, options["--project"], options["--zone"], operation) ++ LOGGER.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"])) + elif options["--action"] == "on": +- conn.instances().start( ++ LOGGER.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"])) ++ operation = conn.instances().start( + project=options["--project"], + zone=options["--zone"], + instance=options["--plug"]).execute() ++ wait_for_operation(conn, options["--project"], options["--zone"], operation) ++ LOGGER.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"])) + except Exception as err: + fail_usage("Failed: set_power_status: {}".format(str(err))) + +@@ -71,11 +98,24 @@ def define_new_opts(): + "required" : "1", + "order" : 3 + } ++ all_opt["logging"] = { ++ "getopt" : ":", ++ "longopt" : "logging", ++ "help" : "--logging=[bool] Logging, true/false", ++ "shortdesc" : "Stackdriver-logging support.", ++ "longdesc" : "If enabled (set to true), IP failover logs will be posted to stackdriver logging.", ++ "required" : "0", ++ "default" : "false", ++ "order" : 4 ++ } + + def main(): + conn = None ++ global LOGGER ++ ++ hostname = platform.node() + +- device_opt = ["port", "no_password", "zone", "project"] ++ device_opt = ["port", "no_password", "zone", "project", "logging"] + + atexit.register(atexit_handler) + +@@ -97,6 +137,25 @@ def main(): + + run_delay(options) + ++ # Prepare logging ++ logging_env = options.get('--logging') ++ if logging_env: ++ logging_env = logging_env.lower() ++ if any(x in logging_env for x in ['yes', 'true', 'enabled']): ++ try: ++ import google.cloud.logging.handlers ++ client = google.cloud.logging.Client() ++ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname) ++ formatter = logging.Formatter('gcp:stonish "%(message)s"') ++ LOGGER = logging.getLogger(hostname) ++ handler.setFormatter(formatter) ++ LOGGER.addHandler(handler) ++ LOGGER.setLevel(logging.INFO) ++ except ImportError: ++ LOGGER.error('Couldn\'t import google.cloud.logging, ' ++ 'disabling Stackdriver-logging support') ++ ++ # Prepare cli + try: + credentials = None + if tuple(googleapiclient.__version__) < tuple("1.6.0"): +diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml +index 2a147f21..805ecc6b 100644 +--- a/tests/data/metadata/fence_gce.xml ++++ b/tests/data/metadata/fence_gce.xml +@@ -30,6 +30,11 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui + + Project ID. + ++ ++ ++ ++ Stackdriver-logging support. ++ + + + + +From bb34acd8b0b150599c393d56dd81a7d8185b27d3 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Tue, 26 Jun 2018 10:44:41 -0300 +Subject: [PATCH 2/7] fence_gce: set project and zone as not required + +Try to retrieve the GCE project if the script is being executed inside a +GCE machine if --project is not provided. +Try to retrieve the zone automatically from GCE if --zone is not +provided. +--- + agents/gce/fence_gce.py | 63 +++++++++++++++++++++++++++++++++++++-- + tests/data/metadata/fence_gce.xml | 4 +-- + 2 files changed, 63 insertions(+), 4 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 3af5bfc8..e53dc5a6 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -12,6 +12,8 @@ + + + LOGGER = logging ++METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/' ++METADATA_HEADERS = {'Metadata-Flavor': 'Google'} + + + def translate_status(instance_status): +@@ -81,13 +83,56 @@ def set_power_status(conn, options): + fail_usage("Failed: set_power_status: {}".format(str(err))) + + ++def get_instance(conn, project, zone, instance): ++ request = conn.instances().get( ++ project=project, zone=zone, instance=instance) ++ return request.execute() ++ ++ ++def get_zone(conn, project, instance): ++ request = conn.instances().aggregatedList(project=project) ++ while request is not None: ++ response = request.execute() ++ zones = response.get('items', {}) ++ for zone in zones.values(): ++ for inst in zone.get('instances', []): ++ if inst['name'] == instance: ++ return inst['zone'].split("/")[-1] ++ request = conn.instances().aggregatedList_next( ++ previous_request=request, previous_response=response) ++ raise Exception("Unable to find instance %s" % (instance)) ++ ++ ++def get_metadata(metadata_key, params=None, timeout=None): ++ """Performs a GET request with the metadata headers. ++ ++ Args: ++ metadata_key: string, the metadata to perform a GET request on. ++ params: dictionary, the query parameters in the GET request. ++ timeout: int, timeout in seconds for metadata requests. ++ ++ Returns: ++ HTTP response from the GET request. ++ ++ Raises: ++ urlerror.HTTPError: raises when the GET request fails. ++ """ ++ timeout = timeout or 60 ++ metadata_url = os.path.join(METADATA_SERVER, metadata_key) ++ params = urlparse.urlencode(params or {}) ++ url = '%s?%s' % (metadata_url, params) ++ request = urlrequest.Request(url, headers=METADATA_HEADERS) ++ request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({})) ++ return request_opener.open(request, timeout=timeout * 1.1).read() ++ ++ + def define_new_opts(): + all_opt["zone"] = { + "getopt" : ":", + "longopt" : "zone", + "help" : "--zone=[name] Zone, e.g. us-central1-b", + "shortdesc" : "Zone.", +- "required" : "1", ++ "required" : "0", + "order" : 2 + } + all_opt["project"] = { +@@ -95,7 +140,7 @@ def define_new_opts(): + "longopt" : "project", + "help" : "--project=[name] Project ID", + "shortdesc" : "Project ID.", +- "required" : "1", ++ "required" : "0", + "order" : 3 + } + all_opt["logging"] = { +@@ -109,6 +154,7 @@ def define_new_opts(): + "order" : 4 + } + ++ + def main(): + conn = None + global LOGGER +@@ -165,6 +211,19 @@ def main(): + except Exception as err: + fail_usage("Failed: Create GCE compute v1 connection: {}".format(str(err))) + ++ # Get project and zone ++ if not options.get("--project"): ++ try: ++ options["--project"] = get_metadata('project/project-id') ++ except Exception as err: ++ fail_usage("Failed retrieving GCE project. Please provide --project option: {}".format(str(err))) ++ ++ if not options.get("--zone"): ++ try: ++ options["--zone"] = get_zone(conn, options['--project'], options['--plug']) ++ except Exception as err: ++ fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err))) ++ + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) +diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml +index 805ecc6b..507b8385 100644 +--- a/tests/data/metadata/fence_gce.xml ++++ b/tests/data/metadata/fence_gce.xml +@@ -20,12 +20,12 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui + + Physical plug number on device, UUID or identification of machine + +- ++ + + + Zone. + +- ++ + + + Project ID. + +From 8ae1af8068d1718a861a25bf954e14392384fa55 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Wed, 4 Jul 2018 09:25:46 -0300 +Subject: [PATCH 3/7] fence_gce: add power cycle as default method + +Add function to power cycle an instance and set cycle as the default +method to reboot. +--- + agents/gce/fence_gce.py | 21 +++++++++++++++++++-- + tests/data/metadata/fence_gce.xml | 8 ++++++++ + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index e53dc5a6..3f77dc24 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -83,6 +83,21 @@ def set_power_status(conn, options): + fail_usage("Failed: set_power_status: {}".format(str(err))) + + ++def power_cycle(conn, options): ++ try: ++ LOGGER.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"])) ++ operation = conn.instances().reset( ++ project=options["--project"], ++ zone=options["--zone"], ++ instance=options["--plug"]).execute() ++ wait_for_operation(conn, options["--project"], options["--zone"], operation) ++ LOGGER.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"])) ++ return True ++ except Exception as err: ++ LOGGER.error("Failed: power_cycle: {}".format(str(err))) ++ return False ++ ++ + def get_instance(conn, project, zone, instance): + request = conn.instances().get( + project=project, zone=zone, instance=instance) +@@ -161,13 +176,15 @@ def main(): + + hostname = platform.node() + +- device_opt = ["port", "no_password", "zone", "project", "logging"] ++ device_opt = ["port", "no_password", "zone", "project", "logging", "method"] + + atexit.register(atexit_handler) + + define_new_opts() + + all_opt["power_timeout"]["default"] = "60" ++ all_opt["method"]["default"] = "cycle" ++ all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)" + + options = check_input(device_opt, process_input(device_opt)) + +@@ -225,7 +242,7 @@ def main(): + fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err))) + + # Operate the fencing device +- result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) ++ result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list, power_cycle) + sys.exit(result) + + if __name__ == "__main__": +diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml +index 507b8385..f522550f 100644 +--- a/tests/data/metadata/fence_gce.xml ++++ b/tests/data/metadata/fence_gce.xml +@@ -10,6 +10,14 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui + + Fencing action + ++ ++ ++ ++ ++ Method to fence ++ + + + + +From 68644764695b79a3b75826fe009ea7da675677f7 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Thu, 5 Jul 2018 11:04:32 -0300 +Subject: [PATCH 4/7] fence_gce: add missing imports to retrieve the project + +--- + agents/gce/fence_gce.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 3f77dc24..9b7b5e55 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -2,9 +2,18 @@ + + import atexit + import logging ++import os + import platform + import sys + import time ++if sys.version_info >= (3, 0): ++ # Python 3 imports. ++ import urllib.parse as urlparse ++ import urllib.request as urlrequest ++else: ++ # Python 2 imports. ++ import urllib as urlparse ++ import urllib2 as urlrequest + sys.path.append("@FENCEAGENTSLIBDIR@") + + import googleapiclient.discovery + +From f8f3f11187341622c26e4e439dfda6a37ad660b0 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Thu, 5 Jul 2018 11:05:32 -0300 +Subject: [PATCH 5/7] fence_gce: s/--loging/--stackdriver-logging/ + +--- + agents/gce/fence_gce.py | 42 ++++++++++++++++++--------------------- + tests/data/metadata/fence_gce.xml | 11 +++++++--- + 2 files changed, 27 insertions(+), 26 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 9b7b5e55..a6befe39 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -167,14 +167,13 @@ def define_new_opts(): + "required" : "0", + "order" : 3 + } +- all_opt["logging"] = { +- "getopt" : ":", +- "longopt" : "logging", +- "help" : "--logging=[bool] Logging, true/false", ++ all_opt["stackdriver-logging"] = { ++ "getopt" : "", ++ "longopt" : "stackdriver-logging", ++ "help" : "--stackdriver-logging Enable Logging to Stackdriver", + "shortdesc" : "Stackdriver-logging support.", +- "longdesc" : "If enabled (set to true), IP failover logs will be posted to stackdriver logging.", ++ "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging.", + "required" : "0", +- "default" : "false", + "order" : 4 + } + +@@ -185,7 +184,7 @@ def main(): + + hostname = platform.node() + +- device_opt = ["port", "no_password", "zone", "project", "logging", "method"] ++ device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", "method"] + + atexit.register(atexit_handler) + +@@ -210,22 +209,19 @@ def main(): + run_delay(options) + + # Prepare logging +- logging_env = options.get('--logging') +- if logging_env: +- logging_env = logging_env.lower() +- if any(x in logging_env for x in ['yes', 'true', 'enabled']): +- try: +- import google.cloud.logging.handlers +- client = google.cloud.logging.Client() +- handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname) +- formatter = logging.Formatter('gcp:stonish "%(message)s"') +- LOGGER = logging.getLogger(hostname) +- handler.setFormatter(formatter) +- LOGGER.addHandler(handler) +- LOGGER.setLevel(logging.INFO) +- except ImportError: +- LOGGER.error('Couldn\'t import google.cloud.logging, ' +- 'disabling Stackdriver-logging support') ++ if options.get('--stackdriver-logging'): ++ try: ++ import google.cloud.logging.handlers ++ client = google.cloud.logging.Client() ++ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname) ++ formatter = logging.Formatter('gcp:stonish "%(message)s"') ++ LOGGER = logging.getLogger(hostname) ++ handler.setFormatter(formatter) ++ LOGGER.addHandler(handler) ++ LOGGER.setLevel(logging.INFO) ++ except ImportError: ++ LOGGER.error('Couldn\'t import google.cloud.logging, ' ++ 'disabling Stackdriver-logging support') + + # Prepare cli + try: +diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml +index f522550f..79b82ebb 100644 +--- a/tests/data/metadata/fence_gce.xml ++++ b/tests/data/metadata/fence_gce.xml +@@ -38,9 +38,14 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui + + Project ID. + +- +- +- ++ ++ ++ ++ Stackdriver-logging support. ++ ++ ++ ++ + Stackdriver-logging support. + + + +From 9ae0a072424fa982e1d18a2cb661628c38601c3a Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Sat, 7 Jul 2018 18:42:01 -0300 +Subject: [PATCH 6/7] fence_gce: use root logger for stackdriver + +--- + agents/gce/fence_gce.py | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index a6befe39..1d5095ae 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -20,7 +20,6 @@ + from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action + + +-LOGGER = logging + METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/' + METADATA_HEADERS = {'Metadata-Flavor': 'Google'} + +@@ -73,37 +72,37 @@ def wait_for_operation(conn, project, zone, operation): + def set_power_status(conn, options): + try: + if options["--action"] == "off": +- LOGGER.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"])) ++ logging.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"])) + operation = conn.instances().stop( + project=options["--project"], + zone=options["--zone"], + instance=options["--plug"]).execute() + wait_for_operation(conn, options["--project"], options["--zone"], operation) +- LOGGER.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"])) ++ logging.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"])) + elif options["--action"] == "on": +- LOGGER.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"])) ++ logging.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"])) + operation = conn.instances().start( + project=options["--project"], + zone=options["--zone"], + instance=options["--plug"]).execute() + wait_for_operation(conn, options["--project"], options["--zone"], operation) +- LOGGER.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"])) ++ logging.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"])) + except Exception as err: + fail_usage("Failed: set_power_status: {}".format(str(err))) + + + def power_cycle(conn, options): + try: +- LOGGER.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"])) ++ logging.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"])) + operation = conn.instances().reset( + project=options["--project"], + zone=options["--zone"], + instance=options["--plug"]).execute() + wait_for_operation(conn, options["--project"], options["--zone"], operation) +- LOGGER.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"])) ++ logging.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"])) + return True + except Exception as err: +- LOGGER.error("Failed: power_cycle: {}".format(str(err))) ++ logging.error("Failed: power_cycle: {}".format(str(err))) + return False + + +@@ -180,7 +179,6 @@ def define_new_opts(): + + def main(): + conn = None +- global LOGGER + + hostname = platform.node() + +@@ -209,18 +207,21 @@ def main(): + run_delay(options) + + # Prepare logging +- if options.get('--stackdriver-logging'): ++ if options.get('--stackdriver-logging') is not None: + try: + import google.cloud.logging.handlers + client = google.cloud.logging.Client() + handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname) ++ handler.setLevel(logging.INFO) + formatter = logging.Formatter('gcp:stonish "%(message)s"') +- LOGGER = logging.getLogger(hostname) + handler.setFormatter(formatter) +- LOGGER.addHandler(handler) +- LOGGER.setLevel(logging.INFO) ++ root_logger = logging.getLogger() ++ if options.get('--verbose') is None: ++ root_logger.setLevel(logging.INFO) ++ logging.getLogger("googleapiclient").setLevel(logging.ERROR) ++ root_logger.addHandler(handler) + except ImportError: +- LOGGER.error('Couldn\'t import google.cloud.logging, ' ++ logging.error('Couldn\'t import google.cloud.logging, ' + 'disabling Stackdriver-logging support') + + # Prepare cli + +From a52e643708908539d6e5fdb5d36a6cea935e4481 Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Wed, 11 Jul 2018 17:16:49 -0300 +Subject: [PATCH 7/7] fence_gce: minor changes in logging + +- Remove hostname (use --plug instead). +- Supress messages from googleapiclient and oauth2client if not error in +non verbose mode. +- s/stonish/stonith +--- + agents/gce/fence_gce.py | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 1d5095ae..3eca0139 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -3,7 +3,6 @@ + import atexit + import logging + import os +-import platform + import sys + import time + if sys.version_info >= (3, 0): +@@ -180,8 +179,6 @@ def define_new_opts(): + def main(): + conn = None + +- hostname = platform.node() +- + device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", "method"] + + atexit.register(atexit_handler) +@@ -207,18 +204,20 @@ def main(): + run_delay(options) + + # Prepare logging +- if options.get('--stackdriver-logging') is not None: ++ if options.get('--verbose') is None: ++ logging.getLogger('googleapiclient').setLevel(logging.ERROR) ++ logging.getLogger('oauth2client').setLevel(logging.ERROR) ++ if options.get('--stackdriver-logging') is not None and options.get('--plug'): + try: + import google.cloud.logging.handlers + client = google.cloud.logging.Client() +- handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname) ++ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=options['--plug']) + handler.setLevel(logging.INFO) +- formatter = logging.Formatter('gcp:stonish "%(message)s"') ++ formatter = logging.Formatter('gcp:stonith "%(message)s"') + handler.setFormatter(formatter) + root_logger = logging.getLogger() + if options.get('--verbose') is None: + root_logger.setLevel(logging.INFO) +- logging.getLogger("googleapiclient").setLevel(logging.ERROR) + root_logger.addHandler(handler) + except ImportError: + logging.error('Couldn\'t import google.cloud.logging, ' diff --git a/SOURCES/fence_gce-2-filter-aggregatedlist.patch b/SOURCES/fence_gce-2-filter-aggregatedlist.patch new file mode 100644 index 0000000..29b7203 --- /dev/null +++ b/SOURCES/fence_gce-2-filter-aggregatedlist.patch @@ -0,0 +1,25 @@ +From 8e801d513b9a500ac0d717476aadc1cdabc0a92e Mon Sep 17 00:00:00 2001 +From: Helen Koike +Date: Thu, 19 Jul 2018 13:13:53 -0300 +Subject: [PATCH] fence_gce: filter call to aggregatedList + +Don't list all the instances in the project, filter only the one we are +interested in. +--- + agents/gce/fence_gce.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +index 3eca0139..93cd1180 100644 +--- a/agents/gce/fence_gce.py ++++ b/agents/gce/fence_gce.py +@@ -112,7 +112,8 @@ def get_instance(conn, project, zone, instance): + + + def get_zone(conn, project, instance): +- request = conn.instances().aggregatedList(project=project) ++ fl = 'name="%s"' % instance ++ request = conn.instances().aggregatedList(project=project, filter=fl) + while request is not None: + response = request.execute() + zones = response.get('items', {}) diff --git a/SOURCES/fence_gce-3-stackdriver-logging-note.patch b/SOURCES/fence_gce-3-stackdriver-logging-note.patch new file mode 100644 index 0000000..8589b77 --- /dev/null +++ b/SOURCES/fence_gce-3-stackdriver-logging-note.patch @@ -0,0 +1,34 @@ +diff -uNr a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +--- a/agents/gce/fence_gce.py 2018-07-30 16:09:45.811531118 +0200 ++++ b/agents/gce/fence_gce.py 2018-07-30 16:31:28.970202508 +0200 +@@ -174,9 +174,9 @@ + all_opt["stackdriver-logging"] = { + "getopt" : "", + "longopt" : "stackdriver-logging", +- "help" : "--stackdriver-logging Enable Logging to Stackdriver", +- "shortdesc" : "Stackdriver-logging support.", +- "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging.", ++ "help" : "--stackdriver-logging Enable Logging to Stackdriver. Using stackdriver logging requires additional libraries (google-cloud-logging).", ++ "shortdesc" : "Stackdriver-logging support. Requires additional libraries (google-cloud-logging).", ++ "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging. Using stackdriver logging requires additional libraries (google-cloud-logging).", + "required" : "0", + "order" : 4 + } +diff -uNr a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml +--- a/tests/data/metadata/fence_gce.xml 2018-07-30 16:09:45.548532576 +0200 ++++ b/tests/data/metadata/fence_gce.xml 2018-07-30 16:32:05.392988450 +0200 +@@ -41,12 +41,12 @@ + + + +- Stackdriver-logging support. ++ Stackdriver-logging support. Requires additional libraries (google-cloud-logging). + + + + +- Stackdriver-logging support. ++ Stackdriver-logging support. Requires additional libraries (google-cloud-logging). + + + diff --git a/SOURCES/fence_ilo3-fence_ipmilan-show-correct-default-method.patch b/SOURCES/fence_ilo3-fence_ipmilan-show-correct-default-method.patch new file mode 100644 index 0000000..677ebb1 --- /dev/null +++ b/SOURCES/fence_ilo3-fence_ipmilan-show-correct-default-method.patch @@ -0,0 +1,26 @@ +From bd1b11884f33f5fce5ca7618c9f87b540592e1b6 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 2 Jul 2018 16:36:41 +0200 +Subject: [PATCH] fence_ilo3/fence_ipmilan: show correct default method (onoff) + in help + +--- + agents/ipmilan/fence_ipmilan.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/ipmilan/fence_ipmilan.py b/agents/ipmilan/fence_ipmilan.py +index 453d7365..9610f1c6 100644 +--- a/agents/ipmilan/fence_ipmilan.py ++++ b/agents/ipmilan/fence_ipmilan.py +@@ -171,7 +171,7 @@ def main(): + all_opt["lanplus"]["default"] = "1" + + all_opt["ipport"]["default"] = "623" +- all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)\n" \ ++ all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)\n" \ + "WARNING! This fence agent might report success before the node is powered off. " \ + "You should use -m/method onoff if your fence device works correctly with that option." + +-- +2.17.1 + diff --git a/SOURCES/fence_impilan-fence_ilo_ssh-add-ilo5-support.patch b/SOURCES/fence_impilan-fence_ilo_ssh-add-ilo5-support.patch new file mode 100644 index 0000000..8e23e64 --- /dev/null +++ b/SOURCES/fence_impilan-fence_ilo_ssh-add-ilo5-support.patch @@ -0,0 +1,33 @@ +diff -uNr a/agents/ilo_ssh/fence_ilo_ssh.py b/agents/ilo_ssh/fence_ilo_ssh.py +--- a/agents/ilo_ssh/fence_ilo_ssh.py 2018-06-18 12:14:35.000000000 +0200 ++++ b/agents/ilo_ssh/fence_ilo_ssh.py 2018-06-28 12:26:14.274615003 +0200 +@@ -54,7 +54,8 @@ + device via ssh and reboot a specified outlet. " + docs["vendorurl"] = "http://www.hp.com" + docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"), +- ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH")] ++ ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH"), ++ ("fence_ilo5_ssh", "Fence agent for HP iLO5 over SSH")] + show_docs(options, docs) + + options["eol"] = "\r" +diff -uNr a/agents/ipmilan/fence_ipmilan.py b/agents/ipmilan/fence_ipmilan.py +--- a/agents/ipmilan/fence_ipmilan.py 2018-06-18 12:14:35.000000000 +0200 ++++ b/agents/ipmilan/fence_ipmilan.py 2018-06-28 12:26:14.275614990 +0200 +@@ -169,6 +169,8 @@ + all_opt["lanplus"]["default"] = "1" + elif os.path.basename(sys.argv[0]) == "fence_ilo4": + all_opt["lanplus"]["default"] = "1" ++ elif os.path.basename(sys.argv[0]) == "fence_ilo5": ++ all_opt["lanplus"]["default"] = "1" + + all_opt["ipport"]["default"] = "623" + all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)\n" \ +@@ -187,6 +189,7 @@ + docs["vendorurl"] = "" + docs["symlink"] = [("fence_ilo3", "Fence agent for HP iLO3"), + ("fence_ilo4", "Fence agent for HP iLO4"), ++ ("fence_ilo5", "Fence agent for HP iLO5"), + ("fence_imm", "Fence agent for IBM Integrated Management Module"), + ("fence_idrac", "Fence agent for Dell iDRAC")] + show_docs(options, docs) diff --git a/SOURCES/fence_kdump-fix-strncpy-issue.patch b/SOURCES/fence_kdump-fix-strncpy-issue.patch new file mode 100644 index 0000000..7514b81 --- /dev/null +++ b/SOURCES/fence_kdump-fix-strncpy-issue.patch @@ -0,0 +1,36 @@ +From ac83d8ce3d8dd868b0e887528e7c269cee4dcac8 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 31 Jul 2018 15:57:38 +0200 +Subject: [PATCH] fence_kdump: fix strncpy issue + +--- + agents/kdump/fence_kdump.c | 2 +- + agents/kdump/fence_kdump_send.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/kdump/fence_kdump.c b/agents/kdump/fence_kdump.c +index e2f3cd80..768a9344 100644 +--- a/agents/kdump/fence_kdump.c ++++ b/agents/kdump/fence_kdump.c +@@ -351,7 +351,7 @@ get_options_node (fence_kdump_opts_t *opts) + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + +- strncpy (node->name, opts->nodename, sizeof (node->name)); ++ strncpy (node->name, opts->nodename, sizeof (node->name) - 1); + snprintf (node->port, sizeof (node->port), "%d", opts->ipport); + + node->info = NULL; +diff --git a/agents/kdump/fence_kdump_send.c b/agents/kdump/fence_kdump_send.c +index d668bed3..638f8c97 100644 +--- a/agents/kdump/fence_kdump_send.c ++++ b/agents/kdump/fence_kdump_send.c +@@ -116,7 +116,7 @@ get_options_node (fence_kdump_opts_t *opts) + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + +- strncpy (node->name, opts->nodename, sizeof (node->name)); ++ strncpy (node->name, opts->nodename, sizeof (node->name) - 1); + snprintf (node->port, sizeof (node->port), "%d", opts->ipport); + + node->info = NULL; diff --git a/SOURCES/fence_mpath-watchdog-support.patch b/SOURCES/fence_mpath-watchdog-support.patch new file mode 100644 index 0000000..c2f0122 --- /dev/null +++ b/SOURCES/fence_mpath-watchdog-support.patch @@ -0,0 +1,176 @@ +From 199b1efee0ba1f01c27ca689a15465cf4a258ee6 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 22 Jan 2018 11:27:28 +0100 +Subject: [PATCH] fence_mpath: add watchdog support + +--- + agents/Makefile.am | 11 ++++++++ + agents/mpath/fence_mpath.py | 50 ++++++++++++++++++++++++++++++++++--- + configure.ac | 6 +++++ + make/fencebuild.mk | 2 +- + tests/data/metadata/fence_mpath.xml | 2 +- + 5 files changed, 66 insertions(+), 5 deletions(-) + +diff --git a/agents/Makefile.am b/agents/Makefile.am +index 2524a3ab..833d2af5 100644 +--- a/agents/Makefile.am ++++ b/agents/Makefile.am +@@ -50,6 +50,11 @@ zvm_fence_zvm_SOURCES = zvm/fence_zvm.c + zvm_fence_zvm_CFLAGS = -D_GNU_SOURCE -Izvm + endif + ++if BUILD_FENCE_MPATH ++mpathdatadir = $(CLUSTERDATA) ++mpathdata_SCRIPTS = mpath/fence_mpath_check mpath/fence_mpath_check_hardreboot ++endif ++ + if BUILD_FENCE_SCSI + scsidatadir = $(CLUSTERDATA) + scsidata_SCRIPTS = scsi/fence_scsi_check scsi/fence_scsi_check_hardreboot +@@ -72,6 +77,12 @@ manual/fence_ack_manual: manual/fence_ack_manual.in + -e 's#@clustervarrun@#${CLUSTERVARRUN}#g' \ + > $@ + ++mpath/fence_mpath_check: mpath/fence_mpath ++ cp $^ $@ ++ ++mpath/fence_mpath_check_hardreboot: mpath/fence_mpath ++ cp $^ $@ ++ + scsi/fence_scsi_check: scsi/fence_scsi + cp $^ $@ + +diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py +index ac5bc794..d9ac2ef5 100644 +--- a/agents/mpath/fence_mpath.py ++++ b/agents/mpath/fence_mpath.py +@@ -143,25 +143,63 @@ def dev_write(options, dev): + store_fh.write(dev + "\t" + options["--key"] + "\n") + store_fh.close() + +-def dev_read(options): ++def dev_read(options, fail=True): + dev_key = {} + file_path = options["--store-path"] + "/mpath.devices" + try: + store_fh = open(file_path, "r") + except IOError: +- fail_usage("Failed: Cannot open file \"" + file_path + "\"") ++ if fail: ++ fail_usage("Failed: Cannot open file \"" + file_path + "\"") ++ else: ++ return None + # get not empty lines from file + for (device, key) in [line.strip().split() for line in store_fh if line.strip()]: + dev_key[device] = key + store_fh.close() + return dev_key + ++def mpath_check_get_verbose(): ++ try: ++ f = open("/etc/sysconfig/watchdog", "r") ++ except IOError: ++ return False ++ match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE) ++ f.close() ++ return bool(match) ++ ++def mpath_check(hardreboot=False): ++ if len(sys.argv) >= 3 and sys.argv[1] == "repair": ++ return int(sys.argv[2]) ++ options = {} ++ options["--mpathpersist-path"] = "/usr/sbin/mpathpersist" ++ options["--store-path"] = "/var/run/cluster" ++ options["--power-timeout"] = "5" ++ if mpath_check_get_verbose(): ++ logging.getLogger().setLevel(logging.DEBUG) ++ devs = dev_read(options, fail=False) ++ if not devs: ++ logging.error("No devices found") ++ return 0 ++ for dev, key in list(devs.items()): ++ 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) ++ logging.debug("key " + key + " registered with any devices") ++ ++ if hardreboot == True: ++ libc = ctypes.cdll['libc.so.6'] ++ libc.reboot(0x1234567) ++ return 2 ++ + def define_new_opts(): + all_opt["devices"] = { + "getopt" : "d:", + "longopt" : "devices", + "help" : "-d, --devices=[devices] List of devices to use for current operation", +- "required" : "1", ++ "required" : "0", + "shortdesc" : "List of devices to use for current operation. Devices can \ + be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). \ + Each device must support SCSI-3 persistent reservations.", +@@ -205,6 +243,12 @@ def main(): + + define_new_opts() + ++ # fence_mpath_check ++ if os.path.basename(sys.argv[0]) == "fence_mpath_check": ++ sys.exit(mpath_check()) ++ elif os.path.basename(sys.argv[0]) == "fence_mpath_check_hardreboot": ++ sys.exit(mpath_check(hardreboot=True)) ++ + options = check_input(device_opt, process_input(device_opt), other_conditions=True) + + docs = {} +diff --git a/configure.ac b/configure.ac +index e8b24211..24b857b3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -148,6 +148,11 @@ if echo "$AGENTS_LIST" | grep -q -E "all|manual"; then + AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s/manual( |$)//") + fi + ++FENCE_MPATH=0 ++if echo "$AGENTS_LIST" | grep -q -E "all|mpath"; then ++ FENCE_MPATH=1 ++fi ++ + FENCE_SCSI=0 + if echo "$AGENTS_LIST" | grep -q -E "all|scsi"; then + FENCE_SCSI=1 +@@ -312,6 +317,7 @@ AC_SUBST([SNMPBIN]) + AC_SUBST([AGENTS_LIST]) + AM_CONDITIONAL(BUILD_FENCE_KDUMP, test $FENCE_KDUMP -eq 1) + AM_CONDITIONAL(BUILD_FENCE_MANUAL, test $FENCE_MANUAL -eq 1) ++AM_CONDITIONAL(BUILD_FENCE_MPATH, test $FENCE_MPATH -eq 1) + AM_CONDITIONAL(BUILD_FENCE_SCSI, test $FENCE_SCSI -eq 1) + AM_CONDITIONAL(BUILD_FENCE_ZVM, test $FENCE_ZVM -eq 1) + AM_CONDITIONAL(BUILD_XENAPILIB, test $XENAPILIB -eq 1) +diff --git a/make/fencebuild.mk b/make/fencebuild.mk +index e08d5200..6a7c6f63 100644 +--- a/make/fencebuild.mk ++++ b/make/fencebuild.mk +@@ -51,7 +51,7 @@ $(TARGET): + $(call gen_agent_from_py) + + clean: clean-man +- rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(scsidata_SCRIPTS) */*.pyc *.pyc */*.wiki ++ rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(mpathdata_SCRIPTS) $(scsidata_SCRIPTS) */*.pyc */*.wiki + + if [ "$(abs_builddir)" = "$(abs_top_builddir)/lib" ]; then \ + rm -f $(TARGET); \ +diff --git a/tests/data/metadata/fence_mpath.xml b/tests/data/metadata/fence_mpath.xml +index f384e50b..bbe9ad2b 100644 +--- a/tests/data/metadata/fence_mpath.xml ++++ b/tests/data/metadata/fence_mpath.xml +@@ -9,7 +9,7 @@ The fence_mpath agent works by having a unique key for each node that has to be + + Fencing action + +- ++ + + + List of devices to use for current operation. Devices can be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). Each device must support SCSI-3 persistent reservations. diff --git a/SOURCES/fix-version.patch b/SOURCES/fix-version.patch new file mode 100644 index 0000000..dbb2fc2 --- /dev/null +++ b/SOURCES/fix-version.patch @@ -0,0 +1,10 @@ +diff -uNr a/.tarball-version b/.tarball-version +--- a/.tarball-version 1970-01-01 01:00:00.000000000 +0100 ++++ b/.tarball-version 2018-08-20 10:42:03.876068353 +0200 +@@ -0,0 +1 @@ ++4.2.1 +diff -uNr a/.version b/.version +--- a/.version 1970-01-01 01:00:00.000000000 +0100 ++++ b/.version 2018-08-20 10:52:35.712060731 +0200 +@@ -0,0 +1 @@ ++4.2.1 diff --git a/SOURCES/python3-has_key-fixes.patch b/SOURCES/python3-has_key-fixes.patch new file mode 100644 index 0000000..9252cb1 --- /dev/null +++ b/SOURCES/python3-has_key-fixes.patch @@ -0,0 +1,74 @@ +From 29f93ed6f7f79cad801bf08ad9172c8a62183435 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 14 Aug 2018 12:33:41 +0200 +Subject: [PATCH] fence_compute/fence_evacuate/fence_rhevm: dont use has_key + (not supported in Python 3) + +--- + agents/compute/fence_compute.py | 4 ++-- + agents/evacuate/fence_evacuate.py | 4 ++-- + agents/rhevm/fence_rhevm.py | 4 ++-- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index ec2d093c..254e2670 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -311,7 +311,7 @@ def create_nova_connection(options): + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +- http_log_debug=options.has_key("--verbose")) ++ http_log_debug="--verbose" in options) + else: + # OSP >= 11 + # ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None) +@@ -319,7 +319,7 @@ def create_nova_connection(options): + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +- http_log_debug=options.has_key("--verbose")) ++ http_log_debug="--verbose" in options) + + try: + nova.hypervisors.list() +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 615dede7..6818c44f 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -245,7 +245,7 @@ def create_nova_connection(options): + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +- http_log_debug=options.has_key("--verbose")) ++ http_log_debug="--verbose" in options) + else: + # OSP >= 11 + # ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None) +@@ -253,7 +253,7 @@ def create_nova_connection(options): + region_name=options["--region-name"], + endpoint_type=options["--endpoint-type"], + session=keystone_session, auth=keystone_auth, +- http_log_debug=options.has_key("--verbose")) ++ http_log_debug="--verbose" in options) + + try: + nova.hypervisors.list() +diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py +index 0594e66b..c06b7c39 100644 +--- a/agents/rhevm/fence_rhevm.py ++++ b/agents/rhevm/fence_rhevm.py +@@ -74,11 +74,11 @@ def send_command(opt, command, method="GET"): + url = "https:" + else: + url = "http:" +- if opt.has_key("--api-path"): ++ if "--api-path" in opt: + api_path = opt["--api-path"] + else: + api_path = "/ovirt-engine/api" +- if opt.has_key("--disable-http-filter"): ++ if "--disable-http-filter" in opt: + http_filter = 'false' + else: + http_filter = 'true' diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec new file mode 100644 index 0000000..bfb236a --- /dev/null +++ b/SPECS/fence-agents.spec @@ -0,0 +1,1327 @@ +# Copyright 2004-2011 Red Hat, Inc. +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. + +# keep around ready for later user +## global alphatag git0a6184070 + +# bundles +%global bundled_lib_dir bundled +# alibaba +# python-pycryptodome bundle +%global pycryptodome pycryptodome +%global pycryptodome_version 3.6.4 +%global pycryptodome_dir %{bundled_lib_dir}/aliyun/%{pycryptodome} +# python-aliyun-sdk-core bundle +%global aliyunsdkcore aliyun-python-sdk-core +%global aliyunsdkcore_version 2.13.1 +%global aliyunsdkcore_dir %{bundled_lib_dir}/aliyun/%{aliyunsdkcore} +# python-aliyun-sdk-ecs bundle +%global aliyunsdkecs aliyun-python-sdk-ecs +%global aliyunsdkecs_version 4.9.3 +%global aliyunsdkecs_dir %{bundled_lib_dir}/aliyun/%{aliyunsdkecs} +# python-aliyun-sdk-vpc bundle +%global aliyunsdkvpc aliyun-python-sdk-vpc +%global aliyunsdkvpc_version 3.0.2 +%global aliyunsdkvpc_dir %{bundled_lib_dir}/aliyun/%{aliyunsdkvpc} + +Name: fence-agents +Summary: Set of unified programs capable of host isolation ("fencing") +Version: 4.2.1 +Release: 41%{?alphatag:.%{alphatag}}%{?dist} +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +URL: https://github.com/ClusterLabs/fence-agents +Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz +Source1: %{pycryptodome}-%{pycryptodome_version}.tar.gz +Source2: %{aliyunsdkcore}-%{aliyunsdkcore_version}.tar.gz +Source3: %{aliyunsdkecs}-%{aliyunsdkecs_version}.tar.gz +Source4: %{aliyunsdkvpc}-%{aliyunsdkvpc_version}.tar.gz +Patch0: fence_impilan-fence_ilo_ssh-add-ilo5-support.patch +Patch1: fence_mpath-watchdog-support.patch +Patch2: fence_ilo3-fence_ipmilan-show-correct-default-method.patch +Patch3: fence_evacuate-fix-evacuable-tag-mix-issue.patch +Patch4: fence_compute-fence_evacuate-fix-compute-domain.patch +Patch5: fence_gce-1-stackdriver-logging-default-method-cycle.patch +Patch6: fence_gce-2-filter-aggregatedlist.patch +Patch7: fence_aliyun-1.patch +Patch8: fence_aliyun-2.patch +Patch9: fence_aliyun-3-logging.patch +Patch10: fence_aliyun-4-bundled.patch +Patch11: python3-has_key-fixes.patch +Patch12: fence_kdump-fix-strncpy-issue.patch +Patch13: fix-version.patch +Patch14: fence_gce-3-stackdriver-logging-note.patch +Patch15: fence_aliyun-5-list-instance-names.patch +Patch16: fence_aliyun-6-correct-help-indentation.patch +Patch17: fence_cisco_ucs-encode-POSTFIELDS.patch +Patch18: bz1654968-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch +Patch19: bz1654976-1-fence_scsi-watchdog-retry-support.patch +Patch20: bz1654976-2-build-fix-check_used_options.patch +Patch21: bz1654616-fence_hpblade-fix-log_expect_syntax.patch +Patch22: bz1654973-fence_vmware_soap-cleanup-sigterm.patch +Patch23: bz1650214-fence_azure_arm-bundled.patch +Patch24: bz1666914-1-fence_redfish.patch +Patch25: bz1666914-2-fence_redfish-fail-invalid-cert.patch +Patch26: bz1677327-1-fence_redfish-use-ipport-parameter.patch +Patch27: bz1677327-2-fence_redfish-ip-parameter-backward-compatibility.patch +Patch28: bz1696584-fence_gce-fix-python3-encoding-issue.patch +Patch29: bz1709926-fence_mpath-fix-watchdog-hardreboot.patch +Patch30: bz1709780-fence_rhevm-RHEV-v4-API-support.patch +Patch31: bz1712263-fence_rhevm-1-use-UTF8-encoding.patch +Patch32: bz1712263-fence_rhevm-2-fix-debug-encoding-issues.patch +Patch33: bz1700546-fence_azure_arm-skip_shutdown.patch +Patch34: bz1704228-fence_redfish-full-redfish-spec-compliance.patch +Patch35: bz1714458-fence_scsi-node-id-new-format.patch +Patch36: bz1720198-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch +Patch37: bz1732773-fence_vmware_rest-fix-keyerror-suspended-vms.patch +Patch38: bz1748443-fence_zvmip-python3-fixes.patch +Patch39: bz1732766-fence_aliyun-1-add-RAM-role.patch +Patch40: bz1732766-fence_aliyun-2-import-EcsRamRoleCredential.patch +Patch41: bz1734811-fence_iloX_ssh-monitor-timeout-warning.patch +Patch42: bz1751704-fence_mpath-fix-watchdog-trigger-multipath-disconnect.patch +Patch43: bz1760213-fence_compute-disable-service-after-force-down.patch +Patch44: bz1760201-fence_compute-fence_evacuate-1-fix-region_name-type.patch +Patch45: bz1760224-fence_vmware_rest-improve-logging.patch +Patch46: bz1760201-fence_compute-fence_evacuate-2-fix-project-shortopt.patch +Patch47: bz1769783-fencing-improve-stdin-quote-parsing.patch +Patch48: bz1763674-fence_rhevm-add-cookie-support.patch +Patch49: bz1773890-fence_scsi-add-hash-key-value-support.patch +Patch50: bz1774458-fence_sbd-stderr-support.patch +Patch51: bz1771594-1-fencing-inetX_only-SSH-fence_zvmip.patch +Patch52: bz1771594-2-fence_redfish-fence_vmware_soap-suppress-warning.patch +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 + +%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 +%ifarch x86_64 +%global testagents virsh heuristics_ping aliyun aws azure_arm gce +%endif +%ifarch ppc64le +%global testagents virsh lpar heuristics_ping +%endif +%ifarch s390x +%global testagents virsh zvm heuristics_ping +%endif +%ifnarch x86_64 ppc64le s390x +%global testagents virsh heuristics_ping +%endif + +%global allfenceagents %(cat < /dev/null 2>&1 ||: + +%description +A collection of executables to handle isolation ("fencing") of possibly +misbehaving hosts by the means of remote power management, blocking +network, storage, or similar. They operate through a unified interface +(calling conventions) devised for the original Red Hat clustering solution. + +%package common +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Common base for Fence Agents +Requires: python3-pexpect python3-pycurl +BuildArch: noarch +%description common +A collection of executables to handle isolation ("fencing") of possibly +misbehaving hosts by the means of remote power management, blocking +network, storage, or similar. + +This package contains support files including the Python fencing library. +%files common +%doc doc/COPYING.* doc/COPYRIGHT doc/README.licence +%{_datadir}/fence +%exclude %{_datadir}/fence/azure_fence.* +%exclude %{_datadir}/fence/__pycache__/azure_fence.* +%exclude %{_datadir}/fence/XenAPI.* +%exclude %{_datadir}/fence/__pycache__/XenAPI.* +%{_datadir}/cluster +%exclude %{_datadir}/cluster/fence_mpath_check* +%exclude %{_datadir}/cluster/fence_scsi_check* +%exclude %{_sbindir}/* +%exclude %{_mandir}/man8/* + +%package all +License: GPLv2+ and LGPLv2+ and ASL 2.0 +Group: System Environment/Base +Summary: Set of unified programs capable of host isolation ("fencing") +Requires: %(echo "%{allfenceagents}" | sed "s/\( \|$\)/ >= %{version}-%{release}\1/g") +%ifarch i686 x86_64 +Requires: fence-virt +%endif +%ifarch ppc64le +Requires: fence-agents-lpar >= %{version}-%{release} +%endif +%ifarch s390x +Requires: fence-agents-zvm >= %{version}-%{release} +%endif +Provides: %{name} >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +%description all +A collection of executables to handle isolation ("fencing") of possibly +misbehaving hosts by the means of remote power management, blocking +network, storage, or similar. + +This package serves as a catch-all for all supported fence agents. +%files all + +%ifarch x86_64 +%package aliyun +License: GPLv2+ and LGPLv2+ and ASL 2.0 and BSD and MIT +Group: System Environment/Base +Summary: Fence agent for Alibaba Cloud (Aliyun) +Requires: fence-agents-common >= %{version}-%{release} +Requires: python3-jmespath >= 0.9.0 +# python-pycryptodome bundle +Provides: bundled(python-%{pycryptodome}) = %{pycryptodome_version} +# python-aliyun-sdk-core bundle +Provides: bundled(python-aliyun-sdk-core) = %{aliyunsdkcore_version} +# python-aliyun-sdk-ecs bundle +Provides: bundled(python-aliyun-sdk-ecs) = %{aliyunsdkecs_version} +# python-aliyun-sdk-vpc bundle +Provides: bundled(python-aliyun-sdk-vpc) = %{aliyunsdkvpc_version} +Obsoletes: %{name} < %{version}-%{release} +%description aliyun +The fence-agents-aliyun package contains a fence agent for Alibaba Cloud (Aliyun) instances. +%files aliyun +%defattr(-,root,root,-) +# bundled libraries +%doc pycryptodome_README.rst aliyun*_README* +%license pycryptodome_LICENSE.rst +%{_sbindir}/fence_aliyun +%{_mandir}/man8/fence_aliyun.8* +# bundled libraries +/usr/lib/fence-agents/%{bundled_lib_dir}/aliyun +%endif + +%package amt-ws +License: ASL 2.0 +Group: System Environment/Base +Summary: Fence agent for Intel AMT (WS-Man) devices +Requires: fence-agents-common >= %{version}-%{release} +Requires: openwsman-python3 +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description amt-ws +The fence-agents-amt-ws package contains a fence agent for AMT (WS-Man) devices. +%files amt-ws +%defattr(-,root,root,-) +%{_sbindir}/fence_amt_ws +%{_mandir}/man8/fence_amt_ws.8* + +%package apc +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for APC devices +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description apc +Fence agent for APC devices that are accessed via telnet or SSH. +%files apc +%{_sbindir}/fence_apc +%{_mandir}/man8/fence_apc.8* + +%package apc-snmp +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agents for APC devices (SNMP) +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description apc-snmp +Fence agents for APC devices that are accessed via the SNMP protocol. +%files apc-snmp +%{_sbindir}/fence_apc_snmp +%{_mandir}/man8/fence_apc_snmp.8* + +%ifarch x86_64 +%package aws +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Amazon AWS +Requires: fence-agents-common >= %{version}-%{release} +Requires: python3-boto3 +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description aws +Fence agent for Amazon AWS instances. +%files aws +%{_sbindir}/fence_aws +%{_mandir}/man8/fence_aws.8* +%endif + +%ifarch x86_64 +%package azure-arm +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Azure Resource Manager +Requires: fence-agents-common >= %{version}-%{release} +Requires: python3-azure-sdk >= 4.0.0-9 +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description azure-arm +Fence agent for Azure Resource Manager instances. +%files azure-arm +%{_sbindir}/fence_azure_arm +%{_datadir}/fence/azure_fence.py* +%{_datadir}/fence/__pycache__/azure_fence.* +%{_mandir}/man8/fence_azure_arm.8* +%endif + +%package bladecenter +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM BladeCenter +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description bladecenter +Fence agent for IBM BladeCenter devices that are accessed +via telnet or SSH. +%files bladecenter +%{_sbindir}/fence_bladecenter +%{_mandir}/man8/fence_bladecenter.8* + +%package brocade +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Brocade switches +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description brocade +Fence agent for Brocade devices that are accessed via telnet or SSH. +%files brocade +%{_sbindir}/fence_brocade +%{_mandir}/man8/fence_brocade.8* + +%package cisco-mds +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Cisco MDS 9000 series +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description cisco-mds +Fence agent for Cisco MDS 9000 series devices that are accessed +via the SNMP protocol. +%files cisco-mds +%{_sbindir}/fence_cisco_mds +%{_mandir}/man8/fence_cisco_mds.8* + +%package cisco-ucs +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Cisco UCS series +Requires: python3-pycurl +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description cisco-ucs +Fence agent for Cisco UCS series devices that are accessed +via the SNMP protocol. +%files cisco-ucs +%{_sbindir}/fence_cisco_ucs +%{_mandir}/man8/fence_cisco_ucs.8* + +%package compute +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Nova compute nodes +Requires: python3-requests +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description compute +Fence agent for Nova compute nodes. +%files compute +%{_sbindir}/fence_compute +%{_sbindir}/fence_evacuate +%{_mandir}/man8/fence_compute.8* +%{_mandir}/man8/fence_evacuate.8* + +%package drac5 +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Dell DRAC 5 +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description drac5 +Fence agent for Dell DRAC 5 series devices that are accessed +via telnet or SSH. +%files drac5 +%{_sbindir}/fence_drac5 +%{_mandir}/man8/fence_drac5.8* + +%package eaton-snmp +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Eaton network power switches +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description eaton-snmp +Fence agent for Eaton network power switches that are accessed +via the SNMP protocol. +%files eaton-snmp +%{_sbindir}/fence_eaton_snmp +%{_mandir}/man8/fence_eaton_snmp.8* + +%package emerson +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Emerson devices (SNMP) +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description emerson +Fence agent for Emerson devices that are accessed via +the SNMP protocol. +%files emerson +%{_sbindir}/fence_emerson +%{_mandir}/man8/fence_emerson.8* + +%package eps +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for ePowerSwitch 8M+ power switches +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description eps +Fence agent for ePowerSwitch 8M+ power switches that are accessed +via the HTTP(s) protocol. +%files eps +%{_sbindir}/fence_eps +%{_mandir}/man8/fence_eps.8* + +%ifarch x86_64 +%package gce +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for GCE (Google Cloud Engine) +Requires: fence-agents-common >= %{version}-%{release} +Requires: python3-google-api-client +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description gce +Fence agent for GCE (Google Cloud Engine) instances. +%files gce +%{_sbindir}/fence_gce +%{_mandir}/man8/fence_gce.8* +%endif + +%package heuristics-ping +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Pseudo fence agent to affect other agents based on ping-heuristics +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description heuristics-ping +Fence pseudo agent used to affect other agents based on +ping-heuristics. +%files heuristics-ping +%{_sbindir}/fence_heuristics_ping +%{_mandir}/man8/fence_heuristics_ping.8* + +%package hpblade +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for HP BladeSystem devices +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description hpblade +Fence agent for HP BladeSystem devices that are accessed via telnet +or SSH. +%files hpblade +%{_sbindir}/fence_hpblade +%{_mandir}/man8/fence_hpblade.8* + +%package ibmblade +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM BladeCenter +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ibmblade +Fence agent for IBM BladeCenter devices that are accessed +via the SNMP protocol. +%files ibmblade +%{_sbindir}/fence_ibmblade +%{_mandir}/man8/fence_ibmblade.8* + +%package ifmib +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for devices with IF-MIB interfaces +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ifmib +Fence agent for IF-MIB interfaces that are accessed via +the SNMP protocol. +%files ifmib +%{_sbindir}/fence_ifmib +%{_mandir}/man8/fence_ifmib.8* + +%package ilo2 +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agents for HP iLO2 devices +Requires: gnutls-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ilo2 +Fence agents for HP iLO2 devices that are accessed via +the HTTP(s) protocol. +%files ilo2 +%{_sbindir}/fence_ilo +%{_sbindir}/fence_ilo2 +%{_mandir}/man8/fence_ilo.8* +%{_mandir}/man8/fence_ilo2.8* + +%package ilo-moonshot +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for HP iLO Moonshot devices +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ilo-moonshot +Fence agent for HP iLO Moonshot devices that are accessed +via telnet or SSH. +%files ilo-moonshot +%{_sbindir}/fence_ilo_moonshot +%{_mandir}/man8/fence_ilo_moonshot.8* + +%package ilo-mp +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for HP iLO MP devices +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ilo-mp +Fence agent for HP iLO MP devices that are accessed via telnet or SSH. +%files ilo-mp +%{_sbindir}/fence_ilo_mp +%{_mandir}/man8/fence_ilo_mp.8* + +%package ilo-ssh +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agents for HP iLO devices over SSH +Requires: openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ilo-ssh +Fence agents for HP iLO devices that are accessed via telnet or SSH. +%files ilo-ssh +%{_sbindir}/fence_ilo_ssh +%{_mandir}/man8/fence_ilo_ssh.8* +%{_sbindir}/fence_ilo3_ssh +%{_mandir}/man8/fence_ilo3_ssh.8* +%{_sbindir}/fence_ilo4_ssh +%{_mandir}/man8/fence_ilo4_ssh.8* +%{_sbindir}/fence_ilo5_ssh +%{_mandir}/man8/fence_ilo5_ssh.8* + +%package intelmodular +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for devices with Intel Modular interfaces +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description intelmodular +Fence agent for Intel Modular interfaces that are accessed +via the SNMP protocol. +%files intelmodular +%{_sbindir}/fence_intelmodular +%{_mandir}/man8/fence_intelmodular.8* + +%package ipdu +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM iPDU network power switches +Requires: net-snmp-utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ipdu +Fence agent for IBM iPDU network power switches that are accessed +via the SNMP protocol. +%files ipdu +%{_sbindir}/fence_ipdu +%{_mandir}/man8/fence_ipdu.8* + +%package ipmilan +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agents for devices with IPMI interface +Requires: /usr/bin/ipmitool +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description ipmilan +Fence agents for devices with IPMI interface. +%files ipmilan +%{_sbindir}/fence_ipmilan +%{_mandir}/man8/fence_ipmilan.8* +%{_sbindir}/fence_idrac +%{_mandir}/man8/fence_idrac.8* +%{_sbindir}/fence_ilo3 +%{_mandir}/man8/fence_ilo3.8* +%{_sbindir}/fence_ilo4 +%{_mandir}/man8/fence_ilo4.8* +%{_sbindir}/fence_ilo5 +%{_mandir}/man8/fence_ilo5.8* +%{_sbindir}/fence_imm +%{_mandir}/man8/fence_imm.8* + +%package kdump +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for use with kdump crash recovery service +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +# this cannot be noarch since it's compiled +%description kdump +Fence agent for use with kdump crash recovery service. +%files kdump +%{_sbindir}/fence_kdump +%{_libexecdir}/fence_kdump_send +%{_mandir}/man8/fence_kdump.8* +%{_mandir}/man8/fence_kdump_send.8* + +%ifarch ppc64le +%package lpar +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM LPAR +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description lpar +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+ +Group: System Environment/Base +Summary: Fence agent for reservations over Device Mapper Multipath +Requires: device-mapper-multipath +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description mpath +Fence agent for SCSI persistent reservation over +Device Mapper Multipath. +%files mpath +%{_sbindir}/fence_mpath +%{_datadir}/cluster/fence_mpath_check* +%{_mandir}/man8/fence_mpath.8* + +%package redfish +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Redfish +Requires: fence-agents-common >= %{version}-%{release} +Requires: python3-requests +Obsoletes: %{name} < %{version}-%{release} +%description redfish +The fence-agents-redfish package contains a fence agent for Redfish +%files redfish +%defattr(-,root,root,-) +%{_sbindir}/fence_redfish +%{_mandir}/man8/fence_redfish.8* + +%package rhevm +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for RHEV-M +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description rhevm +Fence agent for RHEV-M via REST API. +%files rhevm +%{_sbindir}/fence_rhevm +%{_mandir}/man8/fence_rhevm.8* + +%if 0%{?fedora} || 0%{?rhel} > 7 +%package rsa +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM RSA II +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description rsa +Fence agent for IBM RSA II devices that are accessed +via telnet or SSH. +%files rsa +%{_sbindir}/fence_rsa +%{_mandir}/man8/fence_rsa.8* +%endif + +%package rsb +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for Fujitsu RSB +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description rsb +Fence agent for Fujitsu RSB devices that are accessed +via telnet or SSH. +%files rsb +%{_sbindir}/fence_rsb +%{_mandir}/man8/fence_rsb.8* + +%if 0%{?fedora} || 0%{?rhel} > 7 +%package sbd +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for SBD (storage-based death) +Requires: sbd +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description sbd +Fence agent for SBD (storage-based death). +%files sbd +%{_sbindir}/fence_sbd +%{_mandir}/man8/fence_sbd.8* +%endif + +%package scsi +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for SCSI persistent reservations +Requires: sg3_utils +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description scsi +Fence agent for SCSI persistent reservations. +%files scsi +%{_sbindir}/fence_scsi +%{_datadir}/cluster/fence_scsi_check +%{_datadir}/cluster/fence_scsi_check_hardreboot +%{_mandir}/man8/fence_scsi.8* + +%package virsh +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for virtual machines based on libvirt +Requires: openssh-clients /usr/bin/virsh +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description virsh +Fence agent for virtual machines that are accessed via SSH. +%files virsh +%{_sbindir}/fence_virsh +%{_mandir}/man8/fence_virsh.8* + +%package vmware-rest +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for VMWare with REST API +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description vmware-rest +Fence agent for VMWare with REST API. +%files vmware-rest +%{_sbindir}/fence_vmware_rest +%{_mandir}/man8/fence_vmware_rest.8* + +%package vmware-soap +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for VMWare with SOAP API v4.1+ +Requires: python3-suds python3-requests +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description vmware-soap +Fence agent for VMWare with SOAP API v4.1+. +%files vmware-soap +%{_sbindir}/fence_vmware_soap +%{_mandir}/man8/fence_vmware_soap.8* + +%package wti +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for WTI Network power switches +Requires: telnet openssh-clients +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description wti +Fence agent for WTI network power switches that are accessed +via telnet or SSH. +%files wti +%{_sbindir}/fence_wti +%{_mandir}/man8/fence_wti.8* + +%ifarch s390x +%package zvm +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM z/VM over IP +Requires: fence-agents-common >= %{version}-%{release} +Obsoletes: %{name} < %{version}-%{release} +BuildArch: noarch +%description zvm +Fence agent for IBM z/VM over IP. +%files zvm +%{_sbindir}/fence_zvmip +%{_mandir}/man8/fence_zvmip.8* +%endif + +%changelog +* Thu Feb 13 2020 Oyvind Albrigtsen - 4.2.1-41 +- fence_mpath: add plug parameter support to be able to use pcmk_host_map + Resolves: rhbz#1753228 +- fence_mpath: fix --reserve parameter typo + Resolves: rhbz#1798641 + +* Fri Jan 31 2020 Oyvind Albrigtsen - 4.2.1-40 +- fence_aws: improve logging and metadata/usage text + Resolves: rhbz#1781357 + +* Tue Nov 26 2019 Oyvind Albrigtsen - 4.2.1-39 +- fencing: only use inetX_only parameters for SSH based agents and + fence_zvmip + Resolves: rhbz#1771594 + +* Wed Nov 20 2019 Oyvind Albrigtsen - 4.2.1-38 +- fence_sbd: add stderr support + Resolves: rhbz#1774458 + +* Tue Nov 19 2019 Oyvind Albrigtsen - 4.2.1-37 +- fence_scsi: add hash key-value support + Resolves: rhbz#1773890 + +* Wed Nov 13 2019 Oyvind Albrigtsen - 4.2.1-35 +- fence_rhevm: add cookie support + Resolves: rhbz#1763674 + +* Thu Nov 7 2019 Oyvind Albrigtsen - 4.2.1-34 +- fence_compute/fence_evacuate: fix region_name content type and + project shortopt in usage text and project-domain shortopt + Resolves: rhbz#1760201 +- fencing: improve stdin quote parsing + Resolves: rhbz#1769783 + +* Fri Oct 18 2019 Oyvind Albrigtsen - 4.2.1-33 +- fence_vmware_rest: improve logging + Resolves: rhbz#1760224 + +* Wed Oct 16 2019 Oyvind Albrigtsen - 4.2.1-32 +- fence_compute: disable service after force-down + Resolves: rhbz#1760213 + +* Thu Oct 3 2019 Oyvind Albrigtsen - 4.2.1-31 +- fence_aliyun: add RAM role support + Resolves: rhbz#1732766 +- fence_ilo4_ssh/fence_ilo5_ssh: add monitor timeout warning + Resolves: rhbz#1734811 +- fence_mpath: fix watchdog reboot not triggered when multipath + disconnected + Resolves: rhbz#1751704 + +* Fri Sep 6 2019 Oyvind Albrigtsen - 4.2.1-30 +- fence_zvmip: fix Python 3 issues + Resolves: rhbz#1748443 + +* Thu Jul 25 2019 Oyvind Albrigtsen - 4.2.1-29 +- fence_vmware_rest: fix KeyError issue for suspended VMs + Resolves: rhbz#1732773 + +* Wed Jul 24 2019 Oyvind Albrigtsen - 4.2.1-28 +- fence_mpath: fix watchdog hardreboot + Resolves: rhbz#1709926 + +* Thu Jun 13 2019 Oyvind Albrigtsen - 4.2.1-27 +- fence_scsi watchdog: fix failing on first try when using retry + Resolves: rhbz#1720198 + +* Tue May 28 2019 Oyvind Albrigtsen - 4.2.1-25 +- fence_redfish: add header for full Redfish spec compliance + Resolves: rhbz#1704228 +- fence_scsi: fix to match new node ID format + Resolves: rhbz#1714458 + +* Thu May 23 2019 Oyvind Albrigtsen - 4.2.1-24 +- fence_azure_arm: use skip_shutdown feature + Resolves: rhbz#1700546 + +* Tue May 21 2019 Oyvind Albrigtsen - 4.2.1-23 +- fence_rhevm: add RHEV v4 API support and auto-detection + Resolves: rhbz#1709780 +- fence_rhevm: fix encoding issues + Resolves: rhbz#1712263 + +* Fri Apr 5 2019 Oyvind Albrigtsen - 4.2.1-22 +- fence_gce: fix Python 3 encoding issue + Resolves: rhbz#1696584 + +* Mon Apr 1 2019 Oyvind Albrigtsen - 4.2.1-21 +- Add CI gating tests + Resolves: rhbz#1682125 + +* Fri Mar 22 2019 Oyvind Albrigtsen - 4.2.1-20 +- fence_aliyun: upgrade python-aliyun-sdk-core to fix httplib issue + Resolves: rhbz#1677945 + +* Tue Mar 19 2019 Oyvind Albrigtsen - 4.2.1-18 +- fence_redfish: use ipport parameter + Resolves: rhbz#1677327 + +* Fri Feb 8 2019 Oyvind Albrigtsen - 4.2.1-17 +- fence-agents-vmware-soap: add missing python3-requests dependency + Resolves: rhbz#1591502 + +* Mon Jan 28 2019 Oyvind Albrigtsen - 4.2.1-16 +- fence_redfish: new fence agent + Resolves: rhbz#1666914 + +* Fri Jan 25 2019 Oyvind Albrigtsen - 4.2.1-13 +- fence-agents-scsi: add missing fence-agents-common dependency + Resolves: rhbz#1665170 +- fence_azure_arm: add bundled directory to search path + Resolves: rhbz#1650214 + +* Fri Dec 7 2018 Oyvind Albrigtsen - 4.2.1-11 +- fence_scsi: fix incorrect SCSI-key when node ID is 10 or higher + Resolves: rhbz#1654968 +- fence_scsi: add watchdog retry support + Resolves: rhbz#1654976 +- fence_hpblade: fix log_expect syntax + Resolves: rhbz#1654616 +- fence_vmware_soap: cleanup when receiving SIGTERM + Resolves: rhbz#1654973 + +* Mon Oct 8 2018 Oyvind Albrigtsen - 4.2.1-10 +- spec-file improvements by Jan Pokorny +- fence_aliyun: bundled libraries + Resolves: rhbz#1625208 + +* Tue Aug 14 2018 Oyvind Albrigtsen - 4.2.1-7 +- fence_kdump: fix strncpy issue + +* Wed Jul 11 2018 Oyvind Albrigtsen - 4.2.1-6 +- fence_evacuate: fix evacuable tag mix issue + +* Wed Jul 4 2018 Oyvind Albrigtsen - 4.2.1-5 +- Use %{__python3} macro to set correct Python #! + +* Mon Jun 18 2018 Oyvind Albrigtsen - 4.2.1-4 +- fence_vmware_soap: fix python3-suds issue +- Remove unsupported agents + +* Mon Jun 11 2018 Oyvind Albrigtsen - 4.2.1-2 +- Remove fence-agents-amt due to missing amtterm + +* Thu May 31 2018 Oyvind Albrigtsen - 4.2.1-1 +- new upstream release + +* Thu May 17 2018 Oyvind Albrigtsen - 4.2.0-1 +- new upstream release + +* Thu Feb 15 2018 Oyvind Albrigtsen - 4.1.1-1 +- new upstream release +- fence_vmware_soap / fence_ovh: use Python 2 till python3-suds bug + is fixed + +* Fri Feb 9 2018 Oyvind Albrigtsen - 4.1.0-2 +- new upstream release + +* Wed Feb 07 2018 Fedora Release Engineering - 4.0.24-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Jan 11 2018 Iryna Shcherbina - 4.0.24-14 +- Cleanup no longer needed Python 2 dependencies + +* Tue Nov 07 2017 Troy Dawson - 4.0.24-13 +- Cleanup spec file conditionals + +* Tue Aug 29 2017 Oyvind Albrigtsen - 4.0.24-12 +- fence-agents-common: remove fence_scsi_check files +- fence-scsi: add "fence_scsi_check_hardreboot" + +* Thu Aug 3 2017 Oyvind Albrigtsen - 4.0.24-10 +- fence_zvm: fix "uintptr_t" undeclared + +* Thu Aug 3 2017 Oyvind Albrigtsen - 4.0.24-9 +- Fix encoding for pexpect with Python 3.6 + + Resolves: rhbz#1473908 + +* Wed Aug 02 2017 Fedora Release Engineering - 4.0.24-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 4.0.24-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering - 4.0.24-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Fri Dec 23 2016 Oyvind Albrigtsen - 4.0.24-5 +- Fix to build in Python 3 only environment + +* Mon Dec 19 2016 Miro Hrončok - 4.0.24-4 +- Rebuild for Python 3.6 + +* Wed Sep 21 2016 Marek Grac - 4.0.24-4 +- Remove Obsoletes that are no longer valid + +* Fri Sep 2 2016 Oyvind Albrigtsen - 4.0.24-2 +- fence-agents-common: add dependency on python3-pycurl + +* Fri Aug 26 2016 Oyvind Albrigtsen - 4.0.24-1 +- new upstream release + +* Wed Jul 13 2016 Oyvind Albrigtsen - 4.0.23-2 +- fix build issue on s390 + +* Tue Jul 12 2016 Oyvind Albrigtsen - 4.0.23-1 +- new upstream release +- new package fence-agents-amt-ws +- new package fence-agents-compute +- new package fence-agents-drac +- new package fence-agents-hds-cb +- new package fence-agents-mpath +- new package fence-agents-sanbox2 +- new package fence-agents-sbd +- new package fence-agents-vbox +- new package fence-agents-vmware +- new package fence-agents-xenapi + +* Wed Feb 03 2016 Fedora Release Engineering - 4.0.20-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Aug 11 2015 Marek Grac - 4.0.20-1 +- new upstream release +- new package fence-agents-rcd-serial + +* Wed Jun 17 2015 Fedora Release Engineering - 4.0.16-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Thu Mar 05 2015 Marek Grac - 4.0.16-1 +- new upstream release + +* Mon Feb 09 2015 Marek Grac - 4.0.15-1 +- new upstream release + +* Thu Jan 08 2015 Marek Grac - 4.0.14-1 +- new upstream release +- new packages fence-agents-zvm and fence-agents-emerson + +* Thu Oct 16 2014 Marek Grac - 4.0.12-1 +- new upstream release +- new package fence-agents-ilo-ssh + +* Wed Aug 27 2014 Marek Grac - 4.0.10 +- new upstream release +- new package fence-agents-ilo-moonshot + +* Sat Jun 07 2014 Fedora Release Engineering - 4.0.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri May 16 2014 Marek Grac - 4.0.9 +- new upstream release +- new package fence-agents-pve + +* Mon Apr 07 2014 Marek Grac - 4.0.8-1 +- new upstream release +- new package fence-agents-raritan + +* Wed Feb 26 2014 Marek Grac - 4.0.7-3 +- requires a specific version of fence-agents-common + +* Mon Feb 17 2014 Marek Grac - 4.0.7-2 +- new upstream release +- changed dependancy from nss/nspr to gnutls-utils + +* Fri Jan 10 2014 Marek Grac - 4.0.4-4 +- new upstream release +- new package fence-agents-amt + +* Mon Oct 07 2013 Marek Grac - 4.0.4-3 +- new upstream release +- new package fence-agents-netio + +* Tue Sep 03 2013 Marek Grac - 4.0.3-1 +- new upstream release +- new packages fence-agents-brocade and fence-agents-ovh + +* Sat Aug 03 2013 Fedora Release Engineering - 4.0.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu Jul 18 2013 Petr Pisar - 4.0.1-2 +- Perl 5.18 rebuild + +* Mon Jul 01 2013 Marek Grac - 4.0.1-1 +- new upstream release + +* Mon Jun 24 2013 Marek Grac - 4.0.0-5 +- fence-agents-all should provide fence-agent for clean update path + +* Wed Apr 03 2013 Marek Grac - 4.0.0-4 +- minor changes in spec file + +* Thu Mar 21 2013 Marek Grac - 4.0.0-3 +- minor changes in spec file + +* Mon Mar 18 2013 Marek Grac - 4.0.0-2 +- minor changes in spec file + +* Mon Mar 11 2013 Marek Grac - 4.0.0-1 +- new upstream release +- introducing subpackages + +