diff --git a/openstack/session.py b/openstack/session.py index a45c4de1..5e5b459d 100644 --- a/openstack/session.py +++ b/openstack/session.py @@ -169,7 +169,9 @@ class Session(_session.Session): * When an exact major/minor is specified, e.g., v2.0, it will only match v2.0. """ - match = None + + match_version = None + for version in versions: api_version = self._parse_version(version["id"]) if profile_version.major != api_version.major: @@ -178,23 +180,22 @@ class Session(_session.Session): if profile_version.minor <= api_version.minor: for link in version["links"]: if link["rel"] == "self": - match = link["href"] + resp_link = link['href'] + match_version = parse.urlsplit(resp_link).path # Only break out of the loop on an exact match, # otherwise keep trying. if profile_version.minor == api_version.minor: break - if match is None: + if match_version is None: raise exceptions.EndpointNotFound( "Unable to determine endpoint for %s" % service_type) - # Some services return only the path fragment of a URI. - # If we split and see that we're not given the scheme and netloc, - # construct the match with the root from the service catalog. - match_split = parse.urlsplit(match) - if not all([match_split.scheme, match_split.netloc]): - match = root_endpoint + match + # Make sure "root_endpoint" has no overlap with match_version + root_parts = parse.urlsplit(root_endpoint) + match_version = match_version.replace(root_parts.path, "", 1) + match = utils.urljoin(root_endpoint, match_version) # For services that require the project id in the request URI, # add them in here. diff --git a/openstack/tests/unit/test_session.py b/openstack/tests/unit/test_session.py index 73e91a53..77c9d8c3 100644 --- a/openstack/tests/unit/test_session.py +++ b/openstack/tests/unit/test_session.py @@ -18,6 +18,7 @@ from keystoneauth1 import exceptions as _exceptions from openstack import exceptions from openstack import profile from openstack import session +from openstack import utils class TestSession(testtools.TestCase): @@ -166,7 +167,8 @@ class TestSession(testtools.TestCase): sot._get_version_match, [], None, "service", "root", False) def test__get_version_match_fuzzy(self): - match = "http://devstack/v2.1/" + match = "http://devstack/v2.1" + root_endpoint = "http://devstack" versions = [{"id": "v2.0", "links": [{"href": "http://devstack/v2/", "rel": "self"}]}, @@ -178,11 +180,12 @@ class TestSession(testtools.TestCase): # Look for a v2 match, which we internally denote as a minor # version of -1 so we can find the highest matching minor. rv = sot._get_version_match(versions, session.Version(2, -1), - "service", "root", False) + "service", root_endpoint, False) self.assertEqual(rv, match) def test__get_version_match_exact(self): - match = "http://devstack/v2/" + match = "http://devstack/v2" + root_endpoint = "http://devstack" versions = [{"id": "v2.0", "links": [{"href": match, "rel": "self"}]}, @@ -192,12 +195,12 @@ class TestSession(testtools.TestCase): sot = session.Session(None) rv = sot._get_version_match(versions, session.Version(2, 0), - "service", "root", False) + "service", root_endpoint, False) self.assertEqual(rv, match) def test__get_version_match_fragment(self): root = "http://cloud.net" - match = "/v2/" + match = "/v2" versions = [{"id": "v2.0", "links": [{"href": match, "rel": "self"}]}] sot = session.Session(None) @@ -206,15 +209,17 @@ class TestSession(testtools.TestCase): self.assertEqual(rv, root+match) def test__get_version_match_project_id(self): - match = "http://devstack/v2/" + match = "http://devstack/v2" + root_endpoint = "http://devstack" project_id = "asdf123" versions = [{"id": "v2.0", "links": [{"href": match, "rel": "self"}]}] sot = session.Session(None) sot.get_project_id = mock.Mock(return_value=project_id) rv = sot._get_version_match(versions, session.Version(2, 0), - "service", "root", True) - self.assertEqual(rv, match + project_id) + "service", root_endpoint, True) + match_endpoint = utils.urljoin(match, project_id) + self.assertEqual(rv, match_endpoint) def test_get_endpoint_cached(self): sot = session.Session(None)