From 72504d7f5b4be4a49a0e380b36a5c208ca11611d Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Wed, 13 Mar 2019 12:35:37 +0000 Subject: [PATCH] Use auth_url as identity endpoint when not project scoped There are a set of actions in keystone that can be performed without a project scope, but the current discovery code will try to find the identity endpoint in the catalog. Use the auth_url for identity_endpoint_override when there is either no project info or system-scope declaration. Change-Id: Ibab4b2af2ca71fd9bd388829afcf9062431739ec --- openstack/config/cloud_region.py | 15 ++++++++++++++- openstack/tests/unit/config/test_config.py | 18 ++++++++++++++++++ .../identity-auth-url-f3ae8ef22d2bcab6.yaml | 7 +++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/identity-auth-url-f3ae8ef22d2bcab6.yaml diff --git a/openstack/config/cloud_region.py b/openstack/config/cloud_region.py index 8bb208346..7c5a42f4f 100644 --- a/openstack/config/cloud_region.py +++ b/openstack/config/cloud_region.py @@ -38,6 +38,12 @@ from openstack.config import defaults as config_defaults from openstack import exceptions from openstack import proxy +SCOPE_KEYS = { + 'domain_id', 'domain_name', + 'project_id', 'project_name', + 'system_scope' +} + def _make_key(key, service_type): if not service_type: @@ -313,6 +319,7 @@ class CloudRegion(object): return self._get_config('service_name', service_type) def get_endpoint(self, service_type): + auth = self.config.get('auth', {}) value = self._get_config('endpoint_override', service_type) if not value: value = self._get_config('endpoint', service_type) @@ -320,7 +327,13 @@ class CloudRegion(object): # If endpoint is given and we're using the none auth type, # then the endpoint value is the endpoint_override for every # service. - value = self.config.get('auth', {}).get('endpoint') + value = auth.get('endpoint') + if (not value and service_type == 'identity' + and SCOPE_KEYS.isdisjoint(set(auth.keys()))): + # There are a small number of unscoped identity operations. + # Specifically, looking up a list of projects/domains/system to + # scope to. + value = auth.get('auth_url') return value def get_connect_retries(self, service_type): diff --git a/openstack/tests/unit/config/test_config.py b/openstack/tests/unit/config/test_config.py index aa63b9a81..5a83c2931 100644 --- a/openstack/tests/unit/config/test_config.py +++ b/openstack/tests/unit/config/test_config.py @@ -168,6 +168,23 @@ class TestConfig(base.TestCase): self.assertNotIn('domain-id', cc.auth) self.assertNotIn('domain_id', cc) + def test_get_one_unscoped_identity(self): + single_conf = base._write_yaml({ + 'clouds': { + 'unscoped': { + 'auth': { + 'auth_url': 'http://example.com/v2', + 'username': 'testuser', + 'password': 'testpass', + }, + } + } + }) + c = config.OpenStackConfig(config_files=[single_conf], + vendor_files=[self.vendor_yaml]) + cc = c.get_one() + self.assertEqual('http://example.com/v2', cc.get_endpoint('identity')) + def test_get_one_domain_scoped(self): c = config.OpenStackConfig(config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]) @@ -175,6 +192,7 @@ class TestConfig(base.TestCase): self.assertEqual('12345', cc.auth['domain_id']) self.assertNotIn('user_domain_id', cc.auth) self.assertNotIn('project_domain_id', cc.auth) + self.assertIsNone(cc.get_endpoint('identity')) def test_get_one_infer_user_domain(self): c = config.OpenStackConfig(config_files=[self.cloud_yaml], diff --git a/releasenotes/notes/identity-auth-url-f3ae8ef22d2bcab6.yaml b/releasenotes/notes/identity-auth-url-f3ae8ef22d2bcab6.yaml new file mode 100644 index 000000000..3009b0947 --- /dev/null +++ b/releasenotes/notes/identity-auth-url-f3ae8ef22d2bcab6.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The ``auth_url`` will be used for the default value of + ``identity_endpoint_override`` in the absence of project or system-scope + information. This should simplify some actions such as listing available + projects.