diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 76e0cc56..c6d48fb3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,6 +33,9 @@ Added * GnocchiResourceType.create_resource_type * GnocchiResourceType.create_delete_resource_type * [ci] New Zuul V3 native jobs +* Extend existing@openstack platform to support creating a specification based + on system environment variables. This feature should be available with + Rally>0.11.1 Changed ------- diff --git a/rally_openstack/platforms/existing.py b/rally_openstack/platforms/existing.py index 9c0a62ee..33714125 100644 --- a/rally_openstack/platforms/existing.py +++ b/rally_openstack/platforms/existing.py @@ -195,3 +195,58 @@ class OpenStack(platform.Platform): def _get_validation_context(self): return {"users@openstack": {}} + + @classmethod + def create_spec_from_sys_environ(cls, sys_environ): + + from oslo_utils import strutils + + required_env_vars = ["OS_AUTH_URL", "OS_USERNAME", "OS_PASSWORD"] + missing_env_vars = [v for v in required_env_vars if + v not in sys_environ] + if missing_env_vars: + return {"available": False, + "message": "The following variable(s) are missed: %s" % + missing_env_vars} + tenant_name = sys_environ.get("OS_PROJECT_NAME", + sys_environ.get("OS_TENANT_NAME")) + if tenant_name is None: + return {"available": False, + "message": "One of OS_PROJECT_NAME or OS_TENANT_NAME " + "should be specified."} + + endpoint_type = sys_environ.get("OS_ENDPOINT_TYPE", + sys_environ.get("OS_INTERFACE")) + if endpoint_type and "URL" in endpoint_type: + endpoint_type = endpoint_type.replace("URL", "") + + spec = { + "auth_url": sys_environ["OS_AUTH_URL"], + "admin": { + "username": sys_environ["OS_USERNAME"], + "password": sys_environ["OS_PASSWORD"], + "tenant_name": tenant_name + }, + "endpoint_type": endpoint_type, + "region_name": sys_environ.get("OS_REGION_NAME", ""), + "https_cacert": sys_environ.get("OS_CACERT", ""), + "https_insecure": strutils.bool_from_string( + sys_environ.get("OS_INSECURE")), + "profiler_hmac_key": sys_environ.get("OSPROFILER_HMAC_KEY"), + "profiler_conn_str": sys_environ.get("OSPROFILER_CONN_STR") + } + + user_domain_name = sys_environ.get("OS_USER_DOMAIN_NAME") + project_domain_name = sys_environ.get("OS_PROJECT_DOMAIN_NAME") + identity_api_version = sys_environ.get( + "OS_IDENTITY_API_VERSION", sys_environ.get("IDENTITY_API_VERSION")) + if (identity_api_version == "3" or + (identity_api_version is None and + (user_domain_name or project_domain_name))): + # it is Keystone v3 and it has another config scheme + spec["admin"]["project_name"] = spec["admin"].pop("tenant_name") + spec["admin"]["user_domain_name"] = user_domain_name or "Default" + project_domain_name = project_domain_name or "Default" + spec["admin"]["project_domain_name"] = project_domain_name + + return {"spec": spec, "available": True, "message": "Available"} diff --git a/tests/unit/platforms/test_existing.py b/tests/unit/platforms/test_existing.py index 92c46c6b..752341f2 100644 --- a/tests/unit/platforms/test_existing.py +++ b/tests/unit/platforms/test_existing.py @@ -144,6 +144,77 @@ class ExistingPlatformTestCase(PlatformBaseTestCase): ), existing.OpenStack(spec).create()) + def test_create_spec_from_sys_environ(self): + # keystone v2 + sys_env = { + "OS_AUTH_URL": "https://example.com", + "OS_USERNAME": "user", + "OS_PASSWORD": "pass", + "OS_TENANT_NAME": "projectX", + "OS_INTERFACE": "publicURL", + "OS_REGION_NAME": "Region1", + "OS_CACERT": "Cacert", + "OS_INSECURE": True, + "OSPROFILER_HMAC_KEY": "key", + "OSPROFILER_CONN_STR": "https://example2.com", + } + + result = existing.OpenStack.create_spec_from_sys_environ(sys_env) + self.assertTrue(result["available"]) + self.assertEqual( + { + "admin": { + "username": "user", + "tenant_name": "projectX", + "password": "pass" + }, + "auth_url": "https://example.com", + "endpoint_type": "public", + "region_name": "Region1", + "https_cacert": "Cacert", + "https_insecure": True, + "profiler_hmac_key": "key", + "profiler_conn_str": "https://example2.com" + }, result["spec"]) + + # keystone v3 + sys_env["OS_IDENTITY_API_VERSION"] = "3" + + result = existing.OpenStack.create_spec_from_sys_environ(sys_env) + print(json.dumps(result["spec"], indent=4)) + self.assertEqual( + { + "admin": { + "username": "user", + "project_name": "projectX", + "user_domain_name": "Default", + "password": "pass", + "project_domain_name": "Default" + }, + "endpoint_type": "public", + "auth_url": "https://example.com", + "region_name": "Region1", + "https_cacert": "Cacert", + "https_insecure": True, + "profiler_hmac_key": "key", + "profiler_conn_str": "https://example2.com" + }, result["spec"]) + + def test_create_spec_from_sys_environ_fails_with_missing_vars(self): + sys_env = {"OS_AUTH_URL": "https://example.com"} + result = existing.OpenStack.create_spec_from_sys_environ(sys_env) + self.assertFalse(result["available"]) + self.assertIn("OS_USERNAME", result["message"]) + self.assertIn("OS_PASSWORD", result["message"]) + self.assertNotIn("OS_AUTH_URL", result["message"]) + + sys_env = {"OS_AUTH_URL": "https://example.com", + "OS_USERNAME": "user", + "OS_PASSWORD": "pass"} + result = existing.OpenStack.create_spec_from_sys_environ(sys_env) + self.assertFalse(result["available"]) + self.assertIn("OS_PROJECT_NAME or OS_TENANT_NAME", result["message"]) + def test_destroy(self): self.assertIsNone(existing.OpenStack({}).destroy())