From 61c5eba5f2a0e6fc642fee47351b92e17e03cbd6 Mon Sep 17 00:00:00 2001 From: Pavlo Shchelokovskyy Date: Thu, 5 Oct 2017 16:48:45 +0000 Subject: [PATCH] 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 --- ironicclient/common/http.py | 9 ++++++--- ironicclient/tests/unit/common/test_http.py | 5 +++-- .../notes/fix-token-with-vhosts-5d0a6d53e807fa5e.yaml | 7 +++++++ 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 releasenotes/notes/fix-token-with-vhosts-5d0a6d53e807fa5e.yaml diff --git a/ironicclient/common/http.py b/ironicclient/common/http.py index d4b60bbb7..3a425f861 100644 --- a/ironicclient/common/http.py +++ b/ironicclient/common/http.py @@ -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) diff --git a/ironicclient/tests/unit/common/test_http.py b/ironicclient/tests/unit/common/test_http.py index 1a11a7483..7d4575951 100644 --- a/ironicclient/tests/unit/common/test_http.py +++ b/ironicclient/tests/unit/common/test_http.py @@ -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) diff --git a/releasenotes/notes/fix-token-with-vhosts-5d0a6d53e807fa5e.yaml b/releasenotes/notes/fix-token-with-vhosts-5d0a6d53e807fa5e.yaml new file mode 100644 index 000000000..9c0e2bd0a --- /dev/null +++ b/releasenotes/notes/fix-token-with-vhosts-5d0a6d53e807fa5e.yaml @@ -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 `_.