From 686fe0ced9e37a12cd41f9e408d89404a7602be5 Mon Sep 17 00:00:00 2001 From: Koichi Edagawa Date: Mon, 11 Oct 2021 17:17:28 +0900 Subject: [PATCH] [WIP] Add tenant validation check between VIM and VNF This patch adds a validation check between a VIM and a VNF regarding tenant. If tenants which a VIM and a VNF belong to are different each other, Tacker will stop instantiating the VNF. Implement: blueprint multi-tenant-policy Change-Id: Ia966280c6d565b0021b29f593cd064daec0492f4 --- tacker/common/exceptions.py | 5 ++ tacker/tests/unit/conductor/fakes.py | 13 +++ .../unit/conductor/test_conductor_server.py | 90 ++----------------- tacker/tests/unit/vnflcm/fakes.py | 24 +++++ .../unit/vnflcm/test_load_vnf_interfaces.py | 11 ++- .../tests/unit/vnflcm/test_vnflcm_driver.py | 54 +++-------- .../vnfm/infra_drivers/kubernetes/fakes.py | 1 + tacker/vnflcm/utils.py | 1 + tacker/vnflcm/vnflcm_driver.py | 5 ++ 9 files changed, 78 insertions(+), 126 deletions(-) diff --git a/tacker/common/exceptions.py b/tacker/common/exceptions.py index 19ad46f6e..8cc0f24cc 100644 --- a/tacker/common/exceptions.py +++ b/tacker/common/exceptions.py @@ -431,3 +431,8 @@ class VnfConflictStateWithErrorPoint(Conflict): class InvalidIpAddr(TackerException): message = _('Invalid ip address value in resource %(id)s.') + + +class TenantMatchFailure(TackerException): + message = _('The tenants which target VNF and its VIM belongs to are ' + 'different each other.') diff --git a/tacker/tests/unit/conductor/fakes.py b/tacker/tests/unit/conductor/fakes.py index 580983592..2b9d629cd 100644 --- a/tacker/tests/unit/conductor/fakes.py +++ b/tacker/tests/unit/conductor/fakes.py @@ -549,3 +549,16 @@ def get_change_ext_conn_request_obj(): get_change_ext_conn_request()) return objects.ChangeExtConnRequest.obj_from_primitive( body, None) + + +def get_vim_obj(): + return { + 'vim_id': uuidsentinel.vim_id, + 'vim_name': 'fake_vim', + 'vim_type': 'openstack', + 'vim_auth': { + 'auth_url': 'http://localhost/identity', + 'password': 'test_pw', + 'username': 'test_user', + 'project_name': 'test_project'}, + 'tenant': uuidsentinel.tenant_id} diff --git a/tacker/tests/unit/conductor/test_conductor_server.py b/tacker/tests/unit/conductor/test_conductor_server.py index 6bb59a4ab..0bebf437e 100644 --- a/tacker/tests/unit/conductor/test_conductor_server.py +++ b/tacker/tests/unit/conductor/test_conductor_server.py @@ -1668,14 +1668,6 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnfd_key = 'vnfd_' + vnf_instance.instantiated_vnf_info.flavour_id vnfd_yaml = vnf_dict['vnfd']['attributes'].get(vnfd_key, '') mock_vnfd_dict.return_value = yaml.safe_load(vnfd_yaml) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} vimAssets = {'computeResourceFlavours': [ {'vimConnectionId': uuidsentinel.vim_id, 'vnfdVirtualComputeDescId': 'CDU1', @@ -1695,7 +1687,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): json_data = grant_dict mock_grants.return_value = MockResponse(json_data=json_data) - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() mock_d1.return_value = [] mock_placement.return_value = [] self.conductor.heal(self.context, vnf_instance, vnf_dict, @@ -1852,14 +1844,6 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_lcm_op_occs_id = 'a9c36d21-21aa-4692-8922-7999bbcae08c' mock_exec.return_value = True mock_act.return_value = None - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} vimAssets = {'computeResourceFlavours': [ {'vimConnectionId': uuidsentinel.vim_id, 'vnfdVirtualComputeDescId': 'CDU1', @@ -1904,7 +1888,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): json_data = grant_dict mock_grants.return_value = MockResponse(json_data=json_data) - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() mock_d1.return_value = ['ST1'] res_str = '[{"id_type": "RES_MGMT", "resource_id": ' + \ '"2c6e5cc7-240d-4458-a683-1fe648351200", ' + \ @@ -1988,14 +1972,6 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_lcm_op_occs_id = 'a9c36d21-21aa-4692-8922-7999bbcae08c' mock_exec.return_value = True mock_act.return_value = None - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} vimAssets = {'computeResourceFlavours': [ {'vimConnectionId': uuidsentinel.vim_id, 'vnfdVirtualComputeDescId': 'CDU1', @@ -2020,7 +1996,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): json_data = grant_dict mock_grants.return_value = MockResponse(json_data=json_data) - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() mock_d1.return_value = [] mock_placement.return_value = [] self.assertRaises(exceptions.ValidationError, @@ -2090,18 +2066,10 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_lcm_op_occs_id = 'a9c36d21-21aa-4692-8922-7999bbcae08c' mock_exec.return_value = True mock_act.return_value = None - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} mock_grants.side_effect = \ requests.exceptions.HTTPError("MockException") - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() mock_d1.return_value = [] mock_placement.return_value = [] self.assertRaises(requests.exceptions.HTTPError, @@ -2282,16 +2250,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): fields.VnfInstanceState.INSTANTIATED, scale_status="scale_status") scale_vnf_request = fakes.scale_request("SCALE_IN", 1) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() mock_d1.return_value = ([], [], "", "") vnf_info['addResources'] = [] vnf_info['removeResources'] = [] @@ -2355,16 +2315,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): fields.VnfInstanceState.INSTANTIATED, scale_status="scale_status") scale_vnf_request = fakes.scale_request("SCALE_IN", 1) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() removeResources = [] resRemoveResource = [] resource = objects.ResourceDefinition( @@ -2485,16 +2437,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): fields.VnfInstanceState.INSTANTIATED, scale_status="scale_status") scale_vnf_request = fakes.scale_request("SCALE_OUT", 1) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() addResources = [] resAddResource = [] resource = objects.ResourceDefinition( @@ -2634,16 +2578,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): fields.VnfInstanceState.INSTANTIATED, scale_status="scale_status") scale_vnf_request = fakes.scale_request("SCALE_OUT", 1) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() addResources = [] resource = objects.ResourceDefinition( id='2c6e5cc7-240d-4458-a683-1fe648351280', @@ -2736,16 +2672,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): fields.VnfInstanceState.INSTANTIATED, scale_status="scale_status") scale_vnf_request = fakes.scale_request("SCALE_OUT", 1) - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_vim_obj() addResources = [] resource = objects.ResourceDefinition( id='2c6e5cc7-240d-4458-a683-1fe648351280', diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 3178aa8d4..b3aa84422 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -739,6 +739,30 @@ def get_dummy_vim_connection_info(): 'vim_id': 'fake_vim_id', 'vim_type': 'openstack', 'extra': {}} +def get_dummy_openstack_vim_obj(): + return {'vim_id': uuidsentinel.vim_id, + 'vim_name': 'fake_vim', + 'vim_type': 'openstack', + 'vim_auth': { + 'auth_url': 'http://localhost/identity', + 'password': 'test_pw', + 'username': 'test_user', + 'project_name': 'test_project'}, + 'tenant': uuidsentinel.tenant_id} + + +def get_dummy_kubernetes_vim_obj(): + return {'vim_id': uuidsentinel.vim_id, + 'vim_name': 'fake_vim', + 'vim_type': 'kubernetes', + 'vim_auth': { + 'auth_url': 'http://localhost/8443', + 'password': 'test_pw', + 'username': 'test_user', + 'project_name': 'test_project'}, + 'tenant': uuidsentinel.tenant_id} + + def get_dummy_instantiate_vnf_request(**updates): instantiate_vnf_request = { 'additional_params': None, 'created_at': '', 'deleted': '', diff --git a/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py index 47c177d96..337d2e0fd 100644 --- a/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py +++ b/tacker/tests/unit/vnflcm/test_load_vnf_interfaces.py @@ -130,10 +130,13 @@ class MgmtVnfLcmDriverTest(db_base.SqlTestCase): def _stub_get_vim(self): vim_obj = {'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff', - 'vim_name': 'fake_vim', 'vim_auth': - {'auth_url': 'http://localhost/identity', 'password': - 'test_pw', 'username': 'test_user', 'project_name': - 'test_project'}, 'vim_type': 'openstack'} + 'vim_name': 'fake_vim', + 'vim_auth': + {'auth_url': 'http://localhost/identity', + 'password': 'test_pw', 'username': 'test_user', + 'project_name': 'test_project'}, + 'vim_type': 'openstack', + 'tenant': uuidsentinel.tenant_id} self.vim_client.get_vim.return_value = vim_obj @mock.patch('tacker.vnflcm.utils.get_default_scale_status') diff --git a/tacker/tests/unit/vnflcm/test_vnflcm_driver.py b/tacker/tests/unit/vnflcm/test_vnflcm_driver.py index d019465f1..925d5fd4b 100644 --- a/tacker/tests/unit/vnflcm/test_vnflcm_driver.py +++ b/tacker/tests/unit/vnflcm/test_vnflcm_driver.py @@ -184,10 +184,12 @@ class TestVnflcmDriver(db_base.SqlTestCase): def _stub_get_vim(self): vim_obj = {'vim_id': '6261579e-d6f3-49ad-8bc3-a9cb974778ff', - 'vim_name': 'fake_vim', 'vim_auth': - {'auth_url': 'http://localhost/identity', 'password': - 'test_pw', 'username': 'test_user', 'project_name': - 'test_project'}, 'vim_type': 'openstack'} + 'vim_name': 'fake_vim', + 'vim_auth': {'auth_url': 'http://localhost/identity', + 'password': 'test_pw', 'username': 'test_user', + 'project_name': 'test_project'}, + 'vim_type': 'openstack', + 'tenant': uuidsentinel.tenant_id} self.vim_client.get_vim.return_value = vim_obj @mock.patch('tacker.vnflcm.utils.get_default_scale_status') @@ -1228,16 +1230,7 @@ class TestVnflcmDriver(db_base.SqlTestCase): # Heal as per SOL003 i.e. without vnfcInstanceId heal_vnf_req = objects.HealVnfRequest() - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'openstack', - 'vim_auth': { - 'auth_url': 'http://localhost/identity', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - - mock_vim.return_value = vim_obj + mock_vim.return_value = fakes.get_dummy_openstack_vim_obj() vnf_instance = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) @@ -1915,15 +1908,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): None] mock_vnf_package_vnfd.return_value = fakes.return_vnf_package_vnfd() driver = vnflcm_driver.VnfLcmDriver() - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'kubernetes', - 'vim_auth': { - 'auth_url': 'http://localhost:8443', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - self.vim_client.get_vim.return_value = vim_obj + self.vim_client.get_vim.return_value = \ + fakes.get_dummy_kubernetes_vim_obj() driver.scale_vnf(self.context, vnf_info, vnf_instance, scale_vnf_request) @@ -1959,15 +1945,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() mock_yaml_safe_load.return_value = fakes.vnfd_dict_cnf() driver = vnflcm_driver.VnfLcmDriver() - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'kubernetes', - 'vim_auth': { - 'auth_url': 'http://localhost:8443', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - self.vim_client.get_vim.return_value = vim_obj + self.vim_client.get_vim.return_value = \ + fakes.get_dummy_kubernetes_vim_obj() driver.scale_vnf(self.context, vnf_info, vnf_instance, scale_vnf_request) @@ -3013,15 +2992,8 @@ class TestVnflcmDriver(db_base.SqlTestCase): mock_vnfd_dict.return_value = fakes.vnfd_dict_cnf() operation_params = jsonutils.loads(vnf_lcm_op_occs.operation_params) mock_yaml_safe_load.return_value = fakes.vnfd_dict_cnf() - vim_obj = {'vim_id': uuidsentinel.vim_id, - 'vim_name': 'fake_vim', - 'vim_type': 'kubernetes', - 'vim_auth': { - 'auth_url': 'http://localhost:8443', - 'password': 'test_pw', - 'username': 'test_user', - 'project_name': 'test_project'}} - self.vim_client.get_vim.return_value = vim_obj + self.vim_client.get_vim.return_value = \ + fakes.get_dummy_kubernetes_vim_obj() self._mock_vnf_manager() driver = vnflcm_driver.VnfLcmDriver() diff --git a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py index da1c38f61..e92b994b6 100644 --- a/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py +++ b/tacker/tests/unit/vnfm/infra_drivers/kubernetes/fakes.py @@ -1255,5 +1255,6 @@ def fake_k8s_vim_obj(): 'username': 'test_user', 'project_name': 'test_project'}, 'vim_type': 'kubernetes', + 'tenant': uuidsentinel.tenant_id, 'extra': {}} return vim_obj diff --git a/tacker/vnflcm/utils.py b/tacker/vnflcm/utils.py index 019442bde..65ee9de73 100644 --- a/tacker/vnflcm/utils.py +++ b/tacker/vnflcm/utils.py @@ -64,6 +64,7 @@ def _get_vim(context, vim_connection_info): vim_info = {'id': vim_res['vim_id'], 'vim_id': vim_res['vim_id'], 'vim_type': vim_res['vim_type'], 'access_info': vim_res['vim_auth'], + 'tenant_id': vim_res['tenant'], 'extra': vim_res.get('extra', {})} return vim_info diff --git a/tacker/vnflcm/vnflcm_driver.py b/tacker/vnflcm/vnflcm_driver.py index f1bc382aa..71cddc430 100644 --- a/tacker/vnflcm/vnflcm_driver.py +++ b/tacker/vnflcm/vnflcm_driver.py @@ -514,6 +514,11 @@ class VnfLcmDriver(abstract_driver.VnfInstanceAbstractDriver): vim_info = vnflcm_utils._get_vim(context, instantiate_vnf_req.vim_connection_info) + if vim_info['tenant_id'] != vnf_instance.tenant_id: + LOG.error('The tenants which target VNF and its VIM belongs to ' + 'are different each other.') + raise exceptions.TenantMatchFailure() + vim_connection_info = objects.VimConnectionInfo.obj_from_primitive( vim_info, context)