From 38345d8010d3c3ffb694ae027180a2d3fcc678b0 Mon Sep 17 00:00:00 2001 From: Ayumu Ueha Date: Fri, 14 Jul 2023 02:21:54 +0000 Subject: [PATCH] Enhancement of Tacker API Policy for VNF tenant This patch enables resource access control with tenant information of VNF when Tacker policy enhancement is enabled. Also this patch unifies to `tenant` the key of the tenant information used for CNF policy checks. Implements: blueprint enhance-api-policy Change-Id: Ia6a7c48f290dca05d0b48780dcd5a04c68ae37eb --- .../enhanced_tacker_policy_usage_guide.rst | 146 ++++++------ tacker/api/vnflcm/v1/controller.py | 10 +- tacker/sol_refactored/controller/vnflcm_v2.py | 9 +- .../kubernetes/kubernetes_common.py | 1 + .../infra_drivers/openstack/openstack.py | 2 + .../functional/sol_enhanced_policy/base.py | 159 +++++++++---- .../sol/test_policy_vnflcm_apis_v1.py | 38 ++- .../sol/test_policy_vnflcm_apis_v2.py | 219 ++++++++++-------- .../test_policy_cnflcm_apis_v1.py | 12 + .../controller/test_vnflcm_v2.py | 141 +++++++---- .../infra_drivers/openstack/test_openstack.py | 15 +- tacker/tests/unit/vnflcm/fakes.py | 179 +++++++++++--- tacker/tests/unit/vnflcm/test_controller.py | 4 +- .../openstack/test_openstack_driver.py | 5 + .../kubernetes/kubernetes_driver.py | 1 + tacker/vnfm/infra_drivers/kubernetes/utils.py | 1 + .../vnfm/infra_drivers/openstack/openstack.py | 5 + 17 files changed, 628 insertions(+), 319 deletions(-) diff --git a/doc/source/user/enhanced_tacker_policy_usage_guide.rst b/doc/source/user/enhanced_tacker_policy_usage_guide.rst index cdeac085f..2cf3d0f56 100644 --- a/doc/source/user/enhanced_tacker_policy_usage_guide.rst +++ b/doc/source/user/enhanced_tacker_policy_usage_guide.rst @@ -25,9 +25,8 @@ area, vendor, and tenant. where VIM or VNF is located. * vendor: Vendor attribute is the name of the vendor. It is defined in the definition file of VNF package. VNF obtains this attribute from VNF package. -* tenant: Tenant attribute is the name of the tenant. Tacker Antelope version - only supports the namespace of CNF. The tenant of VNF will be supported in - future releases. +* tenant: Tenant attribute is the name of the tenant. This attribute describes + the namespace of CNF, and the project name of VNF. Enable Enhanced Tacker Policy ----------------------------- @@ -141,7 +140,7 @@ following rules: - vendor - VENDOR_company-a -> {"vendor": ["company-a"]} * - TENANT - - tenant value + - tenant - TENANT_default -> {"tenant": ["default"]} #. For special value in Enhanced Tacker Policy, the corresponding attribute @@ -179,7 +178,7 @@ following rules: - all - {"vendor": "vendor_company-a"} -> {"vendor": ["company-a"]} * - TENANT - - tenant value + - tenant - all - {"tenant": "default"} -> {"tenant": ["default"]} @@ -309,18 +308,18 @@ Create roles | options | {} | +-------------+----------------------------------+ -#. Create the ``TENANT_curry`` role: +#. Create the ``TENANT_tenant-a`` role: .. code-block:: console - $ openstack role create TENANT_curry + $ openstack role create TENANT_tenant-a +-------------+----------------------------------+ | Field | Value | +-------------+----------------------------------+ | description | None | | domain_id | None | | id | cb98edb048ad49399701d4397708f397 | - | name | TENANT_curry | + | name | TENANT_tenant-a | | options | {} | +-------------+----------------------------------+ @@ -357,14 +356,14 @@ Create roles Assign roles to user-project pairs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#. Assign ``AREA_tokyo@japan``, ``VENDOR_company-a`` and ``TENANT_curry`` +#. Assign ``AREA_tokyo@japan``, ``VENDOR_company-a`` and ``TENANT_tenant-a`` to ``user-a``: .. code-block:: console $ openstack role add --user user-a --project nfv AREA_tokyo@japan $ openstack role add --user user-a --project nfv VENDOR_company-a - $ openstack role add --user user-a --project nfv TENANT_curry + $ openstack role add --user user-a --project nfv TENANT_tenant-a Verify the role assignment of ``user-a``: @@ -376,7 +375,7 @@ Assign roles to user-project pairs +------------------+----------------+-------+-------------+--------+--------+-----------+ | VENDOR_company-a | user-a@Default | | nfv@Default | | | False | | AREA_tokyo@japan | user-a@Default | | nfv@Default | | | False | - | TENANT_curry | user-a@Default | | nfv@Default | | | False | + | TENANT_tenant-a | user-a@Default | | nfv@Default | | | False | +------------------+----------------+-------+-------------+--------+--------+-----------+ #. Assign reader to ``user-b``: @@ -433,6 +432,8 @@ When registering a vim, users can specify area attribute for the vim. This is achieved by putting the area attribute into the extra field of the vim configuration file. Please refer to VIM Management [#VIM_Management]_ for how to register a vim. +And the project_name of the vim configuration file is used as tenant attribute +of instantiated VNF. .. warning:: It is highly recommended that users who performs the VIM registration is @@ -446,15 +447,26 @@ to register a vim. .. code-block:: yaml auth_url: 'http://192.168.10.115/identity/v3' - username: 'nfv_user' + username: 'vim-user' password: 'devstack' - project_name: 'nfv' + project_name: 'tenant-a' project_domain_name: 'default' user_domain_name: 'default' cert_verify: 'True' extra: area: tokyo@japan + .. note:: + + The project and VIM user which specified in the vim configuration file must + be created previously and assign the member role to VIM user. + + .. code-block:: console + + $ openstack project create tenant-a --domain default + $ openstack user create --project tenant-a --password devstack vim-user + $ openstack role add --user vim-user --project tenant-a member + Register OpenStack VIM: .. code-block:: console @@ -466,11 +478,11 @@ to register a vim. | Field | Value | +----------------+------------------------------------------------------+ | auth_cred | { | - | | "username": "nfv_user", | + | | "username": "vim-user", | | | "user_domain_name": "default", | | | "cert_verify": "True", | | | "project_id": null, | - | | "project_name": "nfv", | + | | "project_name": "tenant-a" | | | "project_domain_name": "default", | | | "auth_url": "http://192.168.10.115/identity/v3", | | | "key_type": "barbican_key", | @@ -494,7 +506,7 @@ to register a vim. | type | openstack | | updated_at | None | | vim_project | { | - | | "name": "nfv", | + | | "name": "tenant-a", | | | "project_domain_name": "default" | | | } | +----------------+------------------------------------------------------+ @@ -506,9 +518,9 @@ to register a vim. .. code-block:: yaml auth_url: 'http://192.168.10.115/identity/v3' - username: 'nfv_user' + username: 'vim-user' password: 'devstack' - project_name: 'nfv' + project_name: 'tenant-a' project_domain_name: 'default' user_domain_name: 'default' cert_verify: 'True' @@ -526,11 +538,11 @@ to register a vim. | Field | Value | +----------------+------------------------------------------------------+ | auth_cred | { | - | | "username": "nfv_user", | + | | "username": "vim-user", | | | "user_domain_name": "default", | | | "cert_verify": "True", | | | "project_id": null, | - | | "project_name": "nfv", | + | | "project_name": "tenant-a", | | | "project_domain_name": "default", | | | "auth_url": "http://192.168.10.115/identity/v3", | | | "key_type": "barbican_key", | @@ -554,7 +566,7 @@ to register a vim. | type | openstack | | updated_at | None | | vim_project | { | - | | "name": "nfv", | + | | "name": "tenant-a", | | | "project_domain_name": "default" | | | } | +----------------+------------------------------------------------------+ @@ -716,7 +728,7 @@ configuration files that need to be modified in VNF package. ... Create & Instantiate VNF with vendor, area and tenant attributes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Create VNF with vendor attribute ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -734,18 +746,18 @@ Create a VNF with vnfd_id: $ openstack vnflcm create -Instantiate VNF on VIM with area attributes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Instantiate VNF on VIM with area and tenant attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The area attribute of the VNF comes from the used vim. In other -words, you need to specify a VIM in the area where you want to +The area and tenant attribute of the VNF comes from the used vim. In other +words, you need to specify a VIM in the area and tenant where you want to instantiate a VNF. For VNF LCM API version 1, please refer to [#VNF_Lifecycle_Management]_ to instantiate VNF. Below are two samples of . #. If contains the ``vimConnectionInfo`` parameter, the area - attribute comes from vim in it. + and tenant attributes come from vim in it. .. code-block:: json @@ -795,7 +807,7 @@ instantiate VNF. Below are two samples of . #. If doesn't contains the ``vimConnectionInfo`` parameter, the - default vim is used and area attribute comes from it. + default vim is used and area and tenant attributes come from it. .. code-block:: json @@ -807,8 +819,8 @@ For VNF LCM API version 2, please refer to [#VNF_Lifecycle_Management]_ to instantiate VNF. Below are two samples of . #. If the vim in the ``vimConnectionInfo`` parameter of is an - existing vim in the DB, the vendor attribute of the instantiated VNF - comes from this vim. + existing vim in the DB, the area and tenant attribute of the instantiated + VNF comes from this vim. .. code-block:: json @@ -932,9 +944,9 @@ instantiate VNF. Below are two samples of . } #. If the vim in the ``vimConnectionInfo`` parameter of is not - existed in the DB, the vendor attribute of the instantiated VNF comes from - this vim. Users need to specify the area attribute in the - ``vimConnectionInfo`` parameter. + existed in the DB, users need to specify the area and tenant attributes in + the ``vimConnectionInfo`` parameter. The tenant attribute uses the + ``project`` in the ``accessInfo`` of the ``vimConnectionInfo``. .. code-block:: json @@ -1052,11 +1064,11 @@ instantiate VNF. Below are two samples of . "vim1": { "accessInfo": { "password": "devstack", - "project": "nfv", + "project": "tenant-a", "projectDomain": "Default", "region": "RegionOne", "userDomain": "Default", - "username": "nfv_user" + "username": "vim-user" }, "interfaceInfo": { "endpoint": "http://localhost/identity/v3" @@ -1071,9 +1083,8 @@ instantiate VNF. Below are two samples of . Instantiate CNF with tenant attribute ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -In Tacker Antelope verison, only CNF has the tenant attribute. When -instantiating CNF, the tenant attribute of CNF is specified by the namespace in -the additionalParams field of . +When instantiating CNF, the tenant attribute of CNF is specified by the +namespace in the additionalParams field of . .. code-block:: json @@ -1091,7 +1102,7 @@ the additionalParams field of . "Files/kubernetes/deployment.yaml", "Files/kubernetes/namespace.yaml" ], - "namespace": "curry" + "namespace": "tenant-a" } } @@ -1122,11 +1133,11 @@ an example. | Field | Value | +----------------+------------------------------------------------------+ | auth_cred | { | - | | "username": "nfv_user", | + | | "username": "vim-user", | | | "user_domain_name": "default", | | | "cert_verify": "True", | | | "project_id": null, | - | | "project_name": "nfv", | + | | "project_name": "tenant-a", | | | "project_domain_name": "default", | | | "auth_url": "http://192.168.10.115/identity/v3", | | | "key_type": "barbican_key", | @@ -1150,7 +1161,7 @@ an example. | type | openstack | | updated_at | 2023-02-14 07:05:28 | | vim_project | { | - | | "name": "nfv", | + | | "name": "tenant-a", | | | "project_domain_name": "default" | | | } | +----------------+------------------------------------------------------+ @@ -1313,9 +1324,9 @@ enhanced tacker attributes supported by each API. - No * - LCM-List - **GET** /vnflcm/v1/vnf_instances - - Yes(3) - - Yes - Yes(2) + - Yes + - Yes(3) * - LCM-Create - **POST** /vnflcm/v1/vnf_instances - No @@ -1323,14 +1334,14 @@ enhanced tacker attributes supported by each API. - No * - LCM-Show - **GET** /vnflcm/v1/vnf_instances/{vnfInstanceId} - - Yes(3) - - Yes - Yes(2) + - Yes + - Yes(3) * - LCM-Update - **PATCH** /vnflcm/v1/vnf_instances/{vnfInstanceId} - Yes - Yes - - Yes(2) + - Yes * - LCM-Delete - **DELETE** /vnflcm/v1/vnf_instances/{vnfInstanceId} - No @@ -1338,34 +1349,34 @@ enhanced tacker attributes supported by each API. - No * - LCM-Instantiate - **POST** /vnflcm/v1/vnf_instances/{vnfInstanceId}/instantiate + - No - Yes - - Yes - - Yes(2) + - No * - LCM-Scale - **POST** /vnflcm/v1/vnf_instances/{vnfInstanceId}/scale - Yes - Yes - - Yes(2) + - Yes * - LCM-Terminate - **POST** /vnflcm/v1/vnf_instances/{vnfInstanceId}/terminate - Yes - Yes - - Yes(2) + - Yes * - LCM-Heal - **POST** /vnflcm/v1/vnf_instances/{vnfInstanceId}/heal - Yes - Yes - - Yes(2) + - Yes * - LCM-Change-Connectivity - **POST** /vnflcm/v1/vnf_instances/{vnfInstanceId}/change_ext_conn - Yes - Yes - - Yes(2) + - Yes * - LCM-ListV2 - **GET** /vnflcm/v2/vnf_instances - - Yes(4) + - Yes(3) - Yes - - Yes(2) + - Yes(3) * - LCM-CreateV2 - **POST** /vnflcm/v2/vnf_instances - No @@ -1373,14 +1384,14 @@ enhanced tacker attributes supported by each API. - No * - LCM-ShowV2 - **GET** /vnflcm/v2/vnf_instances/{vnfInstanceId} - - Yes(4) + - Yes(3) - Yes - - Yes(2) + - Yes(3) * - LCM-UpdateV2 - **PATCH** /vnflcm/v2/vnf_instances/{vnfInstanceId} - Yes - Yes - - Yes(2) + - Yes * - LCM-DeleteV2 - **DELETE** /vnflcm/v2/vnf_instances/{vnfInstanceId} - No @@ -1388,39 +1399,38 @@ enhanced tacker attributes supported by each API. - No * - LCM-InstantiateV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/instantiate + - No - Yes - - Yes - - Yes(2) + - No * - LCM-ScaleV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/scale - Yes - Yes - - Yes(2) + - Yes * - LCM-TerminateV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/terminate - Yes - Yes - - Yes(2) + - Yes * - LCM-HealV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/heal - Yes - Yes - - Yes(2) + - Yes * - LCM-Change-ConnectivityV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/change_ext_conn - Yes - Yes - - Yes(2) + - Yes * - LCM-Change-VnfPkgV2 - **POST** /vnflcm/v2/vnf_instances/{vnfInstanceId}/change_vnfpkg - Yes - Yes - - Yes(2) + - Yes (1) This is ignored when the state is not `ONBOARDED`. -(2) This is ignored when the instance is vnf(not cnf). -(3) Default vim is used when the state is `NOT_INSTANTIATED`. -(4) This is ignored when the state is not `NOT_INSTANTIATED`. +(2) Default vim is used when the state is `NOT_INSTANTIATED`. +(3) This is ignored when the state is `NOT_INSTANTIATED`. Sample policy.yaml file ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tacker/api/vnflcm/v1/controller.py b/tacker/api/vnflcm/v1/controller.py index de81d9407..e90f4b574 100644 --- a/tacker/api/vnflcm/v1/controller.py +++ b/tacker/api/vnflcm/v1/controller.py @@ -590,15 +590,7 @@ class VnfLcmController(wsgi.Controller): if (vnf_instance.instantiation_state == fields.VnfInstanceState.INSTANTIATED): if vnf_instance.vnf_metadata: - tenant = vnf_instance.vnf_metadata.get('namespace') - - # TODO(kexuesheng): Add steps to get tenant of VNFs deployed - # in OpenStack VIM. This is a temporary workaround until that - # information is available. - if vnf_instance.vim_connection_info: - vim_type = vnf_instance.vim_connection_info[0].vim_type - if vim_type in ["openstack", "ETSINFV.OPENSTACK_KEYSTONE.v_2"]: - tenant = '*' + tenant = vnf_instance.vnf_metadata.get('tenant') else: tenant = '*' diff --git a/tacker/sol_refactored/controller/vnflcm_v2.py b/tacker/sol_refactored/controller/vnflcm_v2.py index a79c73eb2..c47092955 100644 --- a/tacker/sol_refactored/controller/vnflcm_v2.py +++ b/tacker/sol_refactored/controller/vnflcm_v2.py @@ -236,15 +236,8 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController): if (vnf_instance.obj_attr_is_set('instantiatedVnfInfo') and vnf_instance.instantiatedVnfInfo.obj_attr_is_set( 'metadata')): - tenant = (vnf_instance.instantiatedVnfInfo - .metadata.get('namespace')) - - # TODO(kexuesheng): Add steps to get tenant of VNFs deployed - # in OpenStack VIM. This is a temporary workaround until that - # information is available. - if vim_type == "ETSINFV.OPENSTACK_KEYSTONE.V_3": - tenant = '*' + .metadata.get('tenant')) target = { 'vendor': vendor, diff --git a/tacker/sol_refactored/infra_drivers/kubernetes/kubernetes_common.py b/tacker/sol_refactored/infra_drivers/kubernetes/kubernetes_common.py index 3846446e0..7b979107b 100644 --- a/tacker/sol_refactored/infra_drivers/kubernetes/kubernetes_common.py +++ b/tacker/sol_refactored/infra_drivers/kubernetes/kubernetes_common.py @@ -108,6 +108,7 @@ class KubernetesCommon(object): vdu_reses, namespace): metadata = { 'namespace': namespace, + 'tenant': namespace, 'vdu_reses': {vdu_name: vdu_res.body for vdu_name, vdu_res in vdu_reses.items()} } diff --git a/tacker/sol_refactored/infra_drivers/openstack/openstack.py b/tacker/sol_refactored/infra_drivers/openstack/openstack.py index a494b1804..6bc48d8cd 100644 --- a/tacker/sol_refactored/infra_drivers/openstack/openstack.py +++ b/tacker/sol_refactored/infra_drivers/openstack/openstack.py @@ -1579,5 +1579,7 @@ class Openstack(object): # store stack_id and nfv parameters into metadata inst_vnf_info.metadata['stack_id'] = stack_id inst_vnf_info.metadata['nfv'] = nfv_dict + # store tenant name for enhanced policy + inst_vnf_info.metadata['tenant'] = vim_info.accessInfo.get('project') inst.instantiatedVnfInfo = inst_vnf_info diff --git a/tacker/tests/functional/sol_enhanced_policy/base.py b/tacker/tests/functional/sol_enhanced_policy/base.py index 235d68223..914f913a5 100644 --- a/tacker/tests/functional/sol_enhanced_policy/base.py +++ b/tacker/tests/functional/sol_enhanced_policy/base.py @@ -20,6 +20,7 @@ import time import yaml import zipfile +from glanceclient.v2 import client as glance_client from keystoneauth1.identity import v3 from keystoneauth1 import session from keystoneclient.v3 import client as ks_client @@ -46,15 +47,19 @@ class BaseEnhancedPolicyTest(object): vim_base_url = "/v1.0/vims" pkg_base_url = '/vnfpkgm/v1/vnf_packages' user_role_map = {} + vim_user_project_map = {} @classmethod - def setUpClass(cls, subclass_with_user_role_map): - cls.user_role_map = subclass_with_user_role_map.user_role_map + def setUpClass(cls, subclass_with_maps): + cls.user_role_map = subclass_with_maps.user_role_map + cls.vim_user_project_map = subclass_with_maps.vim_user_project_map cls.ks_client = cls.keystone_client() cls.project = cls._get_project() + cls._create_project() cls._create_user_role() cls.create_tacker_http_client_for_user() cls.cleanup_list = [] + cls.images_to_delete = [] @classmethod def create_tacker_http_client_for_user(cls): @@ -69,7 +74,9 @@ class BaseEnhancedPolicyTest(object): @classmethod def tearDownClass(cls): + cls._delete_image() cls._delete_user_role() + cls._delete_project() @classmethod def keystone_client(cls): @@ -151,25 +158,27 @@ class BaseEnhancedPolicyTest(object): @classmethod def _create_project(cls): - project_name = 'policy-test' - projects = cls.ks_client.projects.list() - project_exists = False - for project in projects: - if project_name == project.name: - project_exists = True - cls.project_id = project.id - cls.project = project - break - if not project_exists: - project = cls.ks_client.projects.create(project_name, 'default') - cls.project_id = project.id - cls.project = project + cls.projects = [] + if cls.vim_user_project_map: + # create project + projects = cls.ks_client.projects.list() + project_names = [project.name for project in projects] + projects_to_create = [ + project_name + for project_name in cls.vim_user_project_map.values() + if project_name not in project_names] + if projects_to_create: + for project_name in set(projects_to_create): + project = cls.ks_client.projects.create(project_name, + 'default') + cls.projects.append(project) @classmethod - def _get_project(cls): - vim_params = base.BaseTackerTest.get_credentials( - cls.local_vim_conf_file) - project_name = vim_params['project_name'] + def _get_project(cls, project_name=None): + if not project_name: + vim_params = base.BaseTackerTest.get_credentials( + cls.local_vim_conf_file) + project_name = vim_params['project_name'] projects = cls.ks_client.projects.list() for project in projects: if project.name == project_name: @@ -179,9 +188,9 @@ class BaseEnhancedPolicyTest(object): @classmethod def _delete_project(cls): - if hasattr(cls, 'project_id') and cls.project_id: - if hasattr(cls, 'ks_client') and cls.ks_client: - cls.ks_client.projects.delete(cls.project_id) + if cls.projects: + for project in cls.projects: + cls.ks_client.projects.delete(project.id) @classmethod def _get_user_by_name(cls, name): @@ -229,6 +238,34 @@ class BaseEnhancedPolicyTest(object): project=cls.project.id ) + @classmethod + def create_vim_user(cls): + if cls.vim_user_project_map: + vim_user_project_map = cls.vim_user_project_map + else: + raise Exception('vim_user_project_map is needed.') + users = cls.ks_client.users.list() + usernames = [user.name for user in users] + projects = cls.ks_client.projects.list() + password = 'devstack' + for username in vim_user_project_map.keys(): + vim_username = f'vim_{username}' + if vim_username in usernames: + # already exist + continue + project_name = vim_user_project_map[username] + project_id = [project.id for project in projects + if project_name == project.name][0] + user = cls.ks_client.users.create( + vim_username, project=project_id, password=password) + cls.users.append(user) + # add member role to vim users + cls.ks_client.roles.grant( + cls.role_map.get('member'), + user=cls._get_user_by_name(vim_username), + project=project_id + ) + @classmethod def _create_role(cls, role_name): role = cls.ks_client.roles.create(role_name) @@ -286,11 +323,12 @@ class BaseEnhancedPolicyTest(object): @classmethod def register_vim(cls, client, url, vim_file, name, description, vim_type, - extra, is_default=False): + extra, is_default=False, username=None, tenant=None): base_data = yaml.safe_load(read_file(vim_file)) if vim_type == 'openstack': + username = f'vim_{username}' if username else base_data['username'] auth_cred = { - 'username': base_data['username'], + 'username': username, 'password': base_data['password'], 'user_domain_name': base_data['user_domain_name'] } @@ -299,7 +337,7 @@ class BaseEnhancedPolicyTest(object): else: raise Exception(f'unknown vim type: {vim_type}.') vim_project = { - 'name': base_data['project_name'], + 'name': tenant if tenant else base_data['project_name'], } if 'project_domain_name' in base_data: vim_project['project_domain_name'] = ( @@ -457,7 +495,7 @@ class BaseEnhancedPolicyTest(object): @classmethod def _step_vim_register( cls, username, vim_type, local_vim, vim_name, area, - is_default=False): + is_default=False, tenant=None): extra = {} if area: extra = {'area': area} @@ -465,7 +503,8 @@ class BaseEnhancedPolicyTest(object): cls.get_tk_http_client_by_user(username), cls.vim_base_url, local_vim, vim_name, "{}-{}".format(vim_name, uuidutils.generate_uuid()), - vim_type, extra, is_default=is_default) + vim_type, extra, is_default=is_default, username=username, + tenant=tenant) if resp.status_code == 201: return body.get('vim') else: @@ -488,6 +527,55 @@ class BaseEnhancedPolicyTest(object): return csar_dir + @classmethod + def _glance_client(cls, username=None, tenant=None): + vim_params = base.BaseTackerTest.get_credentials() + auth = v3.Password(auth_url=vim_params['auth_url'], + username=username if username else vim_params['username'], + password=vim_params['password'], + project_name=tenant if tenant else vim_params['project_name'], + user_domain_name=vim_params['user_domain_name'], + project_domain_name=vim_params['project_domain_name']) + verify = 'True' == vim_params.pop('cert_verify', 'False') + auth_ses = session.Session(auth=auth, verify=verify) + return glance_client.Client(session=auth_ses) + + @classmethod + def create_image(cls): + if cls.vim_user_project_map: + vim_user_project_map = cls.vim_user_project_map + else: + raise Exception('vim_user_project_map is needed.') + image_name = "cirros-0.5.2-x86_64-disk" + image_path = os.path.abspath( + os.path.join(os.path.dirname(__file__), + "../../etc/samples/etsi/nfv/common/Files/images", + f"{image_name}.img")) + image_data = { + 'disk_format': 'qcow2', + 'container_format': 'bare', + 'visibility': 'private', + 'name': image_name} + for username, projectname in vim_user_project_map.items(): + glance_client = cls._glance_client(username=f'vim_{username}', + tenant=projectname) + images = glance_client.images.list() + images = list(filter( + lambda image: image.name == image_name, images)) + if not images: + image = glance_client.images.create(**image_data) + with open(image_path, 'rb') as f: + glance_client.images.upload(image.id, f) + cls.images_to_delete.append(image) + + @classmethod + def _delete_image(cls): + if not cls.images_to_delete: + return + glance_client = cls._glance_client() + for image in cls.images_to_delete: + glance_client.images.delete(image.id) + def _register_subscription(self, request_body, http_client=None): if http_client is None: http_client = self.http_client @@ -684,18 +772,6 @@ class VimAPIsTest(BaseTackerTest, BaseEnhancedPolicyTest): class VnflcmAPIsV1Base(vnflcm_base.BaseVnfLcmTest, BaseEnhancedPolicyTest): - user_role_map = { - 'user_a': ['VENDOR_company_A', 'AREA_area_A@region_A', - 'TENANT_namespace-a', 'manager'], - 'user_a_1': ['VENDOR_company_A', 'manager'], - 'user_b': ['VENDOR_company_B', 'AREA_area_B@region_B', - 'TENANT_namespace-b', 'manager'], - 'user_c': ['VENDOR_company_C', 'AREA_area_C@region_C', - 'TENANT_namespace-c', 'manager'], - 'user_all': ['VENDOR_all', 'AREA_all@all', 'TENANT_all', 'manager'], - 'user_admin': ['admin'] - } - @classmethod def setUpClass(cls): vnflcm_base.BaseVnfLcmTest.setUpClass() @@ -704,6 +780,11 @@ class VnflcmAPIsV1Base(vnflcm_base.BaseVnfLcmTest, BaseEnhancedPolicyTest): def setUp(self): super().setUp() + @classmethod + def tearDownClass(cls): + BaseEnhancedPolicyTest.tearDownClass() + vnflcm_base.BaseVnfLcmTest.tearDownClass() + def _step_lcm_create(self, username, vnfd_id, vnf_instance_name, expected_status_code): client = self.get_tk_http_client_by_user(username) diff --git a/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v1.py b/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v1.py index 1a92ad32a..cb578a984 100644 --- a/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v1.py +++ b/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v1.py @@ -24,31 +24,56 @@ from tacker.tests.functional.sol_enhanced_policy.base import ( class VnflcmAPIsV1Test(VnflcmAPIsV1Base): + user_role_map = { + 'user_a': ['VENDOR_company_A', 'AREA_area_A@region_A', + 'TENANT_tenant_A', 'manager'], + 'user_a_1': ['VENDOR_company_A', 'manager'], + 'user_b': ['VENDOR_company_B', 'AREA_area_B@region_B', + 'TENANT_tenant_B', 'manager'], + 'user_c': ['VENDOR_company_C', 'AREA_area_C@region_C', + 'TENANT_tenant_C', 'manager'], + 'user_all': ['VENDOR_all', 'AREA_all@all', + 'TENANT_all', 'manager'], + 'user_admin': ['admin'] + } + vim_user_project_map = { + 'user_a': 'tenant_A', + 'user_b': 'tenant_B', + 'user_c': 'tenant_C' + } + @classmethod def setUpClass(cls): super().setUpClass() + cls.create_vim_user() vim_type = 'openstack' local_vim = 'local-vim.yaml' cls.vim_a = cls._step_vim_register( - 'user_a', vim_type, local_vim, 'vim_a', 'area_A@region_A') + 'user_a', vim_type, local_vim, 'vim_a', 'area_A@region_A', + tenant='tenant_A') cls.vim_a_1 = cls._step_vim_register( - 'user_a', vim_type, local_vim, 'vim_a_1', 'area_A@region_A') + 'user_a', vim_type, local_vim, 'vim_a_1', 'area_A@region_A', + tenant='tenant_A') cls.vim_b = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_b', 'area_B@region_B') + 'user_b', vim_type, local_vim, 'vim_b', 'area_B@region_B', + tenant='tenant_B') cls.vim_b_1 = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_b_1', 'area_B@region_B') + 'user_b', vim_type, local_vim, 'vim_b_1', 'area_B@region_B', + tenant='tenant_B') cls.vim_c = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_c', None) + 'user_c', vim_type, local_vim, 'vim_c', None, + tenant='tenant_C') cls.vim_c_1 = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_c_1', None) + 'user_c', vim_type, local_vim, 'vim_c_1', None, + tenant='tenant_C') cls.pkg_a = cls._step_pkg_create('user_a') @@ -130,6 +155,7 @@ class VnflcmAPIsV1Test(VnflcmAPIsV1Base): port_uuid = self.create_port(neutron_client, network_uuid) ext_vl = get_external_virtual_links(net0_id, net_mgmt_id, port_uuid) + self.create_image() request_body = self._instantiate_vnf_request( "simple", vim_id=vim_id, ext_vl=ext_vl) diff --git a/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v2.py b/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v2.py index 1aa132aa1..5a4aa3735 100644 --- a/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v2.py +++ b/tacker/tests/functional/sol_enhanced_policy/sol/test_policy_vnflcm_apis_v2.py @@ -33,20 +33,29 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): user_role_map = { 'user_a': ['VENDOR_company_A', 'AREA_area_A@region_A', - 'TENANT_namespace_A', 'manager'], + 'TENANT_tenant_A', 'manager'], 'user_a_1': ['VENDOR_company_A', 'manager'], 'user_b': ['VENDOR_company_B', 'AREA_area_B@region_B', - 'TENANT_namespace_B', 'manager'], + 'TENANT_tenant_B', 'manager'], 'user_c': ['VENDOR_company_C', 'AREA_area_C@region_C', - 'TENANT_namespace-c', 'manager'], - 'user_all': ['VENDOR_all', 'AREA_all@all', 'TENANT_all', 'manager'], + 'TENANT_tenant_C', 'manager'], + 'user_all': ['VENDOR_all', 'AREA_all@all', + 'TENANT_all', 'manager'], 'user_admin': ['admin'] } + vim_user_project_map = { + 'user_a': 'tenant_A', + 'user_b': 'tenant_B', + 'user_c': 'tenant_C', + 'user_all': 'tenant_B', + 'user_admin': 'tenant_C' + } @classmethod def setUpClass(cls): CommonVnfLcmTest.setUpClass() BaseEnhancedPolicyTest.setUpClass(cls) + cls.create_vim_user() for user in cls.users: client = cls.get_local_tacker_http_client(user.name) @@ -153,7 +162,8 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): ) return http_client.HttpClient(auth) - def change_ext_conn_max(self, net_ids, subnets, auth_url, area): + def change_ext_conn_max(self, net_ids, subnets, auth_url, area, + username=None, tenant=None): vim_id_1 = uuidutils.generate_uuid() vim_id_2 = uuidutils.generate_uuid() @@ -219,10 +229,10 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): "vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3", "interfaceInfo": {"endpoint": auth_url}, "accessInfo": { - "username": "nfv_user", + "username": f'vim_{username}' if username else "nfv_user", "region": "RegionOne", "password": "devstack", - "project": "nfv", + "project": tenant if tenant else "nfv", "projectDomain": "Default", "userDomain": "Default" }, @@ -266,7 +276,8 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): else: return None - def instantiate_vnf(self, area=None, vim_id=None): + def instantiate_vnf(self, area=None, vim_id=None, username=None, + tenant=None): # Omit except for required attributes # NOTE: Only the following cardinality attributes are set. # - 1 @@ -279,10 +290,10 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): "vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3", "interfaceInfo": {"endpoint": self.auth_url}, "accessInfo": { - "username": "nfv_user", + "username": f'vim_{username}' if username else "nfv_user", "region": "RegionOne", "password": "devstack", - "project": "nfv", + "project": tenant if tenant else "nfv", "projectDomain": "Default", "userDomain": "Default" }, @@ -320,14 +331,16 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): } } - def _step_lcm_instantiate(self, username, inst_id, glance_image, + def _step_lcm_instantiate(self, username, inst_id, tenant, glance_image, flavour_vdu_dict, zone_name_list, expected_status_code, - area=None, vim_id=None): + area=None, vim_id=None): + self.create_image() self.tacker_client = self.get_tk_http_client_by_user(username) self._set_grant_response( False, 'INSTANTIATE', glance_image=glance_image, flavour_vdu_dict=flavour_vdu_dict, zone_name_list=zone_name_list) - instantiate_req = self.instantiate_vnf(area, vim_id) + instantiate_req = self.instantiate_vnf(area, vim_id, username=username, + tenant=tenant) resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req) self.assertEqual(expected_status_code, resp.status_code) if expected_status_code == 202: @@ -427,7 +440,7 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): # update and change_vnfpkg completion. time.sleep(WAIT_LCMOCC_UPDATE_TIME) - def _step_lcm_change_ext_conn(self, username, inst_id, area, + def _step_lcm_change_ext_conn(self, username, inst_id, tenant, area, zone_name_list, expected_status_code): self.tacker_client = self.get_tk_http_client_by_user(username) self._set_grant_response( @@ -485,7 +498,8 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): self.addCleanup(self.delete_port, port_id) change_ext_conn_req = self.change_ext_conn_max( - net_ids, subnet_ids, self.auth_url, area) + net_ids, subnet_ids, self.auth_url, area, username=username, + tenant=tenant) resp, body = self.change_ext_conn(inst_id, change_ext_conn_req) self.assertEqual(expected_status_code, resp.status_code) if expected_status_code == 202: @@ -639,16 +653,16 @@ class VnflcmAPIsV2VNFBase(CommonVnfLcmTest, BaseEnhancedPolicyTest): self._step_lcm_update('user_all', inst_id_b, self.vnfd_id_b_1, 202) # step 35 LCM-Change-ConnectivityV2, Resource Group A / User Group A - self._step_lcm_change_ext_conn( - 'user_a', inst_id_a, 'area_A@region_A', zone_name_list, 202) + self._step_lcm_change_ext_conn('user_a', inst_id_a, 'tenant_A', + 'area_A@region_A', zone_name_list, 202) # step 36 LCM-Change-ConnectivityV2, Resource Group B / User Group A - self._step_lcm_change_ext_conn( - 'user_a', inst_id_b, 'area_B@region_B', zone_name_list, 403) + self._step_lcm_change_ext_conn('user_a', inst_id_b, 'tenant_B', + 'area_B@region_B', zone_name_list, 403) # step 37 LCM-Change-ConnectivityV2, Resource Group B / User Group all - self._step_lcm_change_ext_conn( - 'user_all', inst_id_b, 'area_B@region_B', zone_name_list, 202) + self._step_lcm_change_ext_conn('user_all', inst_id_b, 'tenant_B', + 'area_B@region_B', zone_name_list, 202) # step 38 LCM-Change-VnfPkgV2, Resource Group A / User Group A self._step_lcm_update('user_a', inst_id_a, self.vnfd_id_a, 202) @@ -703,18 +717,87 @@ class VnflcmAPIsV2VNFInstantiateWithArea(VnflcmAPIsV2VNFBase): self.vnflcm_apis_v2_vnf_test_before_instantiate()) # step 12 LCM-InstantiateV2, Resource Group A / User Group A - self._step_lcm_instantiate('user_a', inst_id_a, glance_image, - flavour_vdu_dict, zone_name_list, 202, area='area_A@region_A') + self._step_lcm_instantiate('user_a', inst_id_a, 'tenant_A', + glance_image, flavour_vdu_dict, + zone_name_list, 202, area='area_A@region_A') # step 13 LCM-InstantiateV2, Resource Group B / User Group A - self._step_lcm_instantiate('user_a', inst_id_b, glance_image, - flavour_vdu_dict, zone_name_list, 403, - area='area_B@region_B') + self._step_lcm_instantiate('user_a', inst_id_b, 'tenant_B', + glance_image, flavour_vdu_dict, + zone_name_list, 403, area='area_B@region_B') # step 14 LCM-InstantiateV2, Resource Group B / User Group all - self._step_lcm_instantiate('user_all', inst_id_b, glance_image, + self._step_lcm_instantiate('user_all', inst_id_b, 'tenant_B', + glance_image, flavour_vdu_dict, + zone_name_list, 202, area='area_B@region_B') + + self.vnflcm_apis_v2_vnf_test_after_instantiate( + sub_id, inst_id_a, inst_id_b, zone_name_list, glance_image, + flavour_vdu_dict) + + +class VnflcmAPIsV2VNFInstantiateWithAreaInRegisteredVim(VnflcmAPIsV2VNFBase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + vim_type = 'openstack' + + local_vim = 'local-vim.yaml' + + cls.vim_a = cls._step_vim_register( + 'user_a', vim_type, local_vim, 'vim_a', 'area_A@region_A', + tenant='tenant_A') + + cls.vim_a_1 = cls._step_vim_register( + 'user_a', vim_type, local_vim, 'vim_a_1', 'area_A@region_A', + tenant='tenant_A') + + cls.vim_b = cls._step_vim_register( + 'user_b', vim_type, local_vim, 'vim_b', 'area_B@region_B', + tenant='tenant_B') + + cls.vim_b_1 = cls._step_vim_register( + 'user_b', vim_type, local_vim, 'vim_b_1', 'area_B@region_B', + tenant='tenant_B') + + @classmethod + def tearDownClass(cls): + + cls._step_vim_delete('user_a', cls.vim_a) + cls._step_vim_delete('user_a', cls.vim_a_1) + cls._step_vim_delete('user_b', cls.vim_b) + cls._step_vim_delete('user_b', cls.vim_b_1) + + super().tearDownClass() + + def test_vnflcm_apis_v2_vnf_with_area_in_registered_vim(self): + + glance_image = None + flavour_vdu_dict = None + zone_name_list = None + + sub_id, inst_id_a, inst_id_b = ( + self.vnflcm_apis_v2_vnf_test_before_instantiate()) + + # step 12 LCM-InstantiateV2, Resource Group A / User Group A + self._step_lcm_instantiate('user_a', inst_id_a, 'tenant_A', + glance_image, flavour_vdu_dict, zone_name_list, 202, - area='area_B@region_B') + vim_id=self.vim_a['id']) + + # step 13 LCM-InstantiateV2, Resource Group B / User Group A + self._step_lcm_instantiate('user_a', inst_id_b, 'tenant_B', + glance_image, + flavour_vdu_dict, zone_name_list, 403, + vim_id=self.vim_b['id']) + + # step 14 LCM-InstantiateV2, Resource Group B / User Group all + self._step_lcm_instantiate('user_all', inst_id_b, 'tenant_B', + glance_image, + flavour_vdu_dict, zone_name_list, 202, + vim_id=self.vim_b['id']) self.vnflcm_apis_v2_vnf_test_after_instantiate( sub_id, inst_id_a, inst_id_b, zone_name_list, glance_image, @@ -723,70 +806,6 @@ class VnflcmAPIsV2VNFInstantiateWithArea(VnflcmAPIsV2VNFBase): class VnflcmAPIsV2VNFInstantiateWithoutArea(VnflcmAPIsV2VNFBase): - @classmethod - def setUpClass(cls): - super().setUpClass() - - vim_type = 'openstack' - - local_vim = 'local-vim.yaml' - - cls.vim_a = cls._step_vim_register( - 'user_a', vim_type, local_vim, 'vim_a', 'area_A@region_A') - - cls.vim_a_1 = cls._step_vim_register( - 'user_a', vim_type, local_vim, 'vim_a_1', 'area_A@region_A') - - cls.vim_b = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_b', 'area_B@region_B') - - cls.vim_b_1 = cls._step_vim_register( - 'user_b', vim_type, local_vim, 'vim_b_1', 'area_B@region_B') - - @classmethod - def tearDownClass(cls): - - cls._step_vim_delete('user_a', cls.vim_a) - cls._step_vim_delete('user_a', cls.vim_a_1) - cls._step_vim_delete('user_b', cls.vim_b) - cls._step_vim_delete('user_b', cls.vim_b_1) - - super().tearDownClass() - - def test_vnflcm_apis_v2_vnf_without_area_in_vim_conn_info(self): - - glance_image = None - flavour_vdu_dict = None - zone_name_list = None - - sub_id, inst_id_a, inst_id_b = ( - self.vnflcm_apis_v2_vnf_test_before_instantiate()) - - # step 12 LCM-InstantiateV2, Resource Group A / User Group A - self._step_lcm_instantiate('user_a', inst_id_a, - glance_image, - flavour_vdu_dict, zone_name_list, 202, - vim_id=self.vim_a['id']) - - # step 13 LCM-InstantiateV2, Resource Group B / User Group A - self._step_lcm_instantiate('user_a', inst_id_b, - glance_image, - flavour_vdu_dict, zone_name_list, 403, - vim_id=self.vim_b['id']) - - # step 14 LCM-InstantiateV2, Resource Group B / User Group all - self._step_lcm_instantiate('user_all', inst_id_b, - glance_image, - flavour_vdu_dict, zone_name_list, 202, - vim_id=self.vim_b['id']) - - self.vnflcm_apis_v2_vnf_test_after_instantiate( - sub_id, inst_id_a, inst_id_b, zone_name_list, glance_image, - flavour_vdu_dict) - - -class VnflcmAPIsV2VNFInstanceWithoutArea(VnflcmAPIsV2VNFBase): - @classmethod def setUpClass(cls): super().setUpClass() @@ -796,10 +815,12 @@ class VnflcmAPIsV2VNFInstanceWithoutArea(VnflcmAPIsV2VNFBase): local_vim = 'local-vim.yaml' cls.vim_c = cls._step_vim_register( - 'user_c', vim_type, local_vim, 'vim_c', None) + 'user_c', vim_type, local_vim, 'vim_c', None, + tenant='tenant_C') cls.vim_c_1 = cls._step_vim_register( - 'user_c', vim_type, local_vim, 'vim_c_1', None) + 'user_c', vim_type, local_vim, 'vim_c_1', None, + tenant='tenant_C') @classmethod def tearDownClass(cls): @@ -809,7 +830,7 @@ class VnflcmAPIsV2VNFInstanceWithoutArea(VnflcmAPIsV2VNFBase): super().tearDownClass() - def test_vnflcm_apis_v2_vnf_instance_without_area(self): + def test_vnflcm_apis_v2_vnf_without_area(self): glance_image = None flavour_vdu_dict = None @@ -857,7 +878,7 @@ class VnflcmAPIsV2VNFInstanceWithoutArea(VnflcmAPIsV2VNFBase): self._step_lcm_list('user_admin', [inst_id_c]) # step 8 LCM-InstantiateV2, Resource Group C / User Group C - self._step_lcm_instantiate('user_c', inst_id_c, + self._step_lcm_instantiate('user_c', inst_id_c, 'tenant_C', glance_image, flavour_vdu_dict, zone_name_list, 202, vim_id=self.vim_c['id']) @@ -927,15 +948,15 @@ class VnflcmAPIsV2VNFInstanceWithoutArea(VnflcmAPIsV2VNFBase): # step 27 LCM-Change-ConnectivityV2, Resource Group C / User Group C self._step_lcm_change_ext_conn( - 'user_c', inst_id_c, None, zone_name_list, 403) + 'user_c', inst_id_c, 'tenant_C', None, zone_name_list, 403) # step 28 LCM-Change-ConnectivityV2, Resource Group C / User Group A self._step_lcm_change_ext_conn( - 'user_all', inst_id_c, None, zone_name_list, 403) + 'user_all', inst_id_c, 'tenant_C', None, zone_name_list, 403) # step 29 LCM-Change-ConnectivityV2, Resource Group C / User Group all self._step_lcm_change_ext_conn( - 'user_admin', inst_id_c, None, zone_name_list, 202) + 'user_admin', inst_id_c, 'tenant_C', None, zone_name_list, 202) # step 30 LCM-Change-VnfPkgV2, Resource Group C / User Group C self._step_lcm_change_vnfpkg('user_c', inst_id_c, self.vnfd_id_c_2, diff --git a/tacker/tests/functional/sol_enhanced_policy/sol_kubernetes/test_policy_cnflcm_apis_v1.py b/tacker/tests/functional/sol_enhanced_policy/sol_kubernetes/test_policy_cnflcm_apis_v1.py index cfd143670..7b1be0a57 100644 --- a/tacker/tests/functional/sol_enhanced_policy/sol_kubernetes/test_policy_cnflcm_apis_v1.py +++ b/tacker/tests/functional/sol_enhanced_policy/sol_kubernetes/test_policy_cnflcm_apis_v1.py @@ -20,6 +20,18 @@ from tacker.tests.functional.sol_enhanced_policy.base import ( class VnflcmAPIsV1CNFTest(VnflcmAPIsV1Base): + user_role_map = { + 'user_a': ['VENDOR_company_A', 'AREA_area_A@region_A', + 'TENANT_namespace-a', 'manager'], + 'user_a_1': ['VENDOR_company_A', 'manager'], + 'user_b': ['VENDOR_company_B', 'AREA_area_B@region_B', + 'TENANT_namespace-b', 'manager'], + 'user_c': ['VENDOR_company_C', 'AREA_area_C@region_C', + 'TENANT_namespace-c', 'manager'], + 'user_all': ['VENDOR_all', 'AREA_all@all', 'TENANT_all', 'manager'], + 'user_admin': ['admin'] + } + @classmethod def setUpClass(cls): super().setUpClass() diff --git a/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py b/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py index 0149bb443..7ce68aa0e 100644 --- a/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py +++ b/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py @@ -189,18 +189,18 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): # 'expected_status_code': success_status_code { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@all', 'VENDOR_all', 'TENANT_all' @@ -209,7 +209,7 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@region_A', 'VENDOR_all', 'TENANT_all' @@ -218,12 +218,12 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_vendor, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }, @@ -235,18 +235,18 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates_without_area, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, @@ -258,66 +258,66 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_B@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_B', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_A', - 'TENANT_namespace_B' + 'TENANT_tenant_B' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', @@ -327,40 +327,40 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@region_B', 'VENDOR_provider_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_vendor, 'roles': [ 'AREA_area_A@region_A', 'VENDOR_provider_B', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, - 'tenant': 'namespace_A', + 'tenant': 'tenant_A', 'rules': rule_vendor, 'roles': [ 'AREA_area_A@region_A', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, @@ -372,7 +372,7 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'roles': [ 'AREA_area_B@region_A', 'VENDOR_provider_B', - 'TENANT_namespace_A' + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }, @@ -400,6 +400,39 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): return test_data +def get_test_data_policy_delete(): + rules = {POLICY_NAME.format('delete'): "vendor:%(vendor)s"} + test_data = [ + # 'expected_status_code': http_client.NO_CONTENT + { + 'vnf_instance_updates': {'vnfProvider': 'provider_A'}, + 'rules': rules, + 'roles': ['VENDOR_provider_A'], + 'expected_status_code': http_client.NO_CONTENT + }, + { + 'vnf_instance_updates': {'vnfProvider': 'provider_A'}, + 'rules': rules, + 'roles': ['VENDOR_all'], + 'expected_status_code': http_client.NO_CONTENT + }, + # 'expected_status_code': http_client.FORBIDDEN + { + 'vnf_instance_updates': {'vnfProvider': 'provider_A'}, + 'rules': rules, + 'roles': [], + 'expected_status_code': http_client.FORBIDDEN + }, + { + 'vnf_instance_updates': {'vnfProvider': 'provider_A'}, + 'rules': rules, + 'roles': ['VENDOR_provider_B'], + 'expected_status_code': http_client.FORBIDDEN + }, + ] + return test_data + + def make_vnf_instance( vim_type, instantiation_state, vendor, area=None, tenant=None): vim_connection_info = objects.VimConnectionInfo( @@ -435,8 +468,8 @@ def make_vnf_instance( objects.VnfInstanceV2_InstantiatedVnfInfo( flavourId='fake_flavour_id', vnfState='STARTED', - metadata={'namespace': tenant})) - vnf_inst_fields.update({'metadata': {'namespace': tenant}}) + metadata={'tenant': tenant})) + vnf_inst_fields.update({'metadata': {'tenant': tenant}}) return vnf_instance @@ -452,50 +485,59 @@ def get_test_data_policy_index(): inst_1 = make_vnf_instance( 'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'INSTANTIATED', 'provider_A', - area='area_A@region_A') + area='area_A@region_A', tenant='tenant_A') # OK test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [inst_1.id] }) test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@all', 'VENDOR_all'], + 'roles': ['AREA_all@all', 'VENDOR_all', 'TENANT_all'], 'expected_vnf_inst_ids': [inst_1.id] }) test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_A', 'VENDOR_all'], + 'roles': ['AREA_all@region_A', 'VENDOR_all', 'TENANT_all'], 'expected_vnf_inst_ids': [inst_1.id] }) # wrong region role test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_B', 'VENDOR_all'], + 'roles': ['AREA_all@region_B', 'VENDOR_all', 'TENANT_all'], 'expected_vnf_inst_ids': [] }) # wrong area role test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_B@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_B@region_A', 'VENDOR_provider_A', 'TENANT_all'], 'expected_vnf_inst_ids': [] }) # wrong vendor role test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_B'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_B', 'TENANT_all'], + 'expected_vnf_inst_ids': [] + }) + # wrong tenant role + test_data.append({ + 'vnf_instance_list': [inst_1], + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', 'TENANT_B'], 'expected_vnf_inst_ids': [] }) # without area inst_2 = make_vnf_instance( - 'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'INSTANTIATED', 'provider_A') + 'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'INSTANTIATED', 'provider_A', + tenant='tenant_A') test_data.append({ 'vnf_instance_list': [inst_2], 'rules': rule_area_vendor_tenant, @@ -504,7 +546,8 @@ def get_test_data_policy_index(): }) # NOT_INSTANTIATED inst_3 = make_vnf_instance( - 'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'NOT_INSTANTIATED', 'provider_A') + 'ETSINFV.OPENSTACK_KEYSTONE.V_3', 'NOT_INSTANTIATED', 'provider_A', + tenant='tenant_A') test_data.append({ 'vnf_instance_list': [inst_3], 'rules': rule_area_vendor_tenant, @@ -1837,7 +1880,7 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2): objects.VnfInstanceV2_InstantiatedVnfInfo( flavourId='fake_flavour_id', vnfState='STARTED', - metadata={'namespace': 'namespace_A'})) + metadata={'tenant': 'tenant_A'})) inst.create(self.context) lcmocc.create(self.context) @@ -1897,7 +1940,7 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2): 'maxScaleLevels': max_scale_levels, } if tenant: - instantiated_vnf_info.update({'metadata': {'namespace': tenant}}) + instantiated_vnf_info.update({'metadata': {'tenant': tenant}}) inst.instantiatedVnfInfo = objects.VnfInstanceV2_InstantiatedVnfInfo( **instantiated_vnf_info ) @@ -1931,7 +1974,7 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2): ] ) if tenant: - inst.instantiatedVnfInfo.metadata = {'namespace': tenant} + inst.instantiatedVnfInfo.metadata = {'tenant': tenant} if not vnf_inst_updates: inst.vimConnectionInfo = { "vim1": objects.VimConnectionInfo.from_dict( @@ -2100,17 +2143,15 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2): if expected_status_code != http_client.FORBIDDEN: raise - @ddt.data(*get_test_data_policy_vnf_instantiated( - 'delete', http_client.NO_CONTENT)) + @ddt.data(*get_test_data_policy_delete()) @ddt.unpack @mock.patch.object(nfvo_client.NfvoClient, 'send_inst_delete_notification') def test_delete_enhanced_policy(self, mock_delete, vnf_instance_updates, - tenant, rules, roles, expected_status_code): + rules, roles, expected_status_code): self._overwrite_policy(rules) inst_id, _ = self._create_inst_and_lcmocc('NOT_INSTANTIATED', fields.LcmOperationStateType.COMPLETED, - vnf_inst_updates=vnf_instance_updates, - tenant=tenant) + vnf_inst_updates=vnf_instance_updates) try: result = self.controller.delete( self._fake_request(roles), id=inst_id) @@ -2205,11 +2246,11 @@ class TestVnflcmV2EnhancedPolicy(TestVnflcmV2): ] ) if tenant: - inst.instantiatedVnfInfo.metadata = {'namespace': tenant} + inst.instantiatedVnfInfo.metadata = {'tenant': tenant} # inst.instantiatedVnfInfo = objects.VnfInstanceV2_InstantiatedVnfInfo( # flavourId='fake_flavour_id', # vnfState='STARTED', - # metadata={'namespace': tenant} + # metadata={'tenant': tenant} # ) inst.create(self.context) diff --git a/tacker/tests/unit/sol_refactored/infra_drivers/openstack/test_openstack.py b/tacker/tests/unit/sol_refactored/infra_drivers/openstack/test_openstack.py index ff1f54a5e..4ecf0a3a9 100644 --- a/tacker/tests/unit/sol_refactored/infra_drivers/openstack/test_openstack.py +++ b/tacker/tests/unit/sol_refactored/infra_drivers/openstack/test_openstack.py @@ -1658,7 +1658,8 @@ _inst_info_example = { } ], "metadata": { - "stack_id": STACK_ID + "stack_id": STACK_ID, + "tenant": "nfv" } # "vnfcInfo": omitted } @@ -2239,7 +2240,8 @@ _expected_inst_info = { "VDU2": {"computeFlavourId": "m1.small", "vcImageId": "image-VDU2"} } - } + }, + "tenant": "nfv" } } @@ -2304,7 +2306,8 @@ _expected_inst_info_vnfc_updated["metadata"] = { "fixed_ips": [] } } - } + }, + "tenant": "nfv" } @@ -2764,7 +2767,8 @@ _expected_inst_info_change_ext_conn = { "fixed_ips": [] } } - } + }, + "tenant": "nfv" } } @@ -3184,7 +3188,8 @@ _expected_inst_info_S = { "VDU2-0": {"computeFlavourId": "m1.small"}, "VDU2-VirtualStorage-0": {"vcImageId": "image-VDU2"} } - } + }, + "tenant": "nfv" } } diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 95245fbb7..ab61d59bb 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -1986,65 +1986,95 @@ def get_test_data_policy_index(): } test_data = [] inst_1 = make_vnf_instance('openstack', 'provider_A', - area='area_A@region_A') + area='area_A@region_A', tenant='tenant_A') test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [inst_1.id] }) test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_all@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [inst_1.id] }) test_data.append({ 'vnf_instance_list': [inst_1], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@all', 'VENDOR_all'], + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_tenant_A'], + 'expected_vnf_inst_ids': [inst_1.id] + }) + test_data.append({ + 'vnf_instance_list': [inst_1], + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_all'], 'expected_vnf_inst_ids': [inst_1.id] }) inst_2 = make_vnf_instance( - 'openstack', 'provider_A', area='area_A@region_A', + 'openstack', 'provider_A', area='area_A@region_A', tenant='tenant_A', instantiated_state=fields.VnfInstanceState.INSTANTIATED) test_data.append({ 'vnf_instance_list': [inst_2], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [inst_2.id] }) test_data.append({ 'vnf_instance_list': [inst_2], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_all@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [inst_2.id] }) test_data.append({ 'vnf_instance_list': [inst_2], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@all', 'VENDOR_all'], + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_tenant_A'], + 'expected_vnf_inst_ids': [inst_2.id] + }) + test_data.append({ + 'vnf_instance_list': [inst_2], + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_all'], 'expected_vnf_inst_ids': [inst_2.id] }) inst_3 = make_vnf_instance( - 'openstack', 'provider_A', + 'openstack', 'provider_A', tenant='tenant_A', instantiated_state=fields.VnfInstanceState.INSTANTIATED) test_data.append({ 'vnf_instance_list': [inst_3], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [] }) test_data.append({ 'vnf_instance_list': [inst_3], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_all@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_vnf_inst_ids': [] }) test_data.append({ 'vnf_instance_list': [inst_3], 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@all', 'VENDOR_all'], + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_tenant_A'], + 'expected_vnf_inst_ids': [] + }) + test_data.append({ + 'vnf_instance_list': [inst_3], + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_all@all', 'VENDOR_all', + 'TENANT_all'], 'expected_vnf_inst_ids': [] }) inst_4 = make_vnf_instance( @@ -2130,6 +2160,50 @@ def get_test_data_policy_instantiate(): return test_data +def get_test_data_policy_delete(): + test_data = [ + # 'expected_status_code': http_client.NO_CONTENT + { + 'vnf_instance_updates': {'vnf_provider': 'provider_A'}, + 'rules': { + "os_nfv_orchestration_api:vnf_instances:delete": + "vendor:%(vendor)s" + }, + 'roles': ['VENDOR_provider_A'], + 'expected_status_code': http_client.NO_CONTENT + }, + { + 'vnf_instance_updates': {'vnf_provider': 'provider_A'}, + 'rules': { + "os_nfv_orchestration_api:vnf_instances:delete": + "vendor:%(vendor)s" + }, + 'roles': ['VENDOR_all'], + 'expected_status_code': http_client.NO_CONTENT + }, + # 'expected_status_code': http_client.FORBIDDEN + { + 'vnf_instance_updates': {'vnf_provider': 'provider_A'}, + 'rules': { + "os_nfv_orchestration_api:vnf_instances:delete": + "vendor:%(vendor)s" + }, + 'roles': [], + 'expected_status_code': http_client.FORBIDDEN + }, + { + 'vnf_instance_updates': {'vnf_provider': 'provider_A'}, + 'rules': { + "os_nfv_orchestration_api:vnf_instances:delete": + "vendor:%(vendor)s" + }, + 'roles': ['VENDOR_provider_B'], + 'expected_status_code': http_client.FORBIDDEN + }, + ] + return test_data + + def get_test_data_policy_vnf_not_instantiated( action, success_status_code=http_client.OK): # openstack @@ -2168,7 +2242,8 @@ def get_test_data_policy_vnf_not_instantiated( { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': success_status_code }, { @@ -2194,7 +2269,8 @@ def get_test_data_policy_vnf_not_instantiated( { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_vendor, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': success_status_code }, { @@ -2209,6 +2285,13 @@ def get_test_data_policy_vnf_not_instantiated( 'roles': ['AREA_all@region_A', 'VENDOR_all', 'TENANT_all'], 'expected_status_code': success_status_code }, + { + 'vnf_instance_updates': vnf_instance_updates, + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_B'], + 'expected_status_code': success_status_code + }, # 'expected_status_code': http_client.FORBIDDEN { 'vnf_instance_updates': vnf_instance_updates, @@ -2231,37 +2314,49 @@ def get_test_data_policy_vnf_not_instantiated( { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_B'], + 'roles': ['TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_area_B@region_A', 'VENDOR_provider_A'], + 'roles': ['AREA_area_A@region_A', 'VENDOR_provider_B', + 'TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@region_B', 'VENDOR_provider_A'], + 'roles': ['AREA_area_B@region_A', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all', 'VENDOR_provider_A'], + 'roles': ['AREA_all@region_B', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@', 'VENDOR_provider_A'], + 'roles': ['AREA_all', 'VENDOR_provider_A', + 'TENANT_tenant_A'], + 'expected_status_code': http_client.FORBIDDEN + }, + { + 'vnf_instance_updates': vnf_instance_updates, + 'rules': rule_area_vendor_tenant, + 'roles': ['AREA_all@', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, { 'vnf_instance_updates': vnf_instance_updates_with_wrong_area, 'rules': rule_area_vendor_tenant, - 'roles': ['AREA_all@', 'VENDOR_provider_A'], + 'roles': ['AREA_all@', 'VENDOR_provider_A', + 'TENANT_tenant_A'], 'expected_status_code': http_client.FORBIDDEN }, ] @@ -2283,7 +2378,7 @@ def make_vnf_instance_updates( 'vim_connection_info': [vim_connection_info] } if tenant: - vnf_instance_updates.update({'vnf_metadata': {"namespace": tenant}}) + vnf_instance_updates.update({'vnf_metadata': {"tenant": tenant}}) return vnf_instance_updates @@ -2298,13 +2393,15 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): test_data = [] # openstack vnf_instance_updates_1 = make_vnf_instance_updates( - 'openstack', 'provider_A', area='area_A@region_A') + 'openstack', 'provider_A', area='area_A@region_A', + tenant='tenant_A') test_data.append({ 'vnf_instance_updates': vnf_instance_updates_1, 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }) @@ -2313,7 +2410,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@region_A', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }) @@ -2322,7 +2420,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@all', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }) @@ -2331,7 +2430,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@all', - 'VENDOR_all' + 'VENDOR_all', + 'TENANT_tenant_A' ], 'expected_status_code': success_status_code }) @@ -2340,7 +2440,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_all@all', - 'VENDOR_all' + 'VENDOR_all', + 'TENANT_all' ], 'expected_status_code': success_status_code }) @@ -2350,7 +2451,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_B@region_A', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }) @@ -2360,7 +2462,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_B', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }) @@ -2370,11 +2473,22 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', - 'VENDOR_provider_B' + 'VENDOR_provider_B', + 'TENANT_tenant_A' + ], + 'expected_status_code': http_client.FORBIDDEN + }) + # wrong tenant role + test_data.append({ + 'vnf_instance_updates': vnf_instance_updates_1, + 'rules': rule_area_vendor_tenant, + 'roles': [ + 'AREA_area_A@region_A', + 'VENDOR_provider_A', + 'TENANT_tenant_B' ], 'expected_status_code': http_client.FORBIDDEN }) - vnf_instance_updates_2 = make_vnf_instance_updates( 'openstack', 'provider_A') test_data.append({ @@ -2382,7 +2496,8 @@ def get_test_data_policy_vnf_instantiated(action, success_status_code): 'rules': rule_area_vendor_tenant, 'roles': [ 'AREA_area_A@region_A', - 'VENDOR_provider_A' + 'VENDOR_provider_A', + 'TENANT_tenant_A' ], 'expected_status_code': http_client.FORBIDDEN }) diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py index d903fcb08..e1589df81 100644 --- a/tacker/tests/unit/vnflcm/test_controller.py +++ b/tacker/tests/unit/vnflcm/test_controller.py @@ -29,7 +29,6 @@ from oslo_config import cfg from oslo_policy import policy as oslo_policy from oslo_serialization import jsonutils -from tacker._i18n import _ from tacker.api.views import vnf_subscriptions as vnf_subscription_view from tacker.api.vnflcm.v1 import controller from tacker.api.vnflcm.v1 import sync_resource @@ -5303,8 +5302,7 @@ class TestControllerEnhancedPolicy(TestController): resp = req.get_response(fakes.wsgi_app_v1(fake_auth_context=ctx)) self.assertEqual(expected_status_code, resp.status_code) - @ddt.data(*fakes.get_test_data_policy_vnf_instantiated( - 'delete', http_client.NO_CONTENT)) + @ddt.data(*fakes.get_test_data_policy_delete()) @ddt.unpack @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._delete') diff --git a/tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack_driver.py b/tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack_driver.py index 68a4b18c4..a11891db6 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack_driver.py +++ b/tacker/tests/unit/vnfm/infra_drivers/openstack/test_openstack_driver.py @@ -2040,6 +2040,7 @@ class TestOpenStack(base.FixturedTestCase): vnf_instance = fd_utils.get_vnf_instance_object( instantiated_vnf_info=inst_vnf_info) + vnf_instance.vnf_metadata = None vim_connection_info = fd_utils.get_vim_connection_info_object() resources = [{'resource_name': vnfc_resource_info.vdu_id, @@ -2080,6 +2081,10 @@ class TestOpenStack(base.FixturedTestCase): vnf_virtual_link_resource_info[0].vnf_link_ports[0]. resource_handle.resource_id) + # Check if tenant data is stored in vnf_metadata + self.assertEqual(vnf_instance.vnf_metadata['tenant'], + vim_connection_info.access_info['project_name']) + def test_post_vnf_instantiation_with_ext_managed_virtual_link(self): v_s_resource_info = fd_utils.get_virtual_storage_resource_info( desc_id="storage1", set_resource_id=False) diff --git a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py index 1a8191295..3e80acd2c 100644 --- a/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py +++ b/tacker/vnfm/infra_drivers/kubernetes/kubernetes_driver.py @@ -1733,6 +1733,7 @@ class Kubernetes(abstract_driver.VnfAbstractDriver, if not vnf_instance.vnf_metadata: vnf_instance.vnf_metadata = {} vnf_instance.vnf_metadata['namespace'] = namespace + vnf_instance.vnf_metadata['tenant'] = namespace vnf_instance.save() return {} diff --git a/tacker/vnfm/infra_drivers/kubernetes/utils.py b/tacker/vnfm/infra_drivers/kubernetes/utils.py index 21d6a8a0a..f5e745ea6 100644 --- a/tacker/vnfm/infra_drivers/kubernetes/utils.py +++ b/tacker/vnfm/infra_drivers/kubernetes/utils.py @@ -66,6 +66,7 @@ def check_and_save_namespace( if not vnf_instance.vnf_metadata: vnf_instance.vnf_metadata = {} vnf_instance.vnf_metadata['namespace'] = namespace + vnf_instance.vnf_metadata['tenant'] = namespace vnf_instance.save() diff --git a/tacker/vnfm/infra_drivers/openstack/openstack.py b/tacker/vnfm/infra_drivers/openstack/openstack.py index 792ba1d27..89cfbe388 100644 --- a/tacker/vnfm/infra_drivers/openstack/openstack.py +++ b/tacker/vnfm/infra_drivers/openstack/openstack.py @@ -2586,6 +2586,11 @@ class OpenStack(abstract_driver.VnfAbstractDriver, vim_connection_info, instantiate_vnf_req): self._update_vnfc_resources_and_info( context, vnf_instance, vim_connection_info) + # store tenant information for enhanced policy + if not vnf_instance.vnf_metadata: + vnf_instance.vnf_metadata = {} + access_info = vim_connection_info.access_info + vnf_instance.vnf_metadata['tenant'] = access_info.get('project_name') @log.log def post_change_ext_conn_vnf(self, context, vnf_instance,