diff --git a/tacker/api/vnfpkgm/v1/controller.py b/tacker/api/vnfpkgm/v1/controller.py index 0b0bfcb2f..d15e18df3 100644 --- a/tacker/api/vnfpkgm/v1/controller.py +++ b/tacker/api/vnfpkgm/v1/controller.py @@ -104,8 +104,6 @@ class VnfPkgmController(wsgi.Controller): @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) def show(self, request, id): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'show') # check if id is of type uuid format if not uuidutils.is_uuid_like(id): @@ -119,6 +117,9 @@ class VnfPkgmController(wsgi.Controller): if CONF.oslo_policy.enhanced_tacker_policy: context.can(vnf_package_policies.VNFPKGM % 'show', target=self._get_policy_target(vnf_package)) + else: + context.can(vnf_package_policies.VNFPKGM % 'show', + target={'project_id': vnf_package.tenant_id}) except exceptions.VnfPackageNotFound: msg = _("Can not find requested vnf package: %s") % id raise webob.exc.HTTPNotFound(explanation=msg) @@ -229,13 +230,14 @@ class VnfPkgmController(wsgi.Controller): http_client.CONFLICT)) def delete(self, request, id): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'delete') vnf_package = self._get_vnf_package(id, request) if CONF.oslo_policy.enhanced_tacker_policy: context.can(vnf_package_policies.VNFPKGM % 'delete', target=self._get_policy_target(vnf_package)) + else: + context.can(vnf_package_policies.VNFPKGM % 'delete', + target={'project_id': vnf_package.tenant_id}) if (vnf_package.operational_state == fields.PackageOperationalStateType.ENABLED or @@ -271,14 +273,14 @@ class VnfPkgmController(wsgi.Controller): http_client.REQUESTED_RANGE_NOT_SATISFIABLE)) def fetch_vnf_package_content(self, request, id): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'fetch_package_content') vnf_package = self._get_vnf_package(id, request) if CONF.oslo_policy.enhanced_tacker_policy: context.can(vnf_package_policies.VNFPKGM % 'fetch_package_content', target=self._get_policy_target(vnf_package)) - + else: + context.can(vnf_package_policies.VNFPKGM % 'fetch_package_content', + target={'project_id': vnf_package.tenant_id}) if vnf_package.onboarding_state != \ fields.PackageOnboardingStateType.ONBOARDED: msg = _("VNF Package %(id)s onboarding state " @@ -398,9 +400,6 @@ class VnfPkgmController(wsgi.Controller): http_client.CONFLICT)) def upload_vnf_package_content(self, request, id, body): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can( - vnf_package_policies.VNFPKGM % 'upload_package_content') # check if id is of type uuid format if not uuidutils.is_uuid_like(id): @@ -410,9 +409,15 @@ class VnfPkgmController(wsgi.Controller): try: vnf_package = vnf_package_obj.VnfPackage.get_by_id( request.context, id) + if not CONF.oslo_policy.enhanced_tacker_policy: + context.can( + vnf_package_policies.VNFPKGM % 'upload_package_content', + target={'project_id': vnf_package.tenant_id}) except exceptions.VnfPackageNotFound: msg = _("Can not find requested vnf package: %s") % id return self._make_problem_detail('Not Found', msg, 404) + except exceptions.PolicyNotAuthorized: + raise except Exception as e: return self._make_problem_detail( 'Internal Server Error', str(e), 500) @@ -495,7 +500,6 @@ class VnfPkgmController(wsgi.Controller): def upload_vnf_package_from_uri(self, request, id, body): context = request.environ['tacker.context'] - context.can(vnf_package_policies.VNFPKGM % 'upload_from_uri') url = body['addressInformation'] if not utils.is_valid_url(url): @@ -503,6 +507,10 @@ class VnfPkgmController(wsgi.Controller): raise webob.exc.HTTPBadRequest(explanation=msg) vnf_package = self._get_vnf_package(id, request) + if not CONF.oslo_policy.enhanced_tacker_policy: + context.can( + vnf_package_policies.VNFPKGM % 'upload_from_uri', + target={'project_id': vnf_package.tenant_id}) if vnf_package.onboarding_state != \ fields.PackageOnboardingStateType.CREATED: @@ -528,13 +536,16 @@ class VnfPkgmController(wsgi.Controller): @validation.schema(vnf_packages.patch) def patch(self, request, id, body): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'patch') old_vnf_package = self._get_vnf_package(id, request) if CONF.oslo_policy.enhanced_tacker_policy: context.can(vnf_package_policies.VNFPKGM % 'patch', target=self._get_policy_target(old_vnf_package)) + else: + context.can( + vnf_package_policies.VNFPKGM % 'patch', + target={'project_id': old_vnf_package.tenant_id}) + vnf_package = old_vnf_package.obj_clone() user_data = body.get('userDefinedData') @@ -586,8 +597,6 @@ class VnfPkgmController(wsgi.Controller): http_client.INTERNAL_SERVER_ERROR)) def get_vnf_package_vnfd(self, request, id): context = request.environ['tacker.context'] - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'get_vnf_package_vnfd') valid_accept_headers = ['application/zip', 'text/plain'] accept_headers = request.headers['Accept'].split(',') @@ -604,7 +613,10 @@ class VnfPkgmController(wsgi.Controller): if CONF.oslo_policy.enhanced_tacker_policy: context.can(vnf_package_policies.VNFPKGM % 'get_vnf_package_vnfd', target=self._get_policy_target(vnf_package)) - + else: + context.can( + vnf_package_policies.VNFPKGM % 'get_vnf_package_vnfd', + target={'project_id': vnf_package.tenant_id}) if vnf_package.onboarding_state != \ fields.PackageOnboardingStateType.ONBOARDED: msg = _("VNF Package %(id)s state is not " @@ -646,9 +658,6 @@ class VnfPkgmController(wsgi.Controller): http_client.REQUESTED_RANGE_NOT_SATISFIABLE)) def fetch_vnf_package_artifacts(self, request, id, artifact_path): context = request.environ['tacker.context'] - # get policy - if not CONF.oslo_policy.enhanced_tacker_policy: - context.can(vnf_package_policies.VNFPKGM % 'fetch_artifact') # get vnf_package if not uuidutils.is_uuid_like(id): @@ -663,6 +672,11 @@ class VnfPkgmController(wsgi.Controller): # get policy context.can(vnf_package_policies.VNFPKGM % 'fetch_artifact', target=self._get_policy_target(vnf_package)) + else: + context.can( + vnf_package_policies.VNFPKGM % 'fetch_artifact', + target={'project_id': vnf_package.tenant_id}) + except exceptions.VnfPackageNotFound: msg = _("Can not find requested vnf package: %s") % id raise webob.exc.HTTPNotFound(explanation=msg) diff --git a/tacker/tests/unit/policies/test_vnf_package.py b/tacker/tests/unit/policies/test_vnf_package.py new file mode 100644 index 000000000..67a46b815 --- /dev/null +++ b/tacker/tests/unit/policies/test_vnf_package.py @@ -0,0 +1,307 @@ +# Copyright (C) 2024 NEC, Corp. +# All Rights Reserved. +# +# 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. + +import os +from unittest import mock +import urllib + +from tacker.api.vnfpkgm.v1 import controller +from tacker.common import csar_utils +from tacker.common import exceptions +from tacker.conductor.conductorrpc.vnf_pkgm_rpc import VNFPackageRPCAPI +from tacker.glance_store import store as glance_store +from tacker.objects import vnf_package +from tacker.objects.vnf_software_image import VnfSoftwareImage +from tacker.policies import vnf_package as policies +from tacker.tests import constants +from tacker.tests.unit import fake_request +from tacker.tests.unit.policies import base as base_test +from tacker.tests.unit.vnfpkgm import fakes +from tacker.tests import utils +from tacker import wsgi + + +class VNFPackagePolicyTest(base_test.BasePolicyTest): + """Test VNF Package APIs policies with all possible context. + + This class defines the set of context with different roles + which are allowed and not allowed to pass the policy checks. + With those set of context, it will call the API operation and + verify the expected behaviour. + """ + + def setUp(self): + super(VNFPackagePolicyTest, self).setUp() + self.controller = controller.VnfPkgmController() + # Below user's context will be allowed to create VNF package or + # a few of the VNF package operations in their project. + self.project_authorized_contexts = [ + self.legacy_admin_context, self.project_admin_context, + self.project_member_context, self.project_reader_context, + self.project_foo_context, self.other_project_member_context, + self.other_project_reader_context + ] + self.project_unauthorized_contexts = [] + + # Admin or any user in same project will be allowed to get, + # instantiate, terminate etc operations of VNF package of + # their project. + self.project_member_authorized_contexts = [ + self.legacy_admin_context, self.project_admin_context, + self.project_member_context, self.project_reader_context, + self.project_foo_context + ] + # User from other project will not be allowed to get or perform + # the other project's VNF package operations. + self.project_member_unauthorized_contexts = [ + self.other_project_member_context, + self.other_project_reader_context + ] + + @mock.patch.object(vnf_package, '_vnf_package_create') + @mock.patch.object(vnf_package.VnfPackage, '_from_db_object') + def test_create_vnf_package( + self, mock_from_db, mock_vnf_pack): + body = {'userDefinedData': {'abc': 'xyz'}} + req = fake_request.HTTPRequest.blank('/vnf_packages') + rule_name = policies.VNFPKGM % 'create' + self.common_policy_check(self.project_authorized_contexts, + self.project_unauthorized_contexts, + rule_name, + self.controller.create, + req, body=body) + + @mock.patch.object(VnfSoftwareImage, 'get_by_id') + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_show_vnf_package( + self, mock_vnf_by_id, mock_sw_image_by_id): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={'tenant_id': self.project_id}) + mock_sw_image_by_id.return_value = fakes.return_software_image() + rule_name = policies.VNFPKGM % 'show' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.show, + req, constants.UUID) + + @mock.patch.object(vnf_package.VnfPackagesList, "get_by_marker_filter") + def test_index_vnf_package( + self, mock_vnf_list): + req = fake_request.HTTPRequest.blank('/vnf_packages/') + rule_name = policies.VNFPKGM % 'index' + self.common_policy_check(self.project_authorized_contexts, + self.project_unauthorized_contexts, + rule_name, + self.controller.index, + req) + + @mock.patch.object(vnf_package.VnfPackage, "destroy") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(VNFPackageRPCAPI, "delete_vnf_package") + def test_delete_vnf_package( + self, mock_delete_rpc, mock_vnf_by_id, mock_vnf_pack_destroy): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': self.project_id, + 'operational_state': 'DISABLED'}) + rule_name = policies.VNFPKGM % 'delete' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.delete, + req, constants.UUID) + + @mock.patch.object(controller.VnfPkgmController, "_download") + @mock.patch.object(controller.VnfPkgmController, "_get_range_from_request") + @mock.patch.object(glance_store, 'get_csar_size') + @mock.patch.object(vnf_package.VnfPackage, 'save') + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_fetch_package_content_vnf_package( + self, mock_vnf_by_id, mock_save, + mock_get_csar_size, + mock_get_range, + mock_download): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/' % constants.UUID) + req.response = "" + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={'tenant_id': self.project_id}) + mock_get_csar_size.return_value = 1000 + mock_get_range.return_value = "10-20, 21-30" + mock_download.return_value = "Response" + rule_name = policies.VNFPKGM % 'fetch_package_content' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.fetch_vnf_package_content, + req, constants.UUID) + + @mock.patch.object(glance_store, 'delete_csar') + @mock.patch.object(csar_utils, 'load_csar_data') + @mock.patch.object(glance_store, 'load_csar') + @mock.patch.object(glance_store, 'store_csar') + @mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_content") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(vnf_package.VnfPackage, "save") + def test_upload_vnf_package_content_package( + self, mock_vnf_pack_save, + mock_vnf_by_id, + mock_upload_vnf_package_content, + mock_glance_store, + mock_load_csar, + mock_load_csar_data, + mock_delete_csar): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': self.project_id, + 'onboarding_state': 'CREATED'}) + mock_glance_store.return_value = ( + 'location', 0, 'checksum', 'multihash', 'loc_meta') + rule_name = policies.VNFPKGM % 'upload_package_content' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.upload_vnf_package_content, + req, constants.UUID, + body={'dummy': {'val': 'foo'}}) + + @mock.patch.object(urllib.request, 'urlopen') + @mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_from_uri") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(vnf_package.VnfPackage, "save") + def test_upload_vnf_package_from_uri( + self, mock_vnf_pack_save, + mock_vnf_by_id, + mock_upload_vnf_package_from_uri, + mock_url_open): + rule_name = policies.VNFPKGM % 'upload_from_uri' + body = {"addressInformation": "http://localhost/test_data.zip"} + # NOTE(gmann): This API is little different to test from other APIs. + # In the upload_vnf_package API, vnf package object's onboarding_state + # is being modified to 'UPLOADING' and if we use common_policy_check() + # then first context API call will pass but any further context API + # call will fail. The next context API call will fail because it will + # have the modified vnf package object whose onboarding_state is + # 'UPLOADING' and API raise 409 error. To solve this issue, we have + # to call the API with each context in loop so that we can reset the + # vnf package object's onboarding_state value before API controller + # method is called. + for cxtx in self.project_member_authorized_contexts: + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + req.environ['tacker.context'] = cxtx + vnf_package_obj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': self.project_id, + 'onboarding_state': 'CREATED'}) + mock_vnf_by_id.return_value = vnf_package_obj + self.controller.upload_vnf_package_from_uri( + req, constants.UUID, body=body) + for cxtx in self.project_member_unauthorized_contexts: + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + req.environ['tacker.context'] = cxtx + vnf_package_obj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': self.project_id, + 'onboarding_state': 'CREATED'}) + mock_vnf_by_id.return_value = vnf_package_obj + exc = self.assertRaises( + exceptions.PolicyNotAuthorized, + self.controller.upload_vnf_package_from_uri, + req, constants.UUID, body=body) + self.assertEqual( + "Policy doesn't allow %s to be performed." % rule_name, + exc.format_message()) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(vnf_package.VnfPackage, "save") + def test_patch_vnf_package( + self, mock_vnf_pack_save, + mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' % constants.UUID) + vnf_package_obj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': self.project_id, + 'onboarding_state': 'CREATED', + "user_defined_data": {"testKey1": "val01"}}) + mock_vnf_by_id.return_value = vnf_package_obj + body = {"operationalState": "ENABLED", + "userDefinedData": {"testKey1": "val01", + "testKey2": "val02", + "testkey3": "val03"}} + rule_name = policies.VNFPKGM % 'patch' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.patch, + req, constants.UUID, body=body) + + @mock.patch.object(VNFPackageRPCAPI, "get_vnf_package_vnfd") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_get_vnf_package_vnfd( + self, mock_vnf_by_id, mock_get_vnf_package_vnfd): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/vnfd' % constants.UUID) + req.headers['Accept'] = 'application/zip' + req.response = wsgi.ResponseObject({}) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={'tenant_id': self.project_id}) + fake_vnfd_data = fakes.return_vnfd_data(csar_without_tosca_meta=True) + mock_get_vnf_package_vnfd.return_value = fake_vnfd_data + rule_name = policies.VNFPKGM % 'get_vnf_package_vnfd' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.get_vnf_package_vnfd, + req, constants.UUID) + + @mock.patch.object(controller.VnfPkgmController, "_download_vnf_artifact") + @mock.patch.object(controller.VnfPkgmController, "_get_csar_path") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_fetch_vnf_package_artifacts( + self, mock_vnf_by_id, mock_get_csar_path, + mock_download_vnf_artifact): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/artifacts/%s' + % (constants.UUID, constants.ARTIFACT_PATH)) + req.headers['Range'] = 'bytes=10-30' + req.response = wsgi.ResponseObject({}) + extract_path = utils.test_etc_sample( + 'sample_vnf_package_csar_in_meta_and_manifest') + absolute_artifact_path = ( + os.path.join(extract_path, constants.ARTIFACT_PATH)) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={'tenant_id': self.project_id}, + vnf_artifact_updates={'artifact_path': absolute_artifact_path}) + with open(absolute_artifact_path, 'rb') as f: + data = f.read() + mock_download_vnf_artifact.return_value = data + rule_name = policies.VNFPKGM % 'fetch_artifact' + self.common_policy_check(self.project_member_authorized_contexts, + self.project_member_unauthorized_contexts, + rule_name, + self.controller.fetch_vnf_package_artifacts, + req, constants.UUID, absolute_artifact_path) diff --git a/tacker/tests/unit/vnfpkgm/test_controller.py b/tacker/tests/unit/vnfpkgm/test_controller.py index 5b52fc049..9e1c085c6 100644 --- a/tacker/tests/unit/vnfpkgm/test_controller.py +++ b/tacker/tests/unit/vnfpkgm/test_controller.py @@ -103,7 +103,9 @@ class TestController(base.TestCase): def test_show(self, mock_vnf_by_id, mock_sw_image_by_id): req = fake_request.HTTPRequest.blank( '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) mock_sw_image_by_id.return_value = fakes.return_software_image() expected_result = fakes.VNFPACKAGE_RESPONSE res_dict = self.controller.show(req, constants.UUID) @@ -659,11 +661,13 @@ class TestController(base.TestCase): @mock.patch.object(VNFPackageRPCAPI, "delete_vnf_package") def test_delete_with_204_status(self, mock_delete_rpc, mock_vnf_by_id, mock_vnf_pack_destroy): - vnfpkg_updates = {'operational_state': 'DISABLED'} - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnfpkg_updates) req = fake_request.HTTPRequest.blank( '/vnf_packages/%s' % constants.UUID) + vnfpkg_updates = { + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnfpkg_updates) req.headers['Content-Type'] = 'application/json' req.method = 'DELETE' resp = req.get_response(self.app) @@ -686,24 +690,26 @@ class TestController(base.TestCase): @mock.patch.object(objects.VnfPackage, "get_by_id") def test_delete_with_operational_state_enabled(self, mock_vnf_by_id): - vnfpkg_updates = { - 'operational_state': fields.PackageOperationalStateType.ENABLED} - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnfpkg_updates) req = fake_request.HTTPRequest.blank( '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + vnfpkg_updates = { + 'operational_state': fields.PackageOperationalStateType.ENABLED, + 'tenant_id': req.environ['tacker.context'].project_id} + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnfpkg_updates) self.assertRaises(exc.HTTPConflict, self.controller.delete, req, constants.UUID) @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_delete_with_usage_state_in_use(self, mock_vnf_by_id): - vnfpkg_updates = { - 'usage_state': fields.PackageUsageStateType.IN_USE} - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnfpkg_updates) req = fake_request.HTTPRequest.blank( '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + vnfpkg_updates = { + 'usage_state': fields.PackageUsageStateType.IN_USE, + 'tenant_id': req.environ['tacker.context'].project_id} + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnfpkg_updates) self.assertRaises(exc.HTTPConflict, self.controller.delete, req, constants.UUID) @@ -716,17 +722,19 @@ class TestController(base.TestCase): mock_vnf_by_id, mock_upload_vnf_package_content, mock_glance_store): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' + % constants.UUID) + updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} vnf_package_dict = fakes.fake_vnf_package(updates) vnf_package_obj = objects.VnfPackage(**vnf_package_dict) mock_vnf_by_id.return_value = vnf_package_obj mock_vnf_pack_save.return_value = vnf_package_obj mock_glance_store.return_value = 'location', 0, 'checksum',\ 'multihash', 'loc_meta' - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s/package_content' - % constants.UUID) req.headers['Content-Type'] = 'application/zip' req.method = 'PUT' req.body = jsonutils.dump_as_bytes({'dummy': {'val': 'foo'}}) @@ -768,11 +776,14 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_upload_vnf_package_content_with_invalid_status(self, mock_vnf_by_id): - vnf_obj = fakes.return_vnfpkg_obj() - vnf_obj.__setattr__('onboarding_state', 'ONBOARDED') - mock_vnf_by_id.return_value = vnf_obj req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/package_content' % constants.UUID) + + vnf_obj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + vnf_obj.__setattr__('onboarding_state', 'ONBOARDED') + mock_vnf_by_id.return_value = vnf_obj req.headers['Content-Type'] = 'application/zip' req.method = 'PUT' req.body = jsonutils.dump_as_bytes({'dummy': {'val': 'foo'}}) @@ -792,15 +803,17 @@ class TestController(base.TestCase): mock_upload_vnf_package_from_uri, mock_url_open): body = {"addressInformation": "http://localhost/test_data.zip"} + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} vnf_package_dict = fakes.fake_vnf_package(updates) vnf_package_obj = objects.VnfPackage(**vnf_package_dict) mock_vnf_by_id.return_value = vnf_package_obj mock_vnf_pack_save.return_value = vnf_package_obj - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s/package_content/upload_from_uri' - % constants.UUID) req.headers['Content-Type'] = 'application/json' req.method = 'POST' req.body = jsonutils.dump_as_bytes(body) @@ -837,12 +850,14 @@ class TestController(base.TestCase): mock_vnf_by_id, mock_url_open): body = {"addressInformation": "http://localhost/test_data.zip"} - vnf_obj = fakes.return_vnfpkg_obj() - vnf_obj.__setattr__('onboarding_state', 'ONBOARDED') - mock_vnf_by_id.return_value = vnf_obj req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/package_content/upload_from_uri' % constants.UUID) + vnf_obj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + vnf_obj.__setattr__('onboarding_state', 'ONBOARDED') + mock_vnf_by_id.return_value = vnf_obj self.assertRaises(exc.HTTPConflict, self.controller.upload_vnf_package_from_uri, req, constants.UUID, body=body) @@ -861,7 +876,12 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") @mock.patch.object(vnf_package.VnfPackage, "save") def test_patch(self, mock_save, mock_vnf_by_id): - vnf_package_updates = {'operational_state': 'DISABLED'} + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' + % constants.UUID) + vnf_package_updates = { + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} mock_vnf_by_id.return_value = \ fakes.return_vnfpkg_obj(vnf_package_updates=vnf_package_updates) @@ -869,9 +889,6 @@ class TestController(base.TestCase): "userDefinedData": {"testKey1": "val01", "testKey2": "val02", "testkey3": "val03"}} - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s' - % constants.UUID) req.headers['Content-Type'] = 'application/json' req.method = 'PATCH' req.body = jsonutils.dump_as_bytes(req_body) @@ -905,17 +922,19 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") @mock.patch.object(vnf_package.VnfPackage, "save") def test_patch_update_existing_user_data(self, mock_save, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' + % constants.UUID) + fake_obj = fakes.return_vnfpkg_obj(vnf_package_updates={ "operational_state": "DISABLED", "onboarding_state": "CREATED", "user_data": {"testKey1": "val01", "testKey2": "val02", - "testKey3": "val03"}}) + "testKey3": "val03"}, + "tenant_id": req.environ['tacker.context'].project_id}) mock_vnf_by_id.return_value = fake_obj req_body = {"userDefinedData": {"testKey1": "changed_val01", "testKey2": "changed_val02", "testKey3": "changed_val03"}} - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s' - % constants.UUID) req.headers['Content-Type'] = 'application/json' req.method = 'PATCH' req.body = jsonutils.dump_as_bytes(req_body) @@ -927,11 +946,15 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "save") def test_patch_failed_with_same_user_data(self, mock_save, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank('/vnf_packages/%s' + % constants.UUID) + vnf_package_updates = {"operational_state": "DISABLED", "onboarding_state": "CREATED", "user_data": {"testKey1": "val01", "testKey2": "val02", - "testkey3": "val03"}} + "testkey3": "val03"}, + 'tenant_id': req.environ['tacker.context'].project_id} req_body = {"userDefinedData": {"testKey1": "val01", "testKey2": "val02", "testkey3": "val03"}} @@ -939,8 +962,6 @@ class TestController(base.TestCase): vnf_package_updates=vnf_package_updates) mock_vnf_by_id.return_value = fake_obj - req = fake_request.HTTPRequest.blank('/vnf_packages/%s' - % constants.UUID) self.assertRaises(exc.HTTPConflict, self.controller.patch, req, constants.UUID, body=req_body) @@ -973,27 +994,30 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_patch_failed_with_same_operational_state(self, mock_vnf_by_id): - vnf_package_updates = {'operational_state': 'DISABLED'} + req = fake_request.HTTPRequest.blank('/vnf_packages/%s' + % constants.UUID) + vnf_package_updates = { + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} mock_vnf_by_id.return_value = \ fakes.return_vnfpkg_obj(vnf_package_updates=vnf_package_updates) body = {"operationalState": "DISABLED", "userDefinedData": {"testKey1": "val01", "testKey2": "val02", "testkey3": "val03"}} - req = fake_request.HTTPRequest.blank('/vnf_packages/%s' - % constants.UUID) self.assertRaises(exc.HTTPConflict, self.controller.patch, req, constants.UUID, body=body) @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_patch_not_in_onboarded_state(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank('/vnf_packages/%s' + % constants.UUID) vnf_package_updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( vnf_package_updates=vnf_package_updates) body = {"operationalState": "DISABLED"} - req = fake_request.HTTPRequest.blank('/vnf_packages/%s' - % constants.UUID) self.assertRaises(exc.HTTPBadRequest, self.controller.patch, req, constants.UUID, body=body) @@ -1004,11 +1028,13 @@ class TestController(base.TestCase): 'application/zip,text/plain') def test_get_vnf_package_vnfd_with_valid_accept_headers( self, accept_headers, mock_vnf_by_id, mock_get_vnf_package_vnfd): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() - mock_get_vnf_package_vnfd.return_value = fakes.return_vnfd_data() req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + mock_get_vnf_package_vnfd.return_value = fakes.return_vnfd_data() req.headers['Accept'] = accept_headers req.method = 'GET' resp = req.get_response(self.app) @@ -1017,10 +1043,13 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_get_vnf_package_vnfd_with_invalid_accept_header( self, mock_vnf_by_id): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) req.headers['Accept'] = 'test-invalid-header' req.method = 'GET' self.assertRaises(exc.HTTPNotAcceptable, @@ -1031,11 +1060,13 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_get_vnf_package_vnfd_failed_with_bad_request( self, mock_vnf_by_id, mock_get_vnf_package_vnfd): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() - mock_get_vnf_package_vnfd.return_value = fakes.return_vnfd_data() req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + mock_get_vnf_package_vnfd.return_value = fakes.return_vnfd_data() req.headers['Accept'] = 'text/plain' req.method = 'GET' self.assertRaises(exc.HTTPBadRequest, @@ -1047,12 +1078,15 @@ class TestController(base.TestCase): def test_get_vnf_package_vnfd_for_content_type_text_plain(self, mock_vnf_by_id, mock_get_vnf_package_vnfd): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() - fake_vnfd_data = fakes.return_vnfd_data(csar_without_tosca_meta=True) - mock_get_vnf_package_vnfd.return_value = fake_vnfd_data req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + fake_vnfd_data = fakes.return_vnfd_data(csar_without_tosca_meta=True) + mock_get_vnf_package_vnfd.return_value = fake_vnfd_data req.headers['Accept'] = 'text/plain' req.method = 'GET' resp = req.get_response(self.app) @@ -1064,15 +1098,16 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_get_vnf_package_vnfd_failed_with_invalid_status( self, mock_vnf_by_id): - vnf_package_updates = { - 'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED' - } - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnf_package_updates) req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + vnf_package_updates = { + 'onboarding_state': 'CREATED', + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id + } + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnf_package_updates) req.headers['Accept'] = 'application/zip' req.method = 'GET' resp = req.get_response(self.app) @@ -1108,11 +1143,14 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_get_vnf_package_vnfd_failed_with_internal_server_error( self, mock_vnf_by_id, mock_get_vnf_package_vnfd): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() - mock_get_vnf_package_vnfd.side_effect = tacker_exc.FailedToGetVnfdData req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/vnfd' % constants.UUID) + + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) + mock_get_vnf_package_vnfd.side_effect = tacker_exc.FailedToGetVnfdData req.headers['Accept'] = 'application/zip' req.method = 'GET' resp = req.get_response(self.app) @@ -1173,7 +1211,9 @@ class TestController(base.TestCase): % constants.UUID) request.headers["Range"] = 'bytes=10-20,21-30' request.response = "" - mock_get_vnf_package.return_value = fakes.return_vnfpkg_obj() + mock_get_vnf_package.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': request.environ['tacker.context'].project_id}) mock_get_csar_size.return_value = 1000 mock_get_range.return_value = "10-20, 21-30" mock_download.return_value = "Response" @@ -1195,7 +1235,9 @@ class TestController(base.TestCase): % constants.UUID) request.headers["Range"] = 'bytes=10-20,21-30' request.response = "" - pkgobj = fakes.return_vnfpkg_obj() + pkgobj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': request.environ['tacker.context'].project_id}) pkgobj.onboarding_state = fields.PackageOnboardingStateType.PROCESSING mock_get.return_value = pkgobj id = constants.UUID @@ -1210,7 +1252,9 @@ class TestController(base.TestCase): % constants.UUID) request.headers["Range"] = 'bytes=10-20,21-30' request.response = "" - pkgobj = fakes.return_vnfpkg_obj() + pkgobj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': request.environ['tacker.context'].project_id}) mock_get.return_value = pkgobj id = constants.UUID self.assertRaises(exc.HTTPNotFound, @@ -1230,7 +1274,9 @@ class TestController(base.TestCase): % constants.UUID) request.headers["Range"] = 'bytes=10-20,21-30' request.response = "" - pkgobj = fakes.return_vnfpkg_obj() + pkgobj = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': request.environ['tacker.context'].project_id}) pkgobj.size = 1000 mock_get_range.return_value = "10-20, 21-30" mock_download.return_value = 1000 @@ -1257,7 +1303,6 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_fetch_vnf_package_artifacts_with_invalid_path( self, mock_vnf_by_id, mock_get_csar_path): - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() extract_path = utils.test_etc_sample( 'sample_vnf_package_csar_in_meta_and_manifest') mock_get_csar_path.return_value = extract_path @@ -1266,6 +1311,9 @@ class TestController(base.TestCase): '/vnf_packages/%s/artifacts/%s' % (constants.UUID, constants.INVALID_ARTIFACT_PATH)) req.method = 'GET' + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates={ + 'tenant_id': req.environ['tacker.context'].project_id}) self.assertRaises(exc.HTTPNotFound, self.controller.fetch_vnf_package_artifacts, req, constants.UUID, @@ -1360,15 +1408,16 @@ class TestController(base.TestCase): @mock.patch.object(vnf_package.VnfPackage, "get_by_id") def test_fetch_vnf_package_artifacts_with_invalid_status( self, mock_vnf_by_id): - vnf_package_updates = { - 'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED' - } - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnf_package_updates) req = fake_request.HTTPRequest.blank( '/vnf_packages/%s/artifacts/%s' % (constants.UUID, constants.ARTIFACT_PATH)) + vnf_package_updates = { + 'onboarding_state': 'CREATED', + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id + } + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnf_package_updates) req.method = 'GET' self.assertRaises(exc.HTTPConflict, self.controller.fetch_vnf_package_artifacts, @@ -1396,8 +1445,13 @@ class TestControllerEnhancedPolicy(TestController): mock_glance_store, mock_load_csar, mock_load_csar_data): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' + % constants.UUID) + updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} vnf_package_dict = fakes.fake_vnf_package(updates) vnf_package_obj = objects.VnfPackage(**vnf_package_dict) mock_vnf_by_id.return_value = vnf_package_obj @@ -1408,9 +1462,6 @@ class TestControllerEnhancedPolicy(TestController): '1-9e6d-ab21b87dcfff.zip' mock_load_csar_data.return_value = ( {'provider': 'company'}, mock.ANY, mock.ANY) - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s/package_content' - % constants.UUID) req.headers['Content-Type'] = 'application/zip' req.method = 'PUT' req.body = jsonutils.dump_as_bytes({'dummy': {'val': 'foo'}}) @@ -1437,8 +1488,13 @@ class TestControllerEnhancedPolicy(TestController): mock_load_csar_data, mock_delete_csar, vnf_data, rules, roles, expected_status_code): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' + % constants.UUID) + updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} vnf_package_dict = fakes.fake_vnf_package(updates) vnf_package_obj = objects.VnfPackage(**vnf_package_dict) mock_vnf_by_id.return_value = vnf_package_obj @@ -1452,9 +1508,6 @@ class TestControllerEnhancedPolicy(TestController): policy.set_rules(oslo_policy.Rules.from_dict(rules), overwrite=True) ctx = context.Context( 'fake', 'fake', roles=roles) - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s/package_content' - % constants.UUID) req.headers['Content-Type'] = 'application/zip' req.method = 'PUT' req.body = jsonutils.dump_as_bytes({'dummy': {'val': 'foo'}}) @@ -1490,13 +1543,15 @@ class TestControllerEnhancedPolicy(TestController): @ddt.data(['VENDOR_provider_A'], []) def test_show_enhanced_policy_created( self, roles, mock_vnf_by_id, mock_sw_image_by_id): + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' % constants.UUID) + updates = {'onboarding_state': 'CREATED', - 'operational_state': 'DISABLED'} + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( vnf_package_updates=updates) mock_sw_image_by_id.return_value = fakes.return_software_image() - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s' % constants.UUID) req.method = 'GET' rules = { vnf_package_policies.VNFPKGM % 'show': @@ -1518,11 +1573,13 @@ class TestControllerEnhancedPolicy(TestController): def test_delete_enhanced_policy( self, mock_delete_rpc, mock_vnf_by_id, mock_vnf_pack_destroy, vnfd_updates, rules, roles, expected_status_code): - vnfpkg_updates = {'operational_state': 'DISABLED'} - mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( - vnf_package_updates=vnfpkg_updates, vnfd_updates=vnfd_updates) req = fake_request.HTTPRequest.blank( '/vnf_packages/%s' % constants.UUID) + vnfpkg_updates = { + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj( + vnf_package_updates=vnfpkg_updates, vnfd_updates=vnfd_updates) req.headers['Content-Type'] = 'application/json' req.method = 'DELETE' policy.set_rules(oslo_policy.Rules.from_dict(rules), overwrite=True) @@ -1538,7 +1595,12 @@ class TestControllerEnhancedPolicy(TestController): @mock.patch.object(vnf_package.VnfPackage, "save") def test_patch_enhanced_policy(self, mock_save, mock_vnf_by_id, vnfd_updates, rules, roles, expected_status_code): - vnf_package_updates = {'operational_state': 'DISABLED'} + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' + % constants.UUID) + vnf_package_updates = { + 'operational_state': 'DISABLED', + 'tenant_id': req.environ['tacker.context'].project_id} mock_vnf_by_id.return_value = \ fakes.return_vnfpkg_obj( vnf_package_updates=vnf_package_updates, @@ -1549,9 +1611,6 @@ class TestControllerEnhancedPolicy(TestController): "userDefinedData": {"testKey1": "val01", "testKey2": "val02", "testkey3": "val03"}} - req = fake_request.HTTPRequest.blank( - '/vnf_packages/%s' - % constants.UUID) req.headers['Content-Type'] = 'application/json' req.method = 'PATCH' req.body = jsonutils.dump_as_bytes(req_body)