From 36ef500c4198415440056cf8dcb7d3d96f4466ab Mon Sep 17 00:00:00 2001 From: Hiromu Asahina Date: Wed, 22 Sep 2021 05:16:34 +0000 Subject: [PATCH] Add Location to responses of Create VNF Package According to SOL005 v3.3.1 Table 9.4.2.3.1-1 [1], the HTTP response shall include a "Location" HTTP header that contains the resource URI of the individual VNF package resource. In order to realize the above, this patch adds a Location header, which includes a URL of a created VNF Package, to responses for `POST {apiRoot}/vnfpkgm/{apiMajorVersion}/vnf_packages` requests. Also, this patch removes unused arguments from methods in ViewBuilder. [1] https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/005/03.03.01_60/gs_NFV-SOL005v030301p.pdf Signed-off-by: Hiromu Asahina Change-Id: I754afaaf910de0048f4f11e259c644b3e0baea99 Closes-Bug: #1915109 --- tacker/api/views/vnf_packages.py | 6 +++--- tacker/api/vnfpkgm/v1/controller.py | 15 ++++++++++----- tacker/tests/unit/vnfpkgm/test_controller.py | 8 +++++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/tacker/api/views/vnf_packages.py b/tacker/api/views/vnf_packages.py index 13f168087..31f903c0f 100644 --- a/tacker/api/views/vnf_packages.py +++ b/tacker/api/views/vnf_packages.py @@ -60,10 +60,10 @@ class ViewBuilder(base.BaseViewBuilder): return user_data_response - def create(self, request, vnf_package): + def create(self, vnf_package): return self._get_vnf_package(vnf_package) - def show(self, request, vnf_package): + def show(self, vnf_package): return self._get_vnf_package(vnf_package) def patch(self, vnf_package, new_vnf_package): @@ -77,7 +77,7 @@ class ViewBuilder(base.BaseViewBuilder): return response - def index(self, request, vnf_packages, all_fields=True, + def index(self, vnf_packages, all_fields=True, exclude_fields=None, fields=None, exclude_default=False): # Find out which fields are to be returned in the response. diff --git a/tacker/api/vnfpkgm/v1/controller.py b/tacker/api/vnfpkgm/v1/controller.py index 0a8f671e9..eaf95e90b 100644 --- a/tacker/api/vnfpkgm/v1/controller.py +++ b/tacker/api/vnfpkgm/v1/controller.py @@ -90,7 +90,10 @@ class VnfPkgmController(wsgi.Controller): vnf_package.create() - return self._view_builder.create(request, vnf_package) + headers = {"location": '/vnfpkgm/v1/vnf_packages/%s' % vnf_package.id} + result = self._view_builder.create(vnf_package) + + return wsgi.ResponseObject(result, headers=headers) @wsgi.response(http_client.OK) @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) @@ -111,7 +114,7 @@ class VnfPkgmController(wsgi.Controller): msg = _("Can not find requested vnf package: %s") % id raise webob.exc.HTTPNotFound(explanation=msg) - return self._view_builder.show(request, vnf_package) + return self._view_builder.show(vnf_package) @wsgi.response(http_client.OK) @wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN)) @@ -148,9 +151,11 @@ class VnfPkgmController(wsgi.Controller): vnf_packages = vnf_package_obj.VnfPackagesList.get_by_filters( request.context, read_deleted='no', filters=filters) - return self._view_builder.index(request, vnf_packages, - all_fields=all_fields, exclude_fields=exclude_fields, - fields=fields, exclude_default=exclude_default) + return self._view_builder.index(vnf_packages, + all_fields=all_fields, + exclude_fields=exclude_fields, + fields=fields, + exclude_default=exclude_default) @wsgi.response(http_client.NO_CONTENT) @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND, diff --git a/tacker/tests/unit/vnfpkgm/test_controller.py b/tacker/tests/unit/vnfpkgm/test_controller.py index 33fea8962..34c7376dd 100644 --- a/tacker/tests/unit/vnfpkgm/test_controller.py +++ b/tacker/tests/unit/vnfpkgm/test_controller.py @@ -62,13 +62,16 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package, '_vnf_package_create') @mock.patch.object(vnf_package.VnfPackage, '_from_db_object') - def test_create_with_status_202(self, mock_from_db, mock_vnf_pack): + def test_create_with_status_201(self, mock_from_db, mock_vnf_pack): body = {'userDefinedData': {'abc': 'xyz'}} req = fake_request.HTTPRequest.blank('/vnf_packages') req.body = jsonutils.dump_as_bytes(body) req.headers['Content-Type'] = 'application/json' req.method = 'POST' resp = req.get_response(self.app) + location_pattern = (r'http://localhost/vnfpkgm/v1/vnf_packages/' + r'([a-f]|\d|-){36}') + self.assertRegex(resp.headers['location'], location_pattern) self.assertEqual(http_client.CREATED, resp.status_code) @mock.patch.object(vnf_package, '_vnf_package_create') @@ -81,6 +84,9 @@ class TestController(base.TestCase): req.headers['Content-Type'] = 'application/json' req.method = 'POST' resp = req.get_response(self.app) + location_pattern = (r'http://localhost/vnfpkgm/v1/vnf_packages/' + r'([a-f]|\d|-){36}') + self.assertRegex(resp.headers['location'], location_pattern) self.assertEqual(http_client.CREATED, resp.status_code) @mock.patch.object(VnfSoftwareImage, 'get_by_id')