import fence-agents-4.10.0-18.el9
This commit is contained in:
parent
4ee418dad7
commit
164cdd65e3
@ -0,0 +1,102 @@
|
|||||||
|
From 647841dea9d93922779a4aa7d0b5f52f5bc2b4e9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Dan Kenigsberg <danken@redhat.com>
|
||||||
|
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 <danken@redhat.com>
|
||||||
|
---
|
||||||
|
agents/kubevirt/fence_kubevirt.py | 24 +++++++++++++-----------
|
||||||
|
tests/data/metadata/fence_kubevirt.xml | 2 +-
|
||||||
|
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/tests/data/metadata/fence_kubevirt.xml b/tests/data/metadata/fence_kubevirt.xml
|
||||||
|
index 24e975587..ccb20c224 100644
|
||||||
|
--- a/tests/data/metadata/fence_kubevirt.xml
|
||||||
|
+++ b/tests/data/metadata/fence_kubevirt.xml
|
||||||
|
@@ -23,7 +23,7 @@
|
||||||
|
<content type="boolean" />
|
||||||
|
<shortdesc lang="en">Use SSL connection without verifying certificate</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="namespace" unique="0" required="1">
|
||||||
|
+ <parameter name="namespace" unique="0" required="0">
|
||||||
|
<getopt mixed="--namespace=[namespace]" />
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Namespace of the KubeVirt machine.</shortdesc>
|
98
SOURCES/bz2022334-fence_zvmip-add-disable-ssl.patch
Normal file
98
SOURCES/bz2022334-fence_zvmip-add-disable-ssl.patch
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
From 90c4f78e005ca4141039d1dce032b5f2c2ff4783 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
Date: Thu, 10 Feb 2022 12:22:58 +0100
|
||||||
|
Subject: [PATCH 1/2] fencing: add ability to set bool parameters to 0 or false
|
||||||
|
|
||||||
|
---
|
||||||
|
lib/fencing.py.py | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
|
||||||
|
index 55e38c407..696388d55 100644
|
||||||
|
--- a/lib/fencing.py.py
|
||||||
|
+++ b/lib/fencing.py.py
|
||||||
|
@@ -1502,6 +1502,8 @@ def _parse_input_stdin(avail_opt):
|
||||||
|
opt["--"+all_opt[name]["longopt"].rstrip(":")] = value
|
||||||
|
elif value.lower() in ["1", "yes", "on", "true"]:
|
||||||
|
opt["--"+all_opt[name]["longopt"]] = "1"
|
||||||
|
+ elif value.lower() in ["0", "no", "off", "false"]:
|
||||||
|
+ opt["--"+all_opt[name]["longopt"]] = "0"
|
||||||
|
else:
|
||||||
|
logging.warning("Parse error: Ignoring option '%s' because it does not have value\n", name)
|
||||||
|
|
||||||
|
|
||||||
|
From 249abc8e5620fb1a3d97a0af6db34b1f2cbf3ae5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
Date: Thu, 10 Feb 2022 12:27:02 +0100
|
||||||
|
Subject: [PATCH 2/2] fence_zvmip: add --disable-ssl
|
||||||
|
|
||||||
|
---
|
||||||
|
agents/zvm/fence_zvmip.py | 18 +++++++++++++++++-
|
||||||
|
tests/data/metadata/fence_zvmip.xml | 7 ++++++-
|
||||||
|
2 files changed, 23 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py
|
||||||
|
index 96021b13e..e8f849eda 100644
|
||||||
|
--- a/agents/zvm/fence_zvmip.py
|
||||||
|
+++ b/agents/zvm/fence_zvmip.py
|
||||||
|
@@ -156,11 +156,24 @@ def get_list_of_images(options, command, data_as_plug):
|
||||||
|
conn.close()
|
||||||
|
return (return_code, reason_code, images)
|
||||||
|
|
||||||
|
+def define_new_opts():
|
||||||
|
+ all_opt["disable_ssl"] = {
|
||||||
|
+ "getopt" : "",
|
||||||
|
+ "longopt" : "disable-ssl",
|
||||||
|
+ "help" : "--disable-ssl Don't use SSL connection",
|
||||||
|
+ "required" : "0",
|
||||||
|
+ "shortdesc" : "Don't use SSL",
|
||||||
|
+ "order": 2
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
def main():
|
||||||
|
device_opt = ["ipaddr", "login", "passwd", "port", "method", "missing_as_off",
|
||||||
|
- "inet4_only", "inet6_only", "ssl"]
|
||||||
|
+ "inet4_only", "inet6_only", "ssl", "disable_ssl"]
|
||||||
|
|
||||||
|
atexit.register(atexit_handler)
|
||||||
|
+ define_new_opts()
|
||||||
|
+
|
||||||
|
+ all_opt["ssl"]["help"] = "-z, --ssl Use SSL connection with verifying certificate (Default)"
|
||||||
|
|
||||||
|
all_opt["ipport"]["default"] = "44444"
|
||||||
|
all_opt["shell_timeout"]["default"] = "5"
|
||||||
|
@@ -168,6 +181,9 @@ def main():
|
||||||
|
all_opt["ssl"]["default"] = "1"
|
||||||
|
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
|
||||||
|
|
||||||
|
+ if "--disable-ssl" in options or options["--ssl"] == "0":
|
||||||
|
+ del options["--ssl"]
|
||||||
|
+
|
||||||
|
if len(options.get("--plug", "")) > 8:
|
||||||
|
fail_usage("Failed: Name of image can not be longer than 8 characters")
|
||||||
|
|
||||||
|
diff --git a/tests/data/metadata/fence_zvmip.xml b/tests/data/metadata/fence_zvmip.xml
|
||||||
|
index f32fc159d..0b7ba4785 100644
|
||||||
|
--- a/tests/data/metadata/fence_zvmip.xml
|
||||||
|
+++ b/tests/data/metadata/fence_zvmip.xml
|
||||||
|
@@ -94,7 +94,7 @@ to access the system's directory manager.
|
||||||
|
<parameter name="ssl" unique="0" required="0">
|
||||||
|
<getopt mixed="-z, --ssl" />
|
||||||
|
<content type="boolean" default="1" />
|
||||||
|
- <shortdesc lang="en">Use SSL connection with verifying certificate</shortdesc>
|
||||||
|
+ <shortdesc lang="en">Use SSL connection with verifying certificate (Default)</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ssl_insecure" unique="0" required="0">
|
||||||
|
<getopt mixed="--ssl-insecure" />
|
||||||
|
@@ -111,6 +111,11 @@ to access the system's directory manager.
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Login name</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
+ <parameter name="disable_ssl" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--disable-ssl" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Don't use SSL</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
<parameter name="quiet" unique="0" required="0">
|
||||||
|
<getopt mixed="-q, --quiet" />
|
||||||
|
<content type="boolean" />
|
@ -0,0 +1,313 @@
|
|||||||
|
From 2f741df2ce73da85bbd205d861b527aa141d9776 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
Date: Fri, 14 Jan 2022 14:47:41 +0100
|
||||||
|
Subject: [PATCH 1/2] fencing: add source_env()
|
||||||
|
|
||||||
|
---
|
||||||
|
lib/fencing.py.py | 8 ++++++++
|
||||||
|
1 file changed, 8 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
|
||||||
|
index d85b23568..55e38c407 100644
|
||||||
|
--- a/lib/fencing.py.py
|
||||||
|
+++ b/lib/fencing.py.py
|
||||||
|
@@ -1143,6 +1143,14 @@ def fence_logout(conn, logout_string, sleep=0):
|
||||||
|
except pexpect.ExceptionPexpect:
|
||||||
|
pass
|
||||||
|
|
||||||
|
+def source_env(env_file):
|
||||||
|
+ # POSIX: name shall not contain '=', value doesn't contain '\0'
|
||||||
|
+ output = subprocess.check_output("source {} && env -0".format(env_file), shell=True,
|
||||||
|
+ executable="/bin/sh")
|
||||||
|
+ # replace env
|
||||||
|
+ os.environ.clear()
|
||||||
|
+ os.environ.update(line.partition('=')[::2] for line in output.decode("utf-8").split('\0'))
|
||||||
|
+
|
||||||
|
# Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is
|
||||||
|
# in format a.b.c.d...z and returned dict has key only z
|
||||||
|
def array_to_dict(array):
|
||||||
|
|
||||||
|
From fe2183a97e0a5734702e9cba8da21f01afd8f577 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
Date: Fri, 14 Jan 2022 14:54:10 +0100
|
||||||
|
Subject: [PATCH 2/2] fence_openstack: add support for reading config from
|
||||||
|
clouds.yaml and openrc
|
||||||
|
|
||||||
|
---
|
||||||
|
agents/openstack/fence_openstack.py | 116 ++++++++++++++++++++----
|
||||||
|
tests/data/metadata/fence_openstack.xml | 32 +++++--
|
||||||
|
2 files changed, 126 insertions(+), 22 deletions(-)
|
||||||
|
mode change 100755 => 100644 agents/openstack/fence_openstack.py
|
||||||
|
|
||||||
|
diff --git a/agents/openstack/fence_openstack.py b/agents/openstack/fence_openstack.py
|
||||||
|
old mode 100755
|
||||||
|
new mode 100644
|
||||||
|
index 36b353b52..d3a4be3aa
|
||||||
|
--- a/agents/openstack/fence_openstack.py
|
||||||
|
+++ b/agents/openstack/fence_openstack.py
|
||||||
|
@@ -8,7 +8,7 @@
|
||||||
|
|
||||||
|
sys.path.append("@FENCEAGENTSLIBDIR@")
|
||||||
|
from fencing import *
|
||||||
|
-from fencing import fail_usage, run_delay
|
||||||
|
+from fencing import fail_usage, run_delay, source_env
|
||||||
|
|
||||||
|
try:
|
||||||
|
from novaclient import client
|
||||||
|
@@ -26,6 +26,23 @@ def translate_status(instance_status):
|
||||||
|
return "off"
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
+def get_cloud(options):
|
||||||
|
+ import os, yaml
|
||||||
|
+
|
||||||
|
+ clouds_yaml = os.path.expanduser("~/.config/openstack/clouds.yaml")
|
||||||
|
+ if os.path.exists(clouds_yaml):
|
||||||
|
+ with open(clouds_yaml, "r") as yaml_stream:
|
||||||
|
+ try:
|
||||||
|
+ clouds = yaml.safe_load(yaml_stream)
|
||||||
|
+ except yaml.YAMLError as exc:
|
||||||
|
+ fail_usage("Failed: Unable to read: " + clouds_yaml)
|
||||||
|
+
|
||||||
|
+ cloud = clouds.get("clouds").get(options["--cloud"])
|
||||||
|
+ if not cloud:
|
||||||
|
+ fail_usage("Cloud: {} not found.".format(options["--cloud"]))
|
||||||
|
+
|
||||||
|
+ return cloud
|
||||||
|
+
|
||||||
|
|
||||||
|
def get_nodes_list(conn, options):
|
||||||
|
logging.info("Running %s action", options["--action"])
|
||||||
|
@@ -153,7 +170,7 @@ def define_new_opts():
|
||||||
|
"getopt": ":",
|
||||||
|
"longopt": "auth-url",
|
||||||
|
"help": "--auth-url=[authurl] Keystone Auth URL",
|
||||||
|
- "required": "1",
|
||||||
|
+ "required": "0",
|
||||||
|
"shortdesc": "Keystone Auth URL",
|
||||||
|
"order": 2,
|
||||||
|
}
|
||||||
|
@@ -161,7 +178,7 @@ def define_new_opts():
|
||||||
|
"getopt": ":",
|
||||||
|
"longopt": "project-name",
|
||||||
|
"help": "--project-name=[project] Tenant Or Project Name",
|
||||||
|
- "required": "1",
|
||||||
|
+ "required": "0",
|
||||||
|
"shortdesc": "Keystone Project",
|
||||||
|
"default": "admin",
|
||||||
|
"order": 3,
|
||||||
|
@@ -184,13 +201,38 @@ def define_new_opts():
|
||||||
|
"default": "Default",
|
||||||
|
"order": 5,
|
||||||
|
}
|
||||||
|
+ all_opt["clouds-yaml"] = {
|
||||||
|
+ "getopt": ":",
|
||||||
|
+ "longopt": "clouds-yaml",
|
||||||
|
+ "help": "--clouds-yaml=[clouds-yaml] Path to the clouds.yaml config file",
|
||||||
|
+ "required": "0",
|
||||||
|
+ "shortdesc": "clouds.yaml config file",
|
||||||
|
+ "default": "~/.config/openstack/clouds.yaml",
|
||||||
|
+ "order": 6,
|
||||||
|
+ }
|
||||||
|
+ all_opt["cloud"] = {
|
||||||
|
+ "getopt": ":",
|
||||||
|
+ "longopt": "cloud",
|
||||||
|
+ "help": "--cloud=[cloud] Openstack cloud (from clouds.yaml).",
|
||||||
|
+ "required": "0",
|
||||||
|
+ "shortdesc": "Cloud from clouds.yaml",
|
||||||
|
+ "order": 7,
|
||||||
|
+ }
|
||||||
|
+ all_opt["openrc"] = {
|
||||||
|
+ "getopt": ":",
|
||||||
|
+ "longopt": "openrc",
|
||||||
|
+ "help": "--openrc=[openrc] Path to the openrc config file",
|
||||||
|
+ "required": "0",
|
||||||
|
+ "shortdesc": "openrc config file",
|
||||||
|
+ "order": 8,
|
||||||
|
+ }
|
||||||
|
all_opt["uuid"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
"longopt": "uuid",
|
||||||
|
"help": "--uuid=[uuid] Replaced by -n, --plug",
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "Replaced by port/-n/--plug",
|
||||||
|
- "order": 6,
|
||||||
|
+ "order": 9,
|
||||||
|
}
|
||||||
|
all_opt["cacert"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -199,7 +241,7 @@ def define_new_opts():
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "SSL X.509 certificates file",
|
||||||
|
"default": "",
|
||||||
|
- "order": 7,
|
||||||
|
+ "order": 10,
|
||||||
|
}
|
||||||
|
all_opt["apitimeout"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -209,7 +251,7 @@ def define_new_opts():
|
||||||
|
"shortdesc": "Timeout in seconds to use for API calls, default is 60.",
|
||||||
|
"required": "0",
|
||||||
|
"default": 60,
|
||||||
|
- "order": 8,
|
||||||
|
+ "order": 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -218,11 +260,16 @@ def main():
|
||||||
|
|
||||||
|
device_opt = [
|
||||||
|
"login",
|
||||||
|
+ "no_login",
|
||||||
|
"passwd",
|
||||||
|
+ "no_password",
|
||||||
|
"auth-url",
|
||||||
|
"project-name",
|
||||||
|
"user-domain-name",
|
||||||
|
"project-domain-name",
|
||||||
|
+ "clouds-yaml",
|
||||||
|
+ "cloud",
|
||||||
|
+ "openrc",
|
||||||
|
"port",
|
||||||
|
"no_port",
|
||||||
|
"uuid",
|
||||||
|
@@ -265,19 +312,56 @@ def main():
|
||||||
|
|
||||||
|
run_delay(options)
|
||||||
|
|
||||||
|
- username = options["--username"]
|
||||||
|
- password = options["--password"]
|
||||||
|
- projectname = options["--project-name"]
|
||||||
|
- auth_url = None
|
||||||
|
- try:
|
||||||
|
- auth_url = options["--auth-url"]
|
||||||
|
- except KeyError:
|
||||||
|
- fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
|
||||||
|
- user_domain_name = options["--user-domain-name"]
|
||||||
|
- project_domain_name = options["--project-domain-name"]
|
||||||
|
+ if options.get("--clouds-yaml"):
|
||||||
|
+ if not os.path.exists(os.path.expanduser(options["--clouds-yaml"])):
|
||||||
|
+ fail_usage("Failed: {} does not exist".format(options.get("--clouds-yaml")))
|
||||||
|
+ if not options.get("--cloud"):
|
||||||
|
+ fail_usage("Failed: \"cloud\" not specified")
|
||||||
|
+ cloud = get_cloud(options)
|
||||||
|
+ username = cloud.get("username")
|
||||||
|
+ password = cloud.get("password")
|
||||||
|
+ projectname = cloud.get("project_name")
|
||||||
|
+ auth_url = None
|
||||||
|
+ try:
|
||||||
|
+ auth_url = cloud.get("auth_url")
|
||||||
|
+ except KeyError:
|
||||||
|
+ fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
|
||||||
|
+ user_domain_name = cloud.get("user_domain_name")
|
||||||
|
+ project_domain_name = cloud.get("project_domain_name")
|
||||||
|
+ caverify = cloud.get("verify")
|
||||||
|
+ if caverify in [True, False]:
|
||||||
|
+ options["--ssl-insecure"] = caverify
|
||||||
|
+ else:
|
||||||
|
+ options["--cacert"] = caverify
|
||||||
|
+ if options.get("--openrc") and os.path.exists(os.path.expanduser(options["--openrc"])):
|
||||||
|
+ source_env(options["--openrc"])
|
||||||
|
+ env = os.environ
|
||||||
|
+ username = env.get("OS_USERNAME")
|
||||||
|
+ password = env.get("OS_PASSWORD")
|
||||||
|
+ projectname = env.get("OS_PROJECT_NAME")
|
||||||
|
+ auth_url = None
|
||||||
|
+ try:
|
||||||
|
+ auth_url = env["OS_AUTH_URL"]
|
||||||
|
+ except KeyError:
|
||||||
|
+ fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
|
||||||
|
+ user_domain_name = env.get("OS_USER_DOMAIN_NAME")
|
||||||
|
+ project_domain_name = env.get("OS_PROJECT_DOMAIN_NAME")
|
||||||
|
+ else:
|
||||||
|
+ username = options["--username"]
|
||||||
|
+ password = options["--password"]
|
||||||
|
+ projectname = options["--project-name"]
|
||||||
|
+ auth_url = None
|
||||||
|
+ try:
|
||||||
|
+ auth_url = options["--auth-url"]
|
||||||
|
+ except KeyError:
|
||||||
|
+ fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
|
||||||
|
+ user_domain_name = options["--user-domain-name"]
|
||||||
|
+ project_domain_name = options["--project-domain-name"]
|
||||||
|
+
|
||||||
|
ssl_insecure = "--ssl-insecure" in options
|
||||||
|
cacert = options["--cacert"]
|
||||||
|
apitimeout = options["--apitimeout"]
|
||||||
|
+
|
||||||
|
try:
|
||||||
|
conn = nova_login(
|
||||||
|
username,
|
||||||
|
diff --git a/tests/data/metadata/fence_openstack.xml b/tests/data/metadata/fence_openstack.xml
|
||||||
|
index c8dc2e60f..55a57b4d7 100644
|
||||||
|
--- a/tests/data/metadata/fence_openstack.xml
|
||||||
|
+++ b/tests/data/metadata/fence_openstack.xml
|
||||||
|
@@ -8,7 +8,7 @@
|
||||||
|
<content type="string" default="reboot" />
|
||||||
|
<shortdesc lang="en">Fencing action</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="login" unique="0" required="1" deprecated="1">
|
||||||
|
+ <parameter name="login" unique="0" required="0" deprecated="1">
|
||||||
|
<getopt mixed="-l, --username=[name]" />
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Login name</shortdesc>
|
||||||
|
@@ -48,27 +48,27 @@
|
||||||
|
<content type="boolean" />
|
||||||
|
<shortdesc lang="en">Use SSL connection without verifying certificate</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="username" unique="0" required="1" obsoletes="login">
|
||||||
|
+ <parameter name="username" unique="0" required="0" obsoletes="login">
|
||||||
|
<getopt mixed="-l, --username=[name]" />
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Login name</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="auth-url" unique="0" required="1" deprecated="1">
|
||||||
|
+ <parameter name="auth-url" unique="0" required="0" deprecated="1">
|
||||||
|
<getopt mixed="--auth-url=[authurl]" />
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Keystone Auth URL</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="auth_url" unique="0" required="1" obsoletes="auth-url">
|
||||||
|
+ <parameter name="auth_url" unique="0" required="0" obsoletes="auth-url">
|
||||||
|
<getopt mixed="--auth-url=[authurl]" />
|
||||||
|
<content type="string" />
|
||||||
|
<shortdesc lang="en">Keystone Auth URL</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="project-name" unique="0" required="1" deprecated="1">
|
||||||
|
+ <parameter name="project-name" unique="0" required="0" deprecated="1">
|
||||||
|
<getopt mixed="--project-name=[project]" />
|
||||||
|
<content type="string" default="admin" />
|
||||||
|
<shortdesc lang="en">Keystone Project</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="project_name" unique="0" required="1" obsoletes="project-name">
|
||||||
|
+ <parameter name="project_name" unique="0" required="0" obsoletes="project-name">
|
||||||
|
<getopt mixed="--project-name=[project]" />
|
||||||
|
<content type="string" default="admin" />
|
||||||
|
<shortdesc lang="en">Keystone Project</shortdesc>
|
||||||
|
@@ -93,6 +93,26 @@
|
||||||
|
<content type="string" default="Default" />
|
||||||
|
<shortdesc lang="en">Keystone Project Domain Name</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
+ <parameter name="clouds-yaml" unique="0" required="0" deprecated="1">
|
||||||
|
+ <getopt mixed="--clouds-yaml=[clouds-yaml]" />
|
||||||
|
+ <content type="string" default="~/.config/openstack/clouds.yaml" />
|
||||||
|
+ <shortdesc lang="en">clouds.yaml config file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="clouds_yaml" unique="0" required="0" obsoletes="clouds-yaml">
|
||||||
|
+ <getopt mixed="--clouds-yaml=[clouds-yaml]" />
|
||||||
|
+ <content type="string" default="~/.config/openstack/clouds.yaml" />
|
||||||
|
+ <shortdesc lang="en">clouds.yaml config file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="cloud" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--cloud=[cloud]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Cloud from clouds.yaml</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="openrc" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--openrc=[openrc]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">openrc config file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
<parameter name="uuid" unique="0" required="0">
|
||||||
|
<getopt mixed="--uuid=[uuid]" />
|
||||||
|
<content type="string" />
|
@ -0,0 +1,171 @@
|
|||||||
|
From 7d9572ec947d23fa18ac530f07fe33ba148c9634 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
Date: Mon, 17 Jan 2022 14:32:53 +0100
|
||||||
|
Subject: [PATCH] fence_openstack: fix issues with new clouds.yaml/openrc
|
||||||
|
parameters - hardcoded clouds.yaml paths to work like the openstack cli
|
||||||
|
client (used by the resource agents)
|
||||||
|
|
||||||
|
---
|
||||||
|
agents/openstack/fence_openstack.py | 55 +++++++++++--------------
|
||||||
|
tests/data/metadata/fence_openstack.xml | 10 -----
|
||||||
|
2 files changed, 25 insertions(+), 40 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/agents/openstack/fence_openstack.py b/agents/openstack/fence_openstack.py
|
||||||
|
index d3a4be3aa..666016d78 100644
|
||||||
|
--- a/agents/openstack/fence_openstack.py
|
||||||
|
+++ b/agents/openstack/fence_openstack.py
|
||||||
|
@@ -3,6 +3,7 @@
|
||||||
|
import atexit
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
+import os
|
||||||
|
|
||||||
|
import urllib3
|
||||||
|
|
||||||
|
@@ -27,9 +28,15 @@ def translate_status(instance_status):
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
def get_cloud(options):
|
||||||
|
- import os, yaml
|
||||||
|
+ import yaml
|
||||||
|
|
||||||
|
- clouds_yaml = os.path.expanduser("~/.config/openstack/clouds.yaml")
|
||||||
|
+ clouds_yaml = "~/.config/openstack/clouds.yaml"
|
||||||
|
+ if not os.path.exists(os.path.expanduser(clouds_yaml)):
|
||||||
|
+ clouds_yaml = "/etc/openstack/clouds.yaml"
|
||||||
|
+ if not os.path.exists(os.path.expanduser(clouds_yaml)):
|
||||||
|
+ fail_usage("Failed: ~/.config/openstack/clouds.yaml and /etc/openstack/clouds.yaml does not exist")
|
||||||
|
+
|
||||||
|
+ clouds_yaml = os.path.expanduser(clouds_yaml)
|
||||||
|
if os.path.exists(clouds_yaml):
|
||||||
|
with open(clouds_yaml, "r") as yaml_stream:
|
||||||
|
try:
|
||||||
|
@@ -201,22 +208,13 @@ def define_new_opts():
|
||||||
|
"default": "Default",
|
||||||
|
"order": 5,
|
||||||
|
}
|
||||||
|
- all_opt["clouds-yaml"] = {
|
||||||
|
- "getopt": ":",
|
||||||
|
- "longopt": "clouds-yaml",
|
||||||
|
- "help": "--clouds-yaml=[clouds-yaml] Path to the clouds.yaml config file",
|
||||||
|
- "required": "0",
|
||||||
|
- "shortdesc": "clouds.yaml config file",
|
||||||
|
- "default": "~/.config/openstack/clouds.yaml",
|
||||||
|
- "order": 6,
|
||||||
|
- }
|
||||||
|
all_opt["cloud"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
"longopt": "cloud",
|
||||||
|
- "help": "--cloud=[cloud] Openstack cloud (from clouds.yaml).",
|
||||||
|
+ "help": "--cloud=[cloud] Openstack cloud (from ~/.config/openstack/clouds.yaml or /etc/openstack/clouds.yaml).",
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "Cloud from clouds.yaml",
|
||||||
|
- "order": 7,
|
||||||
|
+ "order": 6,
|
||||||
|
}
|
||||||
|
all_opt["openrc"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -224,7 +222,7 @@ def define_new_opts():
|
||||||
|
"help": "--openrc=[openrc] Path to the openrc config file",
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "openrc config file",
|
||||||
|
- "order": 8,
|
||||||
|
+ "order": 7,
|
||||||
|
}
|
||||||
|
all_opt["uuid"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -232,7 +230,7 @@ def define_new_opts():
|
||||||
|
"help": "--uuid=[uuid] Replaced by -n, --plug",
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "Replaced by port/-n/--plug",
|
||||||
|
- "order": 9,
|
||||||
|
+ "order": 8,
|
||||||
|
}
|
||||||
|
all_opt["cacert"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -241,7 +239,7 @@ def define_new_opts():
|
||||||
|
"required": "0",
|
||||||
|
"shortdesc": "SSL X.509 certificates file",
|
||||||
|
"default": "",
|
||||||
|
- "order": 10,
|
||||||
|
+ "order": 9,
|
||||||
|
}
|
||||||
|
all_opt["apitimeout"] = {
|
||||||
|
"getopt": ":",
|
||||||
|
@@ -251,7 +249,7 @@ def define_new_opts():
|
||||||
|
"shortdesc": "Timeout in seconds to use for API calls, default is 60.",
|
||||||
|
"required": "0",
|
||||||
|
"default": 60,
|
||||||
|
- "order": 11,
|
||||||
|
+ "order": 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -267,7 +265,6 @@ def main():
|
||||||
|
"project-name",
|
||||||
|
"user-domain-name",
|
||||||
|
"project-domain-name",
|
||||||
|
- "clouds-yaml",
|
||||||
|
"cloud",
|
||||||
|
"openrc",
|
||||||
|
"port",
|
||||||
|
@@ -312,28 +309,26 @@ def main():
|
||||||
|
|
||||||
|
run_delay(options)
|
||||||
|
|
||||||
|
- if options.get("--clouds-yaml"):
|
||||||
|
- if not os.path.exists(os.path.expanduser(options["--clouds-yaml"])):
|
||||||
|
- fail_usage("Failed: {} does not exist".format(options.get("--clouds-yaml")))
|
||||||
|
- if not options.get("--cloud"):
|
||||||
|
- fail_usage("Failed: \"cloud\" not specified")
|
||||||
|
+ if options.get("--cloud"):
|
||||||
|
cloud = get_cloud(options)
|
||||||
|
- username = cloud.get("username")
|
||||||
|
- password = cloud.get("password")
|
||||||
|
- projectname = cloud.get("project_name")
|
||||||
|
+ username = cloud.get("auth").get("username")
|
||||||
|
+ password = cloud.get("auth").get("password")
|
||||||
|
+ projectname = cloud.get("auth").get("project_name")
|
||||||
|
auth_url = None
|
||||||
|
try:
|
||||||
|
- auth_url = cloud.get("auth_url")
|
||||||
|
+ auth_url = cloud.get("auth").get("auth_url")
|
||||||
|
except KeyError:
|
||||||
|
fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
|
||||||
|
- user_domain_name = cloud.get("user_domain_name")
|
||||||
|
- project_domain_name = cloud.get("project_domain_name")
|
||||||
|
+ user_domain_name = cloud.get("auth").get("user_domain_name")
|
||||||
|
+ project_domain_name = cloud.get("auth").get("project_domain_name")
|
||||||
|
caverify = cloud.get("verify")
|
||||||
|
if caverify in [True, False]:
|
||||||
|
options["--ssl-insecure"] = caverify
|
||||||
|
else:
|
||||||
|
options["--cacert"] = caverify
|
||||||
|
- if options.get("--openrc") and os.path.exists(os.path.expanduser(options["--openrc"])):
|
||||||
|
+ elif options.get("--openrc"):
|
||||||
|
+ if not os.path.exists(os.path.expanduser(options["--openrc"])):
|
||||||
|
+ fail_usage("Failed: {} does not exist".format(options.get("--openrc")))
|
||||||
|
source_env(options["--openrc"])
|
||||||
|
env = os.environ
|
||||||
|
username = env.get("OS_USERNAME")
|
||||||
|
diff --git a/tests/data/metadata/fence_openstack.xml b/tests/data/metadata/fence_openstack.xml
|
||||||
|
index 55a57b4d7..67b2191b7 100644
|
||||||
|
--- a/tests/data/metadata/fence_openstack.xml
|
||||||
|
+++ b/tests/data/metadata/fence_openstack.xml
|
||||||
|
@@ -93,16 +93,6 @@
|
||||||
|
<content type="string" default="Default" />
|
||||||
|
<shortdesc lang="en">Keystone Project Domain Name</shortdesc>
|
||||||
|
</parameter>
|
||||||
|
- <parameter name="clouds-yaml" unique="0" required="0" deprecated="1">
|
||||||
|
- <getopt mixed="--clouds-yaml=[clouds-yaml]" />
|
||||||
|
- <content type="string" default="~/.config/openstack/clouds.yaml" />
|
||||||
|
- <shortdesc lang="en">clouds.yaml config file</shortdesc>
|
||||||
|
- </parameter>
|
||||||
|
- <parameter name="clouds_yaml" unique="0" required="0" obsoletes="clouds-yaml">
|
||||||
|
- <getopt mixed="--clouds-yaml=[clouds-yaml]" />
|
||||||
|
- <content type="string" default="~/.config/openstack/clouds.yaml" />
|
||||||
|
- <shortdesc lang="en">clouds.yaml config file</shortdesc>
|
||||||
|
- </parameter>
|
||||||
|
<parameter name="cloud" unique="0" required="0">
|
||||||
|
<getopt mixed="--cloud=[cloud]" />
|
||||||
|
<content type="string" />
|
740
SOURCES/bz2042496-fence_ibm_vpc-fence_ibm_powervs.patch
Normal file
740
SOURCES/bz2042496-fence_ibm_vpc-fence_ibm_powervs.patch
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
From 3078e4d55d3bad2bbf9309785fdb2b53afac8d65 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
|
||||||
|
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 @@
|
||||||
|
+<?xml version="1.0" ?>
|
||||||
|
+<resource-agent name="fence_ibm_powervs" shortdesc="Fence agent for IBM PowerVS" >
|
||||||
|
+<longdesc>fence_ibm_powervs is an I/O Fencing agent which can be used with IBM PowerVS to fence virtual machines.</longdesc>
|
||||||
|
+<vendor-url>https://www.ibm.com</vendor-url>
|
||||||
|
+<parameters>
|
||||||
|
+ <parameter name="crn" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--crn=[crn]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">CRN</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="instance" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--instance=[instance]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">PowerVS Instance</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="region" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--region=[region]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Region</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="token" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--token=[token]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Bearer Token</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="action" unique="0" required="1">
|
||||||
|
+ <getopt mixed="-o, --action=[action]" />
|
||||||
|
+ <content type="string" default="reboot" />
|
||||||
|
+ <shortdesc lang="en">Fencing action</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="plug" unique="0" required="1" obsoletes="port">
|
||||||
|
+ <getopt mixed="-n, --plug=[id]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="port" unique="0" required="1" deprecated="1">
|
||||||
|
+ <getopt mixed="-n, --plug=[id]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="quiet" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-q, --quiet" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="verbose" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-v, --verbose" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity.</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="verbose_level" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--verbose-level" />
|
||||||
|
+ <content type="integer" />
|
||||||
|
+ <shortdesc lang="en">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).</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="debug" unique="0" required="0" deprecated="1">
|
||||||
|
+ <getopt mixed="-D, --debug-file=[debugfile]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="debug_file" unique="0" required="0" obsoletes="debug">
|
||||||
|
+ <getopt mixed="-D, --debug-file=[debugfile]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="version" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-V, --version" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Display version information and exit</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="help" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-h, --help" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Display help and exit</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="separator" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-C, --separator=[char]" />
|
||||||
|
+ <content type="string" default="," />
|
||||||
|
+ <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="delay" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--delay=[seconds]" />
|
||||||
|
+ <content type="second" default="0" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="disable_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--disable-timeout=[true/false]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Disable timeout (true/false) (default: true when run from Pacemaker 2.0+)</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="login_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--login-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="5" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="power_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--power-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="30" />
|
||||||
|
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="power_wait" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--power-wait=[seconds]" />
|
||||||
|
+ <content type="second" default="1" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="shell_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--shell-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="15" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="stonith_status_sleep" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--stonith-status-sleep=[seconds]" />
|
||||||
|
+ <content type="second" default="1" />
|
||||||
|
+ <shortdesc lang="en">Sleep X seconds between status calls during a STONITH action</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="retry_on" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--retry-on=[attempts]" />
|
||||||
|
+ <content type="integer" default="1" />
|
||||||
|
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+</parameters>
|
||||||
|
+<actions>
|
||||||
|
+ <action name="on" automatic="0"/>
|
||||||
|
+ <action name="off" />
|
||||||
|
+ <action name="reboot" />
|
||||||
|
+ <action name="status" />
|
||||||
|
+ <action name="list" />
|
||||||
|
+ <action name="list-status" />
|
||||||
|
+ <action name="monitor" />
|
||||||
|
+ <action name="metadata" />
|
||||||
|
+ <action name="manpage" />
|
||||||
|
+ <action name="validate-all" />
|
||||||
|
+</actions>
|
||||||
|
+</resource-agent>
|
||||||
|
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 @@
|
||||||
|
+<?xml version="1.0" ?>
|
||||||
|
+<resource-agent name="fence_ibm_vpc" shortdesc="Fence agent for IBM Cloud VPC" >
|
||||||
|
+<longdesc>fence_ibm_vpc is an I/O Fencing agent which can be used with IBM Cloud VPC to fence virtual machines.</longdesc>
|
||||||
|
+<vendor-url>https://www.ibm.com</vendor-url>
|
||||||
|
+<parameters>
|
||||||
|
+ <parameter name="apikey" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--apikey=[key]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">API Key</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="instance" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--instance=[instance]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Cloud Instance</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="limit" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--limit=[number]" />
|
||||||
|
+ <content type="string" default="50" />
|
||||||
|
+ <shortdesc lang="en">Number of nodes returned by API</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="region" unique="0" required="1">
|
||||||
|
+ <getopt mixed="--region=[region]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Region</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="action" unique="0" required="1">
|
||||||
|
+ <getopt mixed="-o, --action=[action]" />
|
||||||
|
+ <content type="string" default="reboot" />
|
||||||
|
+ <shortdesc lang="en">Fencing action</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="plug" unique="0" required="1" obsoletes="port">
|
||||||
|
+ <getopt mixed="-n, --plug=[id]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="port" unique="0" required="1" deprecated="1">
|
||||||
|
+ <getopt mixed="-n, --plug=[id]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="quiet" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-q, --quiet" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="verbose" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-v, --verbose" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity.</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="verbose_level" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--verbose-level" />
|
||||||
|
+ <content type="integer" />
|
||||||
|
+ <shortdesc lang="en">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).</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="debug" unique="0" required="0" deprecated="1">
|
||||||
|
+ <getopt mixed="-D, --debug-file=[debugfile]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="debug_file" unique="0" required="0" obsoletes="debug">
|
||||||
|
+ <getopt mixed="-D, --debug-file=[debugfile]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="version" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-V, --version" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Display version information and exit</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="help" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-h, --help" />
|
||||||
|
+ <content type="boolean" />
|
||||||
|
+ <shortdesc lang="en">Display help and exit</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="separator" unique="0" required="0">
|
||||||
|
+ <getopt mixed="-C, --separator=[char]" />
|
||||||
|
+ <content type="string" default="," />
|
||||||
|
+ <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="delay" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--delay=[seconds]" />
|
||||||
|
+ <content type="second" default="0" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="disable_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--disable-timeout=[true/false]" />
|
||||||
|
+ <content type="string" />
|
||||||
|
+ <shortdesc lang="en">Disable timeout (true/false) (default: true when run from Pacemaker 2.0+)</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="login_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--login-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="5" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="power_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--power-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="30" />
|
||||||
|
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="power_wait" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--power-wait=[seconds]" />
|
||||||
|
+ <content type="second" default="1" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="shell_timeout" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--shell-timeout=[seconds]" />
|
||||||
|
+ <content type="second" default="15" />
|
||||||
|
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="stonith_status_sleep" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--stonith-status-sleep=[seconds]" />
|
||||||
|
+ <content type="second" default="1" />
|
||||||
|
+ <shortdesc lang="en">Sleep X seconds between status calls during a STONITH action</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+ <parameter name="retry_on" unique="0" required="0">
|
||||||
|
+ <getopt mixed="--retry-on=[attempts]" />
|
||||||
|
+ <content type="integer" default="1" />
|
||||||
|
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
|
||||||
|
+ </parameter>
|
||||||
|
+</parameters>
|
||||||
|
+<actions>
|
||||||
|
+ <action name="on" automatic="0"/>
|
||||||
|
+ <action name="off" />
|
||||||
|
+ <action name="reboot" />
|
||||||
|
+ <action name="status" />
|
||||||
|
+ <action name="list" />
|
||||||
|
+ <action name="list-status" />
|
||||||
|
+ <action name="monitor" />
|
||||||
|
+ <action name="metadata" />
|
||||||
|
+ <action name="manpage" />
|
||||||
|
+ <action name="validate-all" />
|
||||||
|
+</actions>
|
||||||
|
+</resource-agent>
|
@ -59,7 +59,7 @@
|
|||||||
Name: fence-agents
|
Name: fence-agents
|
||||||
Summary: Set of unified programs capable of host isolation ("fencing")
|
Summary: Set of unified programs capable of host isolation ("fencing")
|
||||||
Version: 4.10.0
|
Version: 4.10.0
|
||||||
Release: 14%{?alphatag:.%{alphatag}}%{?dist}
|
Release: 18%{?alphatag:.%{alphatag}}%{?dist}
|
||||||
License: GPLv2+ and LGPLv2+
|
License: GPLv2+ and LGPLv2+
|
||||||
URL: https://github.com/ClusterLabs/fence-agents
|
URL: https://github.com/ClusterLabs/fence-agents
|
||||||
Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz
|
Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz
|
||||||
@ -228,8 +228,13 @@ Patch11: bz2000954-2-fence_kubevirt.patch
|
|||||||
Patch12: bz2022334-fence_zvmip-add-ssl-tls-support.patch
|
Patch12: bz2022334-fence_zvmip-add-ssl-tls-support.patch
|
||||||
Patch13: bz2029791-1-fence_openstack-add-ssl-insecure.patch
|
Patch13: bz2029791-1-fence_openstack-add-ssl-insecure.patch
|
||||||
Patch14: bz2029791-2-fence_openstack-cacert-default.patch
|
Patch14: bz2029791-2-fence_openstack-cacert-default.patch
|
||||||
|
Patch15: bz2000954-3-fence_kubevirt-get-namespace-from-context.patch
|
||||||
|
Patch16: bz2041933-bz2041935-1-fence_openstack-clouds-openrc.patch
|
||||||
|
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
|
||||||
|
|
||||||
%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt 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 hpblade ibmblade ibm_powervs 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
|
%ifarch x86_64
|
||||||
%global testagents virsh heuristics_ping aliyun aws azure_arm gce openstack virt
|
%global testagents virsh heuristics_ping aliyun aws azure_arm gce openstack virt
|
||||||
%endif
|
%endif
|
||||||
@ -338,7 +343,27 @@ BuildRequires: %{systemd_units}
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -n %{name}-%{version}%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}
|
%setup -q -n %{name}-%{version}%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}
|
||||||
%autopatch -p1
|
%patch0 -p1
|
||||||
|
%patch1 -p1
|
||||||
|
%patch2 -p1
|
||||||
|
%patch3 -p1
|
||||||
|
%patch4 -p1
|
||||||
|
%patch5 -p1
|
||||||
|
%patch6 -p1
|
||||||
|
%patch7 -p1
|
||||||
|
%patch8 -p1
|
||||||
|
%patch9 -p1
|
||||||
|
%patch10 -p1
|
||||||
|
%patch11 -p1
|
||||||
|
%patch12 -p1
|
||||||
|
%patch13 -p1
|
||||||
|
%patch14 -p1
|
||||||
|
%patch15 -p1 -F2
|
||||||
|
%patch16 -p1 -F1
|
||||||
|
%patch17 -p1
|
||||||
|
%patch18 -p1
|
||||||
|
%patch19 -p1
|
||||||
|
|
||||||
# prevent compilation of something that won't get used anyway
|
# prevent compilation of something that won't get used anyway
|
||||||
sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
|
sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
|
||||||
|
|
||||||
@ -926,6 +951,17 @@ via the SNMP protocol.
|
|||||||
%{_sbindir}/fence_ibmblade
|
%{_sbindir}/fence_ibmblade
|
||||||
%{_mandir}/man8/fence_ibmblade.8*
|
%{_mandir}/man8/fence_ibmblade.8*
|
||||||
|
|
||||||
|
%package ibm-powervs
|
||||||
|
License: GPLv2+ and LGPLv2+
|
||||||
|
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 ifmib
|
%package ifmib
|
||||||
License: GPLv2+ and LGPLv2+
|
License: GPLv2+ and LGPLv2+
|
||||||
Summary: Fence agent for devices with IF-MIB interfaces
|
Summary: Fence agent for devices with IF-MIB interfaces
|
||||||
@ -1406,6 +1442,23 @@ are located on corosync cluster nodes.
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Feb 11 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-18
|
||||||
|
- fence_zvmip: add SSL/TLS support
|
||||||
|
Resolves: rhbz#2022334
|
||||||
|
|
||||||
|
* Mon Feb 7 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-17
|
||||||
|
- fence_ibm_powervs: new fence agent
|
||||||
|
Resolves: rhbz#2042496
|
||||||
|
|
||||||
|
* Wed Jan 19 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-16
|
||||||
|
- fence_openstack: add support for reading config from clouds.yaml
|
||||||
|
and openrc
|
||||||
|
Resolves: rhbz#2041933, rhbz#2041935
|
||||||
|
|
||||||
|
* Mon Jan 17 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-15
|
||||||
|
- fence_kubevirt: new fence agent
|
||||||
|
Resolves: rhbz#2000954
|
||||||
|
|
||||||
* Tue Jan 11 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-14
|
* Tue Jan 11 2022 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-14
|
||||||
- fence_openstack: add --ssl-insecure
|
- fence_openstack: add --ssl-insecure
|
||||||
Resolves: rhbz#2029791
|
Resolves: rhbz#2029791
|
||||||
@ -1414,14 +1467,6 @@ are located on corosync cluster nodes.
|
|||||||
- fence_amt_ws: fix "or" causing dead code
|
- fence_amt_ws: fix "or" causing dead code
|
||||||
Resolves: rhbz#2010709
|
Resolves: rhbz#2010709
|
||||||
|
|
||||||
* Thu Nov 11 2021 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-12
|
|
||||||
- fence_zvmip: add SSL/TLS support
|
|
||||||
Resolves: rhbz#2022334
|
|
||||||
|
|
||||||
* Mon Nov 8 2021 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-11
|
|
||||||
- fence_kubevirt: new fence agent
|
|
||||||
Resolves: rhbz#2000954
|
|
||||||
|
|
||||||
* Tue Oct 5 2021 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-10
|
* Tue Oct 5 2021 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.10.0-10
|
||||||
- fence_azure_arm: fix sovereign cloud and MSI support
|
- fence_azure_arm: fix sovereign cloud and MSI support
|
||||||
Resolves: rhbz#2010652
|
Resolves: rhbz#2010652
|
||||||
|
Loading…
Reference in New Issue
Block a user