Add RBAC tests for VNF Package APIs

Current tests do not have good test coverage of VNF LCM
APIs policies. Either tests for policies do not exist or
if they exist then they do not cover the actual negative
and positive testing.

Basically this commit does the following:

* Add RBAC tests:
  As we are implementing the project personas (project member
  and reader role) in policies, we need to have the enough
  testing coverage of existing policy behavior and to know
  that with new defaults how the access permissions will
  looks like.

* Pass correct target to oslo policy:
  Currently, APIs are not passing the right targets to oslo
  policy, means VNF instance project_id was not passed as target.
  We need to pass the project_id so that we can check the 'onwer'
  permission correctly at RBAC level and RBAC checks pass and
  request goes to fetch the data from DB where project_id
  is checked. For example, GET VNF API requests by a non
  admin user does not check if requester users is from same
  project of requested VNF or not and request pass the oslo
  policy checks and make DB request. Passing the right project_id
  in oslo policy will return the request (if projectA request projectB
  VNF) from policy checks itself. This can be seen in modified
  test_controller.py tests.

Partial implement blueprint implement-project-personas

Change-Id: I1e8d98d6b94507783ba34d149642c019609247e6
This commit is contained in:
Ghanshyam Mann 2024-02-20 12:01:22 -08:00
parent c2ef23210f
commit 71970bc665
3 changed files with 487 additions and 107 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)