Show v3 endpoints in v2 endpoint list
v3 endpoints that are not migrated from v2 endpoints, were not shown in v2 endpoint list. While it was more clear, separating v2 and v3 endpoints, it was not easy for tools or services which are still using v2 APIs to get the endpoints created by v3 API. Since it won't do harm to return more information, this commit is to show v3 endpoints in API call to list v2 endpoints. NOTE: public interface is required in a v2 endpoints, so only v3 endpoints with public interface are added into the list. Change-Id: Id9b3822f87e973b6eb7dd9fc715c2dba76b9fe04 Closes-Bug: #1480270
This commit is contained in:
parent
af399474b2
commit
0d13a85e93
@ -68,25 +68,59 @@ class Endpoint(controller.V2Controller):
|
||||
"""Merge matching v3 endpoint refs into legacy refs."""
|
||||
self.assert_admin(context)
|
||||
legacy_endpoints = {}
|
||||
v3_endpoints = {}
|
||||
for endpoint in self.catalog_api.list_endpoints():
|
||||
if not endpoint.get('legacy_endpoint_id'):
|
||||
# endpoints created in v3 should not appear on the v2 API
|
||||
if not endpoint.get('legacy_endpoint_id'): # pure v3 endpoint
|
||||
# tell endpoints apart by the combination of
|
||||
# service_id and region_id.
|
||||
# NOTE(muyu): in theory, it's possible that there are more than
|
||||
# one endpoint of one service, one region and one interface,
|
||||
# but in practice, it makes no sense because only one will be
|
||||
# used.
|
||||
key = (endpoint['service_id'], endpoint['region_id'])
|
||||
v3_endpoints.setdefault(key, []).append(endpoint)
|
||||
else: # legacy endpoint
|
||||
if endpoint['legacy_endpoint_id'] not in legacy_endpoints:
|
||||
legacy_ep = endpoint.copy()
|
||||
legacy_ep['id'] = legacy_ep.pop('legacy_endpoint_id')
|
||||
legacy_ep.pop('interface')
|
||||
legacy_ep.pop('url')
|
||||
legacy_ep['region'] = legacy_ep.pop('region_id')
|
||||
|
||||
legacy_endpoints[endpoint['legacy_endpoint_id']] = (
|
||||
legacy_ep)
|
||||
else:
|
||||
legacy_ep = (
|
||||
legacy_endpoints[endpoint['legacy_endpoint_id']])
|
||||
|
||||
# add the legacy endpoint with an interface url
|
||||
legacy_ep['%surl' % endpoint['interface']] = endpoint['url']
|
||||
|
||||
# convert collected v3 endpoints into v2 endpoints
|
||||
for endpoints in v3_endpoints.values():
|
||||
legacy_ep = {}
|
||||
# For v3 endpoints in the same group, contents of extra attributes
|
||||
# can be different, which may cause confusion if a random one is
|
||||
# used. So only necessary attributes are used here.
|
||||
# It's different for legacy v2 endpoints, which are created
|
||||
# with the same "extra" value when being migrated.
|
||||
for key in ('service_id', 'enabled'):
|
||||
legacy_ep[key] = endpoints[0][key]
|
||||
legacy_ep['region'] = endpoints[0]['region_id']
|
||||
for endpoint in endpoints:
|
||||
# Public URL is required for v2 endpoints, so the generated v2
|
||||
# endpoint uses public endpoint's id as its id, which can also
|
||||
# be an indicator whether a public v3 endpoint is present.
|
||||
# It's safe to do so is also because that there is no v2 API to
|
||||
# get an endpoint by endpoint ID.
|
||||
if endpoint['interface'] == 'public':
|
||||
legacy_ep['id'] = endpoint['id']
|
||||
legacy_ep['%surl' % endpoint['interface']] = endpoint['url']
|
||||
|
||||
# this means there is no public URL of this group of v3 endpoints
|
||||
if 'id' not in legacy_ep:
|
||||
continue
|
||||
|
||||
# is this is a legacy endpoint we haven't indexed yet?
|
||||
if endpoint['legacy_endpoint_id'] not in legacy_endpoints:
|
||||
legacy_ep = endpoint.copy()
|
||||
legacy_ep['id'] = legacy_ep.pop('legacy_endpoint_id')
|
||||
legacy_ep.pop('interface')
|
||||
legacy_ep.pop('url')
|
||||
legacy_ep['region'] = legacy_ep.pop('region_id')
|
||||
|
||||
legacy_endpoints[endpoint['legacy_endpoint_id']] = legacy_ep
|
||||
else:
|
||||
legacy_ep = legacy_endpoints[endpoint['legacy_endpoint_id']]
|
||||
|
||||
# add the legacy endpoint with an interface url
|
||||
legacy_ep['%surl' % endpoint['interface']] = endpoint['url']
|
||||
legacy_endpoints[legacy_ep['id']] = legacy_ep
|
||||
return {'endpoints': list(legacy_endpoints.values())}
|
||||
|
||||
@controller.v2_deprecated
|
||||
|
@ -77,6 +77,18 @@ class V2CatalogTestCase(rest.RestfulTestCase):
|
||||
body=body)
|
||||
return body, r
|
||||
|
||||
def _region_create(self):
|
||||
region_id = uuid.uuid4().hex
|
||||
self.catalog_api.create_region({'id': region_id})
|
||||
return region_id
|
||||
|
||||
def _service_create(self):
|
||||
service_id = uuid.uuid4().hex
|
||||
service = unit.new_service_ref()
|
||||
service['id'] = service_id
|
||||
self.catalog_api.create_service(service_id, service)
|
||||
return service_id
|
||||
|
||||
def test_endpoint_create(self):
|
||||
req_body, response = self._endpoint_create()
|
||||
self.assertIn('endpoint', response.result)
|
||||
@ -84,6 +96,78 @@ class V2CatalogTestCase(rest.RestfulTestCase):
|
||||
for field, value in req_body['endpoint'].items():
|
||||
self.assertEqual(value, response.result['endpoint'][field])
|
||||
|
||||
def test_pure_v3_endpoint_with_publicurl_visible_from_v2(self):
|
||||
"""Test pure v3 endpoint can be fetched via v2 API.
|
||||
|
||||
For those who are using v2 APIs, endpoints created by v3 API should
|
||||
also be visible as there are no differences about the endpoints
|
||||
except the format or the internal implementation.
|
||||
And because public url is required for v2 API, so only the v3 endpoints
|
||||
of the service which has the public interface endpoint will be
|
||||
converted into v2 endpoints.
|
||||
"""
|
||||
region_id = self._region_create()
|
||||
service_id = self._service_create()
|
||||
# create a v3 endpoint with three interfaces
|
||||
body = {
|
||||
'endpoint': unit.new_endpoint_ref(service_id,
|
||||
default_region_id=region_id)
|
||||
}
|
||||
for interface in catalog.controllers.INTERFACES:
|
||||
body['endpoint']['interface'] = interface
|
||||
self.admin_request(method='POST',
|
||||
token=self.get_scoped_token(),
|
||||
path='/v3/endpoints',
|
||||
expected_status=http_client.CREATED,
|
||||
body=body)
|
||||
|
||||
r = self.admin_request(token=self.get_scoped_token(),
|
||||
path='/v2.0/endpoints')
|
||||
# v3 endpoints having public url can be fetched via v2.0 API
|
||||
self.assertEqual(1, len(r.result['endpoints']))
|
||||
v2_endpoint = r.result['endpoints'][0]
|
||||
self.assertEqual(service_id, v2_endpoint['service_id'])
|
||||
# check urls just in case.
|
||||
# This is not the focus of this test, so no different urls are used.
|
||||
self.assertEqual(body['endpoint']['url'], v2_endpoint['publicurl'])
|
||||
self.assertEqual(body['endpoint']['url'], v2_endpoint['adminurl'])
|
||||
self.assertEqual(body['endpoint']['url'], v2_endpoint['internalurl'])
|
||||
self.assertNotIn('name', v2_endpoint)
|
||||
|
||||
v3_endpoint = self.catalog_api.get_endpoint(v2_endpoint['id'])
|
||||
# it's the v3 public endpoint's id as the generated v2 endpoint
|
||||
self.assertEqual('public', v3_endpoint['interface'])
|
||||
self.assertEqual(service_id, v3_endpoint['service_id'])
|
||||
|
||||
def test_pure_v3_endpoint_without_publicurl_invisible_from_v2(self):
|
||||
"""Test pure v3 endpoint without public url can't be fetched via v2 API.
|
||||
|
||||
V2 API will return endpoints created by v3 API, but because public url
|
||||
is required for v2 API, so v3 endpoints without public url will be
|
||||
ignored.
|
||||
"""
|
||||
region_id = self._region_create()
|
||||
service_id = self._service_create()
|
||||
# create a v3 endpoint without public interface
|
||||
body = {
|
||||
'endpoint': unit.new_endpoint_ref(service_id,
|
||||
default_region_id=region_id)
|
||||
}
|
||||
for interface in catalog.controllers.INTERFACES:
|
||||
if interface == 'public':
|
||||
continue
|
||||
body['endpoint']['interface'] = interface
|
||||
self.admin_request(method='POST',
|
||||
token=self.get_scoped_token(),
|
||||
path='/v3/endpoints',
|
||||
expected_status=http_client.CREATED,
|
||||
body=body)
|
||||
|
||||
r = self.admin_request(token=self.get_scoped_token(),
|
||||
path='/v2.0/endpoints')
|
||||
# v3 endpoints without public url won't be fetched via v2.0 API
|
||||
self.assertEqual(0, len(r.result['endpoints']))
|
||||
|
||||
def test_endpoint_create_with_null_adminurl(self):
|
||||
req_body, response = self._endpoint_create(adminurl=None)
|
||||
self.assertIsNone(req_body['endpoint']['adminurl'])
|
||||
|
Loading…
x
Reference in New Issue
Block a user