From f5599a3e575ed42bc1d4e7dff688eb19dce22d90 Mon Sep 17 00:00:00 2001 From: Ken Fujimoto Date: Mon, 10 Apr 2023 04:16:08 +0000 Subject: [PATCH] Fix missing modificationsTriggeredByVnfPkgChange This patch fixes the following problems. * Fix the problem that modificationsTriggeredByVnfPkgChange is not included in VnfLcmOpOcc when the change_vnfpkg v2 API is executed finished in COMPLETED. * According to SOL002 specification, vnfcInfo id should be unique in the VNFs. Currently there is no check uniqueness of vnfcInfo id when user sets metadata['VDU_VNFc_mapping'], so implement uniqueness and format checks when VnfInstance creation and Modify VNF Information operation. * Fix to keep the current VnfInstance "vnfConfigurableProperties", "extensions", and "metadata" when vnfdId is changed in Modify VNF Information. This is according to specification of change_vnfpkg v2 API. Closes-Bug: #2015941 Closes-Bug: #2015944 Change-Id: I12e9e432468fe3dd1e7ef5abdcd5cd7688dcf2a0 --- .../sol_refactored/common/lcm_op_occ_utils.py | 38 ++++-- .../common/vnf_instance_utils.py | 31 +++++ .../conductor/vnflcm_driver_v2.py | 45 ++++--- tacker/sol_refactored/controller/vnflcm_v2.py | 1 + .../infra_drivers/openstack/openstack.py | 9 +- .../v2/change_current_vnf_pkg_request.py | 4 - .../common/test_lcm_op_occ_utils.py | 44 ++++++- .../common/test_vnf_instance_utils.py | 30 +++++ .../conductor/test_vnflcm_driver_v2.py | 122 ++++++++++++++++-- .../controller/test_vnflcm_v2.py | 8 +- 10 files changed, 279 insertions(+), 53 deletions(-) diff --git a/tacker/sol_refactored/common/lcm_op_occ_utils.py b/tacker/sol_refactored/common/lcm_op_occ_utils.py index 8c1845596..af8e9017c 100644 --- a/tacker/sol_refactored/common/lcm_op_occ_utils.py +++ b/tacker/sol_refactored/common/lcm_op_occ_utils.py @@ -300,21 +300,24 @@ def _check_modification(inst_saved, inst, attr): return False +def _check_modification_inst(obj, inst_saved, inst): + obj.vnfdId = inst.vnfdId + if inst_saved.vnfProvider != inst.vnfProvider: + obj.vnfProvider = inst.vnfProvider + if inst_saved.vnfProductName != inst.vnfProductName: + obj.vnfProductName = inst.vnfProductName + if inst_saved.vnfSoftwareVersion != inst.vnfSoftwareVersion: + obj.vnfSoftwareVersion = inst.vnfSoftwareVersion + if inst_saved.vnfdVersion != inst.vnfdVersion: + obj.vnfdVersion = inst.vnfdVersion + + def _change_vnf_info(lcmocc, inst_saved, inst): vnf_info_modify = objects.VnfInfoModificationsV2() # vnfdid is required, don't check the existence of the value. if inst_saved.vnfdId != inst.vnfdId: - vnf_info_modify.vnfdId = inst.vnfdId - - if inst_saved.vnfProvider != inst.vnfProvider: - vnf_info_modify.vnfProvider = inst.vnfProvider - if inst_saved.vnfProductName != inst.vnfProductName: - vnf_info_modify.vnfProductName = inst.vnfProductName - if inst_saved.vnfSoftwareVersion != inst.vnfSoftwareVersion: - vnf_info_modify.vnfSoftwareVersion = inst.vnfSoftwareVersion - if inst_saved.vnfdVersion != inst.vnfdVersion: - vnf_info_modify.vnfdVersion = inst.vnfdVersion + _check_modification_inst(vnf_info_modify, inst_saved, inst) attrs = ['vnfInstanceName', 'vnfInstanceDescription', 'vnfConfigurableProperties', 'metadata', 'extensions'] @@ -365,6 +368,18 @@ def _change_vnf_info(lcmocc, inst_saved, inst): lcmocc.changedInfo = vnf_info_modify +def _create_modifications_triggered_by_vnfpkg_change(lcmocc, inst_saved, inst): + vnfpkg_modifications = objects.ModificationsTriggeredByVnfPkgChangeV2() + _check_modification_inst(vnfpkg_modifications, inst_saved, inst) + + attrs = ['vnfConfigurableProperties', 'metadata', 'extensions'] + for attr in attrs: + if _check_modification(inst_saved, inst, attr): + setattr(vnfpkg_modifications, attr, getattr(inst, attr)) + + lcmocc.modificationsTriggeredByVnfPkgChange = vnfpkg_modifications + + def update_lcmocc(lcmocc, inst_saved, inst): # if operation is MODIFY_INFO, make changedInfo of lcmocc. # for other operations, make ResourceChanges of lcmocc @@ -440,6 +455,9 @@ def update_lcmocc(lcmocc, inst_saved, inst): affected_vnfcs.append( _make_affected_vnfc_modified(vnfc, vnfc_saved)) + _create_modifications_triggered_by_vnfpkg_change( + lcmocc, inst_saved, inst) + removed_vls, added_vls, common_vls = _calc_diff( 'vnfVirtualLinkResourceInfo') affected_vls = [] diff --git a/tacker/sol_refactored/common/vnf_instance_utils.py b/tacker/sol_refactored/common/vnf_instance_utils.py index ceb893845..9d7a861aa 100644 --- a/tacker/sol_refactored/common/vnf_instance_utils.py +++ b/tacker/sol_refactored/common/vnf_instance_utils.py @@ -16,6 +16,8 @@ from oslo_log import log as logging +from tacker.sol_refactored.api.schemas import common_types +from tacker.sol_refactored.api import validator from tacker.sol_refactored.common import exceptions as sol_ex from tacker.sol_refactored import objects @@ -79,3 +81,32 @@ def select_vim_info(vim_connection_info): if vim_info.vimType == 'kubernetes': vim_info.vimType = 'ETSINFV.KUBERNETES.V_1' return vim_info + + +def check_metadata_format(metadata): + """Check VnfInstance.metadata format""" + # NOTE: This method checks keys which Tacker supports originally. + # The key supporting is only 'VDU_VNFc_mapping' for the moment. + + _vdu_vnfc_mapping = { + 'type': 'object', + 'patternProperties': { + '^.*$': { + 'type': 'array', + 'items': common_types.IdentifierInVnf + } + } + } + + if 'VDU_VNFc_mapping' in metadata: + schema_validator = validator.SolSchemaValidator(_vdu_vnfc_mapping) + schema_validator.validate(metadata['VDU_VNFc_mapping']) + + all_vnfc_info_ids = list() + for vnfc_info_ids in metadata['VDU_VNFc_mapping'].values(): + all_vnfc_info_ids.extend(vnfc_info_ids) + + if len(all_vnfc_info_ids) > len(set(all_vnfc_info_ids)): + raise sol_ex.SolValidationError( + detail="Duplicated vnfcInfo ids found in " + "metadata['VDU_VNFc_mapping'].") diff --git a/tacker/sol_refactored/conductor/vnflcm_driver_v2.py b/tacker/sol_refactored/conductor/vnflcm_driver_v2.py index fc0b32e0f..4ca7320c9 100644 --- a/tacker/sol_refactored/conductor/vnflcm_driver_v2.py +++ b/tacker/sol_refactored/conductor/vnflcm_driver_v2.py @@ -768,10 +768,9 @@ class VnfLcmDriverV2(object): def _modify_from_vnfd_prop(self, inst, vnfd_prop, attr): if vnfd_prop.get(attr): - setattr(inst, attr, vnfd_prop[attr]) - elif inst.obj_attr_is_set(attr): - # set {} since attribute deletion is not supported. - setattr(inst, attr, {}) + base = getattr(inst, attr) if inst.obj_attr_is_set(attr) else {} + setattr(inst, attr, inst_utils.json_merge_patch( + base, vnfd_prop[attr])) def _modify_from_req(self, inst, req, attr): if req.obj_attr_is_set(attr): @@ -779,6 +778,21 @@ class VnfLcmDriverV2(object): setattr(inst, attr, inst_utils.json_merge_patch( base, getattr(req, attr))) + def _modify_inst_vnfd_id(self, context, inst, vnfd): + pkg_info = self.nfvo_client.get_vnf_package_info_vnfd( + context, inst.vnfdId) + + vnfd_prop = vnfd.get_vnfd_properties() + + inst.vnfProvider = pkg_info.vnfProvider + inst.vnfProductName = pkg_info.vnfProductName + inst.vnfSoftwareVersion = pkg_info.vnfSoftwareVersion + inst.vnfdVersion = pkg_info.vnfdVersion + + attrs = ['vnfConfigurableProperties', 'metadata', 'extensions'] + for attr in attrs: + self._modify_from_vnfd_prop(inst, vnfd_prop, attr) + def _merge_vim_connection_info(self, inst, req): # used by MODIFY_INFO and CHANGE_EXT_CONN # inst.vimConnectionInfo exists since req.vimConnectionInfo @@ -804,26 +818,16 @@ class VnfLcmDriverV2(object): # NOTE: When vnfdId is changed, the values of attributes # in the VnfInstance needs update from new VNFD. inst.vnfdId = req.vnfdId - - pkg_info = self.nfvo_client.get_vnf_package_info_vnfd( - context, inst.vnfdId) - new_vnfd = self.nfvo_client.get_vnfd(context, inst.vnfdId) - new_vnfd_prop = new_vnfd.get_vnfd_properties() - - inst.vnfProvider = pkg_info.vnfProvider - inst.vnfProductName = pkg_info.vnfProductName - inst.vnfSoftwareVersion = pkg_info.vnfSoftwareVersion - inst.vnfdVersion = pkg_info.vnfdVersion - - attrs = ['vnfConfigurableProperties', 'metadata', 'extensions'] - for attr in attrs: - self._modify_from_vnfd_prop(inst, new_vnfd_prop, attr) + self._modify_inst_vnfd_id(context, inst, new_vnfd) attrs = ['vnfConfigurableProperties', 'metadata', 'extensions'] for attr in attrs: self._modify_from_req(inst, req, attr) + if inst.obj_attr_is_set('metadata'): + inst_utils.check_metadata_format(inst.metadata) + if req.obj_attr_is_set('vimConnectionInfo'): self._merge_vim_connection_info(inst, req) @@ -1127,6 +1131,11 @@ class VnfLcmDriverV2(object): raise sol_ex.SolException(sol_detail='not support vim type') inst.vnfdId = grant_req.dstVnfdId + self._modify_inst_vnfd_id(context, inst, vnfd) + + attrs = ['vnfConfigurableProperties', 'extensions'] + for attr in attrs: + self._modify_from_req(inst, req, attr) def change_vnfpkg_rollback( self, context, lcmocc, inst, grant_req, grant, vnfd): diff --git a/tacker/sol_refactored/controller/vnflcm_v2.py b/tacker/sol_refactored/controller/vnflcm_v2.py index b38074a5d..756ad0f87 100644 --- a/tacker/sol_refactored/controller/vnflcm_v2.py +++ b/tacker/sol_refactored/controller/vnflcm_v2.py @@ -76,6 +76,7 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController): metadata = vnfd_prop['metadata'] if 'metadata' in body: metadata = inst_utils.json_merge_patch(metadata, body['metadata']) + inst_utils.check_metadata_format(metadata) inst = objects.VnfInstanceV2( # required fields diff --git a/tacker/sol_refactored/infra_drivers/openstack/openstack.py b/tacker/sol_refactored/infra_drivers/openstack/openstack.py index 2462b3360..60b1c1a39 100644 --- a/tacker/sol_refactored/infra_drivers/openstack/openstack.py +++ b/tacker/sol_refactored/infra_drivers/openstack/openstack.py @@ -1256,12 +1256,10 @@ class Openstack(object): def _make_vnfc_info_id(self, inst, vnfc_res_info): vdu_idx = vnfc_res_info.metadata.get('vdu_idx') if (vdu_idx is not None and inst.obj_attr_is_set('metadata') and - 'VDU_VNFc_mapping' in inst.metadata and - isinstance(inst.metadata['VDU_VNFc_mapping'], dict)): + 'VDU_VNFc_mapping' in inst.metadata): vnfc_info_ids = inst.metadata['VDU_VNFc_mapping'].get( vnfc_res_info.vduId) - if (isinstance(vnfc_info_ids, list) and - len(vnfc_info_ids) > vdu_idx): + if vnfc_info_ids is not None and len(vnfc_info_ids) > vdu_idx: return vnfc_info_ids[vdu_idx] # default vnfc_id @@ -1498,6 +1496,9 @@ class Openstack(object): # re-use current object since # vnfcConfigurableProperties may be set. vnfc_info = old_vnfc_info + # metadata['VDU_VNFc_mapping'] may be changed + vnfc_info.id = self._make_vnfc_info_id(inst, + vnfc_res_info) break if vnfc_info is None: vnfc_info_id = self._make_vnfc_info_id(inst, vnfc_res_info) diff --git a/tacker/sol_refactored/objects/v2/change_current_vnf_pkg_request.py b/tacker/sol_refactored/objects/v2/change_current_vnf_pkg_request.py index a61dbf856..fa48aa384 100644 --- a/tacker/sol_refactored/objects/v2/change_current_vnf_pkg_request.py +++ b/tacker/sol_refactored/objects/v2/change_current_vnf_pkg_request.py @@ -35,10 +35,6 @@ class ChangeCurrentVnfPkgRequest(base.TackerObject, 'vimConnectionInfo': fields.DictOfObjectsField( 'VimConnectionInfo', nullable=True), 'additionalParams': fields.KeyValuePairsField(nullable=True), - # NOTE: 'extensions' is not supported. - # It can be specified but make no effect at all. 'extensions': fields.KeyValuePairsField(nullable=True), - # NOTE: 'vnfConfigurableProperties' is not supported. - # It can be specified but make no effect at all. 'vnfConfigurableProperties': fields.KeyValuePairsField(nullable=True), } diff --git a/tacker/tests/unit/sol_refactored/common/test_lcm_op_occ_utils.py b/tacker/tests/unit/sol_refactored/common/test_lcm_op_occ_utils.py index 1770a5568..8e3e8cfd2 100644 --- a/tacker/tests/unit/sol_refactored/common/test_lcm_op_occ_utils.py +++ b/tacker/tests/unit/sol_refactored/common/test_lcm_op_occ_utils.py @@ -2110,6 +2110,17 @@ _expected_resource_changes_change_vnfpkg = { ] } +_expected_modifications_triggered_by_vnfpkg_change = { + 'vnfdId': 'new_vnfd_id', + 'metadata': { + 'VDU_VNFc_mapping': { + 'VDU1': ['a-001', 'a-010', 'a-011'], + 'VDU2': ['b-001'], + 'VDU3': ['c-001'] + } + }, +} + # lcmocc_info_example _lcmocc_modify_value = { 'id': 'test-1', @@ -2327,12 +2338,36 @@ class TestLcmOpOccUtils(base.BaseTestCase): def test_update_lcmocc_change_vnfpkg(self): # prepare - inst_saved = objects.VnfInstanceV2() + inst_saved = objects.VnfInstanceV2( + vnfdId="old_vnfd_id", + vnfProvider="Company", + vnfProductName="Sample VNF", + vnfSoftwareVersion="1.0", + vnfdVersion="1.0", + metadata={ + 'VDU_VNFc_mapping': { + 'VDU1': ['a-001', 'a-010', 'a-011'], + 'VDU2': ['b-0'] + } + } + ) inst_saved.instantiatedVnfInfo = ( objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict( _inst_info_example_1)) - inst_saved.vnfdId = 'old_vnfd_id' - inst = objects.VnfInstanceV2() + inst = objects.VnfInstanceV2( + vnfdId="new_vnfd_id", + vnfProvider="Company", + vnfProductName="Sample VNF", + vnfSoftwareVersion="1.0", + vnfdVersion="1.0", + metadata={ + 'VDU_VNFc_mapping': { + 'VDU1': ['a-001', 'a-010', 'a-011'], + 'VDU2': ['b-001'], + 'VDU3': ['c-001'] + } + } + ) inst.instantiatedVnfInfo = ( objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict( _inst_info_example_5)) @@ -2346,6 +2381,9 @@ class TestLcmOpOccUtils(base.BaseTestCase): self.assertEqual( _expected_resource_changes_change_vnfpkg, self._sort_resource_changes(lcmocc['resourceChanges'])) + self.assertEqual( + _expected_modifications_triggered_by_vnfpkg_change, + lcmocc['modificationsTriggeredByVnfPkgChange']) @mock.patch.object(objects.base.TackerPersistentObject, 'get_by_id') def test_get_lcmocc(self, mock_lcmocc): diff --git a/tacker/tests/unit/sol_refactored/common/test_vnf_instance_utils.py b/tacker/tests/unit/sol_refactored/common/test_vnf_instance_utils.py index 08d2a55d9..16e8bd57f 100644 --- a/tacker/tests/unit/sol_refactored/common/test_vnf_instance_utils.py +++ b/tacker/tests/unit/sol_refactored/common/test_vnf_instance_utils.py @@ -135,3 +135,33 @@ class TestVnfInstanceUtils(base.BaseTestCase): self.assertEqual( 'ETSINFV.HELM.V_3', inst.vimConnectionInfo['vim1'].vimType) self.assertEqual('ETSINFV.HELM.V_3', result.vimType) + + def test_check_metadata(self): + # VDU_VNFc_mapping is not dict + metadata = { + "VDU_VNFc_mapping": "a-001" + } + self.assertRaises(sol_ex.SolValidationError, + inst_utils.check_metadata_format, metadata) + + # VDU_VNFc_mapping dict value is not list. + metadata = { + "VDU_VNFc_mapping": { + "VDU1": "a-001" + } + } + self.assertRaises(sol_ex.SolValidationError, + inst_utils.check_metadata_format, metadata) + + # Duplicate vnfcInfo id. + metadata = { + "VDU_VNFc_mapping": { + "VDU1": ["a-001", "a-002", "a-003"], + "VDU2": ["a-002"] + } + } + ex = self.assertRaises(sol_ex.SolValidationError, + inst_utils.check_metadata_format, metadata) + expected_detail = ("Duplicated vnfcInfo ids found in " + "metadata['VDU_VNFc_mapping'].") + self.assertEqual(expected_detail, ex.detail) diff --git a/tacker/tests/unit/sol_refactored/conductor/test_vnflcm_driver_v2.py b/tacker/tests/unit/sol_refactored/conductor/test_vnflcm_driver_v2.py index 6797ea5ba..a27e6cc05 100644 --- a/tacker/tests/unit/sol_refactored/conductor/test_vnflcm_driver_v2.py +++ b/tacker/tests/unit/sol_refactored/conductor/test_vnflcm_driver_v2.py @@ -694,6 +694,10 @@ _modify_inst_example = { }, "metadata": { "metadata": "example", + "VDU_VNFc_mapping": { + "VDU1": ["a-001", "a-002", "a-003"], + "VDU2": ["b-001"] + } }, "vimConnectionInfo": { "vim1": { @@ -1251,7 +1255,10 @@ class TestVnfLcmDriverV2(base.BaseTestCase): }, "metadata": { "metadata_1": "example_1", - "metadata_2": None + "metadata_2": None, + "VDU_VNFc_mapping": { + "VDU2": ["b-010"] + } }, "extensions": { "extensions": "example_1" @@ -1293,7 +1300,8 @@ class TestVnfLcmDriverV2(base.BaseTestCase): ] } ) - inst = objects.VnfInstanceV2.from_dict(_modify_inst_example) + inst_example = copy.deepcopy(_modify_inst_example) + inst = objects.VnfInstanceV2.from_dict(inst_example) vnfc_info = objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict( _modify_vnfc_info_example) inst.instantiatedVnfInfo = vnfc_info @@ -1327,7 +1335,11 @@ class TestVnfLcmDriverV2(base.BaseTestCase): }, "metadata": { "metadata": "example", - "metadata_1": "example_1" + "metadata_1": "example_1", + "VDU_VNFc_mapping": { + "VDU1": ["a-001", "a-002", "a-003"], + "VDU2": ["b-010"] + } }, "extensions": { "extensions": "example_1" @@ -1389,7 +1401,11 @@ class TestVnfLcmDriverV2(base.BaseTestCase): vnfdVersion="vnfd version", operationalState="ENABLED" ) - new_vnfd_prop = {} + new_vnfd_prop = { + 'vnfConfigurableProperties': {}, + 'extensions': {}, + 'metadata': {} + } mocked_get_vnf_package_info_vnfd.return_value = pkg_info mocked_get_vnfd.return_value = vnfd_utils.Vnfd(new_vnfd_id) @@ -1418,7 +1434,8 @@ class TestVnfLcmDriverV2(base.BaseTestCase): } } ) - inst = objects.VnfInstanceV2.from_dict(_modify_inst_example) + inst_example = copy.deepcopy(_modify_inst_example) + inst = objects.VnfInstanceV2.from_dict(inst_example) lcmocc = objects.VnfLcmOpOccV2( # required fields id=uuidutils.generate_uuid(), @@ -1443,8 +1460,16 @@ class TestVnfLcmDriverV2(base.BaseTestCase): "vnfProductName": "product_1", "vnfSoftwareVersion": "software version", "vnfdVersion": "vnfd version", - "vnfConfigurableProperties": {}, - "metadata": {}, + "vnfConfigurableProperties": { + "vnfproperties": "example" + }, + "metadata": { + "metadata": "example", + "VDU_VNFc_mapping": { + "VDU1": ["a-001", "a-002", "a-003"], + "VDU2": ["b-001"] + } + }, "vimConnectionInfo": { "vim1": { "vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3", @@ -2092,8 +2117,10 @@ class TestVnfLcmDriverV2(base.BaseTestCase): self.assertEqual(expected_res_ids[key][name], ids) @mock.patch.object(kubernetes.Kubernetes, 'change_vnfpkg') - @mock.patch.object(nfvo_client.NfvoClient, 'get_vnfd') - def test_cnf_change_vnfpkg(self, mock_vnfd, mock_change_vnfpkg): + @mock.patch.object(nfvo_client.NfvoClient, 'get_vnf_package_info_vnfd') + @mock.patch.object(vnfd_utils.Vnfd, 'get_vnfd_properties') + def test_cnf_change_vnfpkg(self, mock_get_vnfd_properties, + mock_get_vnf_package_info_vnfd, mock_change_vnfpkg): # prepare req_inst = objects.InstantiateVnfRequest.from_dict( _inst_cnf_req_example) @@ -2132,7 +2159,21 @@ class TestVnfLcmDriverV2(base.BaseTestCase): isAutomaticInvocation=False, isCancelPending=False, operationParams=req) - mock_vnfd.return_value = self.vnfd_2 + pkg_info = objects.VnfPkgInfoV2( + id=uuidutils.generate_uuid(), + vnfProvider="provider", + vnfProductName="product name", + vnfSoftwareVersion="software version", + vnfdVersion="vnfd version", + operationalState="ENABLED" + ) + vnfd_prop = { + "vnfConfigurableProperties": {}, + "metadata": {}, + "extensions": {} + } + mock_get_vnf_package_info_vnfd.return_value = pkg_info + mock_get_vnfd_properties.return_value = vnfd_prop self.driver.change_vnfpkg_process( self.context, lcmocc, inst, grant_req, grant, self.vnfd_3) @@ -3102,8 +3143,11 @@ class TestVnfLcmDriverV2(base.BaseTestCase): self.assertEqual(2, len(grant_req.addResources)) self.assertEqual(2, len(grant_req.removeResources)) + @mock.patch.object(nfvo_client.NfvoClient, 'get_vnf_package_info_vnfd') + @mock.patch.object(vnfd_utils.Vnfd, 'get_vnfd_properties') @mock.patch.object(openstack.Openstack, 'change_vnfpkg') - def test_change_vnfpkg_process(self, mock_change_vnfpkg): + def test_change_vnfpkg_process(self, mock_change_vnfpkg, + mock_get_vnfd_properties, mock_get_vnf_package_info_vnfd): # openstack req_inst = objects.InstantiateVnfRequest.from_dict(_inst_req_example) req = objects.ChangeCurrentVnfPkgRequest.from_dict( @@ -3120,10 +3164,20 @@ class TestVnfLcmDriverV2(base.BaseTestCase): vimConnectionInfo=req_inst.vimConnectionInfo, instantiatedVnfInfo=( objects.VnfInstanceV2_InstantiatedVnfInfo.from_dict( - _inst_info_example)) + _inst_info_example)), + vnfConfigurableProperties={ + "vnf_config_prop_key": "vnf_config_prop_value" + }, + metadata={ + 'VDU_VNFc_mapping': { + 'VDU1': ['a-001', 'a-010', 'a-011'], + 'VDU2': ['b-0'] + } + } ) + NEW_VNFD_ID = "8557e855-09e3-4f4c-9e4f-bfe5e2025700" grant_req = objects.GrantRequestV1( - dstVnfdId=SAMPLE_VNFD_ID, + dstVnfdId=NEW_VNFD_ID, operation=fields.LcmOperationType.CHANGE_VNFPKG ) grant = objects.GrantV1() @@ -3138,9 +3192,51 @@ class TestVnfLcmDriverV2(base.BaseTestCase): isAutomaticInvocation=False, isCancelPending=False, operationParams=req) + pkg_info = objects.VnfPkgInfoV2( + id=uuidutils.generate_uuid(), + vnfProvider="provider", + vnfProductName="product name", + vnfSoftwareVersion="software version", + vnfdVersion="vnfd version", + operationalState="ENABLED" + ) + vnfd_prop = { + 'vnfConfigurableProperties': {}, + 'extensions': { + 'extensions_key': 'extensions_value' + }, + 'metadata': { + 'VDU_VNFc_mapping': { + 'VDU3': ['c-0'] + } + } + } + mock_get_vnf_package_info_vnfd.return_value = pkg_info + mock_get_vnfd_properties.return_value = vnfd_prop + self.driver.change_vnfpkg_process( self.context, lcmocc, inst, grant_req, grant, self.vnfd_1) + inst = inst.to_dict() + expected_vnfconfigurableproperties_result = { + 'vnf_config_prop_key': 'vnf_config_prop_value' + } + expected_extensions_result = { + 'extensions_key': 'extensions_value' + } + expected_metadata_result = { + 'VDU_VNFc_mapping': { + 'VDU1': ['a-001', 'a-010', 'a-011'], + 'VDU2': ['b-0'], + 'VDU3': ['c-0'] + } + } + + self.assertEqual(expected_vnfconfigurableproperties_result, + inst['vnfConfigurableProperties']) + self.assertEqual(expected_extensions_result, inst['extensions']) + self.assertEqual(expected_metadata_result, inst['metadata']) + # error inst = objects.VnfInstanceV2( # required fields 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 b8a7828ab..ad3bdfd3c 100644 --- a/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py +++ b/tacker/tests/unit/sol_refactored/controller/test_vnflcm_v2.py @@ -707,7 +707,13 @@ class TestVnflcmV2(db_base.SqlTestCase): "vnfdId": vnfd_id, "vnfInstanceName": "test", "vnfInstanceDescription": "test", - "metadata": {"key": "value"} + "metadata": { + "key": "value", + "VDU_VNFc_mapping": { + "VDU1": ["a-001", "a-002", "a-003"], + "VDU2": ["b-001"] + } + } } result = self.controller.create(request=self.request, body=body) self.assertEqual(201, result.status)