Replace tenant with project for keystone catalog

Change-Id: I46113ba17f86b07545584aeddd2d92dc1f67dc98
Partial-Bug: #1017606
This commit is contained in:
Dave Chen 2016-10-09 15:07:19 +08:00
parent fd3e6276a3
commit 4f92ac0461
9 changed files with 64 additions and 59 deletions

View File

@ -212,17 +212,17 @@ class CatalogDriverBase(object):
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def get_catalog(self, user_id, tenant_id):
def get_catalog(self, user_id, project_id):
"""Retrieve and format the current service catalog.
Example::
{ 'RegionOne':
{'compute': {
'adminURL': u'http://host:8774/v1.1/tenantid',
'internalURL': u'http://host:8774/v1.1/tenant_id',
'adminURL': u'http://host:8774/v1.1/project_id',
'internalURL': u'http://host:8774/v1.1/project_id',
'name': 'Compute Service',
'publicURL': u'http://host:8774/v1.1/tenantid'},
'publicURL': u'http://host:8774/v1.1/project_id'},
'ec2': {
'adminURL': 'http://host:8773/services/Admin',
'internalURL': 'http://host:8773/services/Cloud',
@ -236,7 +236,7 @@ class CatalogDriverBase(object):
"""
raise exception.NotImplemented() # pragma: no cover
def get_v3_catalog(self, user_id, tenant_id):
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.
@ -266,7 +266,7 @@ class CatalogDriverBase(object):
:raises keystone.exception.NotFound: If the endpoint doesn't exist.
"""
v2_catalog = self.get_catalog(user_id, tenant_id)
v2_catalog = self.get_catalog(user_id, project_id)
v3_catalog = []
for region_name, region in v2_catalog.items():

View File

@ -253,15 +253,15 @@ class Catalog(base.CatalogDriverBase):
ref.extra = new_endpoint.extra
return ref.to_dict()
def get_catalog(self, user_id, tenant_id):
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 tenant_id: The id of the project. 'tenant_id' will be None
: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 tenant_id as part of their URL will be skipped (as would a whole
a project_id as part of their URL will be skipped (as would a whole
service if, as a consequence, it has no valid endpoints).
:returns: A nested dict representing the service catalog or an
@ -272,13 +272,13 @@ class Catalog(base.CatalogDriverBase):
itertools.chain(CONF.items(), CONF.eventlet_server.items()))
substitutions.update({'user_id': user_id})
silent_keyerror_failures = []
if tenant_id:
if project_id:
substitutions.update({
'tenant_id': tenant_id,
'project_id': tenant_id
'tenant_id': project_id,
'project_id': project_id
})
else:
silent_keyerror_failures = ['tenant_id', 'project_id', ]
silent_keyerror_failures = ['tenant_id', 'project_id']
with sql.session_for_read() as session:
endpoints = (session.query(Endpoint).
@ -315,15 +315,15 @@ class Catalog(base.CatalogDriverBase):
return catalog
def get_v3_catalog(self, user_id, tenant_id):
def get_v3_catalog(self, user_id, project_id):
"""Retrieve and format the current V3 service catalog.
:param user_id: The id of the user who has been authenticated for
creating service catalog.
:param tenant_id: The id of the project. 'tenant_id' will be None in
: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
tenant_id as part of their URL will be skipped.
project_id as part of their URL will be skipped.
:returns: A list representing the service catalog or an empty list
@ -332,13 +332,13 @@ class Catalog(base.CatalogDriverBase):
itertools.chain(CONF.items(), CONF.eventlet_server.items()))
d.update({'user_id': user_id})
silent_keyerror_failures = []
if tenant_id:
if project_id:
d.update({
'tenant_id': tenant_id,
'project_id': tenant_id,
'tenant_id': project_id,
'project_id': project_id,
})
else:
silent_keyerror_failures = ['tenant_id', 'project_id', ]
silent_keyerror_failures = ['tenant_id', 'project_id']
with sql.session_for_read() as session:
services = (session.query(Service).filter(
@ -383,9 +383,9 @@ class Catalog(base.CatalogDriverBase):
# Filter the `catalog_ref` above by any project-endpoint
# association configured by endpoint filter.
filtered_endpoints = {}
if tenant_id:
if project_id:
filtered_endpoints = (
self.catalog_api.list_endpoints_for_project(tenant_id))
self.catalog_api.list_endpoints_for_project(project_id))
# endpoint filter is enabled, only return the filtered endpoints.
if filtered_endpoints:
filtered_ids = list(filtered_endpoints.keys())
@ -412,7 +412,7 @@ class Catalog(base.CatalogDriverBase):
if not service.get('endpoints'):
catalog_ref.remove(service)
# When it arrives here it means it's domain scoped token (
# `tenant_id` is not set) or it's a project scoped token
# `project_id` is not set) or it's a project scoped token
# but the endpoint filtering is not performed.
# Both of them tell us the endpoint filtering is not enabled, so
# check the option of `return_all_endpoints_if_no_filter`, it will

View File

@ -71,7 +71,7 @@ class Catalog(base.CatalogDriverBase):
http://localhost:$(public_port)s/
When expanding the template it will pass in a dict made up of the conf
instance plus a few additional key-values, notably tenant_id and user_id.
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
@ -195,14 +195,14 @@ class Catalog(base.CatalogDriverBase):
def delete_endpoint(self, endpoint_id):
raise exception.NotImplemented()
def get_catalog(self, user_id, tenant_id):
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 tenant_id: The id of the project. 'tenant_id' will be None in
: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 tenant_id
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
@ -213,10 +213,10 @@ class Catalog(base.CatalogDriverBase):
itertools.chain(CONF.items(), CONF.eventlet_server.items()))
substitutions.update({'user_id': user_id})
silent_keyerror_failures = []
if tenant_id:
if project_id:
substitutions.update({
'tenant_id': tenant_id,
'project_id': tenant_id,
'tenant_id': project_id,
'project_id': project_id,
})
else:
silent_keyerror_failures = ['tenant_id', 'project_id', ]

View File

@ -216,15 +216,15 @@ class Manager(manager.Manager):
return self.driver.list_endpoints(hints or driver_hints.Hints())
@MEMOIZE_COMPUTED_CATALOG
def get_catalog(self, user_id, tenant_id):
def get_catalog(self, user_id, project_id):
try:
return self.driver.get_catalog(user_id, tenant_id)
return self.driver.get_catalog(user_id, project_id)
except exception.NotFound:
raise exception.NotFound('Catalog not found for user and tenant')
@MEMOIZE_COMPUTED_CATALOG
def get_v3_catalog(self, user_id, tenant_id):
return self.driver.get_v3_catalog(user_id, tenant_id)
def get_v3_catalog(self, user_id, project_id):
return self.driver.get_v3_catalog(user_id, project_id)
def add_endpoint_to_project(self, endpoint_id, project_id):
self.driver.add_endpoint_to_project(endpoint_id, project_id)

View File

@ -63,9 +63,9 @@ class FormatUrlTests(unit.BaseTestCase):
# list then MalformedEndpoint is raised.
# For example, admin_token isn't allowed.
url_template = ('http://$(public_bind_host)s:$(public_port)d/'
'$(tenant_id)s/$(user_id)s/$(admin_token)s')
'$(project_id)s/$(user_id)s/$(admin_token)s')
values = {'public_bind_host': 'server', 'public_port': 9090,
'tenant_id': 'A', 'user_id': 'B', 'admin_token': 'C'}
'project_id': 'A', 'user_id': 'B', 'admin_token': 'C'}
self.assertRaises(exception.MalformedEndpoint,
utils.format_url,
url_template,

View File

@ -133,10 +133,10 @@ class TestTemplatedCatalog(unit.TestCase, catalog_tests.CatalogTests):
def test_get_catalog_ignores_endpoints_with_invalid_urls(self):
user_id = uuid.uuid4().hex
tenant_id = None
# If the URL has no 'tenant_id' to substitute, we will skip the
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 = self.catalog_api.get_v3_catalog(user_id, tenant_id)
catalog_ref = self.catalog_api.get_v3_catalog(user_id, project_id)
exp_catalog = [
{'endpoints': [],
'type': 'compute',

View File

@ -213,9 +213,9 @@ class V2CatalogTestCase(rest.RestfulTestCase):
'http://127.0.0.1:8774/v1.1/$(nonexistent)s',
# invalid formatting - ValueError
'http://127.0.0.1:8774/v1.1/$(tenant_id)',
'http://127.0.0.1:8774/v1.1/$(tenant_id)t',
'http://127.0.0.1:8774/v1.1/$(tenant_id',
'http://127.0.0.1:8774/v1.1/$(project_id)',
'http://127.0.0.1:8774/v1.1/$(project_id)t',
'http://127.0.0.1:8774/v1.1/$(project_id',
# invalid type specifier - TypeError
# admin_url is a string not an int
@ -223,7 +223,7 @@ class V2CatalogTestCase(rest.RestfulTestCase):
]
# list one valid url is enough, no need to list too much
valid_url = 'http://127.0.0.1:8774/v1.1/$(tenant_id)s'
valid_url = 'http://127.0.0.1:8774/v1.1/$(project_id)s'
# Case one: publicurl, internalurl and adminurl are
# all invalid
@ -308,31 +308,31 @@ class TestV2CatalogAPISQL(unit.TestCase):
def test_get_catalog_ignores_endpoints_with_invalid_urls(self):
user_id = uuid.uuid4().hex
tenant_id = uuid.uuid4().hex
project_id = uuid.uuid4().hex
# the only endpoint in the catalog is the one created in setUp
catalog = self.catalog_api.get_catalog(user_id, tenant_id)
catalog = self.catalog_api.get_catalog(user_id, project_id)
self.assertEqual(1, len(catalog))
# it's also the only endpoint in the backend
self.assertEqual(1, len(self.catalog_api.list_endpoints()))
# create a new, invalid endpoint - malformed type declaration
self.create_endpoint(self.service_id,
url='http://keystone/%(tenant_id)')
url='http://keystone/%(project_id)')
# create a new, invalid endpoint - nonexistent key
self.create_endpoint(self.service_id,
url='http://keystone/%(you_wont_find_me)s')
# verify that the invalid endpoints don't appear in the catalog
catalog = self.catalog_api.get_catalog(user_id, tenant_id)
catalog = self.catalog_api.get_catalog(user_id, project_id)
self.assertEqual(1, len(catalog))
# all three endpoints appear in the backend
self.assertEqual(3, len(self.catalog_api.list_endpoints()))
def test_get_catalog_always_returns_service_name(self):
user_id = uuid.uuid4().hex
tenant_id = uuid.uuid4().hex
project_id = uuid.uuid4().hex
# new_service_ref() returns a ref with a `name`.
named_svc = unit.new_service_ref()
@ -346,7 +346,7 @@ class TestV2CatalogAPISQL(unit.TestCase):
self.create_endpoint(service_id=unnamed_svc['id'])
region = None
catalog = self.catalog_api.get_catalog(user_id, tenant_id)
catalog = self.catalog_api.get_catalog(user_id, project_id)
self.assertEqual(named_svc['name'],
catalog[region][named_svc['type']]['name'])

View File

@ -753,7 +753,7 @@ class CatalogTestCase(test_v3.RestfulTestCase):
def test_endpoint_create_with_valid_url(self):
"""Create endpoint with valid url should be tested,too."""
# list one valid url is enough, no need to list too much
valid_url = 'http://127.0.0.1:8774/v1.1/$(tenant_id)s'
valid_url = 'http://127.0.0.1:8774/v1.1/$(project_id)s'
ref = unit.new_endpoint_ref(self.service_id,
interface='public',
@ -778,9 +778,9 @@ class CatalogTestCase(test_v3.RestfulTestCase):
'http://127.0.0.1:8774/v1.1/$(nonexistent)s',
# invalid formatting - ValueError
'http://127.0.0.1:8774/v1.1/$(tenant_id)',
'http://127.0.0.1:8774/v1.1/$(tenant_id)t',
'http://127.0.0.1:8774/v1.1/$(tenant_id',
'http://127.0.0.1:8774/v1.1/$(project_id)',
'http://127.0.0.1:8774/v1.1/$(project_id)t',
'http://127.0.0.1:8774/v1.1/$(project_id',
# invalid type specifier - TypeError
# admin_url is a string not an int
@ -840,7 +840,7 @@ class TestCatalogAPISQL(unit.TestCase):
# create a new, invalid endpoint - malformed type declaration
self.create_endpoint(self.service_id,
url='http://keystone/%(tenant_id)')
url='http://keystone/%(project_id)')
# create a new, invalid endpoint - nonexistent key
self.create_endpoint(self.service_id,
@ -852,18 +852,18 @@ class TestCatalogAPISQL(unit.TestCase):
# all three appear in the backend
self.assertEqual(3, len(self.catalog_api.list_endpoints()))
# create another valid endpoint - tenant_id will be replaced
# create another valid endpoint - project_id will be replaced
self.create_endpoint(self.service_id,
url='http://keystone/%(tenant_id)s')
url='http://keystone/%(project_id)s')
# there are two valid endpoints, positive check
catalog = self.catalog_api.get_v3_catalog(user_id, project['id'])
self.assertThat(catalog[0]['endpoints'], matchers.HasLength(2))
# If the URL has no 'tenant_id' to substitute, we will skip the
# If the URL has no 'project_id' to substitute, we will skip the
# endpoint which contains this kind of URL, negative check.
tenant_id = None
catalog = self.catalog_api.get_v3_catalog(user_id, tenant_id)
project_id = None
catalog = self.catalog_api.get_v3_catalog(user_id, project_id)
self.assertThat(catalog[0]['endpoints'], matchers.HasLength(1))
def test_get_catalog_always_returns_service_name(self):

View File

@ -0,0 +1,5 @@
---
other:
- The signature of keystone catalog driver interfaces ``get_catalog``
and ``get_v3_catalog`` have been changed in favour of using ``project_id``
instead of ``tenant_id``.