commit 510d72e4eab74db319ee683fb3be8629bdc4ac6c Author: CentOS Sources Date: Tue Aug 6 15:18:43 2019 -0400 import fence-agents-4.2.1-27.el8 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/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..3357efa --- /dev/null +++ b/SPECS/fence-agents.spec @@ -0,0 +1,1191 @@ +# 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: 27%{?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 + +%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: fence-agents >= %{version}-%{release} +Obsoletes: fence-agents < 3.1.13 +%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: fence-agents +%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 +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} +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} +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 +BuildArch: noarch +Obsoletes: fence-agents +%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 +BuildArch: noarch +Obsoletes: fence-agents +%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} +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} +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} +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} +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} +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} +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} +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} +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} +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 +BuildArch: noarch +Obsoletes: fence-agents +%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} +BuildArch: noarch +Obsoletes: fence-agents +%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} +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} +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} +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} +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} +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} +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} +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} +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} +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} +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} +# 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} +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} +BuildArch: noarch +%description mpath +Fence agent for SCSI persistent reservation over +Device Mapper Multipath. +%files mpath +%{_sbindir}/fence_mpath +%{_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: fence-agents +%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} +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} +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} +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} +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} +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} +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} +BuildArch: noarch +Obsoletes: fence-agents +%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} +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} +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} +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 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_mpath: fix watchdog hardreboot + Resolves: rhbz#1709926 +- 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 + +