Fix cropping the endpoint url

`nova version-list` crops the endpoint url to exclude API version and
project-id(for microversions < 2.18). It is ok, but the code was
designed before Nova-API moved under uwsgi, which changed the endpoint
url format.

The latest endpoint url contains the hostname and port which can be one
for several services and it is a wrong case to cut the whole path from
the endpoint.

Closes-Bug: #1702194

Change-Id: Icba858b496855e2ffd71b35168e8057b28236119
This commit is contained in:
Andrey Kurilin 2017-07-03 16:27:29 +03:00
parent da5b563143
commit bd0a2adefe
3 changed files with 45 additions and 6 deletions

View File

@ -100,7 +100,7 @@ class SimpleReadOnlyNovaClientTest(base.ClientTestBase):
self.nova('migration-list', flags='--debug')
def test_version_list(self):
self.nova('version-list')
self.nova('version-list', flags='--debug')
def test_quota_defaults(self):
self.nova('quota-defaults')

View File

@ -30,7 +30,7 @@ class VersionsTest(utils.TestCase):
def test_list_services(self):
vl = self.cs.versions.list()
self.assert_request_id(vl, fakes.FAKE_REQUEST_ID_LIST)
self.cs.assert_called('GET', 'http://nova-api:8774/')
self.cs.assert_called('GET', 'http://nova-api:8774')
def test_get_current(self):
self.cs.callback = []
@ -75,3 +75,28 @@ class VersionsTest(utils.TestCase):
# check that the full request works as expected
cs_2.assert_called('GET', expected_endpoint)
def test_list_versions(self):
fapi = mock.Mock()
version_mgr = versions.VersionManager(fapi)
version_mgr._list = mock.Mock()
data = [
("https://example.com:777/v2", "https://example.com:777"),
("https://example.com/v2", "https://example.com"),
("http://example.com/compute/v2", "http://example.com/compute"),
("https://example.com/v2/prrrooojeect-uuid",
"https://example.com"),
("https://example.com:777/v2.1", "https://example.com:777"),
("https://example.com/v2.1", "https://example.com"),
("http://example.com/compute/v2.1", "http://example.com/compute"),
("https://example.com/v2.1/prrrooojeect-uuid",
"https://example.com"),
("http://example.com/compute", "http://example.com/compute"),
("http://compute.example.com", "http://compute.example.com"),
]
for endpoint, expected in data:
version_mgr._list.reset_mock()
fapi.client.get_endpoint.return_value = endpoint
version_mgr.list()
version_mgr._list.assert_called_once_with(expected, "versions")

View File

@ -78,11 +78,25 @@ class VersionManager(base.ManagerWithFind):
def list(self):
"""List all versions."""
# NOTE: "list versions" API needs to be accessed without base
# URI (like "v2/{project-id}"), so here should be a scheme("http",
# etc.) and a hostname.
endpoint = self.api.client.get_endpoint()
url = urllib.parse.urlparse(endpoint)
version_url = '%s://%s/' % (url.scheme, url.netloc)
# NOTE(andreykurilin): endpoint URL has at least 3 formats:
# 1. the classic (legacy) endpoint:
# http://{host}:{optional_port}/v{2 or 2.1}/{project-id}
# 2. starting from microversion 2.18 project-id is not included:
# http://{host}:{optional_port}/v{2 or 2.1}
# 3. under wsgi:
# http://{host}:{optional_port}/compute/v{2 or 2.1}
if (url.path.endswith("v2") or "/v2/" in url.path or
url.path.endswith("v2.1") or "/v2.1/" in url.path):
# this way should handle all 3 possible formats
path = url.path[:url.path.rfind("/v2")]
version_url = '%s://%s%s' % (url.scheme, url.netloc, path)
else:
# NOTE(andreykurilin): probably, it is one of the next cases:
# * https://compute.example.com/
# * https://example.com/compute
# leave as is without cropping.
version_url = endpoint
return self._list(version_url, "versions")