From 3712dccfdb7ee30243e4efc09fcad1c3197bdb51 Mon Sep 17 00:00:00 2001 From: Brian Rosmaita Date: Fri, 9 Feb 2018 17:12:31 -0500 Subject: [PATCH] Use configured value for import-methods header In Image API v2.6, the image-create response returns an 'OpenStack-image-import-methods' header containing a list of methods available in that cloud. This patch populates that list from the enabled_import_methods configuration setting. Following RFC 7230, if the enabled_import_methods is empty, the header is not returned with the response. Change-Id: I3066da36a0fbb83fe492bddb193975e42ffc5084 Closes-bug: #1748559 --- glance/api/v2/images.py | 13 +++--- glance/tests/unit/v2/test_images_resource.py | 45 ++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/glance/api/v2/images.py b/glance/api/v2/images.py index a736219842..b78b79d840 100644 --- a/glance/api/v2/images.py +++ b/glance/api/v2/images.py @@ -892,12 +892,15 @@ class ResponseSerializer(wsgi.JSONResponseSerializer): response.status_int = http.CREATED self.show(response, image) response.location = self._get_image_href(image) - # TODO(jokke): make this configurable when swift-local is implemented - # and remove the if statement with the config option. + # TODO(rosmaita): remove the outer 'if' statement when the + # enable_image_import config option is removed if CONF.enable_image_import: - import_methods = ("OpenStack-image-import-methods", - "glance-direct") - response.headerlist.append(import_methods) + # according to RFC7230, headers should not have empty fields + # see http://httpwg.org/specs/rfc7230.html#field.components + if CONF.enabled_import_methods: + import_methods = ("OpenStack-image-import-methods", + ','.join(CONF.enabled_import_methods)) + response.headerlist.append(import_methods) def show(self, response, image): image_view = self._format_image(image) diff --git a/glance/tests/unit/v2/test_images_resource.py b/glance/tests/unit/v2/test_images_resource.py index f2ceeafb49..f0408a5fd8 100644 --- a/glance/tests/unit/v2/test_images_resource.py +++ b/glance/tests/unit/v2/test_images_resource.py @@ -3567,6 +3567,51 @@ class TestImagesSerializer(test_utils.BaseTestCase): self.assertEqual('application/json', response.content_type) self.assertEqual('/v2/images/%s' % UUID1, response.location) + def test_create_has_import_methods_header(self): + # NOTE(rosmaita): enabled_import_methods is defined as type + # oslo.config.cfg.ListOpt, so it is stored internally as a list + # but is converted to a string for output in the HTTP header + + header_name = 'OpenStack-image-import-methods' + + # check multiple methods + enabled_methods = ['one', 'two', 'three'] + self.config(enabled_import_methods=enabled_methods) + response = webob.Response() + self.serializer.create(response, self.fixtures[0]) + self.assertEqual(http.CREATED, response.status_int) + header_value = response.headers.get(header_name) + self.assertIsNotNone(header_value) + self.assertItemsEqual(enabled_methods, header_value.split(',')) + + # check single method + self.config(enabled_import_methods=['swift-party-time']) + response = webob.Response() + self.serializer.create(response, self.fixtures[0]) + self.assertEqual(http.CREATED, response.status_int) + header_value = response.headers.get(header_name) + self.assertIsNotNone(header_value) + self.assertEqual('swift-party-time', header_value) + + # no header for empty config value + self.config(enabled_import_methods=[]) + response = webob.Response() + self.serializer.create(response, self.fixtures[0]) + self.assertEqual(http.CREATED, response.status_int) + headers = response.headers.keys() + self.assertNotIn(header_name, headers) + + # TODO(rosmaita): remove this test when the enable_image_import + # option is removed + def test_create_has_no_import_methods_header(self): + header_name = 'OpenStack-image-import-methods' + self.config(enable_image_import=False) + response = webob.Response() + self.serializer.create(response, self.fixtures[0]) + self.assertEqual(http.CREATED, response.status_int) + headers = response.headers.keys() + self.assertNotIn(header_name, headers) + def test_update(self): expected = { 'id': UUID1,