- all agents: unify ssl parameters to avoid having to use --ssl when
using --ssl-secure/--ssl-insecure for some agents Resolves: rhbz#2072420 - fence_gce: update fence agent Resolves: rhbz#2079889
This commit is contained in:
parent
ee358ecb60
commit
14fa257026
291
bz2072420-all-agents-unify-ssl-parameters.patch
Normal file
291
bz2072420-all-agents-unify-ssl-parameters.patch
Normal file
@ -0,0 +1,291 @@
|
||||
From 999f2f8b4dc7d258679daf8c3f13d9b317ff4435 Mon Sep 17 00:00:00 2001
|
||||
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||
Date: Thu, 7 Apr 2022 13:11:12 +0200
|
||||
Subject: [PATCH] all agents: unify ssl parameters to avoid having to use --ssl
|
||||
when using --ssl-secure/--ssl-insecure for some agents
|
||||
|
||||
THIS MIGHT BREAK SETUPS USING fence_docker or fence_pve!
|
||||
---
|
||||
agents/cisco_ucs/fence_cisco_ucs.py | 9 +++++----
|
||||
agents/docker/fence_docker.py | 9 ++++++---
|
||||
agents/ibmz/fence_ibmz.py | 4 ++--
|
||||
agents/rhevm/fence_rhevm.py | 8 ++++----
|
||||
agents/skalar/fence_skalar.py | 2 +-
|
||||
agents/vmware_rest/fence_vmware_rest.py | 8 ++++----
|
||||
agents/vmware_soap/fence_vmware_soap.py | 2 +-
|
||||
agents/vmware_vcloud/fence_vmware_vcloud.py | 4 ++--
|
||||
agents/zvm/fence_zvmip.py | 8 +++++---
|
||||
lib/fencing.py.py | 6 ++++++
|
||||
tests/data/metadata/fence_docker.xml | 4 ++--
|
||||
13 files changed, 64 insertions(+), 31 deletions(-)
|
||||
|
||||
diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py
|
||||
index 2280dbbc7..b85379a73 100644
|
||||
--- a/agents/cisco_ucs/fence_cisco_ucs.py
|
||||
+++ b/agents/cisco_ucs/fence_cisco_ucs.py
|
||||
@@ -99,7 +99,7 @@ def get_list(conn, options):
|
||||
|
||||
def send_command(opt, command, timeout):
|
||||
## setup correct URL
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
+ if "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
url = "https:"
|
||||
else:
|
||||
url = "http:"
|
||||
@@ -114,13 +114,14 @@ def send_command(opt, command, timeout):
|
||||
conn.setopt(pycurl.POSTFIELDS, command.encode("ascii"))
|
||||
conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write)
|
||||
conn.setopt(pycurl.TIMEOUT, timeout)
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt:
|
||||
+
|
||||
+ if "--ssl-secure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
|
||||
-
|
||||
- if "--ssl-insecure" in opt:
|
||||
+ elif "--ssl-insecure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
|
||||
+
|
||||
conn.perform()
|
||||
result = web_buffer.getvalue().decode()
|
||||
|
||||
diff --git a/agents/docker/fence_docker.py b/agents/docker/fence_docker.py
|
||||
index fef87da86..004402518 100644
|
||||
--- a/agents/docker/fence_docker.py
|
||||
+++ b/agents/docker/fence_docker.py
|
||||
@@ -43,7 +43,7 @@ def get_list(conn, options):
|
||||
|
||||
|
||||
def send_cmd(options, cmd, post = False):
|
||||
- url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd)
|
||||
+ url = "http%s://%s:%s/v%s/%s" % ("s" if "--ssl-secure" in options or "--ssl-insecure" in options else "", options["--ip"], options["--ipport"], options["--api-version"], cmd)
|
||||
conn = pycurl.Curl()
|
||||
output_buffer = io.BytesIO()
|
||||
if logging.getLogger().getEffectiveLevel() < logging.WARNING:
|
||||
@@ -55,7 +55,8 @@ def send_cmd(options, cmd, post = False):
|
||||
conn.setopt(pycurl.POSTFIELDSIZE, 0)
|
||||
conn.setopt(pycurl.WRITEFUNCTION, output_buffer.write)
|
||||
conn.setopt(pycurl.TIMEOUT, int(options["--shell-timeout"]))
|
||||
- if "--ssl" in options:
|
||||
+
|
||||
+ if "--ssl-secure" in options:
|
||||
if not (set(("--tlscert", "--tlskey", "--tlscacert")) <= set(options)):
|
||||
fail_usage("Failed. If --ssl option is used, You have to also \
|
||||
specify: --tlscert, --tlskey and --tlscacert")
|
||||
@@ -63,7 +64,7 @@ def send_cmd(options, cmd, post = False):
|
||||
conn.setopt(pycurl.SSLCERT, options["--tlscert"])
|
||||
conn.setopt(pycurl.SSLKEY, options["--tlskey"])
|
||||
conn.setopt(pycurl.CAINFO, options["--tlscacert"])
|
||||
- else:
|
||||
+ elif "--ssl-insecure" in options:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
|
||||
|
||||
@@ -136,6 +137,8 @@ def main():
|
||||
|
||||
device_opt = ["ipaddr", "no_password", "no_login", "port", "method", "web", "tlscert", "tlskey", "tlscacert", "ssl", "api_version"]
|
||||
|
||||
+ all_opt["ssl"]["default"] = "1"
|
||||
+
|
||||
options = check_input(device_opt, process_input(device_opt))
|
||||
|
||||
docs = { }
|
||||
diff --git a/agents/ibmz/fence_ibmz.py b/agents/ibmz/fence_ibmz.py
|
||||
index 47408ccf4..d477adeb9 100644
|
||||
--- a/agents/ibmz/fence_ibmz.py
|
||||
+++ b/agents/ibmz/fence_ibmz.py
|
||||
@@ -534,7 +534,7 @@ def main():
|
||||
requests_log.propagate = True
|
||||
if "--verbose" in options:
|
||||
requests_log.setLevel(logging.DEBUG)
|
||||
- if "--ssl-secure" not in options:
|
||||
+ if "--ssl-insecure" in options:
|
||||
urllib3.disable_warnings(
|
||||
category=urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
@@ -548,7 +548,7 @@ def main():
|
||||
'connect_timeout': int(options['--connect-timeout']),
|
||||
'read_timeout': int(options['--read-timeout']),
|
||||
'port': int(options['--ipport']),
|
||||
- 'ssl_verify': bool('--ssl-secure' in options),
|
||||
+ 'ssl_verify': bool('--ssl-insecure' not in options),
|
||||
}
|
||||
try:
|
||||
conn = APIClient(hmc_address, hmc_userid, hmc_password, config)
|
||||
diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py
|
||||
index 25aecbe58..5f74d06f6 100644
|
||||
--- a/agents/rhevm/fence_rhevm.py
|
||||
+++ b/agents/rhevm/fence_rhevm.py
|
||||
@@ -85,7 +85,7 @@ def send_command(opt, command, method="GET"):
|
||||
logging.debug("auto-detected API version: " + opt["--api-version"])
|
||||
|
||||
## setup correct URL
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
+ if "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
url = "https:"
|
||||
else:
|
||||
url = "http:"
|
||||
@@ -126,11 +126,11 @@ def send_command(opt, command, method="GET"):
|
||||
conn.setopt(pycurl.COOKIEJAR, cookie_file)
|
||||
|
||||
conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"]))
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt:
|
||||
+
|
||||
+ if "--ssl-secure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
|
||||
-
|
||||
- if "--ssl-insecure" in opt:
|
||||
+ elif "--ssl-insecure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
|
||||
|
||||
diff --git a/agents/skalar/fence_skalar.py b/agents/skalar/fence_skalar.py
|
||||
index 959527411..0e11d83f9 100644
|
||||
--- a/agents/skalar/fence_skalar.py
|
||||
+++ b/agents/skalar/fence_skalar.py
|
||||
@@ -200,7 +200,7 @@ def main():
|
||||
run_delay(options)
|
||||
|
||||
proto = "https://"
|
||||
- if "--ssl" in options or "--ssl-secure" in options:
|
||||
+ if "--ssl-secure" in options:
|
||||
ssl_verify = True
|
||||
elif "--ssl-insecure" in options:
|
||||
ssl_verify = False
|
||||
diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py
|
||||
index e49fd5663..4b884fc62 100644
|
||||
--- a/agents/vmware_rest/fence_vmware_rest.py
|
||||
+++ b/agents/vmware_rest/fence_vmware_rest.py
|
||||
@@ -69,7 +69,7 @@ def connect(opt):
|
||||
conn = pycurl.Curl()
|
||||
|
||||
## setup correct URL
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
+ if "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
conn.base_url = "https:"
|
||||
else:
|
||||
conn.base_url = "http:"
|
||||
@@ -89,11 +89,11 @@ def connect(opt):
|
||||
conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"])
|
||||
|
||||
conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"]))
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt:
|
||||
+
|
||||
+ if "--ssl-secure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
|
||||
-
|
||||
- if "--ssl-insecure" in opt:
|
||||
+ elif "--ssl-insecure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 0)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 0)
|
||||
|
||||
diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py
|
||||
index 2cd45e0b3..51fb0f147 100644
|
||||
--- a/agents/vmware_soap/fence_vmware_soap.py
|
||||
+++ b/agents/vmware_soap/fence_vmware_soap.py
|
||||
@@ -34,7 +34,7 @@ def send(self, request):
|
||||
def soap_login(options):
|
||||
run_delay(options)
|
||||
|
||||
- if "--ssl" in options or "--ssl-secure" in options or "--ssl-insecure" in options:
|
||||
+ if "--ssl-secure" in options or "--ssl-insecure" in options:
|
||||
if "--ssl-insecure" in options:
|
||||
import ssl
|
||||
import urllib3
|
||||
diff --git a/agents/vmware_vcloud/fence_vmware_vcloud.py b/agents/vmware_vcloud/fence_vmware_vcloud.py
|
||||
index 42372a83d..7626b82bb 100644
|
||||
--- a/agents/vmware_vcloud/fence_vmware_vcloud.py
|
||||
+++ b/agents/vmware_vcloud/fence_vmware_vcloud.py
|
||||
@@ -60,7 +60,7 @@ def connect(opt):
|
||||
conn = pycurl.Curl()
|
||||
|
||||
## setup correct URL
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
+ if "--ssl-secure" in opt or "--ssl-insecure" in opt:
|
||||
conn.base_url = "https:"
|
||||
else:
|
||||
conn.base_url = "http:"
|
||||
@@ -76,7 +76,7 @@ def connect(opt):
|
||||
conn.setopt(pycurl.USERPWD, opt["--username"] + ":" + opt["--password"])
|
||||
|
||||
conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"]))
|
||||
- if "--ssl" in opt or "--ssl-secure" in opt:
|
||||
+ if "--ssl-secure" in opt:
|
||||
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
|
||||
conn.setopt(pycurl.SSL_VERIFYHOST, 2)
|
||||
elif "--ssl-insecure" in opt:
|
||||
diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py
|
||||
index e8f849eda..90ca95d45 100644
|
||||
--- a/agents/zvm/fence_zvmip.py
|
||||
+++ b/agents/zvm/fence_zvmip.py
|
||||
@@ -26,7 +26,7 @@ def open_socket(options):
|
||||
except socket.gaierror:
|
||||
fail(EC_LOGIN_DENIED)
|
||||
|
||||
- if "--ssl" in options:
|
||||
+ if "--ssl-secure" in options or "--ssl-insecure" in options:
|
||||
import ssl
|
||||
sock = socket.socket()
|
||||
sslcx = ssl.create_default_context()
|
||||
@@ -132,7 +132,7 @@ 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
|
||||
+ recvflag = socket.MSG_WAITALL if "--ssl-secure" not in options and "--ssl-insecure" not in options else 0
|
||||
array_len = struct.unpack("!i", conn.recv(INT4))[0]
|
||||
data = ""
|
||||
|
||||
@@ -182,7 +182,9 @@ def main():
|
||||
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
|
||||
|
||||
if "--disable-ssl" in options or options["--ssl"] == "0":
|
||||
- del options["--ssl"]
|
||||
+ for k in ["--ssl", "--ssl-secure", "--ssl-insecure"]:
|
||||
+ if k in options:
|
||||
+ del options[k]
|
||||
|
||||
if len(options.get("--plug", "")) > 8:
|
||||
fail_usage("Failed: Name of image can not be longer than 8 characters")
|
||||
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
|
||||
index 696388d55..b746ede8b 100644
|
||||
--- a/lib/fencing.py.py
|
||||
+++ b/lib/fencing.py.py
|
||||
@@ -789,6 +789,12 @@ def check_input(device_opt, opt, other_conditions = False):
|
||||
if "--password-script" in options:
|
||||
options["--password"] = os.popen(options["--password-script"]).read().rstrip()
|
||||
|
||||
+ if "--ssl-secure" in options or "--ssl-insecure" in options:
|
||||
+ options["--ssl"] = ""
|
||||
+
|
||||
+ if "--ssl" in options and "--ssl-insecure" not in options:
|
||||
+ options["--ssl-secure"] = ""
|
||||
+
|
||||
if os.environ.get("PCMK_service") == "pacemaker-fenced" and "--disable-timeout" not in options:
|
||||
options["--disable-timeout"] = "1"
|
||||
|
||||
diff --git a/tests/data/metadata/fence_docker.xml b/tests/data/metadata/fence_docker.xml
|
||||
index 723e72280..51c7c470a 100644
|
||||
--- a/tests/data/metadata/fence_docker.xml
|
||||
+++ b/tests/data/metadata/fence_docker.xml
|
||||
@@ -20,7 +20,7 @@
|
||||
</parameter>
|
||||
<parameter name="ipport" unique="0" required="0">
|
||||
<getopt mixed="-u, --ipport=[port]" />
|
||||
- <content type="integer" default="80" />
|
||||
+ <content type="integer" default="443" />
|
||||
<shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
|
||||
</parameter>
|
||||
<parameter name="method" unique="0" required="0">
|
||||
@@ -43,7 +43,7 @@
|
||||
</parameter>
|
||||
<parameter name="ssl" unique="0" required="0">
|
||||
<getopt mixed="-z, --ssl" />
|
||||
- <content type="boolean" />
|
||||
+ <content type="boolean" default="1" />
|
||||
<shortdesc lang="en">Use SSL connection with verifying certificate</shortdesc>
|
||||
</parameter>
|
||||
<parameter name="ssl_insecure" unique="0" required="0">
|
410
bz2079889-fence_gce-update.patch
Normal file
410
bz2079889-fence_gce-update.patch
Normal file
@ -0,0 +1,410 @@
|
||||
--- fence-agents-4.10.0/agents/gce/fence_gce.py 2022-04-29 10:13:50.317888041 +0200
|
||||
+++ fence-agents-4.10.0/agents/gce/fence_gce.py2 2022-04-29 10:17:54.813248566 +0200
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#
|
||||
# Requires the googleapiclient and oauth2client
|
||||
-# RHEL 7.x: google-api-python-client==1.6.7 python-gflags==2.0 pyasn1==0.4.8 rsa==3.4.2
|
||||
-# RHEL 8.x: nothing additional needed
|
||||
-# SLES 12.x: python-google-api-python-client python-oauth2client python-oauth2client-gce
|
||||
-# SLES 15.x: python3-google-api-python-client python3-oauth2client python3-oauth2client-gce
|
||||
+# RHEL 7.x: google-api-python-client==1.6.7 python-gflags==2.0 pyasn1==0.4.8 rsa==3.4.2 pysocks==1.7.1 httplib2==0.19.0
|
||||
+# RHEL 8.x: pysocks==1.7.1 httplib2==0.19.0
|
||||
+# SLES 12.x: python-google-api-python-client python-oauth2client python-oauth2client-gce pysocks==1.7.1 httplib2==0.19.0
|
||||
+# SLES 15.x: python3-google-api-python-client python3-oauth2client pysocks==1.7.1 httplib2==0.19.0
|
||||
#
|
||||
|
||||
import atexit
|
||||
@@ -27,7 +27,7 @@
|
||||
import urllib2 as urlrequest
|
||||
sys.path.append("@FENCEAGENTSLIBDIR@")
|
||||
|
||||
-from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
|
||||
+from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action, run_command
|
||||
try:
|
||||
sys.path.insert(0, '/usr/lib/fence-agents/support/google')
|
||||
import httplib2
|
||||
@@ -42,6 +42,19 @@
|
||||
|
||||
METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/'
|
||||
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
|
||||
+INSTANCE_LINK = 'https://www.googleapis.com/compute/v1/projects/{}/zones/{}/instances/{}'
|
||||
+
|
||||
+def run_on_fail(options):
|
||||
+ if "--runonfail" in options:
|
||||
+ run_command(options, options["--runonfail"])
|
||||
+
|
||||
+def fail_fence_agent(options, message):
|
||||
+ run_on_fail(options)
|
||||
+ fail_usage(message)
|
||||
+
|
||||
+def raise_fence_agent(options, message):
|
||||
+ run_on_fail(options)
|
||||
+ raise Exception(message)
|
||||
|
||||
#
|
||||
# Will use baremetalsolution setting or the environment variable
|
||||
@@ -66,7 +79,7 @@
|
||||
{
|
||||
"matchlength": 4,
|
||||
"match": "https://compute.googleapis.com/compute/v1/projects/(.*)/zones/(.*)/instances/(.*)/reset(.*)",
|
||||
- "replace": "https://baremetalsolution.googleapis.com/v1alpha1/projects/\\1/locations/\\2/instances/\\3:resetInstance\\4"
|
||||
+ "replace": "https://baremetalsolution.googleapis.com/v1/projects/\\1/locations/\\2/instances/\\3:resetInstance\\4"
|
||||
})
|
||||
for uri_replacement in uri_replacements:
|
||||
# each uri_replacement should have matchlength, match, and replace
|
||||
@@ -121,14 +134,17 @@
|
||||
|
||||
def get_nodes_list(conn, options):
|
||||
result = {}
|
||||
+ if "--zone" not in options:
|
||||
+ fail_fence_agent(options, "Failed: get_nodes_list: Please specify the --zone in the command")
|
||||
try:
|
||||
- instanceList = retry_api_execute(options, conn.instances().list(
|
||||
- project=options["--project"],
|
||||
- zone=options["--zone"]))
|
||||
- for instance in instanceList["items"]:
|
||||
- result[instance["id"]] = (instance["name"], translate_status(instance["status"]))
|
||||
+ for zone in options["--zone"].split(","):
|
||||
+ instanceList = retry_api_execute(options, conn.instances().list(
|
||||
+ project=options["--project"],
|
||||
+ zone=zone))
|
||||
+ for instance in instanceList["items"]:
|
||||
+ result[instance["id"]] = (instance["name"], translate_status(instance["status"]))
|
||||
except Exception as err:
|
||||
- fail_usage("Failed: get_nodes_list: {}".format(str(err)))
|
||||
+ fail_fence_agent(options, "Failed: get_nodes_list: {}".format(str(err)))
|
||||
|
||||
return result
|
||||
|
||||
@@ -142,23 +158,54 @@
|
||||
return "off"
|
||||
else:
|
||||
return "on"
|
||||
+ # If zone is not listed for an entry we attempt to get it automatically
|
||||
+ instance = options["--plug"]
|
||||
+ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance]
|
||||
+ instance_status = get_instance_power_status(conn, options, instance, zone)
|
||||
+ # If any of the instances do not match the intended status we return the
|
||||
+ # the opposite status so that the fence agent can change it.
|
||||
+ if instance_status != options.get("--action"):
|
||||
+ return instance_status
|
||||
+
|
||||
+ return options.get("--action")
|
||||
+
|
||||
+
|
||||
+def get_instance_power_status(conn, options, instance, zone):
|
||||
try:
|
||||
- instance = retry_api_execute(options, conn.instances().get(
|
||||
- project=options["--project"],
|
||||
- zone=options["--zone"],
|
||||
- instance=options["--plug"]))
|
||||
+ instance = retry_api_execute(
|
||||
+ options,
|
||||
+ conn.instances().get(project=options["--project"], zone=zone, instance=instance))
|
||||
return translate_status(instance["status"])
|
||||
except Exception as err:
|
||||
- fail_usage("Failed: get_power_status: {}".format(str(err)))
|
||||
+ fail_fence_agent(options, "Failed: get_instance_power_status: {}".format(str(err)))
|
||||
|
||||
|
||||
-def wait_for_operation(conn, options, operation):
|
||||
+def check_for_existing_operation(conn, options, instance, zone, operation_type):
|
||||
+ logging.debug("check_for_existing_operation")
|
||||
+ if "--baremetalsolution" in options:
|
||||
+ # There is no API for checking in progress operations
|
||||
+ return False
|
||||
+
|
||||
+ project = options["--project"]
|
||||
+ target_link = INSTANCE_LINK.format(project, zone, instance)
|
||||
+ query_filter = '(targetLink = "{}") AND (operationType = "{}") AND (status = "RUNNING")'.format(target_link, operation_type)
|
||||
+ result = retry_api_execute(
|
||||
+ options,
|
||||
+ conn.zoneOperations().list(project=project, zone=zone, filter=query_filter, maxResults=1))
|
||||
+
|
||||
+ if "items" in result and result["items"]:
|
||||
+ logging.info("Existing %s operation found", operation_type)
|
||||
+ return result["items"][0]
|
||||
+
|
||||
+
|
||||
+def wait_for_operation(conn, options, zone, operation):
|
||||
if 'name' not in operation:
|
||||
logging.warning('Cannot wait for operation to complete, the'
|
||||
' requested operation will continue asynchronously')
|
||||
- return
|
||||
+ return False
|
||||
+
|
||||
+ wait_time = 0
|
||||
project = options["--project"]
|
||||
- zone = options["--zone"]
|
||||
while True:
|
||||
result = retry_api_execute(options, conn.zoneOperations().get(
|
||||
project=project,
|
||||
@@ -166,56 +213,93 @@
|
||||
operation=operation['name']))
|
||||
if result['status'] == 'DONE':
|
||||
if 'error' in result:
|
||||
- raise Exception(result['error'])
|
||||
- return
|
||||
+ raise_fence_agent(options, result['error'])
|
||||
+ return True
|
||||
+
|
||||
+ if "--errortimeout" in options and wait_time > int(options["--errortimeout"]):
|
||||
+ raise_fence_agent(options, "Operation did not complete before the timeout.")
|
||||
+
|
||||
+ if "--warntimeout" in options and wait_time > int(options["--warntimeout"]):
|
||||
+ logging.warning("Operation did not complete before the timeout.")
|
||||
+ if "--runonwarn" in options:
|
||||
+ run_command(options, options["--runonwarn"])
|
||||
+ return False
|
||||
+
|
||||
+ wait_time = wait_time + 1
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def set_power_status(conn, options):
|
||||
- logging.debug("set_power_status");
|
||||
+ logging.debug("set_power_status")
|
||||
+ instance = options["--plug"]
|
||||
+ # If zone is not listed for an entry we attempt to get it automatically
|
||||
+ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance]
|
||||
+ set_instance_power_status(conn, options, instance, zone, options["--action"])
|
||||
+
|
||||
+
|
||||
+def set_instance_power_status(conn, options, instance, zone, action):
|
||||
+ logging.info("Setting power status of %s in zone %s", instance, zone)
|
||||
+ project = options["--project"]
|
||||
+
|
||||
try:
|
||||
- if options["--action"] == "off":
|
||||
- logging.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"]))
|
||||
- operation = retry_api_execute(options, conn.instances().stop(
|
||||
- project=options["--project"],
|
||||
- zone=options["--zone"],
|
||||
- instance=options["--plug"]))
|
||||
+ if action == "off":
|
||||
+ logging.info("Issuing poweroff of %s in zone %s", instance, zone)
|
||||
+ operation = check_for_existing_operation(conn, options, instance, zone, "stop")
|
||||
+ if operation and "--earlyexit" in options:
|
||||
+ return
|
||||
+ if not operation:
|
||||
+ operation = retry_api_execute(
|
||||
+ options,
|
||||
+ conn.instances().stop(project=project, zone=zone, instance=instance))
|
||||
logging.info("Poweroff command completed, waiting for the operation to complete")
|
||||
- wait_for_operation(conn, options, operation)
|
||||
- logging.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"]))
|
||||
- elif options["--action"] == "on":
|
||||
- logging.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"]))
|
||||
- operation = retry_api_execute(options, conn.instances().start(
|
||||
- project=options["--project"],
|
||||
- zone=options["--zone"],
|
||||
- instance=options["--plug"]))
|
||||
- wait_for_operation(conn, options, operation)
|
||||
- logging.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"]))
|
||||
+ if wait_for_operation(conn, options, zone, operation):
|
||||
+ logging.info("Poweroff of %s in zone %s complete", instance, zone)
|
||||
+ elif action == "on":
|
||||
+ logging.info("Issuing poweron of %s in zone %s", instance, zone)
|
||||
+ operation = check_for_existing_operation(conn, options, instance, zone, "start")
|
||||
+ if operation and "--earlyexit" in options:
|
||||
+ return
|
||||
+ if not operation:
|
||||
+ operation = retry_api_execute(
|
||||
+ options,
|
||||
+ conn.instances().start(project=project, zone=zone, instance=instance))
|
||||
+ if wait_for_operation(conn, options, zone, operation):
|
||||
+ logging.info("Poweron of %s in zone %s complete", instance, zone)
|
||||
except Exception as err:
|
||||
- fail_usage("Failed: set_power_status: {}".format(str(err)))
|
||||
-
|
||||
+ fail_fence_agent(options, "Failed: set_instance_power_status: {}".format(str(err)))
|
||||
|
||||
def power_cycle(conn, options):
|
||||
- logging.debug("power_cycle");
|
||||
+ logging.debug("power_cycle")
|
||||
+ instance = options["--plug"]
|
||||
+ # If zone is not listed for an entry we attempt to get it automatically
|
||||
+ zone = get_zone(conn, options, instance) if "--plugzonemap" not in options else options["--plugzonemap"][instance]
|
||||
+ return power_cycle_instance(conn, options, instance, zone)
|
||||
+
|
||||
+
|
||||
+def power_cycle_instance(conn, options, instance, zone):
|
||||
+ logging.info("Issuing reset of %s in zone %s", instance, zone)
|
||||
+ project = options["--project"]
|
||||
+
|
||||
try:
|
||||
- logging.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"]))
|
||||
- operation = retry_api_execute(options, conn.instances().reset(
|
||||
- project=options["--project"],
|
||||
- zone=options["--zone"],
|
||||
- instance=options["--plug"]))
|
||||
- logging.info("Reset command completed, waiting for the operation to complete")
|
||||
- wait_for_operation(conn, options, operation)
|
||||
- logging.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"]))
|
||||
+ operation = check_for_existing_operation(conn, options, instance, zone, "reset")
|
||||
+ if operation and "--earlyexit" in options:
|
||||
+ return True
|
||||
+ if not operation:
|
||||
+ operation = retry_api_execute(
|
||||
+ options,
|
||||
+ conn.instances().reset(project=project, zone=zone, instance=instance))
|
||||
+ logging.info("Reset command sent, waiting for the operation to complete")
|
||||
+ if wait_for_operation(conn, options, zone, operation):
|
||||
+ logging.info("Reset of %s in zone %s complete", instance, zone)
|
||||
return True
|
||||
except Exception as err:
|
||||
- logging.error("Failed: power_cycle: {}".format(str(err)))
|
||||
- return False
|
||||
+ logging.exception("Failed: power_cycle")
|
||||
+ raise err
|
||||
|
||||
|
||||
-def get_zone(conn, options):
|
||||
+def get_zone(conn, options, instance):
|
||||
logging.debug("get_zone");
|
||||
project = options['--project']
|
||||
- instance = options['--plug']
|
||||
fl = 'name="%s"' % instance
|
||||
request = replace_api_uri(options, conn.instances().aggregatedList(project=project, filter=fl))
|
||||
while request is not None:
|
||||
@@ -227,7 +311,7 @@
|
||||
return inst['zone'].split("/")[-1]
|
||||
request = replace_api_uri(options, conn.instances().aggregatedList_next(
|
||||
previous_request=request, previous_response=response))
|
||||
- raise Exception("Unable to find instance %s" % (instance))
|
||||
+ raise_fence_agent(options, "Unable to find instance %s" % (instance))
|
||||
|
||||
|
||||
def get_metadata(metadata_key, params=None, timeout=None):
|
||||
@@ -326,13 +410,21 @@
|
||||
"required" : "0",
|
||||
"order" : 9
|
||||
}
|
||||
+ all_opt["plugzonemap"] = {
|
||||
+ "getopt" : ":",
|
||||
+ "longopt" : "plugzonemap",
|
||||
+ "help" : "--plugzonemap=[plugzonemap] Comma separated zone map when fencing multiple plugs",
|
||||
+ "shortdesc" : "Comma separated zone map when fencing multiple plugs.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 10
|
||||
+ }
|
||||
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
|
||||
+ "order" : 11
|
||||
}
|
||||
all_opt["proxyport"] = {
|
||||
"getopt" : ":",
|
||||
@@ -341,7 +433,49 @@
|
||||
"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
|
||||
+ "order" : 12
|
||||
+ }
|
||||
+ all_opt["earlyexit"] = {
|
||||
+ "getopt" : "",
|
||||
+ "longopt" : "earlyexit",
|
||||
+ "help" : "--earlyexit Return early if reset is already in progress",
|
||||
+ "shortdesc" : "If an existing reset operation is detected, the fence agent will return before the operation completes with a 0 return code.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 13
|
||||
+ }
|
||||
+ all_opt["warntimeout"] = {
|
||||
+ "getopt" : ":",
|
||||
+ "type" : "second",
|
||||
+ "longopt" : "warntimeout",
|
||||
+ "help" : "--warntimeout=[warn_timeout] Timeout seconds before logging a warning and returning a 0 status code",
|
||||
+ "shortdesc" : "If the operation is not completed within the timeout, the cluster operations are allowed to continue.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 14
|
||||
+ }
|
||||
+ all_opt["errortimeout"] = {
|
||||
+ "getopt" : ":",
|
||||
+ "type" : "second",
|
||||
+ "longopt" : "errortimeout",
|
||||
+ "help" : "--errortimeout=[error_timeout] Timeout seconds before failing and returning a non-zero status code",
|
||||
+ "shortdesc" : "If the operation is not completed within the timeout, cluster is notified of the operation failure.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 15
|
||||
+ }
|
||||
+ all_opt["runonwarn"] = {
|
||||
+ "getopt" : ":",
|
||||
+ "longopt" : "runonwarn",
|
||||
+ "help" : "--runonwarn=[run_on_warn] If a timeout occurs and warning is generated, run the supplied command",
|
||||
+ "shortdesc" : "If a timeout would occur while running the agent, then the supplied command is run.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 16
|
||||
+ }
|
||||
+ all_opt["runonfail"] = {
|
||||
+ "getopt" : ":",
|
||||
+ "longopt" : "runonfail",
|
||||
+ "help" : "--runonfail=[run_on_fail] If a failure occurs, run the supplied command",
|
||||
+ "shortdesc" : "If a failure would occur while running the agent, then the supplied command is run.",
|
||||
+ "required" : "0",
|
||||
+ "order" : 17
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +484,8 @@
|
||||
|
||||
device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging",
|
||||
"method", "baremetalsolution", "apitimeout", "retries", "retrysleep",
|
||||
- "serviceaccount", "proxyhost", "proxyport"]
|
||||
+ "serviceaccount", "plugzonemap", "proxyhost", "proxyport", "earlyexit",
|
||||
+ "warntimeout", "errortimeout", "runonwarn", "runonfail"]
|
||||
|
||||
atexit.register(atexit_handler)
|
||||
|
||||
@@ -431,22 +566,39 @@
|
||||
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)))
|
||||
+ fail_fence_agent(options, "Failed: Create GCE compute v1 connection: {}".format(str(err)))
|
||||
|
||||
# Get project and zone
|
||||
if not options.get("--project"):
|
||||
try:
|
||||
options["--project"] = get_metadata('project/project-id')
|
||||
except Exception as err:
|
||||
- fail_usage("Failed retrieving GCE project. Please provide --project option: {}".format(str(err)))
|
||||
+ fail_fence_agent(options, "Failed retrieving GCE project. Please provide --project option: {}".format(str(err)))
|
||||
|
||||
if "--baremetalsolution" in options:
|
||||
options["--zone"] = "none"
|
||||
- if not options.get("--zone"):
|
||||
- try:
|
||||
- options["--zone"] = get_zone(conn, options)
|
||||
- except Exception as err:
|
||||
- fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err)))
|
||||
+
|
||||
+ # Populates zone automatically if missing from the command
|
||||
+ zones = [] if not "--zone" in options else options["--zone"].split(",")
|
||||
+ options["--plugzonemap"] = {}
|
||||
+ if "--plug" in options:
|
||||
+ for i, instance in enumerate(options["--plug"].split(",")):
|
||||
+ if len(zones) == 1:
|
||||
+ # If only one zone is specified, use it across all plugs
|
||||
+ options["--plugzonemap"][instance] = zones[0]
|
||||
+ continue
|
||||
+
|
||||
+ if len(zones) - 1 >= i:
|
||||
+ # If we have enough zones specified with the --zone flag use the zone at
|
||||
+ # the same index as the plug
|
||||
+ options["--plugzonemap"][instance] = zones[i]
|
||||
+ continue
|
||||
+
|
||||
+ try:
|
||||
+ # In this case we do not have a zone specified so we attempt to detect it
|
||||
+ options["--plugzonemap"][instance] = get_zone(conn, options, instance)
|
||||
+ except Exception as err:
|
||||
+ fail_fence_agent(options, "Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err)))
|
||||
|
||||
# Operate the fencing device
|
||||
result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list, power_cycle)
|
@ -59,7 +59,7 @@
|
||||
Name: fence-agents
|
||||
Summary: Set of unified programs capable of host isolation ("fencing")
|
||||
Version: 4.10.0
|
||||
Release: 21%{?alphatag:.%{alphatag}}%{?dist}
|
||||
Release: 22%{?alphatag:.%{alphatag}}%{?dist}
|
||||
License: GPLv2+ and LGPLv2+
|
||||
URL: https://github.com/ClusterLabs/fence-agents
|
||||
Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz
|
||||
@ -234,6 +234,8 @@ Patch17: bz2041933-bz2041935-2-fence_openstack-clouds-openrc.patch
|
||||
Patch18: bz2042496-fence_ibm_vpc-fence_ibm_powervs.patch
|
||||
Patch19: bz2022334-fence_zvmip-add-disable-ssl.patch
|
||||
Patch20: bz2065114-fence_lpar-refactor.patch
|
||||
Patch21: bz2072420-all-agents-unify-ssl-parameters.patch
|
||||
Patch22: bz2079889-fence_gce-update.patch
|
||||
|
||||
%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate 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
|
||||
@ -365,6 +367,8 @@ BuildRequires: %{systemd_units}
|
||||
%patch18 -p1
|
||||
%patch19 -p1
|
||||
%patch20 -p1
|
||||
%patch21 -p1
|
||||
%patch22 -p1
|
||||
|
||||
# prevent compilation of something that won't get used anyway
|
||||
sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
|
||||
@ -1456,6 +1460,13 @@ are located on corosync cluster nodes.
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Apr 29 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-22
|
||||
- all agents: unify ssl parameters to avoid having to use --ssl when
|
||||
using --ssl-secure/--ssl-insecure for some agents
|
||||
Resolves: rhbz#2072420
|
||||
- fence_gce: update fence agent
|
||||
Resolves: rhbz#2079889
|
||||
|
||||
* Wed Apr 6 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-21
|
||||
- fence_lpar: refactor to avoid duplicate code
|
||||
Resolves: rhbz#2065114
|
||||
|
Loading…
Reference in New Issue
Block a user