Blame SOURCES/bz2041933-bz2041935-1-fence_openstack-clouds-openrc.patch

d4ebfc
From 2f741df2ce73da85bbd205d861b527aa141d9776 Mon Sep 17 00:00:00 2001
d4ebfc
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
d4ebfc
Date: Fri, 14 Jan 2022 14:47:41 +0100
d4ebfc
Subject: [PATCH 1/2] fencing: add source_env()
d4ebfc
d4ebfc
---
d4ebfc
 lib/fencing.py.py | 8 ++++++++
d4ebfc
 1 file changed, 8 insertions(+)
d4ebfc
d4ebfc
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
d4ebfc
index d85b23568..55e38c407 100644
d4ebfc
--- a/lib/fencing.py.py
d4ebfc
+++ b/lib/fencing.py.py
d4ebfc
@@ -1143,6 +1143,14 @@ def fence_logout(conn, logout_string, sleep=0):
d4ebfc
 	except pexpect.ExceptionPexpect:
d4ebfc
 		pass
d4ebfc
 
d4ebfc
+def source_env(env_file):
d4ebfc
+    # POSIX: name shall not contain '=', value doesn't contain '\0'
d4ebfc
+    output = subprocess.check_output("source {} && env -0".format(env_file), shell=True,
d4ebfc
+                          executable="/bin/sh")
d4ebfc
+    # replace env
d4ebfc
+    os.environ.clear()
d4ebfc
+    os.environ.update(line.partition('=')[::2] for line in output.decode("utf-8").split('\0'))
d4ebfc
+
d4ebfc
 # Convert array of format [[key1, value1], [key2, value2], ... [keyN, valueN]] to dict, where key is
d4ebfc
 # in format a.b.c.d...z and returned dict has key only z
d4ebfc
 def array_to_dict(array):
d4ebfc
d4ebfc
From fe2183a97e0a5734702e9cba8da21f01afd8f577 Mon Sep 17 00:00:00 2001
d4ebfc
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
d4ebfc
Date: Fri, 14 Jan 2022 14:54:10 +0100
d4ebfc
Subject: [PATCH 2/2] fence_openstack: add support for reading config from
d4ebfc
 clouds.yaml and openrc
d4ebfc
d4ebfc
---
d4ebfc
 agents/openstack/fence_openstack.py     | 116 ++++++++++++++++++++----
d4ebfc
 tests/data/metadata/fence_openstack.xml |  32 +++++--
d4ebfc
 2 files changed, 126 insertions(+), 22 deletions(-)
d4ebfc
 mode change 100755 => 100644 agents/openstack/fence_openstack.py
d4ebfc
d4ebfc
diff --git a/agents/openstack/fence_openstack.py b/agents/openstack/fence_openstack.py
d4ebfc
old mode 100755
d4ebfc
new mode 100644
d4ebfc
index 36b353b52..d3a4be3aa
d4ebfc
--- a/agents/openstack/fence_openstack.py
d4ebfc
+++ b/agents/openstack/fence_openstack.py
d4ebfc
@@ -8,7 +8,7 @@
d4ebfc
 
d4ebfc
 sys.path.append("@FENCEAGENTSLIBDIR@")
d4ebfc
 from fencing import *
d4ebfc
-from fencing import fail_usage, run_delay
d4ebfc
+from fencing import fail_usage, run_delay, source_env
d4ebfc
 
d4ebfc
 try:
d4ebfc
     from novaclient import client
d4ebfc
@@ -26,6 +26,23 @@ def translate_status(instance_status):
d4ebfc
         return "off"
d4ebfc
     return "unknown"
d4ebfc
 
d4ebfc
+def get_cloud(options):
d4ebfc
+    import os, yaml
d4ebfc
+
d4ebfc
+    clouds_yaml = os.path.expanduser("~/.config/openstack/clouds.yaml")
d4ebfc
+    if os.path.exists(clouds_yaml):
d4ebfc
+        with open(clouds_yaml, "r") as yaml_stream:
d4ebfc
+            try:
d4ebfc
+                clouds = yaml.safe_load(yaml_stream)
d4ebfc
+            except yaml.YAMLError as exc:
d4ebfc
+                fail_usage("Failed: Unable to read: " + clouds_yaml)
d4ebfc
+
d4ebfc
+    cloud = clouds.get("clouds").get(options["--cloud"])
d4ebfc
+    if not cloud:
d4ebfc
+        fail_usage("Cloud: {} not found.".format(options["--cloud"]))
d4ebfc
+
d4ebfc
+    return cloud
d4ebfc
+
d4ebfc
 
d4ebfc
 def get_nodes_list(conn, options):
d4ebfc
     logging.info("Running %s action", options["--action"])
d4ebfc
@@ -153,7 +170,7 @@ def define_new_opts():
d4ebfc
         "getopt": ":",
d4ebfc
         "longopt": "auth-url",
d4ebfc
         "help": "--auth-url=[authurl]           Keystone Auth URL",
d4ebfc
-        "required": "1",
d4ebfc
+        "required": "0",
d4ebfc
         "shortdesc": "Keystone Auth URL",
d4ebfc
         "order": 2,
d4ebfc
     }
d4ebfc
@@ -161,7 +178,7 @@ def define_new_opts():
d4ebfc
         "getopt": ":",
d4ebfc
         "longopt": "project-name",
d4ebfc
         "help": "--project-name=[project]       Tenant Or Project Name",
d4ebfc
-        "required": "1",
d4ebfc
+        "required": "0",
d4ebfc
         "shortdesc": "Keystone Project",
d4ebfc
         "default": "admin",
d4ebfc
         "order": 3,
d4ebfc
@@ -184,13 +201,38 @@ def define_new_opts():
d4ebfc
         "default": "Default",
d4ebfc
         "order": 5,
d4ebfc
     }
d4ebfc
+    all_opt["clouds-yaml"] = {
d4ebfc
+        "getopt": ":",
d4ebfc
+        "longopt": "clouds-yaml",
d4ebfc
+        "help": "--clouds-yaml=[clouds-yaml]  Path to the clouds.yaml config file",
d4ebfc
+        "required": "0",
d4ebfc
+        "shortdesc": "clouds.yaml config file",
d4ebfc
+        "default": "~/.config/openstack/clouds.yaml",
d4ebfc
+        "order": 6,
d4ebfc
+    }
d4ebfc
+    all_opt["cloud"] = {
d4ebfc
+        "getopt": ":",
d4ebfc
+        "longopt": "cloud",
d4ebfc
+        "help": "--cloud=[cloud]              Openstack cloud (from clouds.yaml).",
d4ebfc
+        "required": "0",
d4ebfc
+        "shortdesc": "Cloud from clouds.yaml",
d4ebfc
+        "order": 7,
d4ebfc
+    }
d4ebfc
+    all_opt["openrc"] = {
d4ebfc
+        "getopt": ":",
d4ebfc
+        "longopt": "openrc",
d4ebfc
+        "help": "--openrc=[openrc]              Path to the openrc config file",
d4ebfc
+        "required": "0",
d4ebfc
+        "shortdesc": "openrc config file",
d4ebfc
+        "order": 8,
d4ebfc
+    }
d4ebfc
     all_opt["uuid"] = {
d4ebfc
         "getopt": ":",
d4ebfc
         "longopt": "uuid",
d4ebfc
         "help": "--uuid=[uuid]                  Replaced by -n, --plug",
d4ebfc
         "required": "0",
d4ebfc
         "shortdesc": "Replaced by port/-n/--plug",
d4ebfc
-        "order": 6,
d4ebfc
+        "order": 9,
d4ebfc
     }
d4ebfc
     all_opt["cacert"] = {
d4ebfc
         "getopt": ":",
d4ebfc
@@ -199,7 +241,7 @@ def define_new_opts():
d4ebfc
         "required": "0",
d4ebfc
         "shortdesc": "SSL X.509 certificates file",
d4ebfc
         "default": "",
d4ebfc
-        "order": 7,
d4ebfc
+        "order": 10,
d4ebfc
     }
d4ebfc
     all_opt["apitimeout"] = {
d4ebfc
         "getopt": ":",
d4ebfc
@@ -209,7 +251,7 @@ def define_new_opts():
d4ebfc
         "shortdesc": "Timeout in seconds to use for API calls, default is 60.",
d4ebfc
         "required": "0",
d4ebfc
         "default": 60,
d4ebfc
-        "order": 8,
d4ebfc
+        "order": 11,
d4ebfc
     }
d4ebfc
 
d4ebfc
 
d4ebfc
@@ -218,11 +260,16 @@ def main():
d4ebfc
 
d4ebfc
     device_opt = [
d4ebfc
         "login",
d4ebfc
+        "no_login",
d4ebfc
         "passwd",
d4ebfc
+        "no_password",
d4ebfc
         "auth-url",
d4ebfc
         "project-name",
d4ebfc
         "user-domain-name",
d4ebfc
         "project-domain-name",
d4ebfc
+        "clouds-yaml",
d4ebfc
+        "cloud",
d4ebfc
+        "openrc",
d4ebfc
         "port",
d4ebfc
         "no_port",
d4ebfc
         "uuid",
d4ebfc
@@ -265,19 +312,56 @@ def main():
d4ebfc
 
d4ebfc
     run_delay(options)
d4ebfc
 
d4ebfc
-    username = options["--username"]
d4ebfc
-    password = options["--password"]
d4ebfc
-    projectname = options["--project-name"]
d4ebfc
-    auth_url = None
d4ebfc
-    try:
d4ebfc
-        auth_url = options["--auth-url"]
d4ebfc
-    except KeyError:
d4ebfc
-        fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
d4ebfc
-    user_domain_name = options["--user-domain-name"]
d4ebfc
-    project_domain_name = options["--project-domain-name"]
d4ebfc
+    if options.get("--clouds-yaml"):
d4ebfc
+        if not os.path.exists(os.path.expanduser(options["--clouds-yaml"])):
d4ebfc
+            fail_usage("Failed: {} does not exist".format(options.get("--clouds-yaml")))
d4ebfc
+        if not options.get("--cloud"):
d4ebfc
+            fail_usage("Failed: \"cloud\" not specified")
d4ebfc
+        cloud = get_cloud(options)
d4ebfc
+        username = cloud.get("username")
d4ebfc
+        password = cloud.get("password")
d4ebfc
+        projectname = cloud.get("project_name")
d4ebfc
+        auth_url = None
d4ebfc
+        try:
d4ebfc
+            auth_url = cloud.get("auth_url")
d4ebfc
+        except KeyError:
d4ebfc
+            fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
d4ebfc
+        user_domain_name = cloud.get("user_domain_name")
d4ebfc
+        project_domain_name = cloud.get("project_domain_name")
d4ebfc
+        caverify = cloud.get("verify")
d4ebfc
+        if caverify in [True, False]:
d4ebfc
+                options["--ssl-insecure"] = caverify
d4ebfc
+        else:
d4ebfc
+                options["--cacert"] = caverify
d4ebfc
+    if options.get("--openrc") and os.path.exists(os.path.expanduser(options["--openrc"])):
d4ebfc
+        source_env(options["--openrc"])
d4ebfc
+        env = os.environ
d4ebfc
+        username = env.get("OS_USERNAME")
d4ebfc
+        password = env.get("OS_PASSWORD")
d4ebfc
+        projectname = env.get("OS_PROJECT_NAME")
d4ebfc
+        auth_url = None
d4ebfc
+        try:
d4ebfc
+            auth_url = env["OS_AUTH_URL"]
d4ebfc
+        except KeyError:
d4ebfc
+            fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
d4ebfc
+        user_domain_name = env.get("OS_USER_DOMAIN_NAME")
d4ebfc
+        project_domain_name = env.get("OS_PROJECT_DOMAIN_NAME")
d4ebfc
+    else:
d4ebfc
+        username = options["--username"]
d4ebfc
+        password = options["--password"]
d4ebfc
+        projectname = options["--project-name"]
d4ebfc
+        auth_url = None
d4ebfc
+        try:
d4ebfc
+            auth_url = options["--auth-url"]
d4ebfc
+        except KeyError:
d4ebfc
+            fail_usage("Failed: You have to set the Keystone service endpoint for authorization")
d4ebfc
+        user_domain_name = options["--user-domain-name"]
d4ebfc
+        project_domain_name = options["--project-domain-name"]
d4ebfc
+
d4ebfc
     ssl_insecure = "--ssl-insecure" in options
d4ebfc
     cacert = options["--cacert"]
d4ebfc
     apitimeout = options["--apitimeout"]
d4ebfc
+
d4ebfc
     try:
d4ebfc
         conn = nova_login(
d4ebfc
             username,
d4ebfc
diff --git a/tests/data/metadata/fence_openstack.xml b/tests/data/metadata/fence_openstack.xml
d4ebfc
index c8dc2e60f..55a57b4d7 100644
d4ebfc
--- a/tests/data/metadata/fence_openstack.xml
d4ebfc
+++ b/tests/data/metadata/fence_openstack.xml
d4ebfc
@@ -8,7 +8,7 @@
d4ebfc
 		<content type="string" default="reboot"  />
d4ebfc
 		<shortdesc lang="en">Fencing action</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="login" unique="0" required="1" deprecated="1">
d4ebfc
+	<parameter name="login" unique="0" required="0" deprecated="1">
d4ebfc
 		<getopt mixed="-l, --username=[name]" />
d4ebfc
 		<content type="string"  />
d4ebfc
 		<shortdesc lang="en">Login name</shortdesc>
d4ebfc
@@ -48,27 +48,27 @@
d4ebfc
 		<content type="boolean"  />
d4ebfc
 		<shortdesc lang="en">Use SSL connection without verifying certificate</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="username" unique="0" required="1" obsoletes="login">
d4ebfc
+	<parameter name="username" unique="0" required="0" obsoletes="login">
d4ebfc
 		<getopt mixed="-l, --username=[name]" />
d4ebfc
 		<content type="string"  />
d4ebfc
 		<shortdesc lang="en">Login name</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="auth-url" unique="0" required="1" deprecated="1">
d4ebfc
+	<parameter name="auth-url" unique="0" required="0" deprecated="1">
d4ebfc
 		<getopt mixed="--auth-url=[authurl]" />
d4ebfc
 		<content type="string"  />
d4ebfc
 		<shortdesc lang="en">Keystone Auth URL</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="auth_url" unique="0" required="1" obsoletes="auth-url">
d4ebfc
+	<parameter name="auth_url" unique="0" required="0" obsoletes="auth-url">
d4ebfc
 		<getopt mixed="--auth-url=[authurl]" />
d4ebfc
 		<content type="string"  />
d4ebfc
 		<shortdesc lang="en">Keystone Auth URL</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="project-name" unique="0" required="1" deprecated="1">
d4ebfc
+	<parameter name="project-name" unique="0" required="0" deprecated="1">
d4ebfc
 		<getopt mixed="--project-name=[project]" />
d4ebfc
 		<content type="string" default="admin"  />
d4ebfc
 		<shortdesc lang="en">Keystone Project</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
-	<parameter name="project_name" unique="0" required="1" obsoletes="project-name">
d4ebfc
+	<parameter name="project_name" unique="0" required="0" obsoletes="project-name">
d4ebfc
 		<getopt mixed="--project-name=[project]" />
d4ebfc
 		<content type="string" default="admin"  />
d4ebfc
 		<shortdesc lang="en">Keystone Project</shortdesc>
d4ebfc
@@ -93,6 +93,26 @@
d4ebfc
 		<content type="string" default="Default"  />
d4ebfc
 		<shortdesc lang="en">Keystone Project Domain Name</shortdesc>
d4ebfc
 	</parameter>
d4ebfc
+	<parameter name="clouds-yaml" unique="0" required="0" deprecated="1">
d4ebfc
+		<getopt mixed="--clouds-yaml=[clouds-yaml]" />
d4ebfc
+		<content type="string" default="~/.config/openstack/clouds.yaml"  />
d4ebfc
+		<shortdesc lang="en">clouds.yaml config file</shortdesc>
d4ebfc
+	</parameter>
d4ebfc
+	<parameter name="clouds_yaml" unique="0" required="0" obsoletes="clouds-yaml">
d4ebfc
+		<getopt mixed="--clouds-yaml=[clouds-yaml]" />
d4ebfc
+		<content type="string" default="~/.config/openstack/clouds.yaml"  />
d4ebfc
+		<shortdesc lang="en">clouds.yaml config file</shortdesc>
d4ebfc
+	</parameter>
d4ebfc
+	<parameter name="cloud" unique="0" required="0">
d4ebfc
+		<getopt mixed="--cloud=[cloud]" />
d4ebfc
+		<content type="string"  />
d4ebfc
+		<shortdesc lang="en">Cloud from clouds.yaml</shortdesc>
d4ebfc
+	</parameter>
d4ebfc
+	<parameter name="openrc" unique="0" required="0">
d4ebfc
+		<getopt mixed="--openrc=[openrc]" />
d4ebfc
+		<content type="string"  />
d4ebfc
+		<shortdesc lang="en">openrc config file</shortdesc>
d4ebfc
+	</parameter>
d4ebfc
 	<parameter name="uuid" unique="0" required="0">
d4ebfc
 		<getopt mixed="--uuid=[uuid]" />
d4ebfc
 		<content type="string"  />