diff --git a/.fence-agents.metadata b/.fence-agents.metadata index ee9f972..7d13e41 100644 --- a/.fence-agents.metadata +++ b/.fence-agents.metadata @@ -2,4 +2,6 @@ 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 +74ec77d2e2ef6b2ef8503e6e398faa6f3ba298ae SOURCES/httplib2-0.19.1-py3-none-any.whl 326a73f58a62ebee00c11a12cfdd838b196e0e8e SOURCES/pycryptodome-3.6.4.tar.gz +c8307f47e3b75a2d02af72982a2dfefa3f56e407 SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl diff --git a/.gitignore b/.gitignore index 1b2651e..4881a8f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ 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/httplib2-0.19.1-py3-none-any.whl SOURCES/pycryptodome-3.6.4.tar.gz +SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl 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/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/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index 5315bc1..6642e74 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -25,19 +25,26 @@ %global aliyunsdkvpc aliyun-python-sdk-vpc %global aliyunsdkvpc_version 3.0.2 %global aliyunsdkvpc_dir %{bundled_lib_dir}/aliyun/%{aliyunsdkvpc} +# google cloud +%global httplib2 httplib2 +%global httplib2_version 0.19.1 Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.2.1 -Release: 75%{?alphatag:.%{alphatag}}%{?dist} +Release: 77%{?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 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 @@ -132,9 +139,12 @@ 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: 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 %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 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 @@ -164,6 +174,8 @@ fence-agents-eps \\ fence-agents-heuristics-ping \\ fence-agents-hpblade \\ fence-agents-ibmblade \\ +fence-agents-ibm-powervs \\ +fence-agents-ibm-vpc \\ fence-agents-ifmib \\ fence-agents-ilo2 \\ fence-agents-ilo-moonshot \\ @@ -201,6 +213,10 @@ BuildRequires: python3-devel BuildRequires: python3-pexpect python3-pycurl python3-requests BuildRequires: python3-suds openwsman-python3 python3-boto3 BuildRequires: python3-google-api-client +# google cloud +%ifarch x86_64 +BuildRequires: python3-pip +%endif # turn off the brp-python-bytecompile script # (for F28+ or equivalent, the latter is the preferred form) @@ -303,6 +319,9 @@ BuildRequires: python3-google-api-client %patch91 -p1 %patch92 -p1 %patch93 -p1 +%patch94 -p1 +%patch95 -p1 +%patch96 -p1 -F2 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -386,6 +405,11 @@ 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 ## tree fix up @@ -721,12 +745,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 @@ -734,6 +760,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 @@ -787,6 +815,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 @@ -1175,6 +1227,14 @@ Fence agent for IBM z/VM over IP. %endif %changelog +* Tue Sep 7 2021 Oyvind Albrigtsen - 4.2.1-77 +- fence_gce: add proxy support + Resolves: rhbz#1969953 + +* Thu Sep 2 2021 Oyvind Albrigtsen - 4.2.1-76 +- fence_ibm_vpc/fence_ibm_powervs: new fence agents + Resolves: rhbz#1728203, rhbz#1874862 + * Wed Aug 11 2021 Oyvind Albrigtsen - 4.2.1-75 - fence_gce: add serviceaccount JSON file support Resolves: rhbz#1685814