Merge "Bump Images API version to 2.11"

This commit is contained in:
Zuul 2020-10-02 06:29:53 +00:00 committed by Gerrit Code Review
commit 9fc9148564
4 changed files with 220 additions and 122 deletions

View File

@ -84,6 +84,8 @@ class VersionNegotiationFilter(wsgi.Middleware):
allowed_versions['v2.9'] = 2 allowed_versions['v2.9'] = 2
if CONF.enabled_backends: if CONF.enabled_backends:
allowed_versions['v2.8'] = 2 allowed_versions['v2.8'] = 2
allowed_versions['v2.10'] = 2
allowed_versions['v2.11'] = 2
return allowed_versions return allowed_versions
def _match_version_string(self, subject): def _match_version_string(self, subject):

View File

@ -78,9 +78,10 @@ class Controller(object):
version_objs = [] version_objs = []
if CONF.enabled_backends: if CONF.enabled_backends:
version_objs.extend([ version_objs.extend([
build_version_object(2.10, 'v2', 'CURRENT'), build_version_object(2.11, 'v2', 'CURRENT'),
build_version_object('2.10', 'v2', 'SUPPORTED'),
build_version_object(2.9, 'v2', 'SUPPORTED'), build_version_object(2.9, 'v2', 'SUPPORTED'),
build_version_object(2.8, 'v2', 'SUPPORTED') build_version_object(2.8, 'v2', 'SUPPORTED'),
]) ])
else: else:
version_objs.extend([ version_objs.extend([

View File

@ -15,81 +15,21 @@
"""Version-independent api tests""" """Version-independent api tests"""
import httplib2 import httplib2
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from six.moves import http_client from six.moves import http_client
from glance.tests import functional from glance.tests import functional
from glance.tests.unit import test_versions as tv
def _generate_v2_versions(url):
version_list = []
version_list.extend([
{
'id': 'v2.9',
'status': 'CURRENT',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.7',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.6',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.5',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.4',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.3',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.2',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.1',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
},
{
'id': 'v2.0',
'status': 'SUPPORTED',
'links': [{'rel': 'self', 'href': url % '2'}],
}
])
v2_versions = {'versions': version_list}
return v2_versions
def _generate_all_versions(url):
v2 = _generate_v2_versions(url)
all_versions = {'versions': v2['versions']}
return all_versions
class TestApiVersions(functional.FunctionalTest): class TestApiVersions(functional.FunctionalTest):
def test_version_configurations(self): def test_version_configurations(self):
"""Test that versioning is handled properly through all channels""" """Test that versioning is handled properly through all channels"""
self.start_servers(**self.__dict__.copy()) self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port url = 'http://127.0.0.1:%d' % self.api_port
versions = _generate_all_versions(url) versions = {'versions': tv.get_versions_list(url)}
# Verify version choices returned. # Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port) path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
@ -102,8 +42,41 @@ class TestApiVersions(functional.FunctionalTest):
def test_v2_api_configuration(self): def test_v2_api_configuration(self):
self.start_servers(**self.__dict__.copy()) self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port url = 'http://127.0.0.1:%d' % self.api_port
versions = _generate_v2_versions(url) versions = {'versions': tv.get_versions_list(url)}
# Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
http = httplib2.Http()
response, content_json = http.request(path, 'GET')
self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
content = jsonutils.loads(content_json.decode())
self.assertEqual(versions, content)
class TestApiVersionsMultistore(functional.MultipleBackendFunctionalTest):
def test_version_configurations(self):
"""Test that versioning is handled properly through all channels"""
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d' % self.api_port
versions = {'versions': tv.get_versions_list(url,
enabled_backends=True)}
# Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
http = httplib2.Http()
response, content_json = http.request(path, 'GET')
self.assertEqual(http_client.MULTIPLE_CHOICES, response.status)
content = jsonutils.loads(content_json.decode())
self.assertEqual(versions, content)
def test_v2_api_configuration(self):
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d' % self.api_port
versions = {'versions': tv.get_versions_list(url,
enabled_backends=True)}
# Verify version choices returned. # Verify version choices returned.
path = 'http://%s:%d' % ('127.0.0.1', self.api_port) path = 'http://%s:%d' % ('127.0.0.1', self.api_port)
@ -119,8 +92,8 @@ class TestApiPaths(functional.FunctionalTest):
super(TestApiPaths, self).setUp() super(TestApiPaths, self).setUp()
self.start_servers(**self.__dict__.copy()) self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port url = 'http://127.0.0.1:%d' % self.api_port
self.versions = _generate_all_versions(url) self.versions = {'versions': tv.get_versions_list(url)}
images = {'images': []} images = {'images': []}
self.images_json = jsonutils.dumps(images) self.images_json = jsonutils.dumps(images)

View File

@ -13,78 +13,112 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_serialization import jsonutils import ddt
from six.moves import http_client as http from six.moves import http_client as http
import webob import webob
from oslo_serialization import jsonutils
from glance.api.middleware import version_negotiation from glance.api.middleware import version_negotiation
from glance.api import versions from glance.api import versions
from glance.common.wsgi import Request as WsgiRequest from glance.common.wsgi import Request as WsgiRequest
from glance.tests.unit import base from glance.tests.unit import base
class VersionsTest(base.IsolatedUnitTest): # make this public so it doesn't need to be repeated for the
# functional tests
"""Test the version information returned from the API service.""" def get_versions_list(url, enabled_backends=False):
versions = [
def _get_versions_list(self, url): {
'id': 'v2.7',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.6',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.5',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.4',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.3',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.2',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.1',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.0',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
]
if enabled_backends:
versions = [ versions = [
{ {
'id': 'v2.9', 'id': 'v2.11',
'status': 'CURRENT', 'status': 'CURRENT',
'links': [{'rel': 'self', 'links': [{'rel': 'self',
'href': '%s/v2/' % url}], 'href': '%s/v2/' % url}],
}, },
{ {
'id': 'v2.7', 'id': 'v2.10',
'status': 'SUPPORTED', 'status': 'SUPPORTED',
'links': [{'rel': 'self', 'links': [{'rel': 'self',
'href': '%s/v2/' % url}], 'href': '%s/v2/' % url}],
}, },
{ {
'id': 'v2.6', 'id': 'v2.9',
'status': 'SUPPORTED', 'status': 'SUPPORTED',
'links': [{'rel': 'self', 'links': [{'rel': 'self',
'href': '%s/v2/' % url}], 'href': '%s/v2/' % url}],
}, },
{ {
'id': 'v2.5', 'id': 'v2.8',
'status': 'SUPPORTED', 'status': 'SUPPORTED',
'links': [{'rel': 'self', 'links': [{'rel': 'self',
'href': '%s/v2/' % url}], 'href': '%s/v2/' % url}],
}, }
{ ] + versions
'id': 'v2.4', else:
'status': 'SUPPORTED', versions.insert(0, {
'links': [{'rel': 'self', 'id': 'v2.9',
'href': '%s/v2/' % url}], 'status': 'CURRENT',
}, 'links': [{'rel': 'self',
{ 'href': '%s/v2/' % url}],
'id': 'v2.3', })
'status': 'SUPPORTED',
'links': [{'rel': 'self', return versions
'href': '%s/v2/' % url}],
},
{ class VersionsTest(base.IsolatedUnitTest):
'id': 'v2.2',
'status': 'SUPPORTED', """Test the version information returned from the API service."""
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.1',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
{
'id': 'v2.0',
'status': 'SUPPORTED',
'links': [{'rel': 'self',
'href': '%s/v2/' % url}],
},
]
return versions
def test_get_version_list(self): def test_get_version_list(self):
req = webob.Request.blank('/', base_url='http://127.0.0.1:9292/') req = webob.Request.blank('/', base_url='http://127.0.0.1:9292/')
@ -94,7 +128,14 @@ class VersionsTest(base.IsolatedUnitTest):
self.assertEqual(http.MULTIPLE_CHOICES, res.status_int) self.assertEqual(http.MULTIPLE_CHOICES, res.status_int)
self.assertEqual('application/json', res.content_type) self.assertEqual('application/json', res.content_type)
results = jsonutils.loads(res.body)['versions'] results = jsonutils.loads(res.body)['versions']
expected = self._get_versions_list('http://127.0.0.1:9292') expected = get_versions_list('http://127.0.0.1:9292')
self.assertEqual(expected, results)
self.config(enabled_backends='slow:one,fast:two')
res = versions.Controller().index(req)
results = jsonutils.loads(res.body)['versions']
expected = get_versions_list('http://127.0.0.1:9292',
enabled_backends=True)
self.assertEqual(expected, results) self.assertEqual(expected, results)
def test_get_version_list_public_endpoint(self): def test_get_version_list_public_endpoint(self):
@ -106,7 +147,14 @@ class VersionsTest(base.IsolatedUnitTest):
self.assertEqual(http.MULTIPLE_CHOICES, res.status_int) self.assertEqual(http.MULTIPLE_CHOICES, res.status_int)
self.assertEqual('application/json', res.content_type) self.assertEqual('application/json', res.content_type)
results = jsonutils.loads(res.body)['versions'] results = jsonutils.loads(res.body)['versions']
expected = self._get_versions_list('https://example.com:9292') expected = get_versions_list('https://example.com:9292')
self.assertEqual(expected, results)
self.config(enabled_backends='slow:one,fast:two')
res = versions.Controller().index(req)
results = jsonutils.loads(res.body)['versions']
expected = get_versions_list('https://example.com:9292',
enabled_backends=True)
self.assertEqual(expected, results) self.assertEqual(expected, results)
def test_get_version_list_secure_proxy_ssl_header(self): def test_get_version_list_secure_proxy_ssl_header(self):
@ -118,7 +166,13 @@ class VersionsTest(base.IsolatedUnitTest):
self.assertEqual(http.MULTIPLE_CHOICES, res.status_int) self.assertEqual(http.MULTIPLE_CHOICES, res.status_int)
self.assertEqual('application/json', res.content_type) self.assertEqual('application/json', res.content_type)
results = jsonutils.loads(res.body)['versions'] results = jsonutils.loads(res.body)['versions']
expected = self._get_versions_list(url) expected = get_versions_list(url)
self.assertEqual(expected, results)
self.config(enabled_backends='slow:one,fast:two')
res = versions.Controller().index(req)
results = jsonutils.loads(res.body)['versions']
expected = get_versions_list(url, enabled_backends=True)
self.assertEqual(expected, results) self.assertEqual(expected, results)
def test_get_version_list_secure_proxy_ssl_header_https(self): def test_get_version_list_secure_proxy_ssl_header_https(self):
@ -132,7 +186,13 @@ class VersionsTest(base.IsolatedUnitTest):
self.assertEqual(http.MULTIPLE_CHOICES, res.status_int) self.assertEqual(http.MULTIPLE_CHOICES, res.status_int)
self.assertEqual('application/json', res.content_type) self.assertEqual('application/json', res.content_type)
results = jsonutils.loads(res.body)['versions'] results = jsonutils.loads(res.body)['versions']
expected = self._get_versions_list(ssl_url) expected = get_versions_list(ssl_url)
self.assertEqual(expected, results)
self.config(enabled_backends='slow:one,fast:two')
res = versions.Controller().index(req)
results = jsonutils.loads(res.body)['versions']
expected = get_versions_list(ssl_url, enabled_backends=True)
self.assertEqual(expected, results) self.assertEqual(expected, results)
def test_get_version_list_for_external_app(self): def test_get_version_list_for_external_app(self):
@ -143,7 +203,13 @@ class VersionsTest(base.IsolatedUnitTest):
self.assertEqual(http.MULTIPLE_CHOICES, res.status_int) self.assertEqual(http.MULTIPLE_CHOICES, res.status_int)
self.assertEqual('application/json', res.content_type) self.assertEqual('application/json', res.content_type)
results = jsonutils.loads(res.body)['versions'] results = jsonutils.loads(res.body)['versions']
expected = self._get_versions_list(url) expected = get_versions_list(url)
self.assertEqual(expected, results)
self.config(enabled_backends='slow:one,fast:two')
res = versions.Controller().index(req)
results = jsonutils.loads(res.body)['versions']
expected = get_versions_list(url, enabled_backends=True)
self.assertEqual(expected, results) self.assertEqual(expected, results)
@ -203,12 +269,55 @@ class VersionNegotiationTest(base.IsolatedUnitTest):
self.middleware.process_request(request) self.middleware.process_request(request)
self.assertEqual('/v2/images', request.path_info) self.assertEqual('/v2/images', request.path_info)
def test_request_url_v2_10_unsupported(self): # 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):
request = webob.Request.blank('/v2.8/images')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
def test_request_url_v2_8_enabled_supported(self):
self.config(enabled_backends='slow:one,fast:two')
request = webob.Request.blank('/v2.8/images')
self.middleware.process_request(request)
self.assertEqual('/v2/images', request.path_info)
def test_request_url_v2_10_default_unsupported(self):
request = webob.Request.blank('/v2.10/images') request = webob.Request.blank('/v2.10/images')
resp = self.middleware.process_request(request) resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller) self.assertIsInstance(resp, versions.Controller)
def test_request_url_v2_10_enabled_supported(self):
self.config(enabled_backends='slow:one,fast:two')
request = webob.Request.blank('/v2.10/images')
self.middleware.process_request(request)
self.assertEqual('/v2/images', request.path_info)
def test_request_url_v2_11_default_unsupported(self):
request = webob.Request.blank('/v2.11/images')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
def test_request_url_v2_11_enabled_supported(self):
self.config(enabled_backends='slow:one,fast:two')
request = webob.Request.blank('/v2.11/images')
self.middleware.process_request(request)
self.assertEqual('/v2/images', request.path_info)
# version 2.12 does not exist
def test_request_url_v2_12_default_unsupported(self):
request = webob.Request.blank('/v2.12/images')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
def test_request_url_v2_12_enabled_unsupported(self):
self.config(enabled_backends='slow:one,fast:two')
request = webob.Request.blank('/v2.12/images')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
@ddt.ddt
class VersionsAndNegotiationTest(VersionNegotiationTest, VersionsTest): class VersionsAndNegotiationTest(VersionNegotiationTest, VersionsTest):
""" """
@ -230,25 +339,38 @@ class VersionsAndNegotiationTest(VersionNegotiationTest, VersionsTest):
expected = "/%s/images" % major expected = "/%s/images" % major
self.assertEqual(expected, request.path_info) self.assertEqual(expected, request.path_info)
def test_current_is_negotiated(self): # 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'
@ddt.data(default, enabled)
def test_current_is_negotiated(self, stores):
# NOTE(rosmaita): Bug 1609571: the versions response was correct, but # NOTE(rosmaita): Bug 1609571: the versions response was correct, but
# the negotiation had not been updated for the CURRENT version. # the negotiation had not been updated for the CURRENT version.
self.config(enabled_backends=stores)
to_check = self._get_list_of_version_ids('CURRENT') to_check = self._get_list_of_version_ids('CURRENT')
self.assertTrue(to_check) self.assertTrue(to_check)
for version_id in to_check: for version_id in to_check:
self._assert_version_is_negotiated(version_id) self._assert_version_is_negotiated(version_id)
def test_supported_is_negotiated(self): @ddt.data(default, enabled)
def test_supported_is_negotiated(self, stores):
self.config(enabled_backends=stores)
to_check = self._get_list_of_version_ids('SUPPORTED') to_check = self._get_list_of_version_ids('SUPPORTED')
for version_id in to_check: for version_id in to_check:
self._assert_version_is_negotiated(version_id) self._assert_version_is_negotiated(version_id)
def test_deprecated_is_negotiated(self): @ddt.data(default, enabled)
def test_deprecated_is_negotiated(self, stores):
self.config(enabled_backends=stores)
to_check = self._get_list_of_version_ids('DEPRECATED') to_check = self._get_list_of_version_ids('DEPRECATED')
for version_id in to_check: for version_id in to_check:
self._assert_version_is_negotiated(version_id) self._assert_version_is_negotiated(version_id)
def test_experimental_is_negotiated(self): @ddt.data(default, enabled)
def test_experimental_is_negotiated(self, stores):
self.config(enabled_backends=stores)
to_check = self._get_list_of_version_ids('EXPERIMENTAL') to_check = self._get_list_of_version_ids('EXPERIMENTAL')
for version_id in to_check: for version_id in to_check:
self._assert_version_is_negotiated(version_id) self._assert_version_is_negotiated(version_id)