Do not use urljoin in base http client

this fails when ironic API endpoint is not in the form
"host:port", but "host/vhost" instead
(as when ironic-api is deployed behind Apache),
since the 'vhost' gets swallowed by 'urljoin'.

This leads to a failure when using ironicclient with token and
endpoint passed in, otherwise a SessionClient is used that does
not have this problem.

Simply concat those url parts together (ensuring there is at least a
single '/' between them).

Change-Id: I583e0f9bdc81a655861c6ff508782173021428f0
Closes-Bug: #1721599
This commit is contained in:
Pavlo Shchelokovskyy 2017-10-05 16:48:45 +00:00
parent 60e0ea26fb
commit 61c5eba5f2
3 changed files with 16 additions and 5 deletions

View File

@ -64,7 +64,7 @@ SUPPORTED_ENDPOINT_SCHEME = ('http', 'https')
def _trim_endpoint_api_version(url):
"""Trim API version and trailing slash from endpoint."""
return url.rstrip('/').rstrip(API_VERSION)
return url.rstrip('/').rstrip(API_VERSION).rstrip('/')
def _extract_error_json(body):
@ -274,7 +274,7 @@ class HTTPClient(VersionNegotiationMixin):
body = strutils.mask_password(kwargs['body'])
curl.append('-d \'%s\'' % body)
curl.append(urlparse.urljoin(self.endpoint_trimmed, url))
curl.append(self._make_connection_url(url))
LOG.debug(' '.join(curl))
@staticmethod
@ -292,7 +292,10 @@ class HTTPClient(VersionNegotiationMixin):
LOG.debug('\n'.join(dump))
def _make_connection_url(self, url):
return urlparse.urljoin(self.endpoint_trimmed, url)
# NOTE(pas-ha) we already stripped trailing / from endpoint_trimmed
if not url.startswith('/'):
url = '/' + url
return self.endpoint_trimmed + url
def _parse_version_headers(self, resp):
return self._generic_parse_version_headers(resp.headers.get)

View File

@ -382,9 +382,10 @@ class HttpClientTest(utils.BaseTestCase):
client = http.HTTPClient('http://localhost/')
kwargs = {'headers': {'foo-header': 'bar-header'},
'body': '{"password": "foo"}'}
client.log_curl_request('foo', 'http://127.0.0.1', kwargs)
client.log_curl_request('foo', '/v1/nodes', kwargs)
expected_log = ("curl -i -X foo -H 'foo-header: bar-header' "
"-d '{\"password\": \"***\"}' http://127.0.0.1")
"-d '{\"password\": \"***\"}' "
"http://localhost/v1/nodes")
mock_log.assert_called_once_with(expected_log)
@mock.patch.object(http.LOG, 'debug', autospec=True)

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Fixed a bug where ironicclient instantiated with keystone token and
ironic API endpoint could not access ironic API that has a virtual host
in its endpoint (like "http://hostname/baremetal").
For more details see `bug 1721599 <https://launchpad.net/bugs/1721599>`_.