Ensure endpoints returned is filtered correctly
This patch move some logic to manager layer, so that endpoints filtered by endpoint_group project association will be included in catalog when issue a project scoped token and using `endpoint_filter.sql` as catalog's backend driver. This make sure that call `list_endpoints_for_project` API has the same endpoints with that in catalog returned for project scoped token. Change-Id: I56f4eb6fc524650677b627295dd4338d55164c39 Closes-Bug: #1516469
This commit is contained in:
parent
c7aff6590c
commit
f86448a311
@ -463,22 +463,8 @@ class EndpointFilterV3Controller(_ControllerBase):
|
||||
def list_endpoints_for_project(self, context, project_id):
|
||||
"""List all endpoints currently associated with a given project."""
|
||||
self.resource_api.get_project(project_id)
|
||||
refs = self.catalog_api.list_endpoints_for_project(project_id)
|
||||
filtered_endpoints = {ref['endpoint_id']:
|
||||
self.catalog_api.get_endpoint(ref['endpoint_id'])
|
||||
for ref in refs}
|
||||
|
||||
# need to recover endpoint_groups associated with project
|
||||
# then for each endpoint group return the endpoints.
|
||||
endpoint_groups = self._get_endpoint_groups_for_project(project_id)
|
||||
for endpoint_group in endpoint_groups:
|
||||
endpoint_refs = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group['id'])
|
||||
# now check if any endpoints for current endpoint group are not
|
||||
# contained in the list of filtered endpoints
|
||||
for endpoint_ref in endpoint_refs:
|
||||
if endpoint_ref['id'] not in filtered_endpoints:
|
||||
filtered_endpoints[endpoint_ref['id']] = endpoint_ref
|
||||
filtered_endpoints = self.catalog_api.list_endpoints_for_project(
|
||||
project_id)
|
||||
|
||||
return EndpointV3.wrap_collection(
|
||||
context, [v for v in six.itervalues(filtered_endpoints)])
|
||||
|
@ -119,6 +119,7 @@ def check_endpoint_url(url):
|
||||
|
||||
|
||||
@dependency.provider('catalog_api')
|
||||
@dependency.requires('resource_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the Catalog backend.
|
||||
|
||||
@ -321,6 +322,67 @@ class Manager(manager.Manager):
|
||||
endpoint_group_id, project_id)
|
||||
COMPUTED_CATALOG_REGION.invalidate()
|
||||
|
||||
def _get_endpoint_groups_for_project(self, project_id):
|
||||
# recover the project endpoint group memberships and for each
|
||||
# membership recover the endpoint group
|
||||
self.resource_api.get_project(project_id)
|
||||
try:
|
||||
refs = self.driver.list_endpoint_groups_for_project(
|
||||
project_id)
|
||||
endpoint_groups = [self.driver.get_endpoint_group(
|
||||
ref['endpoint_group_id']) for ref in refs]
|
||||
return endpoint_groups
|
||||
except exception.EndpointGroupNotFound:
|
||||
return []
|
||||
|
||||
def _get_endpoints_filtered_by_endpoint_group(self, endpoint_group_id):
|
||||
endpoints = self.list_endpoints()
|
||||
filters = self.driver.get_endpoint_group(endpoint_group_id)['filters']
|
||||
filtered_endpoints = []
|
||||
|
||||
for endpoint in endpoints:
|
||||
is_candidate = True
|
||||
for key, value in filters.items():
|
||||
if endpoint[key] != value:
|
||||
is_candidate = False
|
||||
break
|
||||
if is_candidate:
|
||||
filtered_endpoints.append(endpoint)
|
||||
return filtered_endpoints
|
||||
|
||||
def list_endpoints_for_project(self, project_id):
|
||||
"""List all endpoints associated with a project.
|
||||
|
||||
:param project_id: project identifier to check
|
||||
:type project_id: string
|
||||
:returns: a list of endpoint ids or an empty list.
|
||||
|
||||
"""
|
||||
refs = self.driver.list_endpoints_for_project(project_id)
|
||||
filtered_endpoints = {}
|
||||
for ref in refs:
|
||||
try:
|
||||
endpoint = self.get_endpoint(ref['endpoint_id'])
|
||||
filtered_endpoints.update({ref['endpoint_id']: endpoint})
|
||||
except exception.EndpointNotFound:
|
||||
# remove bad reference from association
|
||||
self.remove_endpoint_from_project(ref['endpoint_id'],
|
||||
project_id)
|
||||
|
||||
# need to recover endpoint_groups associated with project
|
||||
# then for each endpoint group return the endpoints.
|
||||
endpoint_groups = self._get_endpoint_groups_for_project(project_id)
|
||||
for endpoint_group in endpoint_groups:
|
||||
endpoint_refs = self._get_endpoints_filtered_by_endpoint_group(
|
||||
endpoint_group['id'])
|
||||
# now check if any endpoints for current endpoint group are not
|
||||
# contained in the list of filtered endpoints
|
||||
for endpoint_ref in endpoint_refs:
|
||||
if endpoint_ref['id'] not in filtered_endpoints:
|
||||
filtered_endpoints[endpoint_ref['id']] = endpoint_ref
|
||||
|
||||
return filtered_endpoints
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class CatalogDriverV8(object):
|
||||
|
@ -17,7 +17,6 @@ from oslo_config import cfg
|
||||
from keystone.catalog.backends import sql
|
||||
from keystone.catalog import core as catalog_core
|
||||
from keystone.common import dependency
|
||||
from keystone import exception
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -31,38 +30,33 @@ class EndpointFilterCatalog(sql.Catalog):
|
||||
|
||||
services = {}
|
||||
|
||||
refs = self.catalog_api.list_endpoints_for_project(project_id)
|
||||
dict_of_endpoint_refs = (self.catalog_api.
|
||||
list_endpoints_for_project(project_id))
|
||||
|
||||
if (not refs and
|
||||
if (not dict_of_endpoint_refs and
|
||||
CONF.endpoint_filter.return_all_endpoints_if_no_filter):
|
||||
return super(EndpointFilterCatalog, self).get_v3_catalog(
|
||||
user_id, project_id)
|
||||
|
||||
for entry in refs:
|
||||
try:
|
||||
endpoint = self.get_endpoint(entry['endpoint_id'])
|
||||
if not endpoint['enabled']:
|
||||
# Skip disabled endpoints.
|
||||
continue
|
||||
service_id = endpoint['service_id']
|
||||
services.setdefault(
|
||||
service_id,
|
||||
self.get_service(service_id))
|
||||
service = services[service_id]
|
||||
del endpoint['service_id']
|
||||
del endpoint['enabled']
|
||||
del endpoint['legacy_endpoint_id']
|
||||
endpoint['url'] = catalog_core.format_url(
|
||||
endpoint['url'], substitutions)
|
||||
# populate filtered endpoints
|
||||
if 'endpoints' in services[service_id]:
|
||||
service['endpoints'].append(endpoint)
|
||||
else:
|
||||
service['endpoints'] = [endpoint]
|
||||
except exception.EndpointNotFound:
|
||||
# remove bad reference from association
|
||||
self.catalog_api.remove_endpoint_from_project(
|
||||
entry['endpoint_id'], project_id)
|
||||
for endpoint_id, endpoint in dict_of_endpoint_refs.items():
|
||||
if not endpoint['enabled']:
|
||||
# Skip disabled endpoints.
|
||||
continue
|
||||
service_id = endpoint['service_id']
|
||||
services.setdefault(
|
||||
service_id,
|
||||
self.get_service(service_id))
|
||||
service = services[service_id]
|
||||
del endpoint['service_id']
|
||||
del endpoint['enabled']
|
||||
del endpoint['legacy_endpoint_id']
|
||||
endpoint['url'] = catalog_core.format_url(
|
||||
endpoint['url'], substitutions)
|
||||
# populate filtered endpoints
|
||||
if 'endpoints' in services[service_id]:
|
||||
service['endpoints'].append(endpoint)
|
||||
else:
|
||||
service['endpoints'] = [endpoint]
|
||||
|
||||
# format catalog
|
||||
catalog = []
|
||||
|
@ -1090,6 +1090,15 @@ class EndpointGroupCRUDTestCase(EndpointFilterTestCase):
|
||||
endpoints = self.assertValidEndpointListResponse(r)
|
||||
self.assertEqual(2, len(endpoints))
|
||||
|
||||
# Ensure catalog includes the endpoints from endpoint_group project
|
||||
# association, this is needed when a project scoped token is issued
|
||||
# and "endpoint_filter.sql" backend driver is in place.
|
||||
user_id = uuid.uuid4().hex
|
||||
catalog_list = self.catalog_api.get_v3_catalog(
|
||||
user_id,
|
||||
self.default_domain_project_id)
|
||||
self.assertEqual(2, len(catalog_list))
|
||||
|
||||
# Now remove project endpoint group association
|
||||
url = self._get_project_endpoint_group_url(
|
||||
endpoint_group_id, self.default_domain_project_id)
|
||||
@ -1104,6 +1113,11 @@ class EndpointGroupCRUDTestCase(EndpointFilterTestCase):
|
||||
endpoints = self.assertValidEndpointListResponse(r)
|
||||
self.assertEqual(1, len(endpoints))
|
||||
|
||||
catalog_list = self.catalog_api.get_v3_catalog(
|
||||
user_id,
|
||||
self.default_domain_project_id)
|
||||
self.assertEqual(1, len(catalog_list))
|
||||
|
||||
def test_endpoint_group_project_cleanup_with_project(self):
|
||||
# create endpoint group
|
||||
endpoint_group_id = self._create_valid_endpoint_group(
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1516469 <https://bugs.launchpad.net/keystone/+bug/1516469>`_]
|
||||
Endpoints filtered by endpoint_group project association will be
|
||||
included in catalog when issue a project scoped token and using
|
||||
``endpoint_filter.sql`` as catalog's backend driver.
|
Loading…
Reference in New Issue
Block a user