Record the discovered major api version

With the addition of input ranges for versions it's important for the
user to be able to know what version was discovered. This is already in
the EndpointData model as "api_version" - the value was just never
populated.

In cases where an Endpoint has been discovered and the user has an
EndpointData that now correctly stores the api_version of the discovered
endpoint, and where that user now wants to get microversion metadata,
getting rid of api_version as an input to get_versoined_data made
it awkward to fetch metadata about the already discovered endpoint.

Add a method so that the user can say "please run discovery on this
endpoint to fill in the data, don't look for different endpoints, and
don't make me do the api-version -> min/max transformation myself".

Change-Id: I3031d1eb0967eaa8b911e8e8a06ba722f9e69063
This commit is contained in:
Monty Taylor 2017-07-24 14:35:07 +08:00
parent 928dd259ea
commit 5268d00218
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
2 changed files with 107 additions and 2 deletions

View File

@ -376,6 +376,19 @@ def _combine_relative_url(discovery_url, version_url):
return urllib.parse.urlparse(url).geturl()
def _version_from_url(url):
if not url:
return url
url = urllib.parse.urlparse(url)
for part in reversed(url.path.split('/')):
try:
return normalize_version_number(part)
except Exception:
pass
return None
class Discover(object):
CURRENT_STATUSES = ('stable', 'current', 'supported')
@ -686,7 +699,6 @@ class EndpointData(object):
self.region_name = region_name
self.endpoint_id = endpoint_id
self.raw_endpoint = raw_endpoint
self.api_version = api_version
self.major_version = major_version
self.min_microversion = min_microversion
self.max_microversion = max_microversion
@ -697,6 +709,8 @@ class EndpointData(object):
self._catalog_matches_exactly = False
self._disc = None
self.api_version = api_version or _version_from_url(self.url)
def __copy__(self):
"""Return a new EndpointData based on this one."""
new_data = EndpointData(
@ -725,6 +739,41 @@ class EndpointData(object):
def url(self):
return self.service_url or self.catalog_url
@positional(3)
def get_current_versioned_data(self, session, allow=None, cache=None,
project_id=None):
"""Run version discovery on the current endpoint.
A simplified version of get_versioned_data, get_current_versioned_data
runs discovery but only on the endpoint that has been found already.
It can be useful in some workflows where the user wants version
information about the endpoint they have.
:param session: A session object that can be used for communication.
:type session: keystoneauth1.session.Session
:param dict allow: Extra filters to pass when discovering API
versions. (optional)
:param dict cache: A dict to be used for caching results in
addition to caching them on the Session.
(optional)
:param string project_id: ID of the currently scoped project. Used for
removing project_id components of URLs from
the catalog. (optional)
:returns: A new EndpointData with the requested versioned data.
:rtype: :py:class:`keystoneauth1.discover.EndpointData`
:raises keystoneauth1.exceptions.discovery.DiscoveryFailure: If the
appropriate versioned data
could not be discovered.
"""
min_version, max_version = _normalize_version_args(
self.api_version, None, None)
return self.get_versioned_data(
session=session, allow=allow, cache=cache, allow_version_hack=True,
discover_versions=True,
min_version=min_version, max_version=max_version)
@positional(3)
def get_versioned_data(self, session, allow=None, cache=None,
allow_version_hack=True, project_id=None,
@ -843,6 +892,7 @@ class EndpointData(object):
self.max_microversion = discovered_data['max_microversion']
self.next_min_version = discovered_data['next_min_version']
self.not_before = discovered_data['not_before']
self.api_version = discovered_data['version']
# TODO(mordred): these next two things should be done by Discover
# in versioned_data_for.

View File

@ -499,6 +499,8 @@ class CommonIdentityTests(object):
interface='admin')
self.assertEqual(self.TEST_COMPUTE_ADMIN + '/v3', data.url)
# We should have gotten the version from the URL
self.assertEqual((3, 0), data.api_version)
def test_endpoint_data_no_version_no_discovery(self):
a = self.create_auth_plugin()
@ -510,6 +512,22 @@ class CommonIdentityTests(object):
discover_versions=False)
self.assertEqual(self.TEST_COMPUTE_ADMIN, data.url)
# There's no version in the URL and no document - we have no idea
self.assertEqual(None, data.api_version)
def test_endpoint_data_version_url_no_discovery(self):
a = self.create_auth_plugin()
s = session.Session(auth=a)
data = a.get_endpoint_data(session=s,
service_type='volumev3',
interface='admin',
discover_versions=False)
self.assertEqual(
self.TEST_VOLUME.versions['v3'].service.admin, data.url)
# There's v3 in the URL
self.assertEqual((3, 0), data.api_version)
def test_endpoint_no_version(self):
a = self.create_auth_plugin()
@ -589,6 +607,37 @@ class CommonIdentityTests(object):
self.assertEqual(v3_compute, v3_data.service_url)
self.assertEqual(self.TEST_COMPUTE_ADMIN, v3_data.catalog_url)
def test_get_current_versioned_data(self):
v2_compute = self.TEST_COMPUTE_ADMIN + '/v2.0'
v3_compute = self.TEST_COMPUTE_ADMIN + '/v3'
disc = fixture.DiscoveryList(v2=False, v3=False)
disc.add_v2(v2_compute)
disc.add_v3(v3_compute)
# Make sure that we don't do more than one discovery call
# register responses such that if the discovery URL is hit more than
# once then the response will be invalid and not point to COMPUTE_ADMIN
resps = [{'json': disc}, {'status_code': 500}]
self.requests_mock.get(self.TEST_COMPUTE_ADMIN, resps)
a = self.create_auth_plugin()
s = session.Session(auth=a)
data = a.get_endpoint_data(session=s,
service_type='compute',
interface='admin')
self.assertEqual(v3_compute, data.url)
v3_data = data.get_current_versioned_data(s)
self.assertEqual(v3_compute, v3_data.url)
self.assertEqual(v3_compute, v3_data.service_url)
self.assertEqual(self.TEST_COMPUTE_ADMIN, v3_data.catalog_url)
self.assertEqual((3, 0), v3_data.api_version)
self.assertEqual(None, v3_data.min_microversion)
self.assertEqual(None, v3_data.max_microversion)
def test_interface_list(self):
a = self.create_auth_plugin()
@ -932,8 +981,9 @@ class CommonIdentityTests(object):
data = sess.get_endpoint_data(service_type='network')
# Discovery ran and returned the URL
# Discovery ran and returned the URL and its version
self.assertEqual(url, data.url)
self.assertEqual((2, 1), data.api_version)
# Run with a project_id to ensure that path is covered
self.assertEqual(
@ -1213,6 +1263,7 @@ class CatalogHackTests(utils.TestCase):
self.assertEqual(self.OTHER_URL, data.url)
self.assertEqual((2, 1), data.min_microversion)
self.assertEqual((2, 35), data.max_microversion)
self.assertEqual((2, 1), data.api_version)
def test_forcing_discovery(self):
v2_disc = fixture.V2Discovery(self.V2_URL)
@ -1260,6 +1311,7 @@ class CatalogHackTests(utils.TestCase):
# got v2 url
self.assertEqual(self.V2_URL, data.url)
self.assertEqual((2, 0), data.api_version)
def test_forcing_discovery_list_returns_url(self):
common_disc = fixture.DiscoveryList(href=self.BASE_URL)
@ -1304,6 +1356,7 @@ class CatalogHackTests(utils.TestCase):
# got v2 url
self.assertEqual(self.V2_URL, data.url)
self.assertEqual((2, 0), data.api_version)
def test_latest_version_gets_latest_version(self):
common_disc = fixture.DiscoveryList(href=self.BASE_URL)
@ -1489,6 +1542,7 @@ class CatalogHackTests(utils.TestCase):
self.assertEqual(self.OTHER_URL, data.url)
self.assertEqual((2, 1), data.min_microversion)
self.assertEqual((2, 35), data.max_microversion)
self.assertEqual((2, 1), data.api_version)
def test_get_endpoint_data_compute(self):
common_disc = fixture.DiscoveryList(v2=False, v3=False)
@ -1530,6 +1584,7 @@ class CatalogHackTests(utils.TestCase):
self.assertEqual(self.OTHER_URL, data.url)
self.assertEqual((2, 1), data.min_microversion)
self.assertEqual((2, 35), data.max_microversion)
self.assertEqual((2, 1), data.api_version)
def test_getting_endpoints_on_auth_interface(self):
disc = fixture.DiscoveryList(href=self.BASE_URL)