diff --git a/glance/api/middleware/version_negotiation.py b/glance/api/middleware/version_negotiation.py index d5ab5e2d11..99a5286c46 100644 --- a/glance/api/middleware/version_negotiation.py +++ b/glance/api/middleware/version_negotiation.py @@ -82,15 +82,16 @@ class VersionNegotiationFilter(wsgi.Middleware): allowed_versions['v2.6'] = 2 allowed_versions['v2.7'] = 2 allowed_versions['v2.9'] = 2 - allowed_versions['v2.13'] = 2 if CONF.image_cache_dir: allowed_versions['v2.14'] = 2 + allowed_versions['v2.16'] = 2 allowed_versions['v2.15'] = 2 if CONF.enabled_backends: allowed_versions['v2.8'] = 2 allowed_versions['v2.10'] = 2 allowed_versions['v2.11'] = 2 allowed_versions['v2.12'] = 2 + allowed_versions['v2.13'] = 2 return allowed_versions def _match_version_string(self, subject): diff --git a/glance/api/versions.py b/glance/api/versions.py index 15b0487517..ef64e83c14 100644 --- a/glance/api/versions.py +++ b/glance/api/versions.py @@ -79,7 +79,8 @@ class Controller(object): version_objs = [] if CONF.image_cache_dir: version_objs.extend([ - build_version_object(2.15, 'v2', 'CURRENT'), + build_version_object(2.16, 'v2', 'CURRENT'), + build_version_object(2.15, 'v2', 'SUPPORTED'), build_version_object(2.14, 'v2', 'SUPPORTED'), ]) else: diff --git a/glance/tests/unit/test_versions.py b/glance/tests/unit/test_versions.py index 4acda1fa86..b2a1d3f1d9 100644 --- a/glance/tests/unit/test_versions.py +++ b/glance/tests/unit/test_versions.py @@ -139,12 +139,19 @@ def get_versions_list(url, enabled_backends=False, ] + image_versions[2:] if enabled_cache: + image_versions[0]['status'] = 'SUPPORTED' image_versions.insert(1, { 'id': 'v2.14', 'status': 'SUPPORTED', 'links': [{'rel': 'self', 'href': '%s/v2/' % url}], }) + image_versions.insert(0, { + 'id': 'v2.16', + 'status': 'CURRENT', + 'links': [{'rel': 'self', + 'href': '%s/v2/' % url}], + }) return image_versions @@ -341,6 +348,11 @@ class VersionNegotiationTest(base.IsolatedUnitTest): self.middleware.process_request(request) self.assertEqual('/v2/images', request.path_info) + def test_request_url_v2_15(self): + request = webob.Request.blank('/v2.15/images') + self.middleware.process_request(request) + self.assertEqual('/v2/images', request.path_info) + # note: these need separate unsupported/supported tests to reset the # the memoized allowed_versions in the VersionNegotiationFilter instance def test_request_url_v2_8_default_unsupported(self): @@ -387,31 +399,48 @@ class VersionNegotiationTest(base.IsolatedUnitTest): self.middleware.process_request(request) self.assertEqual('/v2/images', request.path_info) + def test_request_url_v2_13_default_unsupported(self): + request = webob.Request.blank('/v2.13/images') + resp = self.middleware.process_request(request) + self.assertIsInstance(resp, versions.Controller) + def test_request_url_v2_13_enabled_supported(self): + self.config(enabled_backends='slow:one,fast:two') request = webob.Request.blank('/v2.13/images') self.middleware.process_request(request) self.assertEqual('/v2/images', request.path_info) + def test_request_url_v2_14_default_unsupported(self): + request = webob.Request.blank('/v2.14/images') + resp = self.middleware.process_request(request) + self.assertIsInstance(resp, versions.Controller) + def test_request_url_v2_14_enabled_supported(self): self.config(image_cache_dir='/tmp/cache') request = webob.Request.blank('/v2.14/images') self.middleware.process_request(request) self.assertEqual('/v2/images', request.path_info) - def test_request_url_v2_15_enabled_supported(self): - request = webob.Request.blank('/v2.15/images') - self.middleware.process_request(request) - self.assertEqual('/v2/images', request.path_info) - - # version 2.16 does not exist def test_request_url_v2_16_default_unsupported(self): request = webob.Request.blank('/v2.16/images') resp = self.middleware.process_request(request) self.assertIsInstance(resp, versions.Controller) - def test_request_url_v2_16_enabled_unsupported(self): - self.config(enabled_backends='slow:one,fast:two') + def test_request_url_v2_16_enabled_supported(self): + self.config(image_cache_dir='/tmp/cache') request = webob.Request.blank('/v2.16/images') + self.middleware.process_request(request) + self.assertEqual('/v2/images', request.path_info) + + # version 2.17 does not exist + def test_request_url_v2_17_default_unsupported(self): + request = webob.Request.blank('/v2.17/images') + resp = self.middleware.process_request(request) + self.assertIsInstance(resp, versions.Controller) + + def test_request_url_v2_17_enabled_unsupported(self): + self.config(enabled_backends='slow:one,fast:two') + request = webob.Request.blank('/v2.17/images') resp = self.middleware.process_request(request) self.assertIsInstance(resp, versions.Controller) @@ -438,38 +467,54 @@ class VersionsAndNegotiationTest(VersionNegotiationTest, VersionsTest): expected = "/%s/images" % major self.assertEqual(expected, request.path_info) - # the content of the version list depends on whether - # CONF.enabled_backends is set or not, so check both cases - default = '' - enabled = 'slow:one,fast:two' + # the content of the version list depends on two configuration + # options: + # - CONF.enabled_backends + # - CONF.image_cache_dir + # So we need to check a bunch of combinations + cache = '/var/cache' + multistore = 'slow:one,fast:two' - @ddt.data(default, enabled) - def test_current_is_negotiated(self, stores): + combos = ((None, None), + (None, multistore), + (cache, None), + (cache, multistore)) + + @ddt.data(*combos) + @ddt.unpack + def test_current_is_negotiated(self, cache, multistore): # NOTE(rosmaita): Bug 1609571: the versions response was correct, but # the negotiation had not been updated for the CURRENT version. - self.config(enabled_backends=stores) + self.config(enabled_backends=multistore) + self.config(image_cache_dir=cache) to_check = self._get_list_of_version_ids('CURRENT') self.assertTrue(to_check) for version_id in to_check: self._assert_version_is_negotiated(version_id) - @ddt.data(default, enabled) - def test_supported_is_negotiated(self, stores): - self.config(enabled_backends=stores) + @ddt.data(*combos) + @ddt.unpack + def test_supported_is_negotiated(self, cache, multistore): + self.config(enabled_backends=multistore) + self.config(image_cache_dir=cache) to_check = self._get_list_of_version_ids('SUPPORTED') for version_id in to_check: self._assert_version_is_negotiated(version_id) - @ddt.data(default, enabled) - def test_deprecated_is_negotiated(self, stores): - self.config(enabled_backends=stores) + @ddt.data(*combos) + @ddt.unpack + def test_deprecated_is_negotiated(self, cache, multistore): + self.config(enabled_backends=multistore) + self.config(image_cache_dir=cache) to_check = self._get_list_of_version_ids('DEPRECATED') for version_id in to_check: self._assert_version_is_negotiated(version_id) - @ddt.data(default, enabled) - def test_experimental_is_negotiated(self, stores): - self.config(enabled_backends=stores) + @ddt.data(*combos) + @ddt.unpack + def test_experimental_is_negotiated(self, cache, multistore): + self.config(enabled_backends=multistore) + self.config(image_cache_dir=cache) to_check = self._get_list_of_version_ids('EXPERIMENTAL') for version_id in to_check: self._assert_version_is_negotiated(version_id) diff --git a/releasenotes/notes/api-2.16-8417b1e23322fedb.yaml b/releasenotes/notes/api-2.16-8417b1e23322fedb.yaml new file mode 100644 index 0000000000..0fa514da44 --- /dev/null +++ b/releasenotes/notes/api-2.16-8417b1e23322fedb.yaml @@ -0,0 +1,19 @@ +--- +features: + - | + When the Glance image cache is being used, the CURRENT version of + the Image service API, as indicated in the ``GET /versions`` response, + is 2.16. + +upgrade: + - | + The Image service API call ``PUT /v2/cache/{image_id}`` now returns + a 202 (Accepted) response code to indicate success. In glance 24.0.0 + (the initial Yoga release), it had mistakenly returned a 200. + +fixes: + - | + Bug `1971521 `_: + Fixed the success response code of the REST API call + ``PUT /v2/cache/{image_id}`` to be 202 (Accepted), following the + original design of the feature.