Fixing multi-region support in templated v3 catalog
Previously each region had its own entry for each service_type with only it's own endpoints listed. This patch changes this so that each service type has the endpoints from all regions listed. We also move the flawed templated get_v3_catalog function call from the base catalog class into the templated class. Change-Id: Ifddf08990539b6ac7d8289d410092b2ae9f5cbed Closes-Bug: #1703666
This commit is contained in:
parent
7bf25736bd
commit
1483e056bd
@ -240,8 +240,6 @@ class CatalogDriverBase(provider_api.ProviderAPIMixin, object):
|
||||
def get_v3_catalog(self, user_id, project_id):
|
||||
"""Retrieve and format the current V3 service catalog.
|
||||
|
||||
The default implementation builds the V3 catalog from the V2 catalog.
|
||||
|
||||
Example::
|
||||
|
||||
[
|
||||
@ -267,38 +265,7 @@ class CatalogDriverBase(provider_api.ProviderAPIMixin, object):
|
||||
:raises keystone.exception.NotFound: If the endpoint doesn't exist.
|
||||
|
||||
"""
|
||||
v2_catalog = self.get_catalog(user_id, project_id)
|
||||
v3_catalog = []
|
||||
|
||||
for region_name, region in v2_catalog.items():
|
||||
for service_type, service in region.items():
|
||||
service_v3 = {
|
||||
'type': service_type,
|
||||
'endpoints': []
|
||||
}
|
||||
|
||||
for attr, value in service.items():
|
||||
# Attributes that end in URL are interfaces. In the V2
|
||||
# catalog, these are internalURL, publicURL, and adminURL.
|
||||
# For example, <region_name>.publicURL=<URL> in the V2
|
||||
# catalog becomes the V3 interface for the service:
|
||||
# { 'interface': 'public', 'url': '<URL>', 'region':
|
||||
# 'region: '<region_name>' }
|
||||
if attr.endswith('URL'):
|
||||
v3_interface = attr[:-len('URL')]
|
||||
service_v3['endpoints'].append({
|
||||
'interface': v3_interface,
|
||||
'region': region_name,
|
||||
'url': value,
|
||||
})
|
||||
continue
|
||||
|
||||
# Other attributes are copied to the service.
|
||||
service_v3[attr] = value
|
||||
|
||||
v3_catalog.append(service_v3)
|
||||
|
||||
return v3_catalog
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
|
@ -241,6 +241,53 @@ class Catalog(base.CatalogDriverBase):
|
||||
|
||||
return catalog
|
||||
|
||||
def get_v3_catalog(self, user_id, project_id):
|
||||
"""Retrieve and format the current V3 service catalog.
|
||||
|
||||
This implementation builds the V3 catalog from the V2 catalog.
|
||||
|
||||
:param user_id: The id of the user who has been authenticated for
|
||||
creating service catalog.
|
||||
:param project_id: The id of the project. 'project_id' will be None in
|
||||
the case this being called to create a catalog to go in a domain
|
||||
scoped token. In this case, any endpoint that requires a project_id
|
||||
as part of their URL will be skipped.
|
||||
|
||||
:returns: A list representing the service catalog or an empty list
|
||||
|
||||
"""
|
||||
v2_catalog = self.get_catalog(user_id, project_id)
|
||||
v3_catalog = {}
|
||||
|
||||
for region_name, region in v2_catalog.items():
|
||||
for service_type, service in region.items():
|
||||
if service_type not in v3_catalog:
|
||||
v3_catalog[service_type] = {
|
||||
'type': service_type,
|
||||
'endpoints': []
|
||||
}
|
||||
|
||||
for attr, value in service.items():
|
||||
# Attributes that end in URL are interfaces. In the V2
|
||||
# catalog, these are internalURL, publicURL, and adminURL.
|
||||
# For example, <region_name>.publicURL=<URL> in the V2
|
||||
# catalog becomes the V3 interface for the service:
|
||||
# { 'interface': 'public', 'url': '<URL>', 'region':
|
||||
# 'region: '<region_name>' }
|
||||
if attr.endswith('URL'):
|
||||
v3_interface = attr[:-len('URL')]
|
||||
v3_catalog[service_type]['endpoints'].append({
|
||||
'interface': v3_interface,
|
||||
'region': region_name,
|
||||
'url': value,
|
||||
})
|
||||
continue
|
||||
|
||||
# Other attributes are copied to the service.
|
||||
v3_catalog[service_type][attr] = value
|
||||
|
||||
return list(v3_catalog.values())
|
||||
|
||||
def add_endpoint_to_project(self, endpoint_id, project_id):
|
||||
raise exception.NotImplemented()
|
||||
|
||||
|
27
keystone/tests/unit/default_catalog_multi_region.templates
Normal file
27
keystone/tests/unit/default_catalog_multi_region.templates
Normal file
@ -0,0 +1,27 @@
|
||||
# config for templated.Catalog, using camelCase because I don't want to do
|
||||
# translations for keystone compat
|
||||
catalog.RegionOne.identity.publicURL = http://region-one:$(public_port)s/v3
|
||||
catalog.RegionOne.identity.adminURL = http://region-one:$(admin_port)s/v3
|
||||
catalog.RegionOne.identity.internalURL = http://region-one:$(admin_port)s/v3
|
||||
catalog.RegionOne.identity.name = 'Identity Service'
|
||||
catalog.RegionOne.identity.id = 1
|
||||
|
||||
# fake compute service for now to help novaclient tests work
|
||||
catalog.RegionOne.compute.publicURL = http://region-one:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionOne.compute.adminURL = http://region-one:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionOne.compute.internalURL = http://region-one:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionOne.compute.name = 'Compute Service'
|
||||
catalog.RegionOne.compute.id = 2
|
||||
|
||||
# second region for multi-region testing
|
||||
catalog.RegionTwo.identity.publicURL = http://region-two:$(public_port)s/v3
|
||||
catalog.RegionTwo.identity.adminURL = http://region-two:$(admin_port)s/v3
|
||||
catalog.RegionTwo.identity.internalURL = http://region-two:$(admin_port)s/v3
|
||||
catalog.RegionTwo.identity.name = 'Identity Service'
|
||||
catalog.RegionTwo.identity.id = 1
|
||||
|
||||
catalog.RegionTwo.compute.publicURL = http://region-two:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionTwo.compute.adminURL = http://region-two:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionTwo.compute.internalURL = http://region-two:8774/v1.1/$(tenant_id)s
|
||||
catalog.RegionTwo.compute.name = 'Compute Service'
|
||||
catalog.RegionTwo.compute.id = 2
|
@ -129,6 +129,64 @@ class TestTemplatedCatalog(unit.TestCase, catalog_tests.CatalogTests):
|
||||
'id': '1'}]
|
||||
self.assert_catalogs_equal(exp_catalog, catalog_ref)
|
||||
|
||||
def test_get_multi_region_v3_catalog(self):
|
||||
user_id = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
|
||||
catalog_api = PROVIDERS.catalog_api
|
||||
|
||||
# Load the multi-region catalog.
|
||||
catalog_api._load_templates(
|
||||
unit.dirs.tests('default_catalog_multi_region.templates'))
|
||||
|
||||
catalog_ref = catalog_api.get_v3_catalog(user_id, project_id)
|
||||
exp_catalog = [
|
||||
{'endpoints': [
|
||||
{'interface': 'admin',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:8774/v1.1/%s' % project_id},
|
||||
{'interface': 'public',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:8774/v1.1/%s' % project_id},
|
||||
{'interface': 'internal',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:8774/v1.1/%s' % project_id},
|
||||
{'interface': 'admin',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:8774/v1.1/%s' % project_id},
|
||||
{'interface': 'public',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:8774/v1.1/%s' % project_id},
|
||||
{'interface': 'internal',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:8774/v1.1/%s' % project_id}],
|
||||
'type': 'compute',
|
||||
'name': "'Compute Service'",
|
||||
'id': '2'},
|
||||
{'endpoints': [
|
||||
{'interface': 'admin',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:35357/v3'},
|
||||
{'interface': 'public',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:5000/v3'},
|
||||
{'interface': 'internal',
|
||||
'region': 'RegionOne',
|
||||
'url': 'http://region-one:35357/v3'},
|
||||
{'interface': 'admin',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:35357/v3'},
|
||||
{'interface': 'public',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:5000/v3'},
|
||||
{'interface': 'internal',
|
||||
'region': 'RegionTwo',
|
||||
'url': 'http://region-two:35357/v3'}],
|
||||
'type': 'identity',
|
||||
'name': "'Identity Service'",
|
||||
'id': '1'}]
|
||||
self.assert_catalogs_equal(exp_catalog, catalog_ref)
|
||||
|
||||
def test_get_catalog_ignores_endpoints_with_invalid_urls(self):
|
||||
user_id = uuid.uuid4().hex
|
||||
project_id = None
|
||||
|
8
releasenotes/notes/bug-1703666-b8a990f2bf5b62f0.yaml
Normal file
8
releasenotes/notes/bug-1703666-b8a990f2bf5b62f0.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
[`bug 1703666 <https://bugs.launchpad.net/keystone/+bug/1703666>`_]
|
||||
Fixing multi-region support for the templated v3 catalog by making sure
|
||||
that the catalog contains only one definition per endpoint, and that
|
||||
each region is listed under that endpoint. Previously each region
|
||||
and endpoint would have had its own definition.
|
Loading…
x
Reference in New Issue
Block a user