From 39746b74179c996954b1e5f4ed94517e0b4af2d6 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Thu, 2 May 2024 16:33:20 +0900 Subject: [PATCH] Remove templated catalog driver The driver was deprecated in 2024.1 release because of the unmaintained default template[1]. [1] 307296af5e170ca6b0d44fd5ec85a39bd6b5e572 Change-Id: If7b040a39679b2707565ecd0bd8a06b7db7503c1 --- etc/default_catalog.templates | 37 -- keystone/catalog/backends/templated.py | 345 --------------- keystone/conf/catalog.py | 18 +- keystone/tests/unit/core.py | 6 +- keystone/tests/unit/default_catalog.templates | 14 - .../default_catalog_multi_region.templates | 27 -- keystone/tests/unit/test_backend_templated.py | 415 ------------------ keystone/tests/unit/test_v3_catalog.py | 31 -- ...lated-catalog-driver-042dd821dbad684a.yaml | 6 + setup.cfg | 1 - 10 files changed, 10 insertions(+), 890 deletions(-) delete mode 100644 etc/default_catalog.templates delete mode 100644 keystone/catalog/backends/templated.py delete mode 100644 keystone/tests/unit/default_catalog.templates delete mode 100644 keystone/tests/unit/default_catalog_multi_region.templates delete mode 100644 keystone/tests/unit/test_backend_templated.py create mode 100644 releasenotes/notes/remove-templated-catalog-driver-042dd821dbad684a.yaml diff --git a/etc/default_catalog.templates b/etc/default_catalog.templates deleted file mode 100644 index 106d1cfe92..0000000000 --- a/etc/default_catalog.templates +++ /dev/null @@ -1,37 +0,0 @@ -# config for templated.Catalog, using camelCase because I don't want to do -# translations for keystone compat -catalog.RegionOne.identity.publicURL = http://localhost:5000/v3 -catalog.RegionOne.identity.adminURL = http://localhost:5000/v3 -catalog.RegionOne.identity.internalURL = http://localhost:5000/v3 -catalog.RegionOne.identity.name = Identity Service - -# fake compute service for now to help novaclient tests work -catalog.RegionOne.computev21.publicURL = http://localhost:8774/v2.1 -catalog.RegionOne.computev21.adminURL = http://localhost:8774/v2.1 -catalog.RegionOne.computev21.internalURL = http://localhost:8774/v2.1 -catalog.RegionOne.computev21.name = Compute Service V2.1 - -catalog.RegionOne.volumev3.publicURL = http://localhost:8776/v3 -catalog.RegionOne.volumev3.adminURL = http://localhost:8776/v3 -catalog.RegionOne.volumev3.internalURL = http://localhost:8776/v3 -catalog.RegionOne.volumev3.name = Volume Service V3 - -catalog.RegionOne.image.publicURL = http://localhost:9292 -catalog.RegionOne.image.adminURL = http://localhost:9292 -catalog.RegionOne.image.internalURL = http://localhost:9292 -catalog.RegionOne.image.name = Image Service - -catalog.RegionOne.network.publicURL = http://localhost:9696 -catalog.RegionOne.network.adminURL = http://localhost:9696 -catalog.RegionOne.network.internalURL = http://localhost:9696 -catalog.RegionOne.network.name = Network Service - -catalog.RegionOne.placement.publicURL = http://localhost:8778 -catalog.RegionOne.placement.adminURL = http://localhost:8778 -catalog.RegionOne.placement.internalURL = http://localhost:8778 -catalog.RegionOne.placement.name = Placement Service - -catalog.RegionOne.orchestration.publicURL = http://localhost:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.adminURL = http://localhost:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.internalURL = http://localhost:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.name = Orchestration Service diff --git a/keystone/catalog/backends/templated.py b/keystone/catalog/backends/templated.py deleted file mode 100644 index a4f508e0ae..0000000000 --- a/keystone/catalog/backends/templated.py +++ /dev/null @@ -1,345 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os.path - -from oslo_log import log - -from keystone.catalog.backends import base -from keystone.common import utils -import keystone.conf -from keystone import exception - -LOG = log.getLogger(__name__) - -CONF = keystone.conf.CONF - - -def parse_templates(template_lines): - o = {} - for line in template_lines: - if ' = ' not in line: - continue - - k, v = line.strip().split(' = ') - if not k.startswith('catalog.'): - continue - - parts = k.split('.') - - region = parts[1] - # NOTE(termie): object-store insists on having a dash - service = parts[2].replace('_', '-') - key = parts[3] - - region_ref = o.get(region, {}) - service_ref = region_ref.get(service, {}) - service_ref[key] = v - - region_ref[service] = service_ref - o[region] = region_ref - - return o - - -class Catalog(base.CatalogDriverBase): - """A backend that generates endpoints for the Catalog based on templates. - - It is usually configured via config entries that look like: - - catalog.$REGION.$SERVICE.$key = $value - - and is stored in a similar looking hierarchy. - - When expanding the template it will pass in a dict made up of the conf - instance plus a few additional key-values, notably project_id and user_id. - - It does not care what the keys and values are but it is worth noting that - keystone_compat will expect certain keys to be there so that it can munge - them into the output format keystone expects. These keys are: - - name - the name of the service, most likely repeated for all services of - the same type, across regions. - - adminURL - the url of the admin endpoint - - publicURL - the url of the public endpoint - - internalURL - the url of the internal endpoint - - """ - - def __init__(self, templates=None): - super().__init__() - LOG.warning( - 'The templated catalog driver has been deprecated and ' - 'will be removed in a future release.' - ) - if templates: - self.templates = templates - else: - template_file = CONF.catalog.template_file - if not os.path.exists(template_file): - template_file = CONF.find_file(template_file) - self._load_templates(template_file) - - def _load_templates(self, template_file): - try: - with open(template_file) as f: - self.templates = parse_templates(f) - except OSError: - LOG.critical('Unable to open template file %s', template_file) - raise - - # region crud - - def create_region(self, region_ref): - raise exception.NotImplemented() - - def list_regions(self, hints): - return [ - {'id': region_id, 'description': '', 'parent_region_id': ''} - for region_id in self.templates - ] - - def get_region(self, region_id): - if region_id in self.templates: - return {'id': region_id, 'description': '', 'parent_region_id': ''} - raise exception.RegionNotFound(region_id=region_id) - - def update_region(self, region_id, region_ref): - raise exception.NotImplemented() - - def delete_region(self, region_id): - raise exception.NotImplemented() - - # service crud - - def create_service(self, service_id, service_ref): - raise exception.NotImplemented() - - def _list_services(self, hints): - for region_ref in self.templates.values(): - for service_type, service_ref in region_ref.items(): - yield { - 'id': service_type, - 'enabled': True, - 'name': service_ref.get('name', ''), - 'description': service_ref.get('description', ''), - 'type': service_type, - } - - def list_services(self, hints): - return list(self._list_services(hints=None)) - - def get_service(self, service_id): - for service in self._list_services(hints=None): - if service['id'] == service_id: - return service - raise exception.ServiceNotFound(service_id=service_id) - - def update_service(self, service_id, service_ref): - raise exception.NotImplemented() - - def delete_service(self, service_id): - raise exception.NotImplemented() - - # endpoint crud - - def create_endpoint(self, endpoint_id, endpoint_ref): - raise exception.NotImplemented() - - def _list_endpoints(self): - for region_id, region_ref in self.templates.items(): - for service_type, service_ref in region_ref.items(): - for key in service_ref: - if key.endswith('URL'): - interface = key[:-3] - endpoint_id = f'{region_id}-{service_type}-{interface}' - yield { - 'id': endpoint_id, - 'service_id': service_type, - 'interface': interface, - 'url': service_ref[key], - 'legacy_endpoint_id': None, - 'region_id': region_id, - 'enabled': True, - } - - def list_endpoints(self, hints): - return list(self._list_endpoints()) - - def get_endpoint(self, endpoint_id): - for endpoint in self._list_endpoints(): - if endpoint['id'] == endpoint_id: - return endpoint - raise exception.EndpointNotFound(endpoint_id=endpoint_id) - - def update_endpoint(self, endpoint_id, endpoint_ref): - raise exception.NotImplemented() - - def delete_endpoint(self, endpoint_id): - raise exception.NotImplemented() - - def get_catalog(self, user_id, project_id): - """Retrieve and format the V2 service 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 nested dict representing the service catalog or an - empty dict. - - """ - substitutions = dict(CONF.items()) - substitutions.update({'user_id': user_id}) - silent_keyerror_failures = [] - if project_id: - substitutions.update( - {'tenant_id': project_id, 'project_id': project_id} - ) - else: - silent_keyerror_failures = ['tenant_id', 'project_id'] - - catalog = {} - # TODO(davechen): If there is service with no endpoints, we should - # skip the service instead of keeping it in the catalog. - # see bug #1436704. - for region, region_ref in self.templates.items(): - catalog[region] = {} - for service, service_ref in region_ref.items(): - service_data = {} - try: - for k, v in service_ref.items(): - formatted_value = utils.format_url( - v, - substitutions, - silent_keyerror_failures=silent_keyerror_failures, - ) - if formatted_value: - service_data[k] = formatted_value - except exception.MalformedEndpoint: # nosec(tkelsey) - continue # this failure is already logged in format_url() - catalog[region][service] = service_data - - 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, .publicURL= in the V2 - # catalog becomes the V3 interface for the service: - # { 'interface': 'public', 'url': '', 'region': - # 'region: '' } - 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() - - def remove_endpoint_from_project(self, endpoint_id, project_id): - raise exception.NotImplemented() - - def check_endpoint_in_project(self, endpoint_id, project_id): - raise exception.NotImplemented() - - def list_endpoints_for_project(self, project_id): - raise exception.NotImplemented() - - def list_projects_for_endpoint(self, endpoint_id): - raise exception.NotImplemented() - - def delete_association_by_endpoint(self, endpoint_id): - raise exception.NotImplemented() - - def delete_association_by_project(self, project_id): - raise exception.NotImplemented() - - def create_endpoint_group(self, endpoint_group): - raise exception.NotImplemented() - - def get_endpoint_group(self, endpoint_group_id): - raise exception.NotImplemented() - - def update_endpoint_group(self, endpoint_group_id, endpoint_group): - raise exception.NotImplemented() - - def delete_endpoint_group(self, endpoint_group_id): - raise exception.NotImplemented() - - def add_endpoint_group_to_project(self, endpoint_group_id, project_id): - raise exception.NotImplemented() - - def get_endpoint_group_in_project(self, endpoint_group_id, project_id): - raise exception.NotImplemented() - - def list_endpoint_groups(self, hints): - raise exception.NotImplemented() - - def list_endpoint_groups_for_project(self, project_id): - raise exception.NotImplemented() - - def list_projects_associated_with_endpoint_group(self, endpoint_group_id): - raise exception.NotImplemented() - - def remove_endpoint_group_from_project( - self, endpoint_group_id, project_id - ): - raise exception.NotImplemented() - - def delete_endpoint_group_association_by_project(self, project_id): - raise exception.NotImplemented() diff --git a/keystone/conf/catalog.py b/keystone/conf/catalog.py index d4f304f70f..24a466e0af 100644 --- a/keystone/conf/catalog.py +++ b/keystone/conf/catalog.py @@ -14,17 +14,6 @@ from oslo_config import cfg from keystone.conf import utils -template_file = cfg.StrOpt( - 'template_file', - default='default_catalog.templates', - help=utils.fmt( - """ -Absolute path to the file used for the templated catalog backend. This option -is only used if the `[catalog] driver` is set to `templated`. -""" - ), -) - driver = cfg.StrOpt( 'driver', default='sql', @@ -32,9 +21,8 @@ driver = cfg.StrOpt( """ Entry point for the catalog driver in the `keystone.catalog` namespace. Keystone provides a `sql` option (which supports basic CRUD operations through -SQL), a `templated` option (which loads the catalog from a templated catalog -file on disk), and a `endpoint_filter.sql` option (which supports arbitrary -service catalogs per project). +SQL) and a `endpoint_filter.sql` option (which supports arbitrary service +catalogs per project). """ ), ) @@ -75,7 +63,7 @@ have enough services or endpoints to exceed a reasonable limit. GROUP_NAME = __name__.split('.')[-1] -ALL_OPTS = [template_file, driver, caching, cache_time, list_limit] +ALL_OPTS = [driver, caching, cache_time, list_limit] def register_opts(conf): diff --git a/keystone/tests/unit/core.py b/keystone/tests/unit/core.py index 2f8380e3fa..e7ceb49c5d 100644 --- a/keystone/tests/unit/core.py +++ b/keystone/tests/unit/core.py @@ -897,11 +897,7 @@ class TestCase(BaseTestCase): enabled=True, proxies=['oslo_cache.testing.CacheIsolatingProxy'], ) - self.config_fixture.config( - group='catalog', - driver='sql', - template_file=dirs.tests('default_catalog.templates'), - ) + self.config_fixture.config(group='catalog', driver='sql') self.config_fixture.config( group='saml', certfile=signing_certfile, keyfile=signing_keyfile ) diff --git a/keystone/tests/unit/default_catalog.templates b/keystone/tests/unit/default_catalog.templates deleted file mode 100644 index b00a79cf2e..0000000000 --- a/keystone/tests/unit/default_catalog.templates +++ /dev/null @@ -1,14 +0,0 @@ -# config for templated.Catalog, using camelCase because I don't want to do -# translations for keystone compat -catalog.RegionOne.identity.publicURL = http://localhost:5000/v3 -catalog.RegionOne.identity.adminURL = http://localhost:35357/v3 -catalog.RegionOne.identity.internalURL = http://localhost:35357/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://localhost:8774/v1.1/$(tenant_id)s -catalog.RegionOne.compute.adminURL = http://localhost:8774/v1.1/$(tenant_id)s -catalog.RegionOne.compute.internalURL = http://localhost:8774/v1.1/$(tenant_id)s -catalog.RegionOne.compute.name = 'Compute Service' -catalog.RegionOne.compute.id = 2 diff --git a/keystone/tests/unit/default_catalog_multi_region.templates b/keystone/tests/unit/default_catalog_multi_region.templates deleted file mode 100644 index 452535677b..0000000000 --- a/keystone/tests/unit/default_catalog_multi_region.templates +++ /dev/null @@ -1,27 +0,0 @@ -# config for templated.Catalog, using camelCase because I don't want to do -# translations for keystone compat -catalog.RegionOne.identity.publicURL = http://region-one:5000/v3 -catalog.RegionOne.identity.adminURL = http://region-one:35357/v3 -catalog.RegionOne.identity.internalURL = http://region-one:35357/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:5000/v3 -catalog.RegionTwo.identity.adminURL = http://region-two:35357/v3 -catalog.RegionTwo.identity.internalURL = http://region-two:35357/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 diff --git a/keystone/tests/unit/test_backend_templated.py b/keystone/tests/unit/test_backend_templated.py deleted file mode 100644 index c70ed31a12..0000000000 --- a/keystone/tests/unit/test_backend_templated.py +++ /dev/null @@ -1,415 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock -import uuid - -from keystone.catalog.backends import base as catalog_base -from keystone.common import provider_api -from keystone.tests import unit -from keystone.tests.unit.catalog import test_backends as catalog_tests -from keystone.tests.unit import default_fixtures -from keystone.tests.unit.ksfixtures import database - -PROVIDERS = provider_api.ProviderAPIs -BROKEN_WRITE_FUNCTIONALITY_MSG = ( - "Templated backend doesn't correctly implement write operations" -) - - -class TestTemplatedCatalog(unit.TestCase, catalog_tests.CatalogTests): - DEFAULT_FIXTURE = { - 'RegionOne': { - 'compute': { - 'adminURL': 'http://localhost:8774/v1.1/bar', - 'publicURL': 'http://localhost:8774/v1.1/bar', - 'internalURL': 'http://localhost:8774/v1.1/bar', - 'name': "'Compute Service'", - 'id': '2', - }, - 'identity': { - 'adminURL': 'http://localhost:35357/v3', - 'publicURL': 'http://localhost:5000/v3', - 'internalURL': 'http://localhost:35357/v3', - 'name': "'Identity Service'", - 'id': '1', - }, - } - } - - def setUp(self): - super().setUp() - self.useFixture(database.Database()) - self.load_backends() - self.load_fixtures(default_fixtures) - - def config_overrides(self): - super().config_overrides() - self.config_fixture.config( - group='catalog', - driver='templated', - template_file=unit.dirs.tests('default_catalog.templates'), - ) - - def test_get_catalog(self): - catalog_ref = PROVIDERS.catalog_api.get_catalog('foo', 'bar') - self.assertDictEqual(self.DEFAULT_FIXTURE, catalog_ref) - - # NOTE(lbragstad): This test is skipped because the catalog is being - # modified within the test and not through the API. - @unit.skip_if_cache_is_enabled('catalog') - def test_catalog_ignored_malformed_urls(self): - # both endpoints are in the catalog - catalog_ref = PROVIDERS.catalog_api.get_catalog('foo', 'bar') - self.assertEqual(2, len(catalog_ref['RegionOne'])) - - region = PROVIDERS.catalog_api.driver.templates['RegionOne'] - region['compute']['adminURL'] = 'http://localhost:8774/v1.1/$(tenant)s' - - # the malformed one has been removed - catalog_ref = PROVIDERS.catalog_api.get_catalog('foo', 'bar') - self.assertEqual(1, len(catalog_ref['RegionOne'])) - - def test_get_v3_catalog_endpoint_disabled(self): - self.skip_test_overrides( - "Templated backend doesn't have disabled endpoints" - ) - - def assert_catalogs_equal(self, expected, observed): - def sort_key(d): - return d['id'] - - for e, o in zip( - sorted(expected, key=sort_key), sorted(observed, key=sort_key) - ): - expected_endpoints = e.pop('endpoints') - observed_endpoints = o.pop('endpoints') - self.assertDictEqual(e, o) - self.assertCountEqual(expected_endpoints, observed_endpoints) - - def test_get_v3_catalog(self): - user_id = uuid.uuid4().hex - project_id = uuid.uuid4().hex - catalog_ref = PROVIDERS.catalog_api.get_v3_catalog(user_id, project_id) - exp_catalog = [ - { - 'endpoints': [ - { - 'interface': 'admin', - 'region': 'RegionOne', - 'url': f'http://localhost:8774/v1.1/{project_id}', - }, - { - 'interface': 'public', - 'region': 'RegionOne', - 'url': f'http://localhost:8774/v1.1/{project_id}', - }, - { - 'interface': 'internal', - 'region': 'RegionOne', - 'url': f'http://localhost:8774/v1.1/{project_id}', - }, - ], - 'type': 'compute', - 'name': "'Compute Service'", - 'id': '2', - }, - { - 'endpoints': [ - { - 'interface': 'admin', - 'region': 'RegionOne', - 'url': 'http://localhost:35357/v3', - }, - { - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000/v3', - }, - { - 'interface': 'internal', - 'region': 'RegionOne', - 'url': 'http://localhost:35357/v3', - }, - ], - 'type': 'identity', - 'name': "'Identity Service'", - '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': f'http://region-one:8774/v1.1/{project_id}', - }, - { - 'interface': 'public', - 'region': 'RegionOne', - 'url': f'http://region-one:8774/v1.1/{project_id}', - }, - { - 'interface': 'internal', - 'region': 'RegionOne', - 'url': f'http://region-one:8774/v1.1/{project_id}', - }, - { - 'interface': 'admin', - 'region': 'RegionTwo', - 'url': f'http://region-two:8774/v1.1/{project_id}', - }, - { - 'interface': 'public', - 'region': 'RegionTwo', - 'url': f'http://region-two:8774/v1.1/{project_id}', - }, - { - 'interface': 'internal', - 'region': 'RegionTwo', - 'url': f'http://region-two:8774/v1.1/{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 - # If the URL has no 'project_id' to substitute, we will skip the - # endpoint which contains this kind of URL. - catalog_ref = PROVIDERS.catalog_api.get_v3_catalog(user_id, project_id) - exp_catalog = [ - { - 'endpoints': [], - 'type': 'compute', - 'name': "'Compute Service'", - 'id': '2', - }, - { - 'endpoints': [ - { - 'interface': 'admin', - 'region': 'RegionOne', - 'url': 'http://localhost:35357/v3', - }, - { - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000/v3', - }, - { - 'interface': 'internal', - 'region': 'RegionOne', - 'url': 'http://localhost:35357/v3', - }, - ], - 'type': 'identity', - 'name': "'Identity Service'", - 'id': '1', - }, - ] - self.assert_catalogs_equal(exp_catalog, catalog_ref) - - def test_list_regions_filtered_by_parent_region_id(self): - self.skip_test_overrides('Templated backend does not support hints') - - def test_service_filtering(self): - self.skip_test_overrides("Templated backend doesn't support filtering") - - def test_list_services_with_hints(self): - hints = {} - services = PROVIDERS.catalog_api.list_services(hints=hints) - exp_services = [ - { - 'type': 'compute', - 'description': '', - 'enabled': True, - 'name': "'Compute Service'", - 'id': 'compute', - }, - { - 'type': 'identity', - 'description': '', - 'enabled': True, - 'name': "'Identity Service'", - 'id': 'identity', - }, - ] - self.assertCountEqual(exp_services, services) - - # NOTE(dstanek): the following methods have been overridden - # from unit.catalog.test_backends.CatalogTests. - - def test_region_crud(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - @unit.skip_if_cache_disabled('catalog') - def test_cache_layer_region_crud(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - @unit.skip_if_cache_disabled('catalog') - def test_invalidate_cache_when_updating_region(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_update_region_extras(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_create_region_with_duplicate_id(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_delete_region_returns_not_found(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_create_region_invalid_parent_region_returns_not_found(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_avoid_creating_circular_references_in_regions_update(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - @mock.patch.object( - catalog_base.CatalogDriverBase, - "_ensure_no_circle_in_hierarchical_regions", - ) - def test_circular_regions_can_be_deleted(self, mock_ensure_on_circle): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_service_crud(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - @unit.skip_if_cache_disabled('catalog') - def test_cache_layer_service_crud(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - @unit.skip_if_cache_disabled('catalog') - def test_invalidate_cache_when_updating_service(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_delete_service_with_endpoint(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_cache_layer_delete_service_with_endpoint(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_delete_service_returns_not_found(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_update_endpoint_nonexistent_service(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_create_endpoint_nonexistent_region(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_update_endpoint_nonexistent_region(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_get_endpoint_returns_not_found(self): - self.skip_test_overrides( - "Templated backend doesn't use IDs for endpoints." - ) - - def test_delete_endpoint_returns_not_found(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_create_endpoint(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_update_endpoint(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_list_endpoints(self): - expected_urls = { - 'http://localhost:5000/v3', - 'http://localhost:35357/v3', - 'http://localhost:8774/v1.1/$(tenant_id)s', - } - endpoints = PROVIDERS.catalog_api.list_endpoints() - self.assertEqual(expected_urls, {e['url'] for e in endpoints}) - - @unit.skip_if_cache_disabled('catalog') - def test_invalidate_cache_when_updating_endpoint(self): - self.skip_test_overrides(BROKEN_WRITE_FUNCTIONALITY_MSG) - - def test_delete_endpoint_group_association_by_project(self): - # Deleting endpoint group association is not supported by the templated - # driver, but it should be silent about it and not raise an error. - PROVIDERS.catalog_api.delete_endpoint_group_association_by_project( - uuid.uuid4().hex - ) - - def test_delete_association_by_endpoint(self): - # Deleting endpoint association is not supported by the templated - # driver, but it should be silent about it and not raise an error. - PROVIDERS.catalog_api.delete_association_by_endpoint(uuid.uuid4().hex) - - def test_delete_association_by_project(self): - # Deleting endpoint association is not supported by the templated - # driver, but it should be silent about it and not raise an error. - PROVIDERS.catalog_api.delete_association_by_project(uuid.uuid4().hex) diff --git a/keystone/tests/unit/test_v3_catalog.py b/keystone/tests/unit/test_v3_catalog.py index 5e43ecfb18..0dcad4947a 100644 --- a/keystone/tests/unit/test_v3_catalog.py +++ b/keystone/tests/unit/test_v3_catalog.py @@ -1030,34 +1030,3 @@ class TestCatalogAPISQLRegions(unit.TestCase): for k in keys: self.assertEqual(ref.get(k), entity[k], k) self.assertEqual(entity['region_id'], entity['region']) - - -class TestCatalogAPITemplatedProject(test_v3.RestfulTestCase): - """Templated Catalog doesn't support full API. - - Eg. No region/endpoint creation. - - """ - - def config_overrides(self): - super().config_overrides() - self.config_fixture.config(group='catalog', driver='templated') - - def load_fixtures(self, fixtures): - self.load_sample_data(create_region_and_endpoints=False) - - def test_project_delete(self): - """Deleting a project should not result in an 500 ISE. - - Deleting a project will create a notification, which the EndpointFilter - functionality will use to clean up any project->endpoint and - project->endpoint_group relationships. The templated catalog does not - support such relationships, but the act of attempting to delete them - should not cause a NotImplemented exception to be exposed to an API - caller. - - Deleting an endpoint has a similar notification and clean up - mechanism, but since we do not allow deletion of endpoints with the - templated catalog, there is no testing to do for that action. - """ - self.delete(f'/projects/{self.project_id}') diff --git a/releasenotes/notes/remove-templated-catalog-driver-042dd821dbad684a.yaml b/releasenotes/notes/remove-templated-catalog-driver-042dd821dbad684a.yaml new file mode 100644 index 0000000000..dca111340d --- /dev/null +++ b/releasenotes/notes/remove-templated-catalog-driver-042dd821dbad684a.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + The templated catalog driver has been removed. + The ``[catalog] template_file`` option, which was used by the templated + catalog driver has also been removed. diff --git a/setup.cfg b/setup.cfg index 5b68a70d66..1460b311d0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -83,7 +83,6 @@ keystone.auth.mapped = keystone.catalog = sql = keystone.catalog.backends.sql:Catalog - templated = keystone.catalog.backends.templated:Catalog keystone.credential = sql = keystone.credential.backends.sql:Credential