diff --git a/releasenotes/notes/support-ext-nw-change-in-changevnf-23a2adfd82c30f9c.yaml b/releasenotes/notes/support-ext-nw-change-in-changevnf-23a2adfd82c30f9c.yaml new file mode 100644 index 000000000..380df63bc --- /dev/null +++ b/releasenotes/notes/support-ext-nw-change-in-changevnf-23a2adfd82c30f9c.yaml @@ -0,0 +1,9 @@ +features: + - | + Support Change Current VNF Package API to + add and delete external Connection Point (CP). + Support `extManagedVirtualLinks` attribute + in ChangeCurrentVnfPkgRequest to change + external management networks. + These support only when using StandardUserData + as the UserData class. diff --git a/tacker/sol_refactored/infra_drivers/openstack/heat_utils.py b/tacker/sol_refactored/infra_drivers/openstack/heat_utils.py index ab5a2502e..6f7c94101 100644 --- a/tacker/sol_refactored/infra_drivers/openstack/heat_utils.py +++ b/tacker/sol_refactored/infra_drivers/openstack/heat_utils.py @@ -53,7 +53,13 @@ class HeatClient(object): def update_stack(self, stack_name, fields, wait=True): path = f"stacks/{stack_name}" - resp, body = self.client.do_request(path, "PATCH", + # It was assumed that PATCH is used and therefore 'fields' + # contains only update parts and 'existing' is not used. + # Now full replacing 'fields' is supported and it is indicated + # by 'existing' is False. if 'existing' is specified and + # it is False, PUT is used. + method = "PATCH" if fields.pop('existing', True) else "PUT" + resp, body = self.client.do_request(path, method, expected_status=[202], body=fields) if wait: @@ -107,7 +113,7 @@ class HeatClient(object): LOG.info("%s %s done.", operation, stack_name.split('/')[0]) raise loopingcall.LoopingCallDone() elif status in failed_status: - LOG.error("% %s failed.", operation, stack_name.split('/')[0]) + LOG.error("%s %s failed.", operation, stack_name.split('/')[0]) sol_title = "%s failed" % operation raise sol_ex.StackOperationFailed(sol_title=sol_title, sol_detail=status_reason) diff --git a/tacker/sol_refactored/infra_drivers/openstack/openstack.py b/tacker/sol_refactored/infra_drivers/openstack/openstack.py index 4739fe0ba..1cc6222b2 100644 --- a/tacker/sol_refactored/infra_drivers/openstack/openstack.py +++ b/tacker/sol_refactored/infra_drivers/openstack/openstack.py @@ -126,11 +126,22 @@ class Openstack(object): stack_name = heat_utils.get_stack_name(inst) heat_client.delete_stack(stack_name) + def _is_full_fields(self, fields): + # NOTE: fields made by UserData class contains only update parts + # and 'existing' is not specified (and is thought as True) by + # default. if 'existing' is specified and it is False, fields is + # a full content. + return not fields.get('existing', True) + def _update_fields(self, heat_client, stack_name, fields): + if self._is_full_fields(fields): + # used by change_vnfpkg(, rollback) only at the moment. + return fields + if 'nfv' in fields.get('parameters', {}): parameters = heat_client.get_parameters(stack_name) LOG.debug("ORIG parameters: %s", parameters) - # NOTE: parameters['nfv'] is string + # NOTE: Using json.loads because parameters['nfv'] is string orig_nfv_dict = json.loads(parameters.get('nfv', '{}')) fields['parameters']['nfv'] = inst_utils.json_merge_patch( orig_nfv_dict, fields['parameters']['nfv']) @@ -334,6 +345,10 @@ class Openstack(object): vdu_name = _rsc_with_idx(vnfc.vduId, vnfc.metadata.get('vdu_idx')) return vdu_dict.get(vdu_name, {}).get('computeFlavourId') + def _get_zone_from_vdu_dict(self, vnfc, vdu_dict): + vdu_name = _rsc_with_idx(vnfc.vduId, vnfc.metadata.get('vdu_idx')) + return vdu_dict.get(vdu_name, {}).get('locationConstraints') + def _get_images_from_vdu_dict(self, vnfc, storage_infos, vdu_dict): vdu_idx = vnfc.metadata.get('vdu_idx') vdu_name = _rsc_with_idx(vnfc.vduId, vdu_idx) @@ -364,6 +379,20 @@ class Openstack(object): for vnfc in inst.instantiatedVnfInfo.vnfcResourceInfo if vnfc.computeResource.resourceId in vnfc_res_ids] + if self._is_full_fields(fields): + # NOTE: it is used by StandardUserData only at the moment, + # use it to check the fields is constructed by + # StandardUserData (and its inheritance) or not. + method = self._change_vnfpkg_rolling_update_user_data_standard + else: + # method for DefaultUserData (and its inheritance) + method = self._change_vnfpkg_rolling_update_user_data_default + + method(req, inst, grant_req, grant, vnfd, fields, heat_client, + vnfcs, is_rollback) + + def _change_vnfpkg_rolling_update_user_data_default(self, req, inst, + grant_req, grant, vnfd, fields, heat_client, vnfcs, is_rollback): templates = {} def _get_template(parent_stack_id): @@ -400,8 +429,7 @@ class Openstack(object): heat_client.update_stack(parent_stack_id, vdu_fields) else: # pickup 'vcImageId' and 'computeFlavourId' from vdu_dict - vdu_idx = vnfc.metadata.get('vdu_idx') - vdu_name = _rsc_with_idx(vnfc.vduId, vdu_idx) + vdu_name = vnfc.vduId new_vdus = {} flavor = self._get_flavor_from_vdu_dict(vnfc, vdu_dict) if flavor: @@ -418,17 +446,14 @@ class Openstack(object): # pickup 'CP' updates cp_names = vnfd.get_vdu_cps( inst.instantiatedVnfInfo.flavourId, vnfc.vduId) - new_cps = {} - for cp_name in cp_names: - cp_name = _rsc_with_idx(cp_name, vdu_idx) - if cp_name in cp_dict: - new_cps[cp_name] = cp_dict[cp_name] + new_cps = {cp_name: cp_dict[cp_name] + for cp_name in cp_names if cp_name in cp_dict} update_fields = { 'parameters': {'nfv': {'VDU': new_vdus, 'CP': new_cps}} } update_fields = self._update_fields(heat_client, stack_name, - update_fields) + update_fields) LOG.debug("stack fields: %s", update_fields) heat_client.update_stack(stack_name, update_fields) @@ -436,6 +461,80 @@ class Openstack(object): self._execute_coordinate_vnf_script(req, vnfd, vnfc, heat_client, is_rollback) + def _change_vnfpkg_rolling_update_user_data_standard(self, req, inst, + grant_req, grant, vnfd, fields, heat_client, vnfcs, is_rollback): + stack_name = heat_utils.get_stack_name(inst) + + # make base template + base_template = heat_client.get_template(stack_name) + new_template = yaml.safe_load(fields['template']) + diff_reses = { + res_name: res_value + for res_name, res_value in new_template['resources'].items() + if res_name not in base_template['resources'].keys() + } + base_template['resources'].update(diff_reses) + + base_files = heat_client.get_files(stack_name) + base_files.update(fields['files']) + + base_parameters = heat_client.get_parameters(stack_name) + # NOTE: Using json.loads because parameters['nfv'] is string + base_nfv_dict = json.loads(base_parameters.get('nfv', '{}')) + new_nfv_dict = fields['parameters']['nfv'] + + def _get_param_third_keys(res): + """Get third parameter keys + + example: + --- + VDU1-1: + type: VDU1.yaml + properties: + flavor: { get_param: [ nfv, VDU, VDU1-1, computeFlavourId ] } + image-VDU1: { get_param: [ nfv, VDU, VDU1-1, vcImageId ] } + net1: { get_param: [ nfv, CP, VDU1_CP1-1, network ] } + --- + returns {'VDU1-1', 'VDU1_CP1-1'} + """ + + keys = set() + for prop_value in res.get('properties', {}).values(): + if not isinstance(prop_value, dict): + continue + for key, value in prop_value.items(): + if (key == 'get_param' and isinstance(value, list) and + len(value) >= 4 and value[0] == 'nfv'): + keys.add(value[2]) + return keys + + for vnfc in vnfcs: + vdu_idx = vnfc.metadata.get('vdu_idx') + vdu_name = _rsc_with_idx(vnfc.vduId, vdu_idx) + + # replace VDU_{idx} part + target_res = new_template['resources'][vdu_name] + base_template['resources'][vdu_name] = target_res + + # update parameters + third_keys = _get_param_third_keys(target_res) + for item in ['VDU', 'CP']: + for key, value in new_nfv_dict.get(item, {}).items(): + if key in third_keys: + base_nfv_dict[item][key] = value + + update_fields = { + 'template': base_template, + 'files': base_files, + 'parameters': {'nfv': base_nfv_dict} + } + LOG.debug("update %s: stack fields: %s", vdu_name, update_fields) + heat_client.update_stack(stack_name, update_fields) + + # execute coordinate_vnf_script + self._execute_coordinate_vnf_script(req, vnfd, vnfc, heat_client, + is_rollback) + def _get_ssh_ip(self, stack_id, cp_name, heat_client): # NOTE: It is assumed that if the user want to use floating_ip, # he must specify the resource name of 'OS::Neutron::FloatingIP' @@ -997,6 +1096,10 @@ class Openstack(object): storage_infos, nfv_dict['VDU']) for vdu_name, image in images.items(): metadata[f'image-{vdu_name}'] = image + zone = self._get_zone_from_vdu_dict(vnfc_res_info, + nfv_dict['VDU']) + if zone is not None: + metadata['zone'] = zone def _make_instantiated_vnf_info(self, req, inst, grant_req, grant, vnfd, heat_client, is_rollback=False, stack_id=None): @@ -1005,6 +1108,7 @@ class Openstack(object): 'stack_id'] stack_name = heat_utils.get_stack_name(inst, stack_id) heat_reses = heat_client.get_resources(stack_name) + # NOTE: Using json.loads because parameters['nfv'] is string nfv_dict = json.loads(heat_client.get_parameters(stack_name)['nfv']) op = grant_req.operation diff --git a/tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py b/tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py index d957a65a7..1edfc42f7 100644 --- a/tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py +++ b/tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py @@ -137,24 +137,24 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} vdu_idxes = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) vdu_idxes[vdu_name] = 0 zones = {} for res in grant_req['addResources']: if res['type'] != 'COMPUTE': continue vdu_name = res['resourceTemplateId'] - if vdu_name not in poped_vdu: + if vdu_name not in popped_vdu: continue vdu_idx = vdu_idxes[vdu_name] vdu_idxes[vdu_name] += 1 zones[add_idx(vdu_name, vdu_idx)] = ( common_script_utils.get_param_zone_by_vnfc( res['id'], grant)) - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res nfv_dict = common_script_utils.init_nfv_dict(top_hot) @@ -231,10 +231,10 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} vdu_idxes = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) vdu_idxes[vdu_name] = common_script_utils.get_current_capacity( vdu_name, inst) @@ -243,14 +243,14 @@ class StandardUserData(userdata_utils.AbstractUserData): if res['type'] != 'COMPUTE': continue vdu_name = res['resourceTemplateId'] - if vdu_name not in poped_vdu: + if vdu_name not in popped_vdu: continue vdu_idx = vdu_idxes[vdu_name] vdu_idxes[vdu_name] += 1 zones[add_idx(vdu_name, vdu_idx)] = ( common_script_utils.get_param_zone_by_vnfc( res['id'], grant)) - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res nfv_dict = common_script_utils.init_nfv_dict(top_hot) @@ -393,9 +393,9 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) for inst_vnfc in inst['instantiatedVnfInfo'].get( 'vnfcResourceInfo', []): @@ -403,7 +403,7 @@ class StandardUserData(userdata_utils.AbstractUserData): if vdu_idx is None: continue vdu_name = inst_vnfc['vduId'] - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res nfv_dict = common_script_utils.init_nfv_dict(top_hot) @@ -424,9 +424,9 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) for inst_vnfc in inst['instantiatedVnfInfo'].get( 'vnfcResourceInfo', []): @@ -434,7 +434,7 @@ class StandardUserData(userdata_utils.AbstractUserData): if vdu_idx is None: continue vdu_name = inst_vnfc['vduId'] - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res nfv_dict = common_script_utils.init_nfv_dict(top_hot) @@ -455,9 +455,9 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) for res in grant_req['removeResources']: if res['type'] != 'COMPUTE': @@ -469,7 +469,7 @@ class StandardUserData(userdata_utils.AbstractUserData): vdu_idx = inst_vnfc['metadata']['vdu_idx'] break vdu_name = res['resourceTemplateId'] - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res nfv_dict = common_script_utils.init_nfv_dict(top_hot) @@ -499,28 +499,65 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) - for res in grant_req['removeResources']: - if res['type'] != 'COMPUTE': + target_vnfc_res_ids = [ + res['resource']['resourceId'] + for res in grant_req['removeResources'] + if res['type'] == 'COMPUTE' + ] + + cur_hot_reses = {} + new_hot_reses = {} + images = {} + flavors = {} + zones = {} + for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']: + vdu_idx = inst_vnfc['metadata'].get('vdu_idx') + if vdu_idx is None: + # should not be None. just check for consistency. continue - for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']: - if (inst_vnfc['computeResource']['resourceId'] == - res['resource']['resourceId']): - # must be found - vdu_idx = inst_vnfc['metadata']['vdu_idx'] - break - vdu_name = res['resourceTemplateId'] - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) - top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res + vdu_name = inst_vnfc['vduId'] + vdu_name_idx = add_idx(vdu_name, vdu_idx) - nfv_dict = common_script_utils.init_nfv_dict(top_hot) + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) + top_hot['resources'][vdu_name_idx] = res - vdus = nfv_dict.get('VDU', {}) - for vdu_name, vdu_value in vdus.items(): - vdu_name = rm_idx(vdu_name) + if (inst_vnfc['computeResource']['resourceId'] in + target_vnfc_res_ids): + new_hot_reses[vdu_name_idx] = res + else: + cur_hot_reses[vdu_name_idx] = res + + # NOTE: only zone is necessary for new_hot_reses + for key, value in inst_vnfc['metadata'].items(): + if key == 'flavor': + flavors[vdu_name_idx] = value + elif key == 'zone': + zones[vdu_name_idx] = value + elif key.startswith('image-'): + image_vdu = key.replace('image-', '') + images[image_vdu] = value + + cur_nfv_dict = common_script_utils.init_nfv_dict( + {'resources': cur_hot_reses}) + new_nfv_dict = common_script_utils.init_nfv_dict( + {'resources': new_hot_reses}) + cur_vdus = cur_nfv_dict.get('VDU', {}) + new_vdus = new_nfv_dict.get('VDU', {}) + + for vdu_name_idx, vdu_value in cur_vdus.items(): + if 'computeFlavourId' in vdu_value: + vdu_value['computeFlavourId'] = flavors.get(vdu_name_idx) + if 'vcImageId' in vdu_value: + vdu_value['vcImageId'] = images.get(vdu_name_idx) + if 'locationConstraints' in vdu_value: + vdu_value['locationConstraints'] = zones.get(vdu_name_idx) + + for vdu_name_idx, vdu_value in new_vdus.items(): + vdu_name = rm_idx(vdu_name_idx) if 'computeFlavourId' in vdu_value: vdu_value['computeFlavourId'] = ( common_script_utils.get_param_flavor( @@ -529,14 +566,33 @@ class StandardUserData(userdata_utils.AbstractUserData): vdu_value['vcImageId'] = common_script_utils.get_param_image( vdu_name, flavour_id, vnfd, grant) if 'locationConstraints' in vdu_value: - vdu_value.pop('locationConstraints') + vdu_value['locationConstraints'] = zones.get(vdu_name_idx) - cps = nfv_dict.get('CP', {}) - new_cps = _get_new_cps_from_req(cps, req, grant) + vdus = cur_vdus + vdus.update(new_vdus) + + cps = cur_nfv_dict.get('CP', {}) + cps.update(new_nfv_dict.get('CP', {})) + # NOTE: req includes only different part. some CPs in new_nfv_dict + # may be necessary to get from inst. + cur_cps = _get_new_cps_from_inst(cps, inst) + req_cps = _get_new_cps_from_req(cps, req, grant) + for cp_name in cps.keys(): + if cp_name in req_cps: + cps[cp_name] = req_cps[cp_name] + else: + cps[cp_name] = cur_cps[cp_name] + + common_script_utils.apply_ext_managed_vls(top_hot, req, grant) fields = { - 'parameters': {'nfv': {'VDU': vdus, 'CP': new_cps}} + 'template': yaml.safe_dump(top_hot), + 'parameters': {'nfv': {'VDU': vdus, 'CP': cps}}, + 'files': {}, + 'existing': False } + for key, value in hot_dict.get('files', {}).items(): + fields['files'][key] = yaml.safe_dump(value) return fields @@ -549,56 +605,57 @@ class StandardUserData(userdata_utils.AbstractUserData): top_hot = hot_dict['template'] # first modify VDU resources - poped_vdu = {} + popped_vdu = {} for vdu_name in vnfd.get_vdu_nodes(flavour_id).keys(): - poped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) - - for res in grant_req['removeResources']: - if res['type'] != 'COMPUTE': - continue - for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']: - if (inst_vnfc['computeResource']['resourceId'] == - res['resource']['resourceId']): - # must be found - vdu_idx = inst_vnfc['metadata']['vdu_idx'] - break - vdu_name = res['resourceTemplateId'] - res = add_idx_to_vdu_template(poped_vdu[vdu_name], vdu_idx) - top_hot['resources'][add_idx(vdu_name, vdu_idx)] = res - - nfv_dict = common_script_utils.init_nfv_dict(top_hot) + popped_vdu[vdu_name] = top_hot.get('resources', {}).pop(vdu_name) images = {} flavors = {} + zones = {} for inst_vnfc in inst['instantiatedVnfInfo']['vnfcResourceInfo']: vdu_idx = inst_vnfc['metadata'].get('vdu_idx') if vdu_idx is None: + # should not be None. just check for consistency. continue vdu_name = inst_vnfc['vduId'] - if vdu_name in flavors: - continue + vdu_name_idx = add_idx(vdu_name, vdu_idx) + + res = add_idx_to_vdu_template(popped_vdu[vdu_name], vdu_idx) + top_hot['resources'][vdu_name_idx] = res + for key, value in inst_vnfc['metadata'].items(): if key == 'flavor': - flavors[add_idx(vdu_name, vdu_idx)] = value + flavors[vdu_name_idx] = value + elif key == 'zone': + zones[vdu_name_idx] = value elif key.startswith('image-'): image_vdu = key.replace('image-', '') images[image_vdu] = value + nfv_dict = common_script_utils.init_nfv_dict(top_hot) + vdus = nfv_dict.get('VDU', {}) - new_vdus = {} - for vdu_name, vdu_value in vdus.items(): + for vdu_name_idx, vdu_value in vdus.items(): + vdu_name = rm_idx(vdu_name) if 'computeFlavourId' in vdu_value: - new_vdus.setdefault(vdu_name, {}) - new_vdus[vdu_name]['computeFlavourId'] = flavors.get(vdu_name) + vdu_value['computeFlavourId'] = flavors.get(vdu_name_idx) if 'vcImageId' in vdu_value: - new_vdus.setdefault(vdu_name, {}) - new_vdus[vdu_name]['vcImageId'] = images.get(vdu_name) + vdu_value['vcImageId'] = images.get(vdu_name_idx) + if 'locationConstraints' in vdu_value: + vdu_value['locationConstraints'] = zones.get(vdu_name_idx) cps = nfv_dict.get('CP', {}) new_cps = _get_new_cps_from_inst(cps, inst) + common_script_utils.apply_ext_managed_vls(top_hot, req, grant) + fields = { - 'parameters': {'nfv': {'VDU': new_vdus, 'CP': new_cps}} + 'template': yaml.safe_dump(top_hot), + 'parameters': {'nfv': {'VDU': vdus, 'CP': new_cps}}, + 'files': {}, + 'existing': False } + for key, value in hot_dict.get('files', {}).items(): + fields['files'][key] = yaml.safe_dump(value) return fields 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 feb98e9e7..a61dbf856 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 @@ -30,8 +30,6 @@ class ChangeCurrentVnfPkgRequest(base.TackerObject, 'vnfdId': fields.StringField(nullable=False), 'extVirtualLinks': fields.ListOfObjectsField( 'ExtVirtualLinkData', nullable=True), - # NOTE: 'extManagedVirtualLinks' is not supported. - # It can be specified but make no effect at all. 'extManagedVirtualLinks': fields.ListOfObjectsField( 'ExtManagedVirtualLinkData', nullable=True), 'vimConnectionInfo': fields.DictOfObjectsField( diff --git a/tacker/tests/functional/sol_v2/test_individual_vnfc_mgmt.py b/tacker/tests/functional/sol_v2/test_individual_vnfc_mgmt.py index 7df3c55d0..638827a12 100644 --- a/tacker/tests/functional/sol_v2/test_individual_vnfc_mgmt.py +++ b/tacker/tests/functional/sol_v2/test_individual_vnfc_mgmt.py @@ -53,11 +53,18 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest): cls.vnf_pkg_2, cls.vnfd_id_2 = cls.create_vnf_package( pkg_path_2, image_path=image_path, userdata_path=userdata_path) + # for change_vnfpkg network/flavor change test + pkg_path_3 = os.path.join(cur_dir, + "../sol_v2_common/samples/userdata_standard_change_vnfpkg_nw") + cls.vnf_pkg_3, cls.vnfd_id_3 = cls.create_vnf_package( + pkg_path_3, image_path=image_path, userdata_path=userdata_path) + @classmethod def tearDownClass(cls): super(IndividualVnfcMgmtTest, cls).tearDownClass() cls.delete_vnf_package(cls.vnf_pkg_1) cls.delete_vnf_package(cls.vnf_pkg_2) + cls.delete_vnf_package(cls.vnf_pkg_3) def setUp(self): super().setUp() @@ -86,7 +93,12 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest): vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) return vnfc['id'] + def _get_vnfc_cps(self, inst, vdu, index): + vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) + return {cp_info['cpdId'] for cp_info in vnfc['vnfcCpInfo']} + def _get_vnfc_cp_net_id(self, inst, vdu, index, cp): + # this is for external CPs vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) for cp_info in vnfc['vnfcCpInfo']: if cp_info['cpdId'] == cp: @@ -99,6 +111,20 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest): # must be found return ext_vl['resourceHandle']['resourceId'] + def _get_vnfc_cp_net_name(self, inst, vdu, index, cp): + # this is for internal CPs + vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) + for cp_info in vnfc['vnfcCpInfo']: + if cp_info['cpdId'] == cp: + # must be found + link_port_id = cp_info['vnfLinkPortId'] + break + for vl in inst['instantiatedVnfInfo']['vnfVirtualLinkResourceInfo']: + for port in vl['vnfLinkPorts']: + if port['id'] == link_port_id: + # must be found + return vl['vnfVirtualLinkDescId'] + def _get_vnfc_image(self, inst, vdu, index): vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) for key, value in vnfc['metadata'].items(): @@ -106,6 +132,11 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest): # must be found return value + def _get_vnfc_flavor(self, inst, vdu, index): + vnfc = self._get_vnfc_by_vdu_index(inst, vdu, index) + # must exist + return vnfc['metadata']['flavor'] + def _delete_instance(self, inst_id): for _ in range(3): resp, body = self.delete_vnf_instance(inst_id) @@ -559,3 +590,224 @@ class IndividualVnfcMgmtTest(test_vnflcm_basic_common.CommonVnfLcmTest): # Delete VNF instance self._delete_instance(inst_id) + + def test_change_vnfpkg_nw(self): + """Test change_vnfpkg with additional functions + + * Note: + This test focuses change_vnfpkg with the following changes. + - adding external CP + - change internal network + - change flavor + + TODO: add anoter patterns (ex. change extMgdVLs) + + * About LCM operations: + This test includes the following operations. + - Create VNF instance + - 1. Instantiate VNF instance + - Show VNF instance / check + - 2. Change_vnfpkg operation + - Show VNF instance / check + - Terminate VNF instance + - Delete VNF instance + """ + + net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt']) + subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1']) + + # Create VNF instance + create_req = paramgen.sample3_create(self.vnfd_id_1) + resp, body = self.create_vnf_instance(create_req) + self.assertEqual(201, resp.status_code) + inst_id = body['id'] + + # 1. Instantiate VNF instance + instantiate_req = paramgen.sample3_instantiate( + net_ids, subnet_ids, self.auth_url) + instantiate_req['instantiationLevelId'] = "instantiation_level_2" + resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_complete(lcmocc_id) + + # Show VNF instance + resp, inst_1 = self.show_vnf_instance(inst_id) + self.assertEqual(200, resp.status_code) + + # check number of VDUs and indexes + self.assertEqual({0, 1}, self._get_vdu_indexes(inst_1, 'VDU1')) + self.assertEqual({0}, self._get_vdu_indexes(inst_1, 'VDU2')) + + # 2. Change_vnfpkg operation + change_vnfpkg_req = paramgen.sample5_change_vnfpkg(self.vnfd_id_3, + net_ids, subnet_ids) + resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_complete(lcmocc_id) + + # Show VNF instance + resp, inst_2 = self.show_vnf_instance(inst_id) + self.assertEqual(200, resp.status_code) + + # check vnfdId is changed + self.assertEqual(self.vnfd_id_3, inst_2['vnfdId']) + # check images are changed + self.assertNotEqual(self._get_vnfc_image(inst_1, 'VDU1', 0), + self._get_vnfc_image(inst_2, 'VDU1', 0)) + self.assertNotEqual(self._get_vnfc_image(inst_1, 'VDU1', 1), + self._get_vnfc_image(inst_2, 'VDU1', 1)) + self.assertNotEqual(self._get_vnfc_image(inst_1, 'VDU2', 0), + self._get_vnfc_image(inst_2, 'VDU2', 0)) + # check flavor is changed (VDU2 only) + self.assertNotEqual(self._get_vnfc_flavor(inst_1, 'VDU2', 0), + self._get_vnfc_flavor(inst_2, 'VDU2', 0)) + # check external CPs; VDU1_CP4 and VDU2_CP4 are added + self.assertFalse('VDU1_CP4' in self._get_vnfc_cps(inst_1, 'VDU1', 0)) + self.assertFalse('VDU1_CP4' in self._get_vnfc_cps(inst_1, 'VDU1', 1)) + self.assertFalse('VDU2_CP4' in self._get_vnfc_cps(inst_1, 'VDU2', 0)) + self.assertTrue('VDU1_CP4' in self._get_vnfc_cps(inst_2, 'VDU1', 0)) + self.assertTrue('VDU1_CP4' in self._get_vnfc_cps(inst_2, 'VDU1', 1)) + self.assertTrue('VDU2_CP4' in self._get_vnfc_cps(inst_2, 'VDU2', 0)) + self.assertEqual(net_ids['net0'], + self._get_vnfc_cp_net_id(inst_2, 'VDU1', 0, 'VDU1_CP4')) + self.assertEqual(net_ids['net0'], + self._get_vnfc_cp_net_id(inst_2, 'VDU1', 1, 'VDU1_CP4')) + self.assertEqual(net_ids['net0'], + self._get_vnfc_cp_net_id(inst_2, 'VDU2', 0, 'VDU2_CP4')) + # check internal CPs; VDU1_CP3 and VDU2_CP3 are changed + self.assertEqual("internalVL2", + self._get_vnfc_cp_net_name(inst_1, 'VDU1', 0, 'VDU1_CP3')) + self.assertEqual("internalVL2", + self._get_vnfc_cp_net_name(inst_1, 'VDU1', 1, 'VDU1_CP3')) + self.assertEqual("internalVL2", + self._get_vnfc_cp_net_name(inst_1, 'VDU2', 0, 'VDU2_CP3')) + self.assertEqual("internalVL3", + self._get_vnfc_cp_net_name(inst_2, 'VDU1', 0, 'VDU1_CP3')) + self.assertEqual("internalVL3", + self._get_vnfc_cp_net_name(inst_2, 'VDU1', 1, 'VDU1_CP3')) + self.assertEqual("internalVL3", + self._get_vnfc_cp_net_name(inst_2, 'VDU2', 0, 'VDU2_CP3')) + + # Terminate VNF instance + terminate_req = paramgen.sample5_terminate() + resp, body = self.terminate_vnf_instance(inst_id, terminate_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_complete(lcmocc_id) + + # Delete VNF instance + self._delete_instance(inst_id) + + def test_change_vnfpkg_nw_rollback(self): + """Test rollback of change_vnfpkg with additional functions + + * Note: + This test focuses rollback of change_vnfpkg with the following + changes. + - adding external CP + - change internal network + - change flavor + + TODO: add anoter patterns (ex. change extMgdVLs) + + * About LCM operations: + This test includes the following operations. + - Create VNF instance + - 1. Instantiate VNF instance + - Show VNF instance / check + - 2. Change_vnfpkg operation => FAILED_TEMP + - Rollback + - Show VNF instance / check + - Terminate VNF instance + - Delete VNF instance + """ + + net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt']) + subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1']) + + # Create VNF instance + create_req = paramgen.sample3_create(self.vnfd_id_1) + resp, body = self.create_vnf_instance(create_req) + self.assertEqual(201, resp.status_code) + inst_id = body['id'] + + # 1. Instantiate VNF instance + instantiate_req = paramgen.sample3_instantiate( + net_ids, subnet_ids, self.auth_url) + instantiate_req['instantiationLevelId'] = "instantiation_level_2" + resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_complete(lcmocc_id) + + # Show VNF instance + resp, inst_1 = self.show_vnf_instance(inst_id) + self.assertEqual(200, resp.status_code) + + # check number of VDUs and indexes + self.assertEqual({0, 1}, self._get_vdu_indexes(inst_1, 'VDU1')) + self.assertEqual({0}, self._get_vdu_indexes(inst_1, 'VDU2')) + + # 2. Change_vnfpkg operation + self._put_fail_file('change_vnfpkg') + change_vnfpkg_req = paramgen.sample5_change_vnfpkg(self.vnfd_id_3, + net_ids, subnet_ids) + resp, body = self.change_vnfpkg(inst_id, change_vnfpkg_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_failed_temp(lcmocc_id) + self._rm_fail_file('change_vnfpkg') + + # Rollback + resp, body = self.rollback_lcmocc(lcmocc_id) + self.assertEqual(202, resp.status_code) + self.wait_lcmocc_rolled_back(lcmocc_id) + + # Show VNF instance + resp, inst_2 = self.show_vnf_instance(inst_id) + self.assertEqual(200, resp.status_code) + + # check vnfdId is not changed + self.assertEqual(self.vnfd_id_1, inst_2['vnfdId']) + # check images are not changed + self.assertEqual(self._get_vnfc_image(inst_1, 'VDU1', 0), + self._get_vnfc_image(inst_2, 'VDU1', 0)) + self.assertEqual(self._get_vnfc_image(inst_1, 'VDU1', 1), + self._get_vnfc_image(inst_2, 'VDU1', 1)) + self.assertEqual(self._get_vnfc_image(inst_1, 'VDU2', 0), + self._get_vnfc_image(inst_2, 'VDU2', 0)) + # check flavor is not changed (VDU2 only) + self.assertEqual(self._get_vnfc_flavor(inst_1, 'VDU2', 0), + self._get_vnfc_flavor(inst_2, 'VDU2', 0)) + # check external CPs; VDU1_CP4 and VDU2_CP4 are not added + self.assertFalse('VDU1_CP4' in self._get_vnfc_cps(inst_2, 'VDU1', 0)) + self.assertFalse('VDU1_CP4' in self._get_vnfc_cps(inst_2, 'VDU1', 1)) + self.assertFalse('VDU2_CP4' in self._get_vnfc_cps(inst_2, 'VDU2', 0)) + # check internal CPs; VDU1_CP3 and VDU2_CP3 are not changed + self.assertEqual( + self._get_vnfc_cp_net_name(inst_1, 'VDU1', 0, 'VDU1_CP3'), + self._get_vnfc_cp_net_name(inst_2, 'VDU1', 0, 'VDU1_CP3')) + self.assertEqual( + self._get_vnfc_cp_net_name(inst_1, 'VDU1', 1, 'VDU1_CP3'), + self._get_vnfc_cp_net_name(inst_2, 'VDU1', 1, 'VDU1_CP3')) + self.assertEqual( + self._get_vnfc_cp_net_name(inst_1, 'VDU2', 0, 'VDU2_CP3'), + self._get_vnfc_cp_net_name(inst_2, 'VDU2', 0, 'VDU2_CP3')) + + # Terminate VNF instance + terminate_req = paramgen.sample3_terminate() + resp, body = self.terminate_vnf_instance(inst_id, terminate_req) + self.assertEqual(202, resp.status_code) + + lcmocc_id = os.path.basename(resp.headers['Location']) + self.wait_lcmocc_complete(lcmocc_id) + + # Delete VNF instance + self._delete_instance(inst_id) diff --git a/tacker/tests/functional/sol_v2_common/paramgen.py b/tacker/tests/functional/sol_v2_common/paramgen.py index 7bcafd3ca..4e733383d 100644 --- a/tacker/tests/functional/sol_v2_common/paramgen.py +++ b/tacker/tests/functional/sol_v2_common/paramgen.py @@ -1015,7 +1015,7 @@ def sample3_instantiate(net_ids, subnet_ids, auth_url): "extVirtualLinks": [ext_vl_1], "extManagedVirtualLinks": [ { - "id": uuidutils.generate_uuid(), + "id": "ext_managed_vl_1", "vnfVirtualLinkDescId": "internalVL1", "resourceId": net_ids['net_mgmt'] }, @@ -1141,6 +1141,13 @@ def sample4_change_vnfpkg(vnfd_id, net_ids, subnet_ids): ] } ], + "extManagedVirtualLinks": [ + { + "id": "ext_managed_vl_1", + "vnfVirtualLinkDescId": "internalVL1", + "resourceId": net_ids['net_mgmt'] + }, + ], "additionalParams": { "upgrade_type": "RollingUpdate", "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_vnf.py", @@ -1197,3 +1204,139 @@ def server_notification(alarm_id): } } } + + +# sample5 is for change_vnfpkg network change test of StandardUserData +# +def sample5_change_vnfpkg(vnfd_id, net_ids, subnet_ids): + ext_vl_4 = { + "id": "ext_vl_id_net4", + "resourceId": net_ids['net0'], + "extCps": [ + { + "cpdId": "VDU1_CP4", + "cpConfig": { + "VDU1_CP4_1": { + "cpProtocolData": [{ + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [{ + "type": "IPV4", + "numDynamicAddresses": 1}]}}]} + } + }, + { + "cpdId": "VDU2_CP4", + "cpConfig": { + "VDU2_CP4_1": { + "cpProtocolData": [{ + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [{ + "type": "IPV4", + "numDynamicAddresses": 1}]}}]} + } + } + ] + } + + return { + "vnfdId": vnfd_id, + "extVirtualLinks": [ext_vl_4], + "extManagedVirtualLinks": [ + { + "id": "ext_managed_vl_1", + "vnfVirtualLinkDescId": "internalVL1", + "resourceId": net_ids['net_mgmt'] + }, + ], + "additionalParams": { + "upgrade_type": "RollingUpdate", + "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_vnf.py", + "lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_vnf.py", + "vdu_params": [ + { + "vdu_id": "VDU1", + "old_vnfc_param": { + "cp_name": "VDU1_CP1", + "username": "ubuntu", + "password": "ubuntu" + }, + "new_vnfc_param": { + "cp_name": "VDU1_CP1", + "username": "ubuntu", + "password": "ubuntu" + } + }, + { + "vdu_id": "VDU2", + "old_vnfc_param": { + "cp_name": "VDU2_CP1", + "username": "ubuntu", + "password": "ubuntu" + }, + "new_vnfc_param": { + "cp_name": "VDU2_CP1", + "username": "ubuntu", + "password": "ubuntu" + } + } + ], + "lcm-operation-user-data": "./UserData/userdata_standard.py", + "lcm-operation-user-data-class": "StandardUserData" + } + } + + +def sample5_change_vnfpkg_back(vnfd_id, net_ids, subnet_ids): + return { + "vnfdId": vnfd_id, + "extManagedVirtualLinks": [ + { + "id": "ext_managed_vl_1", + "vnfVirtualLinkDescId": "internalVL1", + "resourceId": net_ids['net_mgmt'] + }, + ], + "additionalParams": { + "upgrade_type": "RollingUpdate", + "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_vnf.py", + "lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_vnf.py", + "vdu_params": [ + { + "vdu_id": "VDU1", + "old_vnfc_param": { + "cp_name": "VDU1_CP1", + "username": "ubuntu", + "password": "ubuntu" + }, + "new_vnfc_param": { + "cp_name": "VDU1_CP1", + "username": "ubuntu", + "password": "ubuntu" + } + }, + { + "vdu_id": "VDU2", + "old_vnfc_param": { + "cp_name": "VDU2_CP1", + "username": "ubuntu", + "password": "ubuntu" + }, + "new_vnfc_param": { + "cp_name": "VDU2_CP1", + "username": "ubuntu", + "password": "ubuntu" + } + } + ], + "lcm-operation-user-data": "./UserData/userdata_standard.py", + "lcm-operation-user-data-class": "StandardUserData" + } + } + + +def sample5_terminate(): + return { + "terminationType": "FORCEFUL" + } diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/nested/VDU2.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/nested/VDU2.yaml index bf450bfff..2347906fc 100644 --- a/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/nested/VDU2.yaml +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/nested/VDU2.yaml @@ -45,7 +45,8 @@ resources: multi: type: OS::Cinder::VolumeType properties: - name: VDU2-multi + # making unique name to avoid conflicting with other packages + name: { list_join: ['-', [get_param: OS::stack_name, 'VDU2-multi']] } metadata: { multiattach: " True" } # extVL with numDynamicAddresses and subnet diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/sample3.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/sample3.yaml index b33393766..b008d988a 100644 --- a/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/sample3.yaml +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard/contents/BaseHOT/simple/sample3.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: 'Simple Base HOT for Sample VNF' +description: 'For Test of Individual Vnfc Management: sample3' parameters: nfv: diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU1.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU1.yaml index c0fdb03bb..5ce1cdc70 100644 --- a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU1.yaml +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU1.yaml @@ -6,14 +6,14 @@ parameters: type: string image-VDU1: type: string + zone: + type: string net1: type: string net2: type: string net3: type: string - affinity: - type: string resources: VDU1: @@ -25,14 +25,13 @@ resources: networks: - port: get_resource: VDU1_CP1 -# replace the following line to Port ID when extmanagedVLs' Ports are -# specified in instantiatevnfrequest +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest - port: get_resource: VDU1_CP2 - port: get_resource: VDU1_CP3 - scheduler_hints: - group: { get_param: affinity } + availability_zone: { get_param: zone } # extVL without FixedIP or with numDynamicAddresses VDU1_CP1: @@ -40,8 +39,8 @@ resources: properties: network: { get_param: net1 } -# CPs of internal VLs are deleted when extmanagedVLs and port are -# specified in instantiatevnfrequest +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest VDU1_CP2: type: OS::Neutron::Port properties: diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU2.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU2.yaml index ee3415333..efa0ad35b 100644 --- a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU2.yaml +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/nested/VDU2.yaml @@ -27,8 +27,8 @@ resources: networks: - port: get_resource: VDU2_CP1 -# replace the following line to Port ID when extmanagedVLs' Ports are -# specified in instantiatevnfrequest +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest - port: get_resource: VDU2_CP2 - port: @@ -45,7 +45,8 @@ resources: multi: type: OS::Cinder::VolumeType properties: - name: VDU2-multi + # making unique name to avoid conflicting with other packages + name: { list_join: ['-', [get_param: OS::stack_name, 'VDU2-multi']] } metadata: { multiattach: " True" } # extVL with numDynamicAddresses and subnet @@ -56,8 +57,8 @@ resources: fixed_ips: - subnet: { get_param: subnet1 } -# CPs of internal VLs are deleted when extmanagedVLs and port are -# specified in instantiatevnfrequest +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest VDU2_CP2: type: OS::Neutron::Port properties: diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/sample4.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/sample4.yaml index bad8030ac..2e5d7ae1c 100644 --- a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/sample4.yaml +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg/contents/BaseHOT/simple/sample4.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: 'Simple Base HOT for Sample VNF' +description: 'For Test of Individual Vnfc Management: sample4' parameters: nfv: @@ -11,10 +11,10 @@ resources: properties: flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] } image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] } + zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] } net1: { get_param: [ nfv, CP, VDU1_CP1, network ] } net2: { get_resource: internalVL1 } net3: { get_resource: internalVL2 } - affinity: { get_resource: nfvi_node_affinity } VDU2: type: VDU2.yaml @@ -27,7 +27,7 @@ resources: net3: { get_resource: internalVL2 } affinity: { get_resource: nfvi_node_affinity } -# delete the following lines when extmanagedVLs are specified in instantiatevnfrequest +# delete the following lines when extManagedVLs are specified in InstantiateVnfRequest internalVL1: type: OS::Neutron::Net internalVL2: diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU1-ver2.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU1-ver2.yaml new file mode 100644 index 000000000..fe1ae5052 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU1-ver2.yaml @@ -0,0 +1,61 @@ +heat_template_version: 2013-05-23 +description: 'VDU1 HOT for Sample VNF' + +parameters: + flavor: + type: string + image-VDU1: + type: string + net1: + type: string + net2: + type: string + net3: + type: string + net4: + type: string + zone: + type: string + +resources: + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: flavor } + name: VDU1 + image: { get_param: image-VDU1 } + networks: + - port: + get_resource: VDU1_CP1 +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest + - port: + get_resource: VDU1_CP2 + - port: + get_resource: VDU1_CP3 + - port: + get_resource: VDU1_CP4 + availability_zone: { get_param: zone } + +# extVL without FixedIP or with numDynamicAddresses + VDU1_CP1: + type: OS::Neutron::Port + properties: + network: { get_param: net1 } + + VDU1_CP4: + type: OS::Neutron::Port + properties: + network: { get_param: net4 } + +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest + VDU1_CP2: + type: OS::Neutron::Port + properties: + network: { get_param: net2 } + + VDU1_CP3: + type: OS::Neutron::Port + properties: + network: { get_param: net3 } diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU2-ver2.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU2-ver2.yaml new file mode 100644 index 000000000..a8be1573c --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/nested/VDU2-ver2.yaml @@ -0,0 +1,79 @@ +heat_template_version: 2013-05-23 +description: 'VDU2 HOT for Sample VNF' + +parameters: + flavor: + type: string + image-VDU2-VirtualStorage: + type: string + net1: + type: string + net2: + type: string + net3: + type: string + net4: + type: string + subnet1: + type: string + affinity: + type: string + +resources: + VDU2: + type: OS::Nova::Server + properties: + flavor: { get_param: flavor } + name: VDU2 + block_device_mapping_v2: [{"volume_id": { get_resource: VDU2-VirtualStorage }}] + networks: + - port: + get_resource: VDU2_CP1 +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest + - port: + get_resource: VDU2_CP2 + - port: + get_resource: VDU2_CP3 + - port: + get_resource: VDU2_CP4 + scheduler_hints: + group: {get_param: affinity } + + VDU2-VirtualStorage: + type: OS::Cinder::Volume + properties: + image: { get_param: image-VDU2-VirtualStorage } + size: 1 + volume_type: { get_resource: multi } + multi: + type: OS::Cinder::VolumeType + properties: + # making unique name to avoid conflicting with other packages + name: { list_join: ['-', [get_param: OS::stack_name, 'VDU2-multi']] } + metadata: { multiattach: " True" } + +# extVL with numDynamicAddresses and subnet + VDU2_CP1: + type: OS::Neutron::Port + properties: + network: { get_param: net1 } + fixed_ips: + - subnet: { get_param: subnet1 } + + VDU2_CP4: + type: OS::Neutron::Port + properties: + network: { get_param: net4 } + +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest + VDU2_CP2: + type: OS::Neutron::Port + properties: + network: { get_param: net2 } + + VDU2_CP3: + type: OS::Neutron::Port + properties: + network: { get_param: net3 } diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/sample5.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/sample5.yaml new file mode 100644 index 000000000..f3dd1eec1 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/BaseHOT/simple/sample5.yaml @@ -0,0 +1,59 @@ +heat_template_version: 2013-05-23 +description: 'For Test of Individual Vnfc Management: sample5' + +parameters: + nfv: + type: json + +resources: + VDU1: + type: VDU1-ver2.yaml + properties: + flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] } + image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] } + net1: { get_param: [ nfv, CP, VDU1_CP1, network ] } + net2: { get_resource: internalVL1 } + net3: { get_resource: internalVL3 } + net4: { get_param: [ nfv, CP, VDU1_CP4, network ] } + zone: { get_param: [ nfv, VDU, VDU1, locationConstraints ] } + + VDU2: + type: VDU2-ver2.yaml + properties: + flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] } + image-VDU2-VirtualStorage: { get_param: [ nfv, VDU, VDU2-VirtualStorage, vcImageId ] } + net1: { get_param: [ nfv, CP, VDU2_CP1, network ] } + subnet1: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, subnet ]} + net2: { get_resource: internalVL1 } + net3: { get_resource: internalVL3 } + net4: { get_param: [ nfv, CP, VDU2_CP4, network ] } + affinity: { get_resource: nfvi_node_affinity } + +# delete the following lines when extManagedVLs are specified in InstantiateVnfRequest + internalVL1: + type: OS::Neutron::Net + internalVL3: + type: OS::Neutron::Net + + internalVL1_subnet: + type: OS::Neutron::Subnet + properties: + ip_version: 4 + network: + get_resource: internalVL1 + cidr: 192.168.3.0/24 + internalVL3_subnet: + type: OS::Neutron::Subnet + properties: + ip_version: 4 + network: + get_resource: internalVL3 + cidr: 192.168.5.0/24 + + nfvi_node_affinity: + type: OS::Nova::ServerGroup + properties: + name: nfvi_node_affinity + policies: [ 'affinity' ] + +outputs: {} diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_df_simple.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_df_simple.yaml new file mode 100644 index 000000000..c2dd4cf73 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_df_simple.yaml @@ -0,0 +1,375 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Simple deployment flavour for Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - v2_sample5_types.yaml + +topology_template: + inputs: + descriptor_id: + type: string + descriptor_version: + type: string + provider: + type: string + product_name: + type: string + software_version: + type: string + vnfm_info: + type: list + entry_schema: + type: string + flavour_id: + type: string + flavour_description: + type: string + + substitution_mappings: + node_type: company.provider.VNF + properties: + flavour_id: simple + requirements: + virtual_link_external1_1: [ VDU1_CP1, virtual_link ] + virtual_link_external1_2: [ VDU2_CP1, virtual_link ] + virtual_link_external1_3: [ VDU1_CP4, virtual_link ] + virtual_link_external1_4: [ VDU2_CP4, virtual_link ] + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_description: A simple flavour + interfaces: + Vnflcm: + instantiate_start: + implementation: sample-script + instantiate_end: + implementation: sample-script + terminate_start: + implementation: sample-script + terminate_end: + implementation: sample-script + scale_start: + implementation: sample-script + scale_end: + implementation: sample-script + heal_start: + implementation: sample-script + heal_end: + implementation: sample-script + change_external_connectivity_start: + implementation: sample-script + change_external_connectivity_end: + implementation: sample-script + modify_information_start: + implementation: sample-script + modify_information_end: + implementation: sample-script + artifacts: + sample-script: + description: Sample script + type: tosca.artifacts.Implementation.Python + file: ../Scripts/sample_script.py + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: VDU1-image + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 0 GB + min_ram: 256 MB + size: 12 GB + capabilities: + virtual_compute: + properties: + requested_additional_capabilities: + properties: + requested_additional_capability_name: m1.tiny + support_mandatory: true + target_performance_parameters: + entry_schema: test + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 3 GB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + capabilities: + virtual_compute: + properties: + requested_additional_capabilities: + properties: + requested_additional_capability_name: m1.small + support_mandatory: true + target_performance_parameters: + entry_schema: test + virtual_memory: + virtual_mem_size: 2048 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 3 GB + requirements: + - virtual_storage: VDU2-VirtualStorage + + VDU2-VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 1 GB + rdma_enabled: true + sw_image_data: + name: cirros-0.5.2-x86_64-disk + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 0 GB + min_ram: 256 MB + size: 12 GB + + VDU1_CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU1 + + VDU1_CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL1 + + VDU1_CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL3 + + VDU1_CP4: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU1 + + VDU2_CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU2 + + VDU2_CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL1 + + VDU2_CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL3 + + VDU2_CP4: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU2 + + internalVL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: External Managed Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 192.168.3.0/24 + + internalVL3: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: External Managed Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 192.168.5.0/24 + + groups: + affinityOrAntiAffinityGroup1: + type: tosca.groups.nfv.PlacementGroup + members: [ VDU1, VDU2 ] + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + VDU1_scale: + name: VDU1_scale + description: VDU1 scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU2 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: VDU1_scale + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + VDU1_scale: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + VDU1_scale: + scale_level: 1 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 2 + targets: [ VDU1 ] + + - VDU2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 1 + targets: [ VDU2 ] + + - internalVL1_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL1 ] + + - internalVL3_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL3 ] + + - policy_antiaffinity_group: + type: tosca.policies.nfv.AntiAffinityRule + targets: [ affinityOrAntiAffinityGroup1 ] + properties: + scope: nfvi_node diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_top.vnfd.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_top.vnfd.yaml new file mode 100644 index 000000000..3ea77e0a4 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_top.vnfd.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - v2_sample5_types.yaml + - v2_sample5_df_simple.yaml + +topology_template: + inputs: + selected_flavour: + type: string + description: VNF deployment flavour selected by the consumer. It is provided in the API + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_id: { get_input: selected_flavour } + descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + provider: Company + product_name: Sample VNF + software_version: '1.0' + descriptor_version: '1.0' + vnfm_info: + - Tacker + requirements: + #- virtual_link_external # mapped in lower-level templates + #- virtual_link_internal # mapped in lower-level templates diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_types.yaml b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_types.yaml new file mode 100644 index 000000000..0aac5c339 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Definitions/v2_sample5_types.yaml @@ -0,0 +1,55 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: VNF type definition + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + company.provider.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + descriptor_id: + type: string + constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ] + default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + descriptor_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + provider: + type: string + constraints: [ valid_values: [ 'Company' ] ] + default: 'Company' + product_name: + type: string + constraints: [ valid_values: [ 'Sample VNF' ] ] + default: 'Sample VNF' + software_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + vnfm_info: + type: list + entry_schema: + type: string + constraints: [ valid_values: [ Tacker ] ] + default: [ Tacker ] + flavour_id: + type: string + constraints: [ valid_values: [ simple ] ] + default: simple + flavour_description: + type: string + default: "flavour" + requirements: + - virtual_link_external1: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_external2: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_internal: + capability: tosca.capabilities.nfv.VirtualLinkable + interfaces: + Vnflcm: + type: tosca.interfaces.nfv.Vnflcm diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/coordinate_vnf.py b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/coordinate_vnf.py new file mode 100644 index 000000000..d7057da6d --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/coordinate_vnf.py @@ -0,0 +1,46 @@ +# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import pickle +import sys + + +class FailScript(object): + def __init__(self, vnfc_param): + self.vnfc_param = vnfc_param + + def run(self): + operation = 'change_vnfpkg' + if self.vnfc_param['is_rollback']: + operation += '_rollback' + if os.path.exists(f'/tmp/{operation}'): + raise Exception(f'test {operation} error') + + +def main(): + vnfc_param = pickle.load(sys.stdin.buffer) + script = FailScript(vnfc_param) + script.run() + + +if __name__ == "__main__": + try: + main() + os._exit(0) + except Exception as ex: + sys.stderr.write(str(ex)) + sys.stderr.flush() + os._exit(1) diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/sample_script.py b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/sample_script.py new file mode 100644 index 000000000..cb98d4656 --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/Scripts/sample_script.py @@ -0,0 +1,68 @@ +# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import functools +import os +import pickle +import sys + + +class FailScript(object): + """Define error method for each operation + + For example: + + def instantiate_start(self): + if os.path.exists('/tmp/instantiate_start') + raise Exception('test instantiate_start error') + """ + + def __init__(self, req, inst, grant_req, grant, csar_dir): + self.req = req + self.inst = inst + self.grant_req = grant_req + self.grant = grant + self.csar_dir = csar_dir + + def _fail(self, method): + if os.path.exists(f'/tmp/{method}'): + raise Exception(f'test {method} error') + + def __getattr__(self, name): + return functools.partial(self._fail, name) + + +def main(): + script_dict = pickle.load(sys.stdin.buffer) + + operation = script_dict['operation'] + req = script_dict['request'] + inst = script_dict['vnf_instance'] + grant_req = script_dict['grant_request'] + grant = script_dict['grant_response'] + csar_dir = script_dict['tmp_csar_dir'] + + script = FailScript(req, inst, grant_req, grant, csar_dir) + getattr(script, operation)() + + +if __name__ == "__main__": + try: + main() + os._exit(0) + except Exception as ex: + sys.stderr.write(str(ex)) + sys.stderr.flush() + os._exit(1) diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/TOSCA-Metadata/TOSCA.meta b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 000000000..add63c59a --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/contents/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,4 @@ +TOSCA-Meta-File-Version: 1.0 +CSAR-Version: 1.1 +Created-by: Onboarding portal +Entry-Definitions: Definitions/v2_sample5_top.vnfd.yaml diff --git a/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/pkggen.py b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/pkggen.py new file mode 100644 index 000000000..daa5c07ac --- /dev/null +++ b/tacker/tests/functional/sol_v2_common/samples/userdata_standard_change_vnfpkg_nw/pkggen.py @@ -0,0 +1,60 @@ +# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import os +import shutil +import tempfile + +from oslo_utils import uuidutils + +from tacker.tests.functional.sol_v2_common import paramgen +from tacker.tests.functional.sol_v2_common import utils + + +zip_file_name = os.path.basename(os.path.abspath(".")) + '.zip' +tmp_dir = tempfile.mkdtemp() +vnfd_id = uuidutils.generate_uuid() + +# tacker/tests/etc... +# /functional/sol_v2_common/samples/sampleX +image_dir = "../../../../etc/samples/etsi/nfv/common/Files/images/" +image_file = "cirros-0.5.2-x86_64-disk.img" +image_path = os.path.abspath(image_dir + image_file) + +# tacker/sol_refactored/infra_drivers/openstack/userdata_standard.py +# /tests/functional/sol_v2_common/samples/sampleX +userdata_dir = "../../../../../sol_refactored/infra_drivers/openstack/" +userdata_file = "userdata_standard.py" +userdata_path = os.path.abspath(userdata_dir + userdata_file) + +utils.make_zip(".", tmp_dir, vnfd_id, image_path=image_path, + userdata_path=userdata_path) + +shutil.copy(os.path.join(tmp_dir, zip_file_name), ".") +shutil.rmtree(tmp_dir) + +net_ids = utils.get_network_ids(['net0', 'net1', 'net_mgmt']) +subnet_ids = utils.get_subnet_ids(['subnet0', 'subnet1']) + +change_vnfpkg_req = paramgen.sample5_change_vnfpkg( + vnfd_id, net_ids, subnet_ids) +change_vnfpkg_back_req = paramgen.sample5_change_vnfpkg_back( + "input-original-vnfd-id", net_ids, subnet_ids) + +with open("change_vnfpkg_req", "w") as f: + f.write(json.dumps(change_vnfpkg_req, indent=2)) +with open("change_vnfpkg_back_req", "w") as f: + f.write(json.dumps(change_vnfpkg_back_req, indent=2)) 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 482f35c4f..9983033a5 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 @@ -735,9 +735,7 @@ _change_vnfpkg_example = { "additionalParams": { "upgrade_type": "RollingUpdate", "lcm-operation-coordinate-old-vnf": "./Scripts/coordinate_old_vnf.py", - "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", "lcm-operation-coordinate-new-vnf": "./Scripts/coordinate_new_vnf.py", - "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", "vdu_params": [ { "vdu_id": "VDU1", @@ -769,9 +767,7 @@ _change_cnf_vnfpkg_example = { "additionalParams": { "upgrade_type": "RollingUpdate", "lcm-operation-coordinate-old-vnf": "Scripts/coordinate_old_vnf.py", - "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", "lcm-operation-coordinate-new-vnf": "Scripts/coordinate_new_vnf.py", - "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", "lcm-kubernetes-def-files": [ "Files/new_kubernetes/new_deployment.yaml" ], 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 62dcbfab2..47b747de3 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 @@ -156,6 +156,70 @@ _instantiate_req_example = { } } +# example for test of StandardUserData +_instantiate_req_example_S = { + "flavourId": SAMPLE_FLAVOUR_ID, + "extVirtualLinks": [ + { + "id": "id_ext_vl_1", + "resourceId": "res_id_ext_vl_1", + "extCps": [ + { + "cpdId": "VDU1_CP1", + "cpConfig": { + "VDU1_CP1_1": { + "cpProtocolData": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "numDynamicAddresses": 1 + } + ] + } + } + ] + } + } + }, + { + "cpdId": "VDU2_CP1", + "cpConfig": { + "VDU2_CP1_1": { + "cpProtocolData": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "numDynamicAddresses": 1, + "subnetId": "res_id_subnet" + } + ] + } + } + ] + } + } + } + ] + } + ], + "extManagedVirtualLinks": [ + { + "id": "id_ext_mgd_1", + "vnfVirtualLinkDescId": "internalVL1", + "resourceId": "res_id_internalVL1" + } + ], + "vimConnectionInfo": { + "vim1": _vim_connection_info_example + } +} + # ChangeExtVnfConnectivityRequest example _change_ext_conn_req_example = { "extVirtualLinks": [ @@ -233,54 +297,6 @@ _change_ext_conn_req_example = { ] } -_change_vnfpkg_example = { - "vnfdId": uuidutils.generate_uuid(), - "additionalParams": { - "upgrade_type": "RollingUpdate", - "lcm-operation-coordinate-old-vnf": "Scripts/coordinate_old_vnf.py", - "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", - "lcm-operation-coordinate-new-vnf": "Scripts/coordinate_new_vnf.py", - "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", - "vdu_params": [{ - "vdu_id": "VDU1", - "old_vnfc_param": { - "cp_name": "CP1", - "username": "ubuntu", - "password": "ubuntu" - }, - "new_vnfc_param": { - "cp_name": "CP1", - "username": "ubuntu", - "password": "ubuntu" - }, - }] - } -} - -_change_vnfpkg_example_2 = { - "vnfdId": uuidutils.generate_uuid(), - "additionalParams": { - "upgrade_type": "RollingUpdate", - "lcm-operation-coordinate-old-vnf": "Scripts/coordinate_old_vnf.py", - "lcm-operation-coordinate-old-vnf-class": "CoordinateOldVnf", - "lcm-operation-coordinate-new-vnf": "Scripts/coordinate_new_vnf.py", - "lcm-operation-coordinate-new-vnf-class": "CoordinateNewVnf", - "vdu_params": [{ - "vdu_id": "VDU2", - "old_vnfc_param": { - "cp_name": "CP1", - "username": "ubuntu", - "password": "ubuntu" - }, - "new_vnfc_param": { - "cp_name": "CP1", - "username": "ubuntu", - "password": "ubuntu" - }, - }] - } -} - # heat resources examples # NOTE: # - following attributes which are not related to tests are omitted. @@ -848,6 +864,328 @@ _heat_reses_example = ( _heat_reses_example_change_ext_conn = ( _heat_reses_example_base + _heat_reses_example_cps_after) +# heat resources example for test of StandardUserData +_stack_id_VDU1_0_S = ( + "vnf-881718c6-830b-4232-9e83-4b0cd7678713-VDU1-0-ntteaet43n2s/" + "46c6328e-db32-4da0-8dee-c69079644982") +_href_VDU1_0_S = "".join((_url, _stack_id_VDU1_0_S)) + +_stack_id_VDU1_1_S = ( + "vnf-881718c6-830b-4232-9e83-4b0cd7678713-VDU1-1-vswbicn4ezjc/" + "64e143e1-49dc-4114-ad7c-5bb74cbd1efe") +_href_VDU1_1_S = "".join((_url, _stack_id_VDU1_1_S)) + +_stack_id_VDU2_0_S = ( + "vnf-881718c6-830b-4232-9e83-4b0cd7678713-VDU2-0-hht2ozgyxu7q/" + "f1398e13-26ca-4d87-93ef-883bac1f82f6") +_href_VDU2_0_S = "".join((_url, _stack_id_VDU2_0_S)) + +_heat_reses_example_S = [ + { + "creation_time": "2022-11-24T23:31:01Z", + "resource_name": "VDU1-0", + "physical_resource_id": "46c6328e-db32-4da0-8dee-c69079644982", + "resource_type": "VDU1.yaml", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [] + }, + { + "creation_time": "2022-11-24T23:31:01Z", + "resource_name": "VDU1-1", + "physical_resource_id": "64e143e1-49dc-4114-ad7c-5bb74cbd1efe", + "resource_type": "VDU1.yaml", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [] + }, + { + "creation_time": "2022-11-24T23:31:02Z", + "resource_name": "internalVL2_subnet", + "physical_resource_id": "acbd442b-00cc-4dfa-9243-8943673ff8cb", + "resource_type": "OS::Neutron::Subnet", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [] + }, + { + "creation_time": "2022-11-24T23:31:02Z", + "resource_name": "VDU2-0", + "physical_resource_id": "f1398e13-26ca-4d87-93ef-883bac1f82f6", + "resource_type": "VDU2.yaml", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [] + }, + { + "creation_time": "2022-11-24T23:31:02Z", + "resource_name": "internalVL2", + "physical_resource_id": "res_id_internalVL2", + "resource_type": "OS::Neutron::Net", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [ + "VDU1-0", + "internalVL2_subnet", + "VDU2-0", + "VDU1-1" + ] + }, + { + "creation_time": "2022-11-24T23:31:02Z", + "resource_name": "nfvi_node_affinity", + "physical_resource_id": "a91fc295-72fd-456e-a607-67bbfceabece", + "resource_type": "OS::Nova::ServerGroup", + "links": [ + { + "href": _href, + "rel": "stack" + } + ], + "required_by": [ + "VDU2-0" + ] + }, + { + "creation_time": "2022-11-24T23:31:17Z", + "resource_name": "VDU1", + "physical_resource_id": "res_id_VDU1_0", + "resource_type": "OS::Nova::Server", + "links": [ + { + "href": _href_VDU1_0_S, + "rel": "stack" + } + ], + "required_by": [], + "parent_resource": "VDU1-0" + }, + { + "creation_time": "2022-11-24T23:31:17Z", + "resource_name": "VDU1_CP3", + "physical_resource_id": "res_id_VDU1_CP3_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU1_CP1", + "physical_resource_id": "res_id_VDU1_CP1_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU1_CP2", + "physical_resource_id": "res_id_VDU1_CP2_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU1", + "physical_resource_id": "res_id_VDU1_1", + "resource_type": "OS::Nova::Server", + "links": [ + { + "href": _href_VDU1_1_S, + "rel": "stack" + } + ], + "required_by": [], + "parent_resource": "VDU1-1" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU1_CP3", + "physical_resource_id": "res_id_VDU1_CP3_1", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_1_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-1" + }, + { + "creation_time": "2022-11-24T23:31:19Z", + "resource_name": "VDU1_CP1", + "physical_resource_id": "res_id_VDU1_CP1_1", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_1_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-1" + }, + { + "creation_time": "2022-11-24T23:31:20Z", + "resource_name": "VDU1_CP2", + "physical_resource_id": "res_id_VDU1_CP2_1", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU1_1_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU1" + ], + "parent_resource": "VDU1-1" + }, + { + "creation_time": "2022-11-24T23:31:17Z", + "resource_name": "VDU2", + "physical_resource_id": "res_id_VDU2_0", + "resource_type": "OS::Nova::Server", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [], + "parent_resource": "VDU2-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU2_CP3", + "physical_resource_id": "res_id_VDU2_CP3_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU2" + ], + "parent_resource": "VDU2-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "VDU2-VirtualStorage", + "physical_resource_id": "res_id_VDU2-VirtualStorage_0", + "resource_type": "OS::Cinder::Volume", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU2" + ], + "parent_resource": "VDU2-0" + }, + { + "creation_time": "2022-11-24T23:31:18Z", + "resource_name": "multi", + "physical_resource_id": "3374895e-2f83-4061-bad7-1085215efa68", + "resource_type": "OS::Cinder::VolumeType", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU2-VirtualStorage" + ], + "parent_resource": "VDU2-0" + }, + { + "creation_time": "2022-11-24T23:31:19Z", + "resource_name": "VDU2_CP2", + "physical_resource_id": "res_id_VDU2_CP2_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU2" + ], + "parent_resource": "VDU2-0" + }, + { + "creation_time": "2022-11-24T23:31:20Z", + "resource_name": "VDU2_CP1", + "physical_resource_id": "res_id_VDU2_CP1_0", + "resource_type": "OS::Neutron::Port", + "links": [ + { + "href": _href_VDU2_0_S, + "rel": "stack" + } + ], + "required_by": [ + "VDU2" + ], + "parent_resource": "VDU2-0" + } +] + # heat get_parameters example _nfv_dict = { "VDU": { @@ -860,6 +1198,21 @@ _heat_get_parameters_example = { 'nfv': json.dumps(_nfv_dict) } +# heat get_parameters example for test of StandardUserData +_nfv_dict_S = { + "VDU": { + "VDU1-0": {"vcImageId": "image-VDU1", "computeFlavourId": "m1.tiny", + "locationConstraints": "zone1"}, + "VDU1-1": {"vcImageId": "image-VDU1", "computeFlavourId": "m1.tiny", + "locationConstraints": "zone1"}, + "VDU2-0": {"computeFlavourId": "m1.small"}, + "VDU2-VirtualStorage-0": {"vcImageId": "image-VDU2"} + } +} +_heat_get_parameters_example_S = { + 'nfv': json.dumps(_nfv_dict_S) +} + # heat get_template example _heat_get_template_example = { "resources": { @@ -2266,6 +2619,382 @@ _expected_inst_info_change_ext_conn = { } } +# expected results for test of StandardUserData +_expected_inst_info_S = { + "flavourId": "simple", + "vnfState": "STARTED", + "extCpInfo": [ + { + "id": "cp-res_id_VDU1_CP1_0", + "cpdId": "VDU1_CP1", + "cpConfigId": "VDU1_CP1_1", + "cpProtocolInfo": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "isDynamic": True + } + ] + } + } + ], + "extLinkPortId": "res_id_VDU1_CP1_0", + "associatedVnfcCpId": "VDU1_CP1-res_id_VDU1_0" + }, + { + "id": "cp-res_id_VDU1_CP1_1", + "cpdId": "VDU1_CP1", + "cpConfigId": "VDU1_CP1_1", + "cpProtocolInfo": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "isDynamic": True + } + ] + } + } + ], + "extLinkPortId": "res_id_VDU1_CP1_1", + "associatedVnfcCpId": "VDU1_CP1-res_id_VDU1_1" + }, + { + "id": "cp-res_id_VDU2_CP1_0", + "cpdId": "VDU2_CP1", + "cpConfigId": "VDU2_CP1_1", + "cpProtocolInfo": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "isDynamic": True, + "subnetId": "res_id_subnet" + } + ] + } + } + ], + "extLinkPortId": "res_id_VDU2_CP1_0", + "associatedVnfcCpId": "VDU2_CP1-res_id_VDU2_0" + } + ], + "extVirtualLinkInfo": [ + { + "id": "id_ext_vl_1", + "resourceHandle": { + "resourceId": "res_id_ext_vl_1" + }, + "extLinkPorts": [ + { + "id": "res_id_VDU1_CP1_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP1_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "cp-res_id_VDU1_CP1_0" + }, + { + "id": "res_id_VDU1_CP1_1", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP1_1", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "cp-res_id_VDU1_CP1_1" + }, + { + "id": "res_id_VDU2_CP1_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU2_CP1_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "cp-res_id_VDU2_CP1_0" + } + ], + "currentVnfExtCpData": [ + { + "cpdId": "VDU1_CP1", + "cpConfig": { + "VDU1_CP1_1": { + "cpProtocolData": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "numDynamicAddresses": 1 + } + ] + } + } + ] + } + } + }, + { + "cpdId": "VDU2_CP1", + "cpConfig": { + "VDU2_CP1_1": { + "cpProtocolData": [ + { + "layerProtocol": "IP_OVER_ETHERNET", + "ipOverEthernet": { + "ipAddresses": [ + { + "type": "IPV4", + "numDynamicAddresses": 1, + "subnetId": "res_id_subnet" + } + ] + } + } + ] + } + } + } + ] + } + ], + "extManagedVirtualLinkInfo": [ + { + "id": "id_ext_mgd_1", + "vnfVirtualLinkDescId": "internalVL1", + "networkResource": { + "resourceId": "res_id_internalVL1" + }, + "vnfLinkPorts": [ + { + "id": "res_id_VDU1_CP2_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP2_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU1_CP2-res_id_VDU1_0", + "cpInstanceType": "VNFC_CP" + }, + { + "id": "res_id_VDU1_CP2_1", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP2_1", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU1_CP2-res_id_VDU1_1", + "cpInstanceType": "VNFC_CP" + }, + { + "id": "res_id_VDU2_CP2_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU2_CP2_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU2_CP2-res_id_VDU2_0", + "cpInstanceType": "VNFC_CP" + } + ] + } + ], + "vnfcResourceInfo": [ + { + "id": "res_id_VDU1_1", + "vduId": "VDU1", + "computeResource": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_1", + "vimLevelResourceType": "OS::Nova::Server" + }, + "vnfcCpInfo": [ + { + "id": "VDU1_CP1-res_id_VDU1_1", + "cpdId": "VDU1_CP1", + "vnfExtCpId": "cp-res_id_VDU1_CP1_1" + }, + { + "id": "VDU1_CP2-res_id_VDU1_1", + "cpdId": "VDU1_CP2", + "vnfLinkPortId": "res_id_VDU1_CP2_1" + }, + { + "id": "VDU1_CP3-res_id_VDU1_1", + "cpdId": "VDU1_CP3", + "vnfLinkPortId": "res_id_VDU1_CP3_1" + } + ], + "metadata": { + "creation_time": "2022-11-24T23:31:18Z", + "stack_id": _stack_id_VDU1_1_S, + "vdu_idx": 1, + "flavor": "m1.tiny", + "image-VDU1-1": "image-VDU1", + "zone": "zone1" + } + }, + { + "id": "res_id_VDU1_0", + "vduId": "VDU1", + "computeResource": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_0", + "vimLevelResourceType": "OS::Nova::Server" + }, + "vnfcCpInfo": [ + { + "id": "VDU1_CP1-res_id_VDU1_0", + "cpdId": "VDU1_CP1", + "vnfExtCpId": "cp-res_id_VDU1_CP1_0" + }, + { + "id": "VDU1_CP2-res_id_VDU1_0", + "cpdId": "VDU1_CP2", + "vnfLinkPortId": "res_id_VDU1_CP2_0" + }, + { + "id": "VDU1_CP3-res_id_VDU1_0", + "cpdId": "VDU1_CP3", + "vnfLinkPortId": "res_id_VDU1_CP3_0" + } + ], + "metadata": { + "creation_time": "2022-11-24T23:31:17Z", + "stack_id": _stack_id_VDU1_0_S, + "vdu_idx": 0, + "flavor": "m1.tiny", + "image-VDU1-0": "image-VDU1", + "zone": "zone1" + } + }, + { + "id": "res_id_VDU2_0", + "vduId": "VDU2", + "computeResource": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU2_0", + "vimLevelResourceType": "OS::Nova::Server" + }, + "storageResourceIds": [ + "res_id_VDU2-VirtualStorage_0" + ], + "vnfcCpInfo": [ + { + "id": "VDU2_CP1-res_id_VDU2_0", + "cpdId": "VDU2_CP1", + "vnfExtCpId": "cp-res_id_VDU2_CP1_0" + }, + { + "id": "VDU2_CP2-res_id_VDU2_0", + "cpdId": "VDU2_CP2", + "vnfLinkPortId": "res_id_VDU2_CP2_0" + }, + { + "id": "VDU2_CP3-res_id_VDU2_0", + "cpdId": "VDU2_CP3", + "vnfLinkPortId": "res_id_VDU2_CP3_0" + } + ], + "metadata": { + "creation_time": "2022-11-24T23:31:17Z", + "stack_id": _stack_id_VDU2_0_S, + "vdu_idx": 0, + "flavor": "m1.small", + "image-VDU2-VirtualStorage-0": "image-VDU2" + } + } + ], + "vnfVirtualLinkResourceInfo": [ + { + "id": "res_id_internalVL2", + "vnfVirtualLinkDescId": "internalVL2", + "networkResource": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_internalVL2", + "vimLevelResourceType": "OS::Neutron::Net" + }, + "vnfLinkPorts": [ + { + "id": "res_id_VDU1_CP3_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP3_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU1_CP3-res_id_VDU1_0", + "cpInstanceType": "VNFC_CP" + }, + { + "id": "res_id_VDU1_CP3_1", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU1_CP3_1", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU1_CP3-res_id_VDU1_1", + "cpInstanceType": "VNFC_CP" + }, + { + "id": "res_id_VDU2_CP3_0", + "resourceHandle": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU2_CP3_0", + "vimLevelResourceType": "OS::Neutron::Port" + }, + "cpInstanceId": "VDU2_CP3-res_id_VDU2_0", + "cpInstanceType": "VNFC_CP" + } + ] + } + ], + "virtualStorageResourceInfo": [ + { + "id": "res_id_VDU2-VirtualStorage_0", + "virtualStorageDescId": "VDU2-VirtualStorage", + "storageResource": { + "vimConnectionId": "vim_id_1", + "resourceId": "res_id_VDU2-VirtualStorage_0", + "vimLevelResourceType": "OS::Cinder::Volume" + }, + "metadata": { + "stack_id": _stack_id_VDU2_0_S + } + } + ], + "vnfcInfo": [ + { + "id": "VDU1-res_id_VDU1_1", + "vduId": "VDU1", + "vnfcResourceInfoId": "res_id_VDU1_1", + "vnfcState": "STARTED" + }, + { + "id": "VDU1-res_id_VDU1_0", + "vduId": "VDU1", + "vnfcResourceInfoId": "res_id_VDU1_0", + "vnfcState": "STARTED" + }, + { + "id": "VDU2-res_id_VDU2_0", + "vduId": "VDU2", + "vnfcResourceInfoId": "res_id_VDU2_0", + "vnfcState": "STARTED" + } + ], + "metadata": { + "stack_id": STACK_ID + } +} + mock_resource = { 'resources': [{ 'updated_time': '2021-12-27T02:53:29Z', @@ -2760,6 +3489,9 @@ class TestOpenstack(base.BaseTestCase): self.vnfd_1 = vnfd_utils.Vnfd(SAMPLE_VNFD_ID) self.vnfd_1.init_from_csar_dir(os.path.join(sample_dir, "sample1")) + self.vnfd_S = vnfd_utils.Vnfd(SAMPLE_VNFD_ID) + self.vnfd_S.init_from_csar_dir(os.path.join(sample_dir, + "standard_sample")) def _check_inst_info(self, expected, result): # sort lists before compare with an expected result since @@ -2921,6 +3653,36 @@ class TestOpenstack(base.BaseTestCase): result = inst.to_dict()["instantiatedVnfInfo"] self._check_inst_info(_expected_inst_info_change_ext_conn, result) + def test_make_instantiated_vnf_info_standard(self): + # test of _make_instantiated_vnf_info when StandardUserData is used. + # NOTE: main difference between DefaultUserData is making metadata + # of VnfcResourceInfo. + # prepare + req = objects.InstantiateVnfRequest.from_dict( + _instantiate_req_example_S) + inst = objects.VnfInstanceV2( + id=uuidutils.generate_uuid(), + vimConnectionInfo=req.vimConnectionInfo + ) + grant_req = objects.GrantRequestV1( + operation=fields.LcmOperationType.INSTANTIATE + ) + grant = objects.GrantV1() + + # prepare heat responses + heat_client = mock.Mock() + heat_client.get_resources.return_value = _heat_reses_example_S + heat_client.get_parameters.return_value = ( + _heat_get_parameters_example_S) + + # execute make_instantiated_vnf_info + self.driver._make_instantiated_vnf_info(req, inst, grant_req, grant, + self.vnfd_S, heat_client, stack_id=STACK_ID) + + # check + result = inst.to_dict()["instantiatedVnfInfo"] + self._check_inst_info(_expected_inst_info_S, result) + @mock.patch.object(openstack.heat_utils.HeatClient, 'get_stack_id') @mock.patch.object(openstack.heat_utils.HeatClient, 'get_status') @mock.patch.object(openstack.heat_utils.HeatClient, 'create_stack') diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU1.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU1.yaml new file mode 100644 index 000000000..9b219de05 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU1.yaml @@ -0,0 +1,52 @@ +heat_template_version: 2013-05-23 +description: 'VDU1 HOT for Sample VNF' + +parameters: + flavor: + type: string + image-VDU1: + type: string + net1: + type: string + net2: + type: string + net3: + type: string + zone: + type: string + +resources: + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: flavor } + name: VDU1 + image: { get_param: image-VDU1 } + networks: + - port: + get_resource: VDU1_CP1 +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest + - port: + get_resource: VDU1_CP2 + - port: + get_resource: VDU1_CP3 + availability_zone: { get_param: zone } + +# extVL without FixedIP or with numDynamicAddresses + VDU1_CP1: + type: OS::Neutron::Port + properties: + network: { get_param: net1 } + +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest + VDU1_CP2: + type: OS::Neutron::Port + properties: + network: { get_param: net2 } + + VDU1_CP3: + type: OS::Neutron::Port + properties: + network: { get_param: net3 } diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU2.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU2.yaml new file mode 100644 index 000000000..7763410d0 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/nested/VDU2.yaml @@ -0,0 +1,69 @@ +heat_template_version: 2013-05-23 +description: 'VDU2 HOT for Sample VNF' + +parameters: + flavor: + type: string + image-VDU2-VirtualStorage: + type: string + net1: + type: string + net2: + type: string + net3: + type: string + subnet1: + type: string + affinity: + type: string + +resources: + VDU2: + type: OS::Nova::Server + properties: + flavor: { get_param: flavor } + name: VDU2 + block_device_mapping_v2: [{"volume_id": { get_resource: VDU2-VirtualStorage }}] + networks: + - port: + get_resource: VDU2_CP1 +# replace the following line to Port ID when extManagedVLs' Ports are +# specified in InstantiateVnfRequest + - port: + get_resource: VDU2_CP2 + - port: + get_resource: VDU2_CP3 + scheduler_hints: + group: {get_param: affinity } + + VDU2-VirtualStorage: + type: OS::Cinder::Volume + properties: + image: { get_param: image-VDU2-VirtualStorage } + size: 1 + volume_type: { get_resource: multi } + multi: + type: OS::Cinder::VolumeType + properties: + name: VDU2-multi + metadata: { multiattach: " True" } + +# extVL with numDynamicAddresses and subnet + VDU2_CP1: + type: OS::Neutron::Port + properties: + network: { get_param: net1 } + fixed_ips: + - subnet: { get_param: subnet1 } + +# CPs of internal VLs are deleted when extManagedVLs and port are +# specified in InstantiateVnfRequest + VDU2_CP2: + type: OS::Neutron::Port + properties: + network: { get_param: net2 } + + VDU2_CP3: + type: OS::Neutron::Port + properties: + network: { get_param: net3 } diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/sample3.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/sample3.yaml new file mode 100644 index 000000000..08b421929 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/BaseHOT/simple/sample3.yaml @@ -0,0 +1,57 @@ +heat_template_version: 2013-05-23 +description: 'Simple Base HOT for Sample VNF' + +parameters: + nfv: + type: json + +resources: + VDU1: + type: VDU1.yaml + properties: + flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] } + image-VDU1: { get_param: [ nfv, VDU, VDU1, vcImageId ] } + net1: { get_param: [ nfv, CP, VDU1_CP1, network ] } + net2: { get_resource: internalVL1 } + net3: { get_resource: internalVL2 } + zone: { get_param: [ nfv, VDU, VDU1, locationConstraints ] } + + VDU2: + type: VDU2.yaml + properties: + flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] } + image-VDU2-VirtualStorage: { get_param: [ nfv, VDU, VDU2-VirtualStorage, vcImageId ] } + net1: { get_param: [ nfv, CP, VDU2_CP1, network ] } + subnet1: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, subnet ]} + net2: { get_resource: internalVL1 } + net3: { get_resource: internalVL2 } + affinity: { get_resource: nfvi_node_affinity } + +# delete the following lines when extManagedVLs are specified in InstantiateVnfRequest + internalVL1: + type: OS::Neutron::Net + internalVL2: + type: OS::Neutron::Net + + internalVL1_subnet: + type: OS::Neutron::Subnet + properties: + ip_version: 4 + network: + get_resource: internalVL1 + cidr: 192.168.3.0/24 + internalVL2_subnet: + type: OS::Neutron::Subnet + properties: + ip_version: 4 + network: + get_resource: internalVL2 + cidr: 192.168.4.0/24 + + nfvi_node_affinity: + type: OS::Nova::ServerGroup + properties: + name: nfvi_node_affinity + policies: [ 'affinity' ] + +outputs: {} diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_df_simple.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_df_simple.yaml new file mode 100644 index 000000000..d3efc8796 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_df_simple.yaml @@ -0,0 +1,357 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Simple deployment flavour for Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - v2_sample3_types.yaml + +topology_template: + inputs: + descriptor_id: + type: string + descriptor_version: + type: string + provider: + type: string + product_name: + type: string + software_version: + type: string + vnfm_info: + type: list + entry_schema: + type: string + flavour_id: + type: string + flavour_description: + type: string + + substitution_mappings: + node_type: company.provider.VNF + properties: + flavour_id: simple + requirements: + virtual_link_external1_1: [ VDU1_CP1, virtual_link ] + virtual_link_external1_2: [ VDU2_CP1, virtual_link ] + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_description: A simple flavour + interfaces: + Vnflcm: + instantiate_start: + implementation: sample-script + instantiate_end: + implementation: sample-script + terminate_start: + implementation: sample-script + terminate_end: + implementation: sample-script + scale_start: + implementation: sample-script + scale_end: + implementation: sample-script + heal_start: + implementation: sample-script + heal_end: + implementation: sample-script + change_external_connectivity_start: + implementation: sample-script + change_external_connectivity_end: + implementation: sample-script + modify_information_start: + implementation: sample-script + modify_information_end: + implementation: sample-script + artifacts: + sample-script: + description: Sample script + type: tosca.artifacts.Implementation.Python + file: ../Scripts/sample_script.py + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: cirros-0.5.2-x86_64-disk + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 0 GB + min_ram: 256 MB + size: 12 GB + capabilities: + virtual_compute: + properties: + requested_additional_capabilities: + properties: + requested_additional_capability_name: m1.tiny + support_mandatory: true + target_performance_parameters: + entry_schema: test + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 3 GB + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 1 + capabilities: + virtual_compute: + properties: + requested_additional_capabilities: + properties: + requested_additional_capability_name: m1.tiny + support_mandatory: true + target_performance_parameters: + entry_schema: test + virtual_memory: + virtual_mem_size: 512 MB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 3 GB + requirements: + - virtual_storage: VDU2-VirtualStorage + + VDU2-VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 1 GB + rdma_enabled: true + sw_image_data: + name: VDU2-VirtualStorage-image + version: '0.5.2' + checksum: + algorithm: sha-256 + hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464 + container_format: bare + disk_format: qcow2 + min_disk: 0 GB + min_ram: 256 MB + size: 12 GB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: ../Files/images/cirros-0.5.2-x86_64-disk.img + + VDU1_CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU1 + + VDU1_CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL1 + + VDU1_CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU1 + - virtual_link: internalVL2 + + VDU2_CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU2 + + VDU2_CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL1 + + VDU2_CP3: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 2 + requirements: + - virtual_binding: VDU2 + - virtual_link: internalVL2 + + internalVL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: External Managed Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 192.168.3.0/24 + + internalVL2: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: External Managed Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 192.168.4.0/24 + + groups: + affinityOrAntiAffinityGroup1: + type: tosca.groups.nfv.PlacementGroup + members: [ VDU1, VDU2 ] + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + VDU1_scale: + name: VDU1_scale + description: VDU1 scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU2 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: VDU1_scale + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + VDU1_scale: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + VDU1_scale: + scale_level: 1 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 2 + targets: [ VDU1 ] + + - VDU2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 1 + targets: [ VDU2 ] + + - internalVL1_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL1 ] + + - internalVL2_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ internalVL2 ] + + - policy_antiaffinity_group: + type: tosca.policies.nfv.AntiAffinityRule + targets: [ affinityOrAntiAffinityGroup1 ] + properties: + scope: nfvi_node diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_top.vnfd.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_top.vnfd.yaml new file mode 100644 index 000000000..af82904b3 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_top.vnfd.yaml @@ -0,0 +1,31 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: Sample VNF + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + - v2_sample3_types.yaml + - v2_sample3_df_simple.yaml + +topology_template: + inputs: + selected_flavour: + type: string + description: VNF deployment flavour selected by the consumer. It is provided in the API + + node_templates: + VNF: + type: company.provider.VNF + properties: + flavour_id: { get_input: selected_flavour } + descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + provider: Company + product_name: Sample VNF + software_version: '1.0' + descriptor_version: '1.0' + vnfm_info: + - Tacker + requirements: + #- virtual_link_external # mapped in lower-level templates + #- virtual_link_internal # mapped in lower-level templates diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_types.yaml b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_types.yaml new file mode 100644 index 000000000..8fff47c24 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/Definitions/v2_sample3_types.yaml @@ -0,0 +1,55 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: VNF type definition + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +node_types: + company.provider.VNF: + derived_from: tosca.nodes.nfv.VNF + properties: + descriptor_id: + type: string + constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d7000000 ] ] + default: b1bb0ce7-ebca-4fa7-95ed-4840d7000000 + descriptor_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + provider: + type: string + constraints: [ valid_values: [ 'Company' ] ] + default: 'Company' + product_name: + type: string + constraints: [ valid_values: [ 'Sample VNF' ] ] + default: 'Sample VNF' + software_version: + type: string + constraints: [ valid_values: [ '1.0' ] ] + default: '1.0' + vnfm_info: + type: list + entry_schema: + type: string + constraints: [ valid_values: [ Tacker ] ] + default: [ Tacker ] + flavour_id: + type: string + constraints: [ valid_values: [ simple ] ] + default: simple + flavour_description: + type: string + default: "flavour" + requirements: + - virtual_link_external1: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_external2: + capability: tosca.capabilities.nfv.VirtualLinkable + - virtual_link_internal: + capability: tosca.capabilities.nfv.VirtualLinkable + interfaces: + Vnflcm: + type: tosca.interfaces.nfv.Vnflcm \ No newline at end of file diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/coordinate_vnf.py b/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/coordinate_vnf.py new file mode 100644 index 000000000..d7057da6d --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/coordinate_vnf.py @@ -0,0 +1,46 @@ +# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import pickle +import sys + + +class FailScript(object): + def __init__(self, vnfc_param): + self.vnfc_param = vnfc_param + + def run(self): + operation = 'change_vnfpkg' + if self.vnfc_param['is_rollback']: + operation += '_rollback' + if os.path.exists(f'/tmp/{operation}'): + raise Exception(f'test {operation} error') + + +def main(): + vnfc_param = pickle.load(sys.stdin.buffer) + script = FailScript(vnfc_param) + script.run() + + +if __name__ == "__main__": + try: + main() + os._exit(0) + except Exception as ex: + sys.stderr.write(str(ex)) + sys.stderr.flush() + os._exit(1) diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/sample_script.py b/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/sample_script.py new file mode 100644 index 000000000..cb98d4656 --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/Scripts/sample_script.py @@ -0,0 +1,68 @@ +# Copyright (C) 2022 Nippon Telegraph and Telephone Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import functools +import os +import pickle +import sys + + +class FailScript(object): + """Define error method for each operation + + For example: + + def instantiate_start(self): + if os.path.exists('/tmp/instantiate_start') + raise Exception('test instantiate_start error') + """ + + def __init__(self, req, inst, grant_req, grant, csar_dir): + self.req = req + self.inst = inst + self.grant_req = grant_req + self.grant = grant + self.csar_dir = csar_dir + + def _fail(self, method): + if os.path.exists(f'/tmp/{method}'): + raise Exception(f'test {method} error') + + def __getattr__(self, name): + return functools.partial(self._fail, name) + + +def main(): + script_dict = pickle.load(sys.stdin.buffer) + + operation = script_dict['operation'] + req = script_dict['request'] + inst = script_dict['vnf_instance'] + grant_req = script_dict['grant_request'] + grant = script_dict['grant_response'] + csar_dir = script_dict['tmp_csar_dir'] + + script = FailScript(req, inst, grant_req, grant, csar_dir) + getattr(script, operation)() + + +if __name__ == "__main__": + try: + main() + os._exit(0) + except Exception as ex: + sys.stderr.write(str(ex)) + sys.stderr.flush() + os._exit(1) diff --git a/tacker/tests/unit/sol_refactored/samples/standard_sample/TOSCA-Metadata/TOSCA.meta b/tacker/tests/unit/sol_refactored/samples/standard_sample/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 000000000..c96ce5f5c --- /dev/null +++ b/tacker/tests/unit/sol_refactored/samples/standard_sample/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,4 @@ +TOSCA-Meta-File-Version: 1.0 +CSAR-Version: 1.1 +Created-by: Onboarding portal +Entry-Definitions: Definitions/v2_sample3_top.vnfd.yaml