From 021bc560abbe2e35125b629ab68ba2704ca5c4b7 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: May 10 2022 06:59:37 +0000 Subject: import fence-agents-4.2.1-89.el8 --- diff --git a/.fence-agents.metadata b/.fence-agents.metadata index b269488..a89b55a 100644 --- a/.fence-agents.metadata +++ b/.fence-agents.metadata @@ -1,19 +1,38 @@ +3297473a9d57e93ff378eab173990c1b64673c01 SOURCES/Jinja2-3.0.2.tar.gz +e1b766b2b1601fde67b3b19ed2f13b9746bb1cca SOURCES/MarkupSafe-2.0.1.tar.gz +a8c40a3ae9d4c159382a58db3153d83e5521c51e SOURCES/PyYAML-6.0.tar.gz 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 2512ff4ef016cad0b916006f6acf2a309f908c4d SOURCES/botocore-1.23.46.tar.gz +0d12f48faa727f0979e9ad5c4c80dfa32b73caff SOURCES/cachetools-4.2.4.tar.gz b13e22d55867e2ca5f92e5289cfdc21ba6e343aa SOURCES/certifi-2021.10.8.tar.gz 2384f6cfba4685d901262e073a4455d4cf76d102 SOURCES/chardet-4.0.0.tar.gz 865df92e66e5dc7b940144cbad8115c07dc8784f SOURCES/charset-normalizer-2.0.7.tar.gz e2561df8e7ff9113dab118a651371dd88dab0142 SOURCES/fence-agents-4.2.1.tar.gz +f4e578dc0ed68d6667d7b36cdfc2647d55e9858f SOURCES/google-auth-2.3.0.tar.gz +74ec77d2e2ef6b2ef8503e6e398faa6f3ba298ae SOURCES/httplib2-0.19.1-py3-none-any.whl 08c0449533fc94462f78652dea209099754d9ee4 SOURCES/idna-3.3.tar.gz 356c48dfea2214dd9e7e2b222a99dddfe9c0d05c SOURCES/jmespath-0.10.0.tar.gz +d06a9547b1a87e9c51b0a7c708189d993f2e3d89 SOURCES/kubernetes-12.0.1.tar.gz +f6efa66f6106b069b5c0e0cf8cc677e4e96c91ca SOURCES/oauthlib-3.1.1.tar.gz +570d69d8c108ebb8aee562389d13b07dfb61ce25 SOURCES/openshift-0.12.1.tar.gz bccbc1bf76a9db46998eb8e1ffa2f2a2baf9237a SOURCES/packaging-21.2-py3-none-any.whl +e0fa19f8fda46a1fa2253477499b116b33f67175 SOURCES/pyasn1-0.4.8.tar.gz +43b89feb6864fe359aae89120627165219de313b SOURCES/pyasn1-modules-0.2.8.tar.gz 326a73f58a62ebee00c11a12cfdd838b196e0e8e SOURCES/pycryptodome-3.6.4.tar.gz c8307f47e3b75a2d02af72982a2dfefa3f56e407 SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl +6082312a090f5be5e796e0854294da0738ec0379 SOURCES/pyparsing-3.0.1.tar.gz c2ba10c775b7a52a4b57cac4d4110a0c0f812a82 SOURCES/python-dateutil-2.8.2.tar.gz +1dc2fa004aa6517f1620e55d8a7b8e68a9cf2a47 SOURCES/python-string-utils-1.0.0.tar.gz 8c7a89d183d3e9b70bf91ba5b75eccf7111b9d8d SOURCES/requests-2.26.0.tar.gz +f139aed770519b6a095b8fdc888d03955cbe9d8e SOURCES/requests-oauthlib-1.3.0.tar.gz +e8a53067e03fe1b6682fd99a40a7359396a06daa SOURCES/rsa-4.7.2.tar.gz +d1011ff44cd5a045de0460c1b79ec65592e86860 SOURCES/ruamel.yaml-0.17.16.tar.gz +27de97227bbbde5a9f571f9fad223578d7bdf7cc SOURCES/ruamel.yaml.clib-0.2.6.tar.gz +d5354718cb8c9330d3abc27445467ce8a5ed9d70 SOURCES/setuptools-58.3.0.tar.gz a4f02fddae697614e356cadfddb6241cc7737f38 SOURCES/setuptools_scm-6.3.2.tar.gz 06fa0bb50f2a4e2917fd14c21e9d2d5508ce0163 SOURCES/six-1.16.0.tar.gz b42b7960047441db7dc021cc20e14279bd836f8d SOURCES/tomli-1.0.1.tar.gz eb35c3fd8b0867ae988a15917d6b80e8bdf60222 SOURCES/urllib3-1.26.7.tar.gz +540f083782c584989c1a0f69ffd69ba7aae07db6 SOURCES/websocket-client-1.2.1.tar.gz diff --git a/.gitignore b/.gitignore index 55913df..21e220e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,38 @@ +SOURCES/Jinja2-3.0.2.tar.gz +SOURCES/MarkupSafe-2.0.1.tar.gz +SOURCES/PyYAML-6.0.tar.gz 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/botocore-1.23.46.tar.gz +SOURCES/cachetools-4.2.4.tar.gz SOURCES/certifi-2021.10.8.tar.gz SOURCES/chardet-4.0.0.tar.gz SOURCES/charset-normalizer-2.0.7.tar.gz SOURCES/fence-agents-4.2.1.tar.gz +SOURCES/google-auth-2.3.0.tar.gz +SOURCES/httplib2-0.19.1-py3-none-any.whl SOURCES/idna-3.3.tar.gz SOURCES/jmespath-0.10.0.tar.gz +SOURCES/kubernetes-12.0.1.tar.gz +SOURCES/oauthlib-3.1.1.tar.gz +SOURCES/openshift-0.12.1.tar.gz SOURCES/packaging-21.2-py3-none-any.whl +SOURCES/pyasn1-0.4.8.tar.gz +SOURCES/pyasn1-modules-0.2.8.tar.gz SOURCES/pycryptodome-3.6.4.tar.gz SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl +SOURCES/pyparsing-3.0.1.tar.gz SOURCES/python-dateutil-2.8.2.tar.gz +SOURCES/python-string-utils-1.0.0.tar.gz SOURCES/requests-2.26.0.tar.gz +SOURCES/requests-oauthlib-1.3.0.tar.gz +SOURCES/rsa-4.7.2.tar.gz +SOURCES/ruamel.yaml-0.17.16.tar.gz +SOURCES/ruamel.yaml.clib-0.2.6.tar.gz +SOURCES/setuptools-58.3.0.tar.gz SOURCES/setuptools_scm-6.3.2.tar.gz SOURCES/six-1.16.0.tar.gz SOURCES/tomli-1.0.1.tar.gz SOURCES/urllib3-1.26.7.tar.gz +SOURCES/websocket-client-1.2.1.tar.gz diff --git a/SOURCES/bz1470827-all-agents-log-exceptions-fail.patch b/SOURCES/bz1470827-all-agents-log-exceptions-fail.patch new file mode 100644 index 0000000..34818be --- /dev/null +++ b/SOURCES/bz1470827-all-agents-log-exceptions-fail.patch @@ -0,0 +1,198 @@ +From bf32059e26f6a7d019df0f7949ce66adf997bc21 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 8 Feb 2019 14:16:31 +0100 +Subject: [PATCH] log exceptions to be more detailed when failing + +--- + agents/apc/fence_apc.py | 6 ++++-- + agents/cisco_ucs/fence_cisco_ucs.py | 3 ++- + agents/eps/fence_eps.py | 3 ++- + agents/ilo_moonshot/fence_ilo_moonshot.py | 3 ++- + agents/lpar/fence_lpar.py | 6 ++++-- + agents/ovh/fence_ovh.py | 3 ++- + agents/sanbox2/fence_sanbox2.py | 12 ++++++++---- + agents/vmware_soap/fence_vmware_soap.py | 9 ++++++--- + 8 files changed, 30 insertions(+), 15 deletions(-) + +diff --git a/agents/apc/fence_apc.py b/agents/apc/fence_apc.py +index 24a5a4232..dd0287f83 100644 +--- a/agents/apc/fence_apc.py ++++ b/agents/apc/fence_apc.py +@@ -90,7 +90,8 @@ def get_power_status(conn, options): + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() +- except KeyError: ++ except KeyError as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + + def set_power_status(conn, options): +@@ -199,7 +200,8 @@ def get_power_status5(conn, options): + try: + (_, status) = outlets[options["--plug"]] + return status.lower().strip() +- except KeyError: ++ except KeyError as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + + def set_power_status5(conn, options): +diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py +index ec3117548..2280dbbc7 100644 +--- a/agents/cisco_ucs/fence_cisco_ucs.py ++++ b/agents/cisco_ucs/fence_cisco_ucs.py +@@ -174,7 +174,8 @@ def main(): + if result == None: + ## Cookie is absenting in response + fail(EC_LOGIN_DENIED) +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options_global["cookie"] = result.group(1) +diff --git a/agents/eps/fence_eps.py b/agents/eps/fence_eps.py +index 74c89b95b..f0df86231 100644 +--- a/agents/eps/fence_eps.py ++++ b/agents/eps/fence_eps.py +@@ -56,7 +56,8 @@ def eps_run_command(options, params): + conn.close() + except socket.timeout: + fail(EC_TIMED_OUT) +- except socket.error: ++ except socket.error as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + return result +diff --git a/agents/ilo_moonshot/fence_ilo_moonshot.py b/agents/ilo_moonshot/fence_ilo_moonshot.py +index a066a9c91..6f5cca320 100644 +--- a/agents/ilo_moonshot/fence_ilo_moonshot.py ++++ b/agents/ilo_moonshot/fence_ilo_moonshot.py +@@ -21,7 +21,8 @@ def get_power_status(conn, options): + try: + (_, status) = nodes[options["--plug"]] + return status.lower() +- except KeyError: ++ except KeyError as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + + def set_power_status(conn, options): +diff --git a/agents/lpar/fence_lpar.py b/agents/lpar/fence_lpar.py +index a16103733..66cb65e41 100644 +--- a/agents/lpar/fence_lpar.py ++++ b/agents/lpar/fence_lpar.py +@@ -37,7 +37,8 @@ def get_power_status(conn, options): + try: + status = re.compile("^" + options["--plug"] + ",(.*?),.*$", + re.IGNORECASE | re.MULTILINE).search(conn.before).group(1) +- except AttributeError: ++ except AttributeError as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS_HMC) + elif options["--hmc-version"] in ["4", "IVM"]: + conn.send("lssyscfg -r lpar -m "+ options["--managed"] + +@@ -49,7 +50,8 @@ def get_power_status(conn, options): + + try: + status = re.compile(",state=(.*?),", re.IGNORECASE).search(conn.before).group(1) +- except AttributeError: ++ except AttributeError as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS_HMC) + + return _normalize_status(status) +diff --git a/agents/ovh/fence_ovh.py b/agents/ovh/fence_ovh.py +index f5403c54d..2b7eb864f 100644 +--- a/agents/ovh/fence_ovh.py ++++ b/agents/ovh/fence_ovh.py +@@ -66,7 +66,8 @@ def soap_login(options): + try: + soap = Client(url, doctor=d) + session = soap.service.login(options["--username"], options["--password"], 'en', 0) +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options["session"] = session +diff --git a/agents/sanbox2/fence_sanbox2.py b/agents/sanbox2/fence_sanbox2.py +index 679d1d983..179fe0e8b 100644 +--- a/agents/sanbox2/fence_sanbox2.py ++++ b/agents/sanbox2/fence_sanbox2.py +@@ -28,7 +28,8 @@ def get_power_status(conn, options): + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + +@@ -54,7 +55,8 @@ def set_power_status(conn, options): + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + +@@ -66,7 +68,8 @@ def set_power_status(conn, options): + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + +@@ -91,7 +94,8 @@ def get_list_devices(conn, options): + conn.send_eol("admin end") + conn.send_eol("exit") + conn.close() +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + pass + fail(EC_TIMED_OUT) + +diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py +index f2ab68b02..a7f08b3d6 100644 +--- a/agents/vmware_soap/fence_vmware_soap.py ++++ b/agents/vmware_soap/fence_vmware_soap.py +@@ -68,7 +68,8 @@ def soap_login(options): + conn.service.Login(mo_SessionManager, options["--username"], options["--password"]) + except requests.exceptions.SSLError as ex: + fail_usage("Server side certificate verification failed: %s" % ex) +- except Exception: ++ except Exception as e: ++ logging.error("Server side certificate verification failed: {}".format(str(e))) + fail(EC_LOGIN_DENIED) + + options["ServiceContent"] = ServiceContent +@@ -126,7 +127,8 @@ def get_power_status(conn, options): + + try: + raw_machines = conn.service.RetrievePropertiesEx(mo_PropertyCollector, propFilterSpec) +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + + (machines, uuid, mappingToUUID) = process_results(raw_machines, {}, {}, {}) +@@ -135,7 +137,8 @@ def get_power_status(conn, options): + while hasattr(raw_machines, 'token'): + try: + raw_machines = conn.service.ContinueRetrievePropertiesEx(mo_PropertyCollector, raw_machines.token) +- except Exception: ++ except Exception as e: ++ logging.error("Failed: {}".format(str(e))) + fail(EC_STATUS) + (more_machines, more_uuid, more_mappingToUUID) = process_results(raw_machines, {}, {}, {}) + machines.update(more_machines) diff --git a/SOURCES/bz1728203-bz1874862-fence_ibm_vpc-fence_ibm_powervs.patch b/SOURCES/bz1728203-bz1874862-fence_ibm_vpc-fence_ibm_powervs.patch new file mode 100644 index 0000000..d68612c --- /dev/null +++ b/SOURCES/bz1728203-bz1874862-fence_ibm_vpc-fence_ibm_powervs.patch @@ -0,0 +1,740 @@ +From 3078e4d55d3bad2bbf9309785fdb2b53afac8d65 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 13 Jul 2021 13:39:33 +0200 +Subject: [PATCH] fence_ibm_vpc/fence_ibm_powervs: new fence agents + +--- + agents/ibm_powervs/fence_ibm_powervs.py | 202 +++++++++++++++++++ + agents/ibm_vpc/fence_ibm_vpc.py | 230 ++++++++++++++++++++++ + tests/data/metadata/fence_ibm_powervs.xml | 134 +++++++++++++ + tests/data/metadata/fence_ibm_vpc.xml | 134 +++++++++++++ + 5 files changed, 724 insertions(+) + create mode 100755 agents/ibm_powervs/fence_ibm_powervs.py + create mode 100755 agents/ibm_vpc/fence_ibm_vpc.py + create mode 100644 tests/data/metadata/fence_ibm_powervs.xml + create mode 100644 tests/data/metadata/fence_ibm_vpc.xml + +diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py +new file mode 100755 +index 000000000..6649771ea +--- /dev/null ++++ b/agents/ibm_powervs/fence_ibm_powervs.py +@@ -0,0 +1,202 @@ ++#!@PYTHON@ -tt ++ ++import sys ++import pycurl, io, json ++import logging ++import atexit ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS ++ ++state = { ++ "ACTIVE": "on", ++ "SHUTOFF": "off", ++ "ERROR": "unknown" ++} ++ ++def get_list(conn, options): ++ outlets = {} ++ ++ try: ++ command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) ++ res = send_command(conn, command) ++ except Exception as e: ++ logging.debug("Failed: {}".format(e)) ++ return outlets ++ ++ for r in res["pvmInstances"]: ++ if "--verbose" in options: ++ logging.debug(json.dumps(r, indent=2)) ++ outlets[r["pvmInstanceID"]] = (r["serverName"], state[r["status"]]) ++ ++ return outlets ++ ++def get_power_status(conn, options): ++ try: ++ command = "cloud-instances/{}/pvm-instances/{}".format( ++ options["--instance"], options["--plug"]) ++ res = send_command(conn, command) ++ result = get_list(conn, options)[options["--plug"]][1] ++ except KeyError as e: ++ logging.debug("Failed: Unable to get status for {}".format(e)) ++ fail(EC_STATUS) ++ ++ return result ++ ++def set_power_status(conn, options): ++ action = { ++ "on" : '{"action" : "start"}', ++ "off" : '{"action" : "immediate-shutdown"}', ++ }[options["--action"]] ++ ++ try: ++ send_command(conn, "cloud-instances/{}/pvm-instances/{}/action".format( ++ options["--instance"], options["--plug"]), "POST", action) ++ except Exception as e: ++ logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) ++ fail(EC_STATUS) ++ ++def connect(opt): ++ conn = pycurl.Curl() ++ ++ ## setup correct URL ++ conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" ++ ++ if opt["--verbose-level"] > 1: ++ conn.setopt(pycurl.VERBOSE, 1) ++ ++ conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) ++ conn.setopt(pycurl.SSL_VERIFYPEER, 1) ++ conn.setopt(pycurl.SSL_VERIFYHOST, 2) ++ ++ # set auth token for later requests ++ conn.setopt(pycurl.HTTPHEADER, [ ++ "Content-Type: application/json", ++ "Authorization: Bearer {}".format(opt["--token"]), ++ "CRN: {}".format(opt["--crn"]), ++ "User-Agent: curl", ++ ]) ++ ++ return conn ++ ++def disconnect(conn): ++ conn.close() ++ ++def send_command(conn, command, method="GET", action=None): ++ url = conn.base_url + command ++ ++ conn.setopt(pycurl.URL, url.encode("ascii")) ++ ++ web_buffer = io.BytesIO() ++ ++ if method == "GET": ++ conn.setopt(pycurl.POST, 0) ++ if method == "POST": ++ conn.setopt(pycurl.POSTFIELDS, action) ++ if method == "DELETE": ++ conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") ++ ++ conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) ++ ++ try: ++ conn.perform() ++ except Exception as e: ++ raise(e) ++ ++ rc = conn.getinfo(pycurl.HTTP_CODE) ++ result = web_buffer.getvalue().decode("UTF-8") ++ ++ web_buffer.close() ++ ++ if rc != 200: ++ if len(result) > 0: ++ raise Exception("{}: {}".format(rc, ++ result["value"]["messages"][0]["default_message"])) ++ else: ++ raise Exception("Remote returned {} for request to {}".format(rc, url)) ++ ++ if len(result) > 0: ++ result = json.loads(result) ++ ++ logging.debug("url: {}".format(url)) ++ logging.debug("method: {}".format(method)) ++ logging.debug("response code: {}".format(rc)) ++ logging.debug("result: {}\n".format(result)) ++ ++ return result ++ ++def define_new_opts(): ++ all_opt["token"] = { ++ "getopt" : ":", ++ "longopt" : "token", ++ "help" : "--token=[token] Bearer Token", ++ "required" : "1", ++ "shortdesc" : "Bearer Token", ++ "order" : 0 ++ } ++ all_opt["crn"] = { ++ "getopt" : ":", ++ "longopt" : "crn", ++ "help" : "--crn=[crn] CRN", ++ "required" : "1", ++ "shortdesc" : "CRN", ++ "order" : 0 ++ } ++ all_opt["instance"] = { ++ "getopt" : ":", ++ "longopt" : "instance", ++ "help" : "--instance=[instance] PowerVS Instance", ++ "required" : "1", ++ "shortdesc" : "PowerVS Instance", ++ "order" : 0 ++ } ++ all_opt["region"] = { ++ "getopt" : ":", ++ "longopt" : "region", ++ "help" : "--region=[region] Region", ++ "required" : "1", ++ "shortdesc" : "Region", ++ "order" : 0 ++ } ++ ++ ++def main(): ++ device_opt = [ ++ "token", ++ "crn", ++ "instance", ++ "region", ++ "port", ++ "no_password", ++ ] ++ ++ atexit.register(atexit_handler) ++ define_new_opts() ++ ++ all_opt["shell_timeout"]["default"] = "15" ++ all_opt["power_timeout"]["default"] = "30" ++ all_opt["power_wait"]["default"] = "1" ++ ++ options = check_input(device_opt, process_input(device_opt)) ++ ++ docs = {} ++ docs["shortdesc"] = "Fence agent for IBM PowerVS" ++ docs["longdesc"] = """fence_ibm_powervs is an I/O Fencing agent which can be \ ++used with IBM PowerVS to fence virtual machines.""" ++ docs["vendorurl"] = "https://www.ibm.com" ++ show_docs(options, docs) ++ ++ #### ++ ## Fence operations ++ #### ++ run_delay(options) ++ ++ conn = connect(options) ++ atexit.register(disconnect, conn) ++ ++ result = fence_action(conn, options, set_power_status, get_power_status, get_list) ++ ++ sys.exit(result) ++ ++if __name__ == "__main__": ++ main() +diff --git a/agents/ibm_vpc/fence_ibm_vpc.py b/agents/ibm_vpc/fence_ibm_vpc.py +new file mode 100755 +index 000000000..9f84f7b2d +--- /dev/null ++++ b/agents/ibm_vpc/fence_ibm_vpc.py +@@ -0,0 +1,230 @@ ++#!@PYTHON@ -tt ++ ++import sys ++import pycurl, io, json ++import logging ++import atexit ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS ++ ++state = { ++ "running": "on", ++ "stopped": "off", ++ "starting": "unknown", ++ "stopping": "unknown", ++ "restarting": "unknown", ++ "pending": "unknown", ++} ++ ++def get_list(conn, options): ++ outlets = {} ++ ++ try: ++ command = "instances?version=2021-05-25&generation=2&limit={}".format(options["--limit"]) ++ res = send_command(conn, command) ++ except Exception as e: ++ logging.debug("Failed: Unable to get list: {}".format(e)) ++ return outlets ++ ++ for r in res["instances"]: ++ if options["--verbose-level"] > 1: ++ logging.debug("Node:\n{}".format(json.dumps(r, indent=2))) ++ logging.debug("Status: " + state[r["status"]]) ++ outlets[r["id"]] = (r["name"], state[r["status"]]) ++ ++ return outlets ++ ++def get_power_status(conn, options): ++ try: ++ command = "instances/{}?version=2021-05-25&generation=2".format(options["--plug"]) ++ res = send_command(conn, command) ++ result = state[res["status"]] ++ if options["--verbose-level"] > 1: ++ logging.debug("Result:\n{}".format(json.dumps(res, indent=2))) ++ logging.debug("Status: " + result) ++ except Exception as e: ++ logging.debug("Failed: Unable to get status for {}: {}".format(options["--plug"], e)) ++ fail(EC_STATUS) ++ ++ return result ++ ++def set_power_status(conn, options): ++ action = { ++ "on" : '{"type" : "start"}', ++ "off" : '{"type" : "stop"}', ++ }[options["--action"]] ++ ++ try: ++ command = "instances/{}/actions?version=2021-05-25&generation=2".format(options["--plug"]) ++ send_command(conn, command, "POST", action, 201) ++ except Exception as e: ++ logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) ++ fail(EC_STATUS) ++ ++def get_bearer_token(conn, options): ++ token = None ++ try: ++ conn.setopt(pycurl.HTTPHEADER, [ ++ "Content-Type: application/x-www-form-urlencoded", ++ "User-Agent: curl", ++ ]) ++ token = send_command(conn, "https://iam.cloud.ibm.com/identity/token", "POST", "grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey={}".format(options["--apikey"]))["access_token"] ++ except Exception: ++ logging.error("Failed: Unable to authenticate") ++ fail(EC_LOGIN_DENIED) ++ ++ return token ++ ++def connect(opt): ++ conn = pycurl.Curl() ++ ++ ## setup correct URL ++ conn.base_url = "https://" + opt["--region"] + ".iaas.cloud.ibm.com/v1/" ++ ++ if opt["--verbose-level"] > 1: ++ conn.setopt(pycurl.VERBOSE, 1) ++ ++ conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) ++ conn.setopt(pycurl.SSL_VERIFYPEER, 1) ++ conn.setopt(pycurl.SSL_VERIFYHOST, 2) ++ ++ # get bearer token ++ bearer_token = get_bearer_token(conn, opt) ++ ++ # set auth token for later requests ++ conn.setopt(pycurl.HTTPHEADER, [ ++ "Content-Type: application/json", ++ "Authorization: Bearer {}".format(bearer_token), ++ "User-Agent: curl", ++ ]) ++ ++ return conn ++ ++def disconnect(conn): ++ conn.close() ++ ++def send_command(conn, command, method="GET", action=None, expected_rc=200): ++ if not command.startswith("https"): ++ url = conn.base_url + command ++ else: ++ url = command ++ ++ conn.setopt(pycurl.URL, url.encode("ascii")) ++ ++ web_buffer = io.BytesIO() ++ ++ if method == "GET": ++ conn.setopt(pycurl.POST, 0) ++ if method == "POST": ++ conn.setopt(pycurl.POSTFIELDS, action) ++ if method == "DELETE": ++ conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") ++ ++ conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) ++ ++ try: ++ conn.perform() ++ except Exception as e: ++ raise(e) ++ ++ rc = conn.getinfo(pycurl.HTTP_CODE) ++ result = web_buffer.getvalue().decode("UTF-8") ++ ++ web_buffer.close() ++ ++ # actions (start/stop/reboot) report 201 when they've been created ++ if rc != expected_rc: ++ logging.debug("rc: {}, result: {}".format(rc, result)) ++ if len(result) > 0: ++ raise Exception("{}: {}".format(rc, ++ result["value"]["messages"][0]["default_message"])) ++ else: ++ raise Exception("Remote returned {} for request to {}".format(rc, url)) ++ ++ if len(result) > 0: ++ result = json.loads(result) ++ ++ logging.debug("url: {}".format(url)) ++ logging.debug("method: {}".format(method)) ++ logging.debug("response code: {}".format(rc)) ++ logging.debug("result: {}\n".format(result)) ++ ++ return result ++ ++def define_new_opts(): ++ all_opt["apikey"] = { ++ "getopt" : ":", ++ "longopt" : "apikey", ++ "help" : "--apikey=[key] API Key", ++ "required" : "1", ++ "shortdesc" : "API Key", ++ "order" : 0 ++ } ++ all_opt["instance"] = { ++ "getopt" : ":", ++ "longopt" : "instance", ++ "help" : "--instance=[instance] Cloud Instance", ++ "required" : "1", ++ "shortdesc" : "Cloud Instance", ++ "order" : 0 ++ } ++ all_opt["region"] = { ++ "getopt" : ":", ++ "longopt" : "region", ++ "help" : "--region=[region] Region", ++ "required" : "1", ++ "shortdesc" : "Region", ++ "order" : 0 ++ } ++ all_opt["limit"] = { ++ "getopt" : ":", ++ "longopt" : "limit", ++ "help" : "--limit=[number] Limit number of nodes returned by API", ++ "required" : "1", ++ "default": 50, ++ "shortdesc" : "Number of nodes returned by API", ++ "order" : 0 ++ } ++ ++ ++def main(): ++ device_opt = [ ++ "apikey", ++ "instance", ++ "region", ++ "limit", ++ "port", ++ "no_password", ++ ] ++ ++ atexit.register(atexit_handler) ++ define_new_opts() ++ ++ all_opt["shell_timeout"]["default"] = "15" ++ all_opt["power_timeout"]["default"] = "30" ++ all_opt["power_wait"]["default"] = "1" ++ ++ options = check_input(device_opt, process_input(device_opt)) ++ ++ docs = {} ++ docs["shortdesc"] = "Fence agent for IBM Cloud VPC" ++ docs["longdesc"] = """fence_ibm_vpc is an I/O Fencing agent which can be \ ++used with IBM Cloud VPC to fence virtual machines.""" ++ docs["vendorurl"] = "https://www.ibm.com" ++ show_docs(options, docs) ++ ++ #### ++ ## Fence operations ++ #### ++ run_delay(options) ++ ++ conn = connect(options) ++ atexit.register(disconnect, conn) ++ ++ result = fence_action(conn, options, set_power_status, get_power_status, get_list) ++ ++ sys.exit(result) ++ ++if __name__ == "__main__": ++ main() +diff --git a/tests/data/metadata/fence_ibm_powervs.xml b/tests/data/metadata/fence_ibm_powervs.xml +new file mode 100644 +index 000000000..fe86331bd +--- /dev/null ++++ b/tests/data/metadata/fence_ibm_powervs.xml +@@ -0,0 +1,134 @@ ++ ++ ++fence_ibm_powervs is an I/O Fencing agent which can be used with IBM PowerVS to fence virtual machines. ++https://www.ibm.com ++ ++ ++ ++ ++ CRN ++ ++ ++ ++ ++ PowerVS Instance ++ ++ ++ ++ ++ Region ++ ++ ++ ++ ++ Bearer Token ++ ++ ++ ++ ++ Fencing action ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. ++ ++ ++ ++ ++ Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity. ++ ++ ++ ++ ++ Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin). ++ ++ ++ ++ ++ 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 ++ ++ ++ ++ ++ Disable timeout (true/false) (default: true when run from Pacemaker 2.0+) ++ ++ ++ ++ ++ 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 ++ ++ ++ ++ ++ Sleep X seconds between status calls during a STONITH action ++ ++ ++ ++ ++ Count of attempts to retry power on ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/data/metadata/fence_ibm_vpc.xml b/tests/data/metadata/fence_ibm_vpc.xml +new file mode 100644 +index 000000000..926efcaa0 +--- /dev/null ++++ b/tests/data/metadata/fence_ibm_vpc.xml +@@ -0,0 +1,134 @@ ++ ++ ++fence_ibm_vpc is an I/O Fencing agent which can be used with IBM Cloud VPC to fence virtual machines. ++https://www.ibm.com ++ ++ ++ ++ ++ API Key ++ ++ ++ ++ ++ Cloud Instance ++ ++ ++ ++ ++ Number of nodes returned by API ++ ++ ++ ++ ++ Region ++ ++ ++ ++ ++ Fencing action ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. ++ ++ ++ ++ ++ Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity. ++ ++ ++ ++ ++ Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin). ++ ++ ++ ++ ++ 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 ++ ++ ++ ++ ++ Disable timeout (true/false) (default: true when run from Pacemaker 2.0+) ++ ++ ++ ++ ++ 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 ++ ++ ++ ++ ++ Sleep X seconds between status calls during a STONITH action ++ ++ ++ ++ ++ Count of attempts to retry power on ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ diff --git a/SOURCES/bz1963163-fence_zvmip-add-ssl-tls-support.patch b/SOURCES/bz1963163-fence_zvmip-add-ssl-tls-support.patch new file mode 100644 index 0000000..1e43aa3 --- /dev/null +++ b/SOURCES/bz1963163-fence_zvmip-add-ssl-tls-support.patch @@ -0,0 +1,100 @@ +From 81be3c529ec1165f3135b4f14fbec2a19403cfbe Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 27 Aug 2021 08:53:36 +0200 +Subject: [PATCH] fence_zvmip: add ssl/tls support + +--- + agents/zvm/fence_zvmip.py | 20 ++++++++++++++++---- + tests/data/metadata/fence_zvmip.xml | 19 +++++++++++++++++++ + 2 files changed, 35 insertions(+), 4 deletions(-) + +diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py +index 001106a44..874eb699f 100644 +--- a/agents/zvm/fence_zvmip.py ++++ b/agents/zvm/fence_zvmip.py +@@ -26,12 +26,22 @@ def open_socket(options): + except socket.gaierror: + fail(EC_LOGIN_DENIED) + +- conn = socket.socket() ++ if "--ssl" in options: ++ import ssl ++ sock = socket.socket() ++ sslcx = ssl.create_default_context() ++ if "--ssl-insecure" in options: ++ sslcx.check_hostname = False ++ sslcx.verify_mode = ssl.CERT_NONE ++ conn = sslcx.wrap_socket(sock, server_hostname=options["--ip"]) ++ else: ++ conn = socket.socket() + conn.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + conn.settimeout(float(options["--shell-timeout"]) or None) + try: + conn.connect(addr) +- except socket.error: ++ except socket.error as e: ++ logging.debug(e) + fail(EC_LOGIN_DENIED) + + return conn +@@ -122,11 +132,12 @@ def get_list_of_images(options, command, data_as_plug): + images = set() + + if output_len > 3*INT4: ++ recvflag = socket.MSG_WAITALL if "--ssl" not in options else 0 + array_len = struct.unpack("!i", conn.recv(INT4))[0] + data = "" + + while True: +- read_data = conn.recv(1024, socket.MSG_WAITALL).decode("UTF-8") ++ read_data = conn.recv(1024, recvflag).decode("UTF-8") + data += read_data + if array_len == len(data): + break +@@ -146,7 +157,8 @@ def get_list_of_images(options, command, data_as_plug): + return (return_code, reason_code, images) + + def main(): +- device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off", "inet4_only", "inet6_only"] ++ device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off", ++ "inet4_only", "inet6_only", "ssl"] + + atexit.register(atexit_handler) + +diff --git a/tests/data/metadata/fence_zvmip.xml b/tests/data/metadata/fence_zvmip.xml +index f84115c08..d91192946 100644 +--- a/tests/data/metadata/fence_zvmip.xml ++++ b/tests/data/metadata/fence_zvmip.xml +@@ -91,6 +91,21 @@ to access the system's directory manager. + + Physical plug number on device, UUID or identification of machine + ++ ++ ++ ++ Use SSL connection with verifying certificate ++ ++ ++ ++ ++ Use SSL connection without verifying certificate ++ ++ ++ ++ ++ Use SSL connection with verifying certificate ++ + + + +@@ -181,6 +196,10 @@ to access the system's directory manager. + + Count of attempts to retry power on + ++ ++ ++ Path to gnutls-cli binary ++ + + + diff --git a/SOURCES/bz1969953-fence_gce-1-add-proxy-support.patch b/SOURCES/bz1969953-fence_gce-1-add-proxy-support.patch new file mode 100644 index 0000000..55dbc5b --- /dev/null +++ b/SOURCES/bz1969953-fence_gce-1-add-proxy-support.patch @@ -0,0 +1,70 @@ +diff --color -uNr a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py +--- a/agents/gce/fence_gce.py 2021-06-11 14:57:01.138390529 +0200 ++++ b/agents/gce/fence_gce.py 2021-06-11 15:12:45.829855806 +0200 +@@ -1,6 +1,7 @@ + #!@PYTHON@ -tt + + import atexit ++import httplib2 + import logging + import os + import sys +@@ -18,6 +19,7 @@ + from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action + try: + import googleapiclient.discovery ++ import socks + try: + from google.oauth2.credentials import Credentials as GoogleCredentials + except: +@@ -189,13 +191,30 @@ + "required" : "0", + "order" : 9 + } ++ all_opt["proxyhost"] = { ++ "getopt" : ":", ++ "longopt" : "proxyhost", ++ "help" : "--proxyhost=[proxy_host] The proxy host to use, if one is needed to access the internet (Example: 10.122.0.33)", ++ "shortdesc" : "If a proxy is used for internet access, the proxy host should be specified.", ++ "required" : "0", ++ "order" : 10 ++ } ++ all_opt["proxyport"] = { ++ "getopt" : ":", ++ "type" : "integer", ++ "longopt" : "proxyport", ++ "help" : "--proxyport=[proxy_port] The proxy port to use, if one is needed to access the internet (Example: 3127)", ++ "shortdesc" : "If a proxy is used for internet access, the proxy port should be specified.", ++ "required" : "0", ++ "order" : 11 ++ } + + + def main(): + conn = None + + device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", +- "method", "serviceaccount"] ++ "method", "serviceaccount", "proxyhost", "proxyport"] + + atexit.register(atexit_handler) + +@@ -259,7 +278,17 @@ + credentials = GoogleCredentials.get_application_default() + logging.debug("using application default credentials") + +- conn = googleapiclient.discovery.build('compute', 'v1', credentials=credentials) ++ if options.get("--proxyhost") and options.get("--proxyport"): ++ proxy_info = httplib2.ProxyInfo( ++ proxy_type=socks.PROXY_TYPE_HTTP, ++ proxy_host=options.get("--proxyhost"), ++ proxy_port=int(options.get("--proxyport"))) ++ http = credentials.authorize(httplib2.Http(proxy_info=proxy_info)) ++ conn = googleapiclient.discovery.build( ++ 'compute', 'v1', http=http, cache_discovery=False) ++ else: ++ conn = googleapiclient.discovery.build( ++ 'compute', 'v1', credentials=credentials, cache_discovery=False) + except Exception as err: + fail_usage("Failed: Create GCE compute v1 connection: {}".format(str(err))) + diff --git a/SOURCES/bz1969953-fence_gce-2-bundled.patch b/SOURCES/bz1969953-fence_gce-2-bundled.patch new file mode 100644 index 0000000..5d857e7 --- /dev/null +++ b/SOURCES/bz1969953-fence_gce-2-bundled.patch @@ -0,0 +1,10 @@ +--- a/agents/gce/fence_gce.py 2021-09-07 11:39:36.718667514 +0200 ++++ b/agents/gce/fence_gce.py 2021-09-07 11:39:30.423648309 +0200 +@@ -17,6 +17,7 @@ + + from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action + try: ++ sys.path.insert(0, '/usr/lib/fence-agents/bundled/google') + import googleapiclient.discovery + try: + from google.oauth2.credentials import Credentials as GoogleCredentials diff --git a/SOURCES/bz1969953-fence_gce-3-fix-httplib2-import.patch b/SOURCES/bz1969953-fence_gce-3-fix-httplib2-import.patch new file mode 100644 index 0000000..a915239 --- /dev/null +++ b/SOURCES/bz1969953-fence_gce-3-fix-httplib2-import.patch @@ -0,0 +1,18 @@ +--- a/agents/gce/fence_gce.py 2021-10-19 10:29:17.000000000 +0000 ++++ b/agents/gce/fence_gce.py 2021-10-26 15:26:11.348781027 +0000 +@@ -1,7 +1,6 @@ + #!@PYTHON@ -tt + + import atexit +-import httplib2 + import logging + import os + import sys +@@ -19,6 +18,7 @@ + from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action + try: + sys.path.insert(0, '/usr/lib/fence-agents/bundled/google') ++ import httplib2 + import googleapiclient.discovery + import socks + try: diff --git a/SOURCES/bz1971683-fence_sbd-dont-spam-logs-disable-timeout.patch b/SOURCES/bz1971683-fence_sbd-dont-spam-logs-disable-timeout.patch new file mode 100644 index 0000000..393ca78 --- /dev/null +++ b/SOURCES/bz1971683-fence_sbd-dont-spam-logs-disable-timeout.patch @@ -0,0 +1,23 @@ +From b220f963934f69044a39109fa065a95cd0972183 Mon Sep 17 00:00:00 2001 +From: Hideo Yamauchi +Date: Fri, 2 Jul 2021 09:09:49 +0900 +Subject: [PATCH] Mid: fence_sbd: A warning message is output when + disable-timeout is enabled. + +--- + agents/sbd/fence_sbd.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/sbd/fence_sbd.py b/agents/sbd/fence_sbd.py +index 3ae8df6e3..0c876b16e 100644 +--- a/agents/sbd/fence_sbd.py ++++ b/agents/sbd/fence_sbd.py +@@ -398,7 +398,7 @@ def main(): + # then that defined within sbd we should report this. + power_timeout = int(options["--power-timeout"]) + sbd_msg_timeout = get_msg_timeout(options) +- if power_timeout <= sbd_msg_timeout: ++ if 0 < power_timeout <= sbd_msg_timeout: + logging.warn("power timeout needs to be \ + greater then sbd message timeout") + diff --git a/SOURCES/bz1977588-1-fencing-add-EC_FETCH_VM_UUID.patch b/SOURCES/bz1977588-1-fencing-add-EC_FETCH_VM_UUID.patch new file mode 100644 index 0000000..e598bdf --- /dev/null +++ b/SOURCES/bz1977588-1-fencing-add-EC_FETCH_VM_UUID.patch @@ -0,0 +1,22 @@ +diff --color -uNr a/lib/fencing.py.py b/lib/fencing.py.py +--- a/lib/fencing.py.py 2021-11-01 10:14:04.045398051 +0100 ++++ b/lib/fencing.py.py 2021-11-01 10:24:47.111235305 +0100 +@@ -29,6 +29,7 @@ + EC_STATUS_HMC = 9 + EC_PASSWORD_MISSING = 10 + EC_INVALID_PRIVILEGES = 11 ++EC_FETCH_VM_UUID = 12 + + LOG_FORMAT = "%(asctime)-15s %(levelname)s: %(message)s" + +@@ -574,7 +575,9 @@ + EC_STATUS_HMC : "Failed: Either unable to obtain correct plug status, " + "partition is not available or incorrect HMC version used", + EC_PASSWORD_MISSING : "Failed: You have to set login password", +- EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action." ++ EC_INVALID_PRIVILEGES : "Failed: The user does not have the correct privileges to do the requested action.", ++ EC_FETCH_VM_UUID : "Failed: Can not find VM UUID by its VM name given in the parameter." ++ + }[error_code] + "\n" + logging.error("%s\n", message) + if stop: diff --git a/SOURCES/bz1977588-2-fence_kubevirt.patch b/SOURCES/bz1977588-2-fence_kubevirt.patch new file mode 100644 index 0000000..9ac8927 --- /dev/null +++ b/SOURCES/bz1977588-2-fence_kubevirt.patch @@ -0,0 +1,144 @@ +diff --color -uNr a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py +--- a/agents/kubevirt/fence_kubevirt.py 1970-01-01 01:00:00.000000000 +0100 ++++ b/agents/kubevirt/fence_kubevirt.py 2021-10-25 13:25:59.904501348 +0200 +@@ -0,0 +1,140 @@ ++#!@PYTHON@ -tt ++ ++import sys ++import logging ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, fail_usage, run_delay, EC_STATUS ++ ++try: ++ sys.path.insert(0, '/usr/lib/fence-agents/bundled/kubevirt') ++ from kubernetes.client.exceptions import ApiException ++except ImportError: ++ logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible") ++ ++def get_nodes_list(conn, options): ++ logging.debug("Starting list/monitor operation") ++ result = {} ++ try: ++ apiversion = options.get("--apiversion") ++ namespace = options.get("--namespace") ++ include_uninitialized = True ++ vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') ++ vm_list = vm_api.get(namespace=namespace) ++ for vm in vm_list.items: ++ result[vm.metadata.name] = ("", None) ++ except Exception as e: ++ logging.error("Exception when calling VirtualMachine list: %s", e) ++ return result ++ ++def get_power_status(conn, options): ++ logging.debug("Starting get status operation") ++ try: ++ apiversion = options.get("--apiversion") ++ namespace = options.get("--namespace") ++ name = options.get("--plug") ++ vmi_api = conn.resources.get(api_version=apiversion, ++ kind='VirtualMachineInstance') ++ vmi = vmi_api.get(name=name, namespace=namespace) ++ if vmi is not None: ++ phase = vmi.status.phase ++ if phase == "Running": ++ return "on" ++ return "off" ++ except ApiException as e: ++ if e.status == 404: ++ return "off" ++ logging.error("Failed to get power status, with API Exception: %s", e) ++ fail(EC_STATUS) ++ except Exception as e: ++ logging.error("Failed to get power status, with Exception: %s", e) ++ fail(EC_STATUS) ++ ++def set_power_status(conn, options): ++ logging.debug("Starting set status operation") ++ try: ++ apiversion= options.get("--apiversion") ++ namespace = options.get("--namespace") ++ name = options.get("--plug") ++ action = 'start' if options["--action"] == "on" else 'stop' ++ virtctl_vm_action(conn, action, namespace, name, apiversion) ++ except Exception as e: ++ logging.error("Failed to set power status, with Exception: %s", e) ++ fail(EC_STATUS) ++ ++def define_new_opts(): ++ all_opt["namespace"] = { ++ "getopt" : ":", ++ "longopt" : "namespace", ++ "help" : "--namespace=[namespace] Namespace of the KubeVirt machine", ++ "shortdesc" : "Namespace of the KubeVirt machine.", ++ "required" : "1", ++ "order" : 2 ++ } ++ all_opt["kubeconfig"] = { ++ "getopt" : ":", ++ "longopt" : "kubeconfig", ++ "help" : "--kubeconfig=[kubeconfig] Kubeconfig file path", ++ "shortdesc": "Kubeconfig file path", ++ "required": "0", ++ "order": 4 ++ } ++ all_opt["apiversion"] = { ++ "getopt" : ":", ++ "longopt" : "apiversion", ++ "help" : "--apiversion=[apiversion] Version of the KubeVirt API", ++ "shortdesc" : "Version of the KubeVirt API.", ++ "required" : "0", ++ "default" : "kubevirt.io/v1", ++ "order" : 5 ++ } ++ ++def virtctl_vm_action(conn, action, namespace, name, apiversion): ++ path = '/apis/subresources.{api_version}/namespaces/{namespace}/virtualmachines/{name}/{action}' ++ path = path.format(api_version=apiversion, namespace=namespace, name=name, action=action) ++ return conn.request('put', path, header_params={'accept': '*/*'}) ++ ++def validate_options(required_options_list, options): ++ for required_option in required_options_list: ++ if required_option not in options: ++ fail_usage("Failed: %s option must be provided" % required_option) ++ ++# Main agent method ++def main(): ++ conn = None ++ ++ device_opt = ["port", "namespace", "kubeconfig", "ssl_insecure", "no_password", "apiversion"] ++ define_new_opts() ++ options = check_input(device_opt, process_input(device_opt)) ++ ++ docs = {} ++ docs["shortdesc"] = "Fence agent for KubeVirt" ++ docs["longdesc"] = "fence_kubevirt is an I/O Fencing agent for KubeVirt." ++ docs["vendorurl"] = "https://kubevirt.io/" ++ show_docs(options, docs) ++ ++ run_delay(options) ++ ++ validate_options(['--namespace'], options) ++ ++ # Disable insecure-certificate-warning message ++ if "--ssl-insecure" in options: ++ import urllib3 ++ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) ++ ++ try: ++ from kubernetes import config ++ from openshift.dynamic import DynamicClient ++ kubeconfig = options.get('--kubeconfig') ++ k8s_client = config.new_client_from_config(config_file=kubeconfig) ++ conn = DynamicClient(k8s_client) ++ except ImportError: ++ logging.error("Couldn\'t import kubernetes.config or " ++ "openshift.dynamic.DynamicClient - not found or not accessible") ++ ++ # 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() diff --git a/SOURCES/bz1977588-3-fence_kubevirt-fix-status.patch b/SOURCES/bz1977588-3-fence_kubevirt-fix-status.patch new file mode 100644 index 0000000..fb62dd2 --- /dev/null +++ b/SOURCES/bz1977588-3-fence_kubevirt-fix-status.patch @@ -0,0 +1,55 @@ +From c23bfc3b9fc6e1dc7b1350e340171f3827fb6fb7 Mon Sep 17 00:00:00 2001 +From: Nir Argaman +Date: Mon, 1 Nov 2021 08:34:00 +0200 +Subject: [PATCH] fence_kubevirt: Fix kubevirt VM status + +--- + agents/kubevirt/fence_kubevirt.py | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py +index 70c14d89a..61ffcaa09 100755 +--- a/agents/kubevirt/fence_kubevirt.py ++++ b/agents/kubevirt/fence_kubevirt.py +@@ -4,7 +4,7 @@ + import logging + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * +-from fencing import fail, fail_usage, run_delay, EC_STATUS ++from fencing import fail, fail_usage, run_delay, EC_STATUS, EC_FETCH_VM_UUID + + try: + from kubernetes.client.exceptions import ApiException +@@ -35,13 +35,15 @@ def get_power_status(conn, options): + vmi_api = conn.resources.get(api_version=apiversion, + kind='VirtualMachineInstance') + vmi = vmi_api.get(name=name, namespace=namespace) +- if vmi is not None: +- phase = vmi.status.phase +- if phase == "Running": +- return "on" +- return "off" ++ return translate_status(vmi.status.phase) + except ApiException as e: + if e.status == 404: ++ try: ++ vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') ++ vm = vm_api.get(name=name, namespace=namespace) ++ except ApiException as e: ++ logging.error("VM %s doesn't exist", name) ++ fail(EC_FETCH_VM_UUID) + return "off" + logging.error("Failed to get power status, with API Exception: %s", e) + fail(EC_STATUS) +@@ -49,6 +51,11 @@ def get_power_status(conn, options): + logging.error("Failed to get power status, with Exception: %s", e) + fail(EC_STATUS) + ++def translate_status(instance_status): ++ if instance_status == "Running": ++ return "on" ++ return "unknown" ++ + def set_power_status(conn, options): + logging.debug("Starting set status operation") + try: diff --git a/SOURCES/bz1977588-4-fence_kubevirt-power-timeout-40s.patch b/SOURCES/bz1977588-4-fence_kubevirt-power-timeout-40s.patch new file mode 100644 index 0000000..684a46c --- /dev/null +++ b/SOURCES/bz1977588-4-fence_kubevirt-power-timeout-40s.patch @@ -0,0 +1,35 @@ +From a3d8ce78ed5687954847560f77daafe6474de33f Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 2 Nov 2021 09:44:33 +0100 +Subject: [PATCH] fence_kubevirt: set default power-timeout to 40s + +--- + agents/kubevirt/fence_kubevirt.py | 6 ++++++ + tests/data/metadata/fence_kubevirt.xml | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py +index 61ffcaa09..8392b75a0 100755 +--- a/agents/kubevirt/fence_kubevirt.py ++++ b/agents/kubevirt/fence_kubevirt.py +@@ -2,6 +2,7 @@ + + import sys + import logging ++import atexit + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * + from fencing import fail, fail_usage, run_delay, EC_STATUS, EC_FETCH_VM_UUID +@@ -110,7 +111,12 @@ def main(): + conn = None + + device_opt = ["port", "namespace", "kubeconfig", "ssl_insecure", "no_password", "apiversion"] ++ ++ atexit.register(atexit_handler) + define_new_opts() ++ ++ all_opt["power_timeout"]["default"] = "40" ++ + options = check_input(device_opt, process_input(device_opt)) + + docs = {} diff --git a/SOURCES/bz1977588-5-fence_kubevirt-get-namespace-from-context.patch b/SOURCES/bz1977588-5-fence_kubevirt-get-namespace-from-context.patch new file mode 100644 index 0000000..aa394e0 --- /dev/null +++ b/SOURCES/bz1977588-5-fence_kubevirt-get-namespace-from-context.patch @@ -0,0 +1,88 @@ +From 647841dea9d93922779a4aa7d0b5f52f5bc2b4e9 Mon Sep 17 00:00:00 2001 +From: Dan Kenigsberg +Date: Thu, 13 Jan 2022 14:57:26 +0200 +Subject: [PATCH] fence_kubevirt: take default namespace from context + +If --namespace is not provided to kubectl, a default one is taken from +kubeconfig context. Let fence_kubevirt behave similarly. + +Signed-off-by: Dan Kenigsberg +--- + agents/kubevirt/fence_kubevirt.py | 24 +++++++++++++----------- + 2 files changed, 14 insertions(+), 12 deletions(-) + +diff --git a/agents/kubevirt/fence_kubevirt.py b/agents/kubevirt/fence_kubevirt.py +index 8392b75a0..8c27a0334 100755 +--- a/agents/kubevirt/fence_kubevirt.py ++++ b/agents/kubevirt/fence_kubevirt.py +@@ -12,12 +12,21 @@ + except ImportError: + logging.error("Couldn\'t import kubernetes.client.exceptions.ApiException - not found or not accessible") + ++def _get_namespace(options): ++ from kubernetes import config ++ ++ ns = options.get("--namespace") ++ if ns is None: ++ ns = config.kube_config.list_kube_config_contexts()[1]['context']['namespace'] ++ ++ return ns ++ + def get_nodes_list(conn, options): + logging.debug("Starting list/monitor operation") + result = {} + try: + apiversion = options.get("--apiversion") +- namespace = options.get("--namespace") ++ namespace = _get_namespace(options) + include_uninitialized = True + vm_api = conn.resources.get(api_version=apiversion, kind='VirtualMachine') + vm_list = vm_api.get(namespace=namespace) +@@ -31,7 +40,7 @@ def get_power_status(conn, options): + logging.debug("Starting get status operation") + try: + apiversion = options.get("--apiversion") +- namespace = options.get("--namespace") ++ namespace = _get_namespace(options) + name = options.get("--plug") + vmi_api = conn.resources.get(api_version=apiversion, + kind='VirtualMachineInstance') +@@ -61,7 +70,7 @@ def set_power_status(conn, options): + logging.debug("Starting set status operation") + try: + apiversion= options.get("--apiversion") +- namespace = options.get("--namespace") ++ namespace = _get_namespace(options) + name = options.get("--plug") + action = 'start' if options["--action"] == "on" else 'stop' + virtctl_vm_action(conn, action, namespace, name, apiversion) +@@ -75,7 +84,7 @@ def define_new_opts(): + "longopt" : "namespace", + "help" : "--namespace=[namespace] Namespace of the KubeVirt machine", + "shortdesc" : "Namespace of the KubeVirt machine.", +- "required" : "1", ++ "required" : "0", + "order" : 2 + } + all_opt["kubeconfig"] = { +@@ -101,11 +110,6 @@ def virtctl_vm_action(conn, action, namespace, name, apiversion): + path = path.format(api_version=apiversion, namespace=namespace, name=name, action=action) + return conn.request('put', path, header_params={'accept': '*/*'}) + +-def validate_options(required_options_list, options): +- for required_option in required_options_list: +- if required_option not in options: +- fail_usage("Failed: %s option must be provided" % required_option) +- + # Main agent method + def main(): + conn = None +@@ -127,8 +131,6 @@ def main(): + + run_delay(options) + +- validate_options(['--namespace'], options) +- + # Disable insecure-certificate-warning message + if "--ssl-insecure" in options: + import urllib3 diff --git a/SOURCES/bz2010710-1-fence_amt_ws-fix-or-dead-code.patch b/SOURCES/bz2010710-1-fence_amt_ws-fix-or-dead-code.patch new file mode 100644 index 0000000..bdbeab0 --- /dev/null +++ b/SOURCES/bz2010710-1-fence_amt_ws-fix-or-dead-code.patch @@ -0,0 +1,22 @@ +From 06855a8227fa91f6216119daa3d32d5858c62837 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 27 Sep 2021 12:05:41 +0200 +Subject: [PATCH] fence_amt_ws: fix "or" causing dead code + +--- + agents/amt_ws/fence_amt_ws.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/agents/amt_ws/fence_amt_ws.py b/agents/amt_ws/fence_amt_ws.py +index 23c8a61a4..122cec309 100755 +--- a/agents/amt_ws/fence_amt_ws.py ++++ b/agents/amt_ws/fence_amt_ws.py +@@ -148,7 +148,7 @@ def set_boot_order(_, client, options): + + if options["--boot-option"] == "pxe": + device = "Intel(r) AMT: Force PXE Boot" +- elif options["--boot-option"] == "hd" or "hdsafe": ++ elif options["--boot-option"] in ["hd", "hdsafe"]: + device = "Intel(r) AMT: Force Hard-drive Boot" + elif options["--boot-option"] == "cd": + device = "Intel(r) AMT: Force CD/DVD Boot" diff --git a/SOURCES/bz2010710-2-fence_amt_ws-boot-option.patch b/SOURCES/bz2010710-2-fence_amt_ws-boot-option.patch new file mode 100644 index 0000000..dd37fef --- /dev/null +++ b/SOURCES/bz2010710-2-fence_amt_ws-boot-option.patch @@ -0,0 +1,32 @@ +From 9812473270e9a404c632358c1debfa4a1fb440fe Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 20 Oct 2021 15:46:42 +0200 +Subject: [PATCH] fence_amt_ws: fix --boot-option (choices are uppercased while + getting parsed) + +--- + agents/amt_ws/fence_amt_ws.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/amt_ws/fence_amt_ws.py b/agents/amt_ws/fence_amt_ws.py +index 122cec309..5e7452a97 100755 +--- a/agents/amt_ws/fence_amt_ws.py ++++ b/agents/amt_ws/fence_amt_ws.py +@@ -146,13 +146,13 @@ def set_boot_order(_, client, options): + wsman = 'http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd' + namespace = CIM_BootConfigSetting + +- if options["--boot-option"] == "pxe": ++ if options["--boot-option"] == "PXE": + device = "Intel(r) AMT: Force PXE Boot" +- elif options["--boot-option"] in ["hd", "hdsafe"]: ++ elif options["--boot-option"] in ["HD", "HDSAFE"]: + device = "Intel(r) AMT: Force Hard-drive Boot" +- elif options["--boot-option"] == "cd": ++ elif options["--boot-option"] == "CD": + device = "Intel(r) AMT: Force CD/DVD Boot" +- elif options["--boot-option"] == "diag": ++ elif options["--boot-option"] == "DIAG": + device = "Intel(r) AMT: Force Diagnostic Boot" + else: + logging.error('Boot device: %s not supported.', \ diff --git a/SOURCES/bz2048857-fence_aws-botocore-bundled.patch b/SOURCES/bz2048857-fence_aws-botocore-bundled.patch new file mode 100644 index 0000000..7e31da1 --- /dev/null +++ b/SOURCES/bz2048857-fence_aws-botocore-bundled.patch @@ -0,0 +1,11 @@ +--- a/agents/aws/fence_aws.py 2022-02-09 10:51:19.579385154 +0100 ++++ b/agents/aws/fence_aws.py 2022-02-09 10:51:47.148478185 +0100 +@@ -7,6 +7,8 @@ + from fencing import * + from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler + ++sys.path.insert(0, '/usr/lib/fence-agents/bundled/aws') ++ + import requests + import boto3 + from requests import HTTPError diff --git a/SOURCES/bz2052627-fence_aws-botocore-bundled.patch b/SOURCES/bz2052627-fence_aws-botocore-bundled.patch deleted file mode 100644 index 7e31da1..0000000 --- a/SOURCES/bz2052627-fence_aws-botocore-bundled.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/agents/aws/fence_aws.py 2022-02-09 10:51:19.579385154 +0100 -+++ b/agents/aws/fence_aws.py 2022-02-09 10:51:47.148478185 +0100 -@@ -7,6 +7,8 @@ - from fencing import * - from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler - -+sys.path.insert(0, '/usr/lib/fence-agents/bundled/aws') -+ - import requests - import boto3 - from requests import HTTPError diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index 91d118b..576566a 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -26,55 +26,120 @@ %global aliyunsdkvpc_version 3.0.2 %global aliyunsdkvpc_dir %{bundled_lib_dir}/aliyun/%{aliyunsdkvpc} # aws -%global botocore botocore -%global botocore_version 1.23.46 -%global urllib3 urllib3 -%global urllib3_version 1.26.7 -%global requests requests -%global requests_version 2.26.0 -%global certifi certifi -%global certifi_version 2021.10.8 -%global chrstnormalizer charset-normalizer -%global chrstnormalizer_version 2.0.7 -%global idna idna -%global idna_version 3.3 -%global chardet chardet -%global chardet_version 4.0.0 -%global dateutil dateutil -%global dateutil_version 2.8.2 -%global six six -%global six_version 1.16.0 -%global jmespath jmespath -%global jmespath_version 0.10.0 +%global botocore botocore +%global botocore_version 1.23.46 +%global chardet chardet +%global chardet_version 4.0.0 +## for pip install only +%global jmespath jmespath +%global jmespath_version 0.10.0 +# google cloud +%global httplib2 httplib2 +%global httplib2_version 0.19.1 +# kubevirt +%global openshift openshift +%global openshift_version 0.12.1 +%global ruamelyamlclib ruamel.yaml.clib +%global ruamelyamlclib_version 0.2.6 +%global kubernetes kubernetes +%global kubernetes_version 12.0.1 +%global certifi certifi +%global certifi_version 2021.10.8 +%global googleauth google-auth +%global googleauth_version 2.3.0 +%global cachetools cachetools +%global cachetools_version 4.2.4 +%global pyasn1modules pyasn1-modules +%global pyasn1modules_version 0.2.8 +%global pyasn1 pyasn1 +%global pyasn1_version 0.4.8 +%global dateutil dateutil +%global dateutil_version 2.8.2 +%global pyyaml PyYAML +%global pyyaml_version 6.0 +%global six six +%global six_version 1.16.0 +%global urllib3 urllib3 +%global urllib3_version 1.26.7 +%global websocketclient websocket-client +%global websocketclient_version 1.2.1 +%global jinja2 Jinja2 +%global jinja2_version 3.0.2 +%global markupsafe MarkupSafe +%global markupsafe_version 2.0.1 +%global stringutils string-utils +%global stringutils_version 1.0.0 +%global requests requests +%global requests_version 2.26.0 +%global chrstnormalizer charset-normalizer +%global chrstnormalizer_version 2.0.7 +%global idna idna +%global idna_version 3.3 +%global reqstsoauthlib requests-oauthlib +%global reqstsoauthlib_version 1.3.0 +%global oauthlib oauthlib +%global oauthlib_version 3.1.1 +%global ruamelyaml ruamel.yaml +%global ruamelyaml_version 0.17.16 +%global setuptools setuptools +%global setuptools_version 58.3.0 Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.2.1 -Release: 75%{?alphatag:.%{alphatag}}%{?dist}.2 +Release: 89%{?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 +# aliyun Source1: %{pycryptodome}-%{pycryptodome_version}.tar.gz Source2: %{aliyunsdkcore}-%{aliyunsdkcore_version}.tar.gz Source3: %{aliyunsdkecs}-%{aliyunsdkecs_version}.tar.gz Source4: %{aliyunsdkvpc}-%{aliyunsdkvpc_version}.tar.gz +# google cloud +Source5: %{httplib2}-%{httplib2_version}-py3-none-any.whl +Source6: pyparsing-2.4.7-py2.py3-none-any.whl # aws -Source5: %{botocore}-%{botocore_version}.tar.gz -Source6: %{urllib3}-%{urllib3_version}.tar.gz -Source7: %{requests}-%{requests_version}.tar.gz -Source8: %{certifi}-%{certifi_version}.tar.gz -Source9: %{chrstnormalizer}-%{chrstnormalizer_version}.tar.gz -Source10: %{idna}-%{idna_version}.tar.gz -Source11: %{chardet}-%{chardet_version}.tar.gz -Source12: python-%{dateutil}-%{dateutil_version}.tar.gz -Source13: %{six}-%{six_version}.tar.gz -Source14: %{jmespath}-%{jmespath_version}.tar.gz -## for build process only -Source15: setuptools_scm-6.3.2.tar.gz -Source16: packaging-21.2-py3-none-any.whl -Source17: pyparsing-2.4.7-py2.py3-none-any.whl -Source18: tomli-1.0.1.tar.gz +Source7: %{botocore}-%{botocore_version}.tar.gz +Source8: %{jmespath}-%{jmespath_version}.tar.gz +Source9: %{chardet}-%{chardet_version}.tar.gz +# kubevirt +## pip download --no-binary :all: openshift "ruamel.yaml.clib>=0.1.2" +### BEGIN +Source10: %{openshift}-%{openshift_version}.tar.gz +Source11: %{ruamelyamlclib}-%{ruamelyamlclib_version}.tar.gz +Source12: %{kubernetes}-%{kubernetes_version}.tar.gz +Source13: %{certifi}-%{certifi_version}.tar.gz +Source14: %{googleauth}-%{googleauth_version}.tar.gz +Source15: %{cachetools}-%{cachetools_version}.tar.gz +Source16: %{pyasn1modules}-%{pyasn1modules_version}.tar.gz +Source17: %{pyasn1}-%{pyasn1_version}.tar.gz +Source18: python-%{dateutil}-%{dateutil_version}.tar.gz +Source19: %{pyyaml}-%{pyyaml_version}.tar.gz +## rsa is dependency for "pip install", +## but gets removed to use cryptography lib instead +Source20: rsa-4.7.2.tar.gz +Source21: %{six}-%{six_version}.tar.gz +Source22: %{urllib3}-%{urllib3_version}.tar.gz +Source23: %{websocketclient}-%{websocketclient_version}.tar.gz +Source24: %{jinja2}-%{jinja2_version}.tar.gz +Source25: %{markupsafe}-%{markupsafe_version}.tar.gz +Source26: python-%{stringutils}-%{stringutils_version}.tar.gz +Source27: %{requests}-%{requests_version}.tar.gz +Source28: %{chrstnormalizer}-%{chrstnormalizer_version}.tar.gz +Source29: %{idna}-%{idna_version}.tar.gz +Source30: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz +Source31: %{oauthlib}-%{oauthlib_version}.tar.gz +Source32: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz +Source33: %{setuptools}-%{setuptools_version}.tar.gz +## required for installation +Source34: setuptools_scm-6.3.2.tar.gz +Source35: packaging-21.2-py3-none-any.whl +Source36: pyparsing-3.0.1.tar.gz +Source37: tomli-1.0.1.tar.gz +### END + 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 @@ -169,10 +234,24 @@ Patch90: bz1920947-fence_redfish-2-add-diag-action-logic.patch Patch91: bz1920947-fence_redfish-3-fix-typo.patch Patch92: bz1922437-fence_mpath-watchdog-retry-support.patch Patch93: bz1685814-fence_gce-add-serviceaccount-file-support.patch -Patch94: bz2052627-fence_aws-botocore-bundled.patch +Patch94: bz1728203-bz1874862-fence_ibm_vpc-fence_ibm_powervs.patch +Patch95: bz1969953-fence_gce-1-add-proxy-support.patch +Patch96: bz1969953-fence_gce-2-bundled.patch +Patch97: bz1470827-all-agents-log-exceptions-fail.patch +Patch98: bz2010710-1-fence_amt_ws-fix-or-dead-code.patch +Patch99: bz2010710-2-fence_amt_ws-boot-option.patch +Patch100: bz1969953-fence_gce-3-fix-httplib2-import.patch +Patch101: bz1971683-fence_sbd-dont-spam-logs-disable-timeout.patch +Patch102: bz1977588-1-fencing-add-EC_FETCH_VM_UUID.patch +Patch103: bz1977588-2-fence_kubevirt.patch +Patch104: bz1977588-3-fence_kubevirt-fix-status.patch +Patch105: bz1977588-4-fence_kubevirt-power-timeout-40s.patch +Patch106: bz1963163-fence_zvmip-add-ssl-tls-support.patch +Patch107: bz1977588-5-fence_kubevirt-get-namespace-from-context.patch +Patch108: bz2048857-fence_aws-botocore-bundled.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 hds_cb hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti +%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hds_cb hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti %ifarch x86_64 %global testagents virsh heuristics_ping aliyun aws azure_arm gce %endif @@ -238,7 +317,7 @@ BuildRequires: gnutls-utils BuildRequires: python3-devel BuildRequires: python3-pexpect python3-pycurl python3-requests BuildRequires: python3-suds openwsman-python3 python3-boto3 -BuildRequires: python3-google-api-client python3-pip +BuildRequires: python3-google-api-client python3-pip python3-wheel python3-jinja2 # turn off the brp-python-bytecompile script # (for F28+ or equivalent, the latter is the preferred form) @@ -342,6 +421,20 @@ BuildRequires: python3-google-api-client python3-pip %patch92 -p1 %patch93 -p1 %patch94 -p1 +%patch95 -p1 +%patch96 -p1 -F2 +%patch97 -p1 +%patch98 -p1 +%patch99 -p1 +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 -F1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -425,16 +518,27 @@ popd pushd %{aliyunsdkvpc_dir} %{__python3} setup.py install -O1 --skip-build --root %{buildroot} --install-lib /usr/lib/fence-agents/%{bundled_lib_dir}/aliyun popd + +# google cloud +## for httplib2 install only +%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} pyparsing +%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/google --no-index --find-links %{_sourcedir} httplib2 %endif +# aws/kubevirt +%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} setuptools-scm + # aws %ifarch x86_64 -%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} setuptools-scm %{__python3} -m pip install --user --no-index --find-links %{_sourcedir} jmespath %{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/aws --no-index --find-links %{_sourcedir} botocore %{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/aws --no-index --find-links %{_sourcedir} requests %endif +# kubevirt +%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt --no-index --find-links %{_sourcedir} openshift +rm -rf %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt/rsa* + ## tree fix up # fix libfence permissions chmod 0755 %{buildroot}%{_datadir}/fence/*.py @@ -780,12 +884,14 @@ via the HTTP(s) protocol. %ifarch x86_64 %package gce -License: GPLv2+ and LGPLv2+ +License: GPLv2+ and LGPLv2+ and MIT Group: System Environment/Base Summary: Fence agent for GCE (Google Cloud Engine) Requires: fence-agents-common >= %{version}-%{release} Requires: python3-google-api-client Requires: python3-pysocks +# google cloud +Provides: bundled(python-httplib2) = %{httplib2_version} Obsoletes: %{name} < %{version}-%{release} BuildArch: noarch %description gce @@ -793,6 +899,8 @@ Fence agent for GCE (Google Cloud Engine) instances. %files gce %{_sbindir}/fence_gce %{_mandir}/man8/fence_gce.8* +# bundled libraries +/usr/lib/fence-agents/%{bundled_lib_dir}/google %endif %package heuristics-ping @@ -846,6 +954,30 @@ via the SNMP protocol. %{_sbindir}/fence_ibmblade %{_mandir}/man8/fence_ibmblade.8* +%package ibm-powervs +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM PowerVS +Requires: fence-agents-common = %{version}-%{release} +BuildArch: noarch +%description ibm-powervs +Fence agent for IBM PowerVS that are accessed via REST API. +%files ibm-powervs +%{_sbindir}/fence_ibm_powervs +%{_mandir}/man8/fence_ibm_powervs.8* + +%package ibm-vpc +License: GPLv2+ and LGPLv2+ +Group: System Environment/Base +Summary: Fence agent for IBM Cloud VPC +Requires: fence-agents-common = %{version}-%{release} +BuildArch: noarch +%description ibm-vpc +Fence agent for IBM Cloud VPC that are accessed via REST API. +%files ibm-vpc +%{_sbindir}/fence_ibm_vpc +%{_mandir}/man8/fence_ibm_vpc.8* + %package ifmib License: GPLv2+ and LGPLv2+ Group: System Environment/Base @@ -1013,6 +1145,41 @@ Fence agent for use with kdump crash recovery service. %{_mandir}/man8/fence_kdump.8* %{_mandir}/man8/fence_kdump_send.8* +%package kubevirt +License: GPLv2+ and LGPLv2+ and ASL 2.0 and BSD and BSD-2-Clause and BSD-3-Clause and ISC and MIT and MPL-2.0 +Summary: Fence agent for KubeVirt platform +Requires: fence-agents-common = %{version}-%{release} +Provides: bundled(python3-%{openshift}) = %{openshift_version} +Provides: bundled(python3-%{ruamelyamlclib}) = %{ruamelyamlclib_version} +Provides: bundled(python3-%{kubernetes}) = %{kubernetes_version} +Provides: bundled(python3-%{certifi}) = %{certifi_version} +Provides: bundled(python3-%{googleauth}) = %{googleauth_version} +Provides: bundled(python3-%{cachetools}) = %{cachetools_version} +Provides: bundled(python3-%{pyasn1modules}) = %{pyasn1modules_version} +Provides: bundled(python3-%{pyasn1}) = %{pyasn1_version} +Provides: bundled(python3-%{dateutil}) = %{dateutil_version} +Provides: bundled(python3-%{pyyaml}) = %{pyyaml_version} +Provides: bundled(python3-%{six}) = %{six_version} +Provides: bundled(python3-%{urllib3}) = %{urllib3_version} +Provides: bundled(python3-%{websocketclient}) = %{websocketclient_version} +Provides: bundled(python3-%{jinja2}) = %{jinja2_version} +Provides: bundled(python3-%{markupsafe}) = %{markupsafe_version} +Provides: bundled(python3-%{stringutils}) = %{stringutils_version} +Provides: bundled(python3-%{requests}) = %{requests_version} +Provides: bundled(python3-%{chrstnormalizer}) = %{chrstnormalizer_version} +Provides: bundled(python3-%{idna}) = %{idna_version} +Provides: bundled(python3-%{reqstsoauthlib}) = %{reqstsoauthlib_version} +Provides: bundled(python3-%{oauthlib}) = %{oauthlib_version} +Provides: bundled(python3-%{ruamelyaml}) = %{ruamelyaml_version} +Provides: bundled(python3-%{setuptools}) = %{setuptools_version} +%description kubevirt +Fence agent for KubeVirt platform. +%files kubevirt +%{_sbindir}/fence_kubevirt +%{_mandir}/man8/fence_kubevirt.8* +# bundled libraries +/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt + %package lpar License: GPLv2+ and LGPLv2+ Group: System Environment/Base @@ -1234,9 +1401,39 @@ Fence agent for IBM z/VM over IP. %endif %changelog -* Fri Feb 11 2022 Oyvind Albrigtsen - 4.2.1-75.2 +* Fri Mar 4 2022 Oyvind Albrigtsen - 4.2.1-89 +- fence_ibm_vpc: new fence agent + Resolves: rhbz#1728203 + +* Fri Feb 11 2022 Oyvind Albrigtsen - 4.2.1-88 - fence_aws: upgrade botocore to fix IMDSv2 support - Resolves: rhbz#2052627 + Resolves: rhbz#2048857 + +* Wed Jan 19 2022 Oyvind Albrigtsen - 4.2.1-85 +- fence_ibm_powervs: new fence agent + Resolves: rhbz#1874862 + +* Mon Jan 17 2022 Oyvind Albrigtsen - 4.2.1-84 +- fence_kubevirt: new fence agent + Resolves: rhbz#1977588 + +* Thu Nov 11 2021 Oyvind Albrigtsen - 4.2.1-83 +- fence_zvmip: add SSL/TLS support + Resolves: rhbz#1963163 + +* Tue Nov 2 2021 Oyvind Albrigtsen - 4.2.1-80 +- fence_sbd: dont spam logs when disable_timeout is enabled + Resolves: rhbz#1971683 + +* Wed Oct 27 2021 Oyvind Albrigtsen - 4.2.1-79 +- fence_amt_ws: fix "or" causing dead code + Resolves: rhbz#2010710 +- fence_gce: add proxy support + Resolves: rhbz#1969953 + +* Tue Oct 19 2021 Oyvind Albrigtsen - 4.2.1-78 +- all agents: log exceptions when failing + Resolves: rhbz#1470827 * Wed Aug 11 2021 Oyvind Albrigtsen - 4.2.1-75 - fence_gce: add serviceaccount JSON file support