From 58476dec0e62d9621916279f7a95fbbcd3d5dd7f Mon Sep 17 00:00:00 2001 From: Christian Rohmann Date: Tue, 29 Aug 2023 14:36:45 +0200 Subject: [PATCH] Fix Swift endpoint conversion to determine info/caps url This adds some robustness and flexibility converting the Swift endpoint URL from the registry to the one exposing the info / capabilities. Additionally some unit tests were added to ensure different use-cases and URL patterns are covered. Story: 2010898 Task: 48689 Related-Bug: #1712358 Change-Id: I321ae9375d16e21771ee9d9bce1c61f85627c879 --- openstack/object_store/v1/info.py | 31 +++++++++---- .../tests/unit/object_store/v1/test_info.py | 44 +++++++++++++++++++ .../notes/bug-2010898-430da335e4df0efe.yaml | 5 +++ 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 openstack/tests/unit/object_store/v1/test_info.py create mode 100644 releasenotes/notes/bug-2010898-430da335e4df0efe.yaml diff --git a/openstack/object_store/v1/info.py b/openstack/object_store/v1/info.py index f3999ad0a..ac83d8265 100644 --- a/openstack/object_store/v1/info.py +++ b/openstack/object_store/v1/info.py @@ -11,10 +11,12 @@ # License for the specific language governing permissions and limitations # under the License. +import re import urllib from openstack import exceptions from openstack import resource +from openstack import utils class Info(resource.Resource): @@ -32,6 +34,24 @@ class Info(resource.Resource): staticweb = resource.Body("staticweb", type=dict) tempurl = resource.Body("tempurl", type=dict) + # The endpoint in the catalog has version and project-id in it + # To get capabilities, we have to disassemble and reassemble the URL + # to append 'info' + # This logic is taken from swiftclient + def _get_info_url(self, url): + URI_PATTERN_VERSION = re.compile(r'\/v\d+\.?\d*(\/.*)?') + scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( + url + ) + if URI_PATTERN_VERSION.search(path): + path = URI_PATTERN_VERSION.sub('/info', path) + else: + path = utils.urljoin(path, 'info') + + return urllib.parse.urlunparse( + (scheme, netloc, path, params, query, fragment) + ) + def fetch( self, session, @@ -60,18 +80,11 @@ class Info(resource.Resource): if not self.allow_fetch: raise exceptions.MethodNotSupported(self, "fetch") - # The endpoint in the catalog has version and project-id in it - # To get capabilities, we have to disassemble and reassemble the URL - # This logic is taken from swiftclient - session = self._get_session(session) - endpoint = urllib.parse.urlparse(session.get_endpoint()) - url = "{scheme}://{netloc}/info".format( - scheme=endpoint.scheme, netloc=endpoint.netloc - ) + info_url = self._get_info_url(session.get_endpoint()) microversion = self._get_microversion(session, action='fetch') - response = session.get(url, microversion=microversion) + response = session.get(info_url, microversion=microversion) kwargs = {} if error_message: kwargs['error_message'] = error_message diff --git a/openstack/tests/unit/object_store/v1/test_info.py b/openstack/tests/unit/object_store/v1/test_info.py new file mode 100644 index 000000000..36f5e7e9f --- /dev/null +++ b/openstack/tests/unit/object_store/v1/test_info.py @@ -0,0 +1,44 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from openstack.object_store.v1 import info +from openstack.tests.unit import base + + +class TestInfo(base.TestCase): + def setUp(self): + super(TestInfo, self).setUp() + + def test_get_info_url(self): + sot = info.Info() + test_urls = { + 'http://object.cloud.example.com': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/v1': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/v1/': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/swift': 'http://object.cloud.example.com/swift/info', + 'http://object.cloud.example.com/swift/': 'http://object.cloud.example.com/swift/info', + 'http://object.cloud.example.com/v1.0': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/swift/v1.0': 'http://object.cloud.example.com/swift/info', + 'http://object.cloud.example.com/v111': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/v111/test': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/v1/test': 'http://object.cloud.example.com/info', + 'http://object.cloud.example.com/swift/v1.0/test': 'http://object.cloud.example.com/swift/info', + 'http://object.cloud.example.com/v1.0/test': 'http://object.cloud.example.com/info', + 'https://object.cloud.example.com/swift/v1/AUTH_%(tenant_id)s': 'https://object.cloud.example.com/swift/info', + 'https://object.cloud.example.com/swift/v1/AUTH_%(project_id)s': 'https://object.cloud.example.com/swift/info', + 'https://object.cloud.example.com/services/swift/v1/AUTH_%(project_id)s': 'https://object.cloud.example.com/services/swift/info', + 'https://object.cloud.example.com/services/swift/v1/AUTH_%(project_id)s/': 'https://object.cloud.example.com/services/swift/info', + 'https://object.cloud.example.com/info/v1/AUTH_%(project_id)s/': 'https://object.cloud.example.com/info/info', + } + for uri_k, uri_v in test_urls.items(): + self.assertEqual(sot._get_info_url(uri_k), uri_v) diff --git a/releasenotes/notes/bug-2010898-430da335e4df0efe.yaml b/releasenotes/notes/bug-2010898-430da335e4df0efe.yaml new file mode 100644 index 000000000..2d09fc799 --- /dev/null +++ b/releasenotes/notes/bug-2010898-430da335e4df0efe.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + [`bug 2010898 `_] + Fix Swift endpoint url handling to determine info/caps url