From c2df0090189c90a4b90a2d2b1e6527bdc22ae2d3 Mon Sep 17 00:00:00 2001 From: Eric K Date: Tue, 6 Feb 2018 19:23:53 -0800 Subject: [PATCH] Fix swift auth issue by specifying version in url Swift client does not always handle unversioned identity URL properly. Leading to authorization failure because keystone cannot handle incorrect path, returning 404. To work around the issue, congress swift driver specifies the version in url if none is already provided. Partial-Bug: 1677380 Change-Id: I8df7dac60e4f7cb3c2ec792e13f687d5844c8409 --- congress/datasources/swift_driver.py | 38 +++++++++++++- .../tests/datasources/test_swift_driver.py | 51 +++++++++++++++++++ .../notes/swift-auth-9593642ad5ec18f7.yaml | 8 +++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/swift-auth-9593642ad5ec18f7.yaml diff --git a/congress/datasources/swift_driver.py b/congress/datasources/swift_driver.py index 8f20197f3..032f2f369 100644 --- a/congress/datasources/swift_driver.py +++ b/congress/datasources/swift_driver.py @@ -18,6 +18,7 @@ from __future__ import division from __future__ import absolute_import from oslo_log import log as logging +from six.moves.urllib.parse import urlparse import swiftclient.service from congress.datasources import constants @@ -27,6 +28,32 @@ from congress.datasources import datasource_utils as ds_utils LOG = logging.getLogger(__name__) +def _append_path_to_url(url, version_str): + if len(url) == 0 or url[-1] != '/': + return url + '/' + version_str + else: + return url + version_str + + +def _auth_url_specifies_version(url): + url = str(url) + parsed_url = urlparse(url) + path_parts = parsed_url.path.split('/') + last_path_part = None + + # find the last non-empty path part + for i in range(1, len(path_parts)): + if len(path_parts[-i]) > 0: + last_path_part = path_parts[-i] + break + if last_path_part is None: + return False + + if last_path_part in ['v2.0', 'v2', 'v3']: + return True + return False + + class SwiftDriver(datasource_driver.PollingDataSourceDriver, datasource_driver.ExecutionDriver): @@ -64,8 +91,6 @@ class SwiftDriver(datasource_driver.PollingDataSourceDriver, super(SwiftDriver, self).__init__(name, args=args) datasource_driver.ExecutionDriver.__init__(self) options = self.get_swift_credentials_v1(args) - # TODO(ramineni): Enable v3 support - options['os_auth_url'] = options['os_auth_url'].replace('v3', 'v2.0') self.swift_service = swiftclient.service.SwiftService(options) self.add_executable_client_methods(self.swift_service, 'swiftclient.service') @@ -94,6 +119,15 @@ class SwiftDriver(datasource_driver.PollingDataSourceDriver, options['os_password'] = creds['password'] options['os_tenant_name'] = creds['tenant_name'] options['os_auth_url'] = creds['auth_url'] + + # Note(ekcs: swift does not always handle unversioned URL correctly, + # as a work-around, this driver appends 'v3' if no version provided + if (not _auth_url_specifies_version(url=options['os_auth_url']) and + len(options['os_auth_url']) != 0): + options['os_auth_url'] = _append_path_to_url( + options['os_auth_url'], 'v3') + options['auth_version'] = '3' + return options def initialize_update_methods(self): diff --git a/congress/tests/datasources/test_swift_driver.py b/congress/tests/datasources/test_swift_driver.py index bdd8ec84e..f03d383b3 100644 --- a/congress/tests/datasources/test_swift_driver.py +++ b/congress/tests/datasources/test_swift_driver.py @@ -112,3 +112,54 @@ class TestSwiftDriver(base.TestCase): self.driver.execute('updateObject', api_args) self.assertEqual(expected_ans, swift_client.testkey) + + def test_auth_url_specifies_version(self): + # False + self.assertEqual( + swift_driver._auth_url_specifies_version(''), + False) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/'), + False) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def'), + False) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/v1/'), + False) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/abc/'), + False) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/abc'), + False) + + # True + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/v2/'), + True) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/v3'), + True) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/v2.0/'), + True) + self.assertEqual( + swift_driver._auth_url_specifies_version('http://abc.def/v2.0/'), + True) + + def test_append_path_to_url(self): + # no ending slash + self.assertEqual( + swift_driver._append_path_to_url('http://abc.def/abc', 'v321'), + 'http://abc.def/abc/v321') + + # ending slash + self.assertEqual( + swift_driver._append_path_to_url('http://abc.def/abc/', 'v321'), + 'http://abc.def/abc/v321') + + # multiple ending slashes + self.assertEqual( + swift_driver._append_path_to_url('http://abc.def/abc///', 'v321'), + 'http://abc.def/abc///v321') diff --git a/releasenotes/notes/swift-auth-9593642ad5ec18f7.yaml b/releasenotes/notes/swift-auth-9593642ad5ec18f7.yaml new file mode 100644 index 000000000..d58e43f54 --- /dev/null +++ b/releasenotes/notes/swift-auth-9593642ad5ec18f7.yaml @@ -0,0 +1,8 @@ +--- +prelude: > +fixes: + - Workaround added for an issue where Swift client, + and the Congress Swift driver using Swift client, + do not always handle unversioned auth URL correctly. + The workaround adds /v3 to the end of an unversioned + auth URL.