# Copyright (C) 2022 Fujitsu # 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 yaml from oslo_serialization import jsonutils from oslo_utils import uuidutils from tacker.tests import uuidsentinel class GrantV2: GRANT_REQ_PATH = '/grant/v2/grants' TOKEN = '/token' ZONES = [ { "id": uuidsentinel.zone_id, "zoneId": "nova", "vimConnectionId": uuidsentinel.vim_connection_id } ] ADDITIONAL_PARAMS = { "key": "value" } @staticmethod def _make_vim_connection_info(): access_info = { "username": "nfv_user", "region": "RegionOne", "password": "devstack", "project": "nfv", "projectDomain": "Default", "userDomain": "Default" } return { "vim1": { "vimId": uuidsentinel.vim_connection_id, "vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3", "interfaceInfo": {"endpoint": 'http://127.0.0.1/identity/v3'}, "accessInfo": access_info, "extra": {"dummy-key": "dummy-val"} } } @staticmethod def make_grant_v2_links(request_body): link = { "self": { # set fake server port. "href": os.path.join( 'http://localhost:9990', 'grant/v2/grants')}, "vnfLcmOpOcc": { "href": os.path.join( 'http://localhost:9890/vnflcm/v1/vnf_lcm_op_occs', request_body['vnfLcmOpOccId'])}, "vnfInstance": { "href": os.path.join( 'http://localhost:9890/vnflcm/v1/vnf_instances', request_body['vnfInstanceId'])}} return link @staticmethod def _make_add_resources(req_add_resources, zones=None, placement_constraints=None): add_resources = [] for req_add_resource in req_add_resources: res_add_resource = { "resourceDefinitionId": req_add_resource['id'], "vimConnectionId": uuidsentinel.vim_connection_id } if req_add_resource['type'] == 'COMPUTE': if placement_constraints: zone_id_dict = (GrantV2. _get_zone_id_from_placement_constraint( placement_constraints, zones)) if zone_id_dict[req_add_resource['id']]: res_add_resource["zoneId"] = zone_id_dict[ req_add_resource['id']] add_resources.append(res_add_resource) return add_resources @staticmethod def _get_zone_id_from_placement_constraint(placement_constraints, zones): zone_id_dict = {} for placement_constraint in placement_constraints: for index in range(len(placement_constraint['resource'])): if placement_constraint[ 'affinityOrAntiAffinity'] == 'AFFINITY': # In this fake_grant, if the user set 'AFFINITY' # rule in VNF Package, it will always use the first # `Availability Zone` to create VM. zone_id_dict[placement_constraint[ 'resource'][index]['resourceId']] = zones[0]['id'] else: try: zone_id_dict[placement_constraint[ 'resource'][index]['resourceId']] = zones[ index]['id'] except IndexError: print( "The number of 'Availability Zone'" "cannot support current case.") raise IndexError return zone_id_dict @staticmethod def _make_zones(zone_name_list): zone = [] for name in zone_name_list: zone_dict = { "id": uuidutils.generate_uuid(), "zoneId": name, "vimConnectionId": uuidsentinel.vim_connection_id } zone.append(zone_dict) return zone @staticmethod def _make_remove_resources(req_remove_resources): res_remove_resources = [] for req_remove_resource in req_remove_resources: res_remove_resource = { "resourceDefinitionId": req_remove_resource['id'] } res_remove_resources.append(res_remove_resource) return res_remove_resources @staticmethod def _make_update_resources(req_update_resources, zones=None, placement_constraints=None): res_update_resources = [] for req_update_resource in req_update_resources: res_update_resource = { "resourceDefinitionId": req_update_resource['id'], "vimConnectionId": uuidsentinel.vim_connection_id } if req_update_resource['type'] == 'COMPUTE': if placement_constraints: zone_id_dict = (GrantV2. _get_zone_id_from_placement_constraint( placement_constraints, zones)) if zone_id_dict[req_update_resource['id']]: res_update_resource["zoneId"] = zone_id_dict[ req_update_resource['id']] res_update_resources.append(res_update_resource) return res_update_resources @staticmethod def get_vdu_list(add_resources): vdu_list = [] for add_resource in add_resources: if add_resource['type'] == 'COMPUTE' or ( add_resource['type'] == 'STORAGE'): if add_resource.get('vduId'): vdu_list.append(add_resource['vduId']) else: vdu_list.append(add_resource['resourceTemplateId']) return vdu_list @staticmethod def _make_vim_assets(add_resources, image_id_dict, flavour_id_dict): # set m1.tiny="1" for flavour_id vdu_list = GrantV2.get_vdu_list(add_resources) flavors = [GrantV2._generate_flavour(vdu, flavour_id_dict) for vdu in vdu_list if flavour_id_dict.get(vdu)] images = [GrantV2._generate_image(vdu, image_id_dict) for vdu in vdu_list if image_id_dict.get(vdu)] vim_assets = { 'computeResourceFlavours': flavors, 'softwareImages': images, } return vim_assets @staticmethod def _generate_flavour(vdu, flavour_id_dict): if flavour_id_dict.get(vdu): return { "vimConnectionId": uuidsentinel.vim_connection_id, "vnfdVirtualComputeDescId": vdu, "vimFlavourId": flavour_id_dict[vdu] } return None @staticmethod def _generate_image(vdu, image_id_dict): if image_id_dict.get(vdu): return { "vimConnectionId": uuidsentinel.vim_connection_id, "vnfdSoftwareImageId": vdu, "vimSoftwareImageId": image_id_dict[vdu] } return None @staticmethod def _make_response_template(request_body): res = { "id": uuidsentinel.__getattr__(request_body['vnfLcmOpOccId']), "vnfInstanceId": request_body['vnfInstanceId'], "vnfLcmOpOccId": request_body['vnfLcmOpOccId'], } res["_links"] = { "self": { # set fake server port. "href": os.path.join( 'http://localhost:9990', GrantV2.GRANT_REQ_PATH)}, "vnfLcmOpOcc": { "href": os.path.join( 'http://localhost:9890/vnflcm/v2/vnf_lcm_op_occs', request_body['vnfLcmOpOccId'])}, "vnfInstance": { "href": os.path.join( 'http://localhost:9890/vnflcm/v2/vnf_instances', request_body['vnfInstanceId'])}} return res @staticmethod def convert_body_to_dict(body): if isinstance(body, str): return jsonutils.loads(body) return body @staticmethod def make_inst_response_body( request_body, image_id_dict, flavour_id_dict, zone_name_list): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) res["vimConnectionInfo"] = GrantV2._make_vim_connection_info() res["zones"] = GrantV2._make_zones(zone_name_list) if 'addResources' in request_body.keys(): res["addResources"] = GrantV2._make_add_resources( request_body['addResources'], res["zones"], request_body.get('placementConstraints')) res["vimAssets"] = GrantV2._make_vim_assets( request_body['addResources'], image_id_dict, flavour_id_dict) res["additionalParams"] = GrantV2.ADDITIONAL_PARAMS return res @staticmethod def make_heal_response_body(request_body, image_id_dict, flavour_id_dict, zone_name_list): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) res["vimConnectionInfo"] = GrantV2._make_vim_connection_info() res["zones"] = GrantV2._make_zones(zone_name_list) if 'addResources' in request_body.keys(): res["addResources"] = GrantV2._make_add_resources( request_body['addResources'], res["zones"], request_body.get('placementConstraints')) res["vimAssets"] = GrantV2._make_vim_assets( request_body['addResources'], image_id_dict, flavour_id_dict) if 'removeResources' in request_body.keys(): res["removeResources"] = GrantV2._make_remove_resources( request_body['removeResources']) if 'updateResources' in request_body.keys(): res["updateResources"] = GrantV2._make_update_resources( request_body['updateResources'], res["zones"], request_body.get('placementConstraints')) return res @staticmethod def make_scale_response_body( request_body, image_id_dict, flavour_id_dict, zone_name_list): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) if 'addResources' in request_body.keys(): res["zones"] = GrantV2._make_zones(zone_name_list) res["addResources"] = GrantV2._make_add_resources( request_body['addResources'], res["zones"], request_body.get('placementConstraints')) res["vimAssets"] = GrantV2._make_vim_assets( request_body['addResources'], image_id_dict, flavour_id_dict) res["vimConnectionInfo"] = GrantV2._make_vim_connection_info() if 'removeResources' in request_body.keys(): res["removeResources"] = GrantV2._make_remove_resources( request_body['removeResources']) return res @staticmethod def make_term_response_body(request_body): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) if 'removeResources' in request_body.keys(): res["removeResources"] = GrantV2._make_remove_resources( request_body['removeResources']) return res @staticmethod def make_change_ext_conn_response_body( request_body, zone_name_list): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) res["vimConnectionInfo"] = GrantV2._make_vim_connection_info() res["zones"] = GrantV2._make_zones(zone_name_list) if 'updateResources' in request_body.keys(): res["updateResources"] = GrantV2._make_update_resources( request_body['updateResources'], res["zones"], request_body.get('placementConstraints')) res["additionalParams"] = GrantV2.ADDITIONAL_PARAMS return res @staticmethod def make_change_vnfpkg_response_body( request_body): request_body = GrantV2.convert_body_to_dict(request_body) res = GrantV2._make_response_template(request_body) if 'addResources' in request_body.keys(): res["addResources"] = GrantV2._make_add_resources( request_body['addResources']) if 'removeResources' in request_body.keys(): res["removeResources"] = GrantV2._make_remove_resources( request_body['removeResources']) if 'updateResources' in request_body.keys(): res["updateResources"] = GrantV2._make_update_resources( request_body['updateResources']) return res @staticmethod def get_sw_image(package_dir, vnfd_path): csar_package_path = package_dir yaml_file = os.path.join(csar_package_path, vnfd_path) with open(yaml_file, 'r', encoding='utf-8') as f: config_content = yaml.safe_load(f.read()) nodes = (config_content .get('topology_template', {}) .get('node_templates', {})) types = ['tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.Vdu.VirtualBlockStorage'] sw_image = {} for name, data in nodes.items(): if (data['type'] in types and data.get('properties', {}).get('sw_image_data')): image = data['properties']['sw_image_data']['name'] sw_image[name] = image return sw_image @staticmethod def get_compute_flavor(package_dir, vnfd_path): csar_package_path = package_dir yaml_file = os.path.join(csar_package_path, vnfd_path) with open(yaml_file, 'r', encoding='utf-8') as f: config_content = yaml.safe_load(f.read()) nodes = (config_content .get('topology_template', {}) .get('node_templates', {})) types = ['tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.Vdu.VirtualBlockStorage'] flavor = {} for name, data in nodes.items(): if (data['type'] in types and data.get('capabilities', {}) .get('virtual_compute', {}) .get('properties', {}) .get('requested_additional_capabilities', {}) .get('properties')): flavour = data['capabilities']['virtual_compute'][ 'properties']['requested_additional_capabilities'][ 'properties']['requested_additional_capability_name'] flavor[name] = flavour return flavor @staticmethod def get_sw_data(package_dir, vnfd_path): csar_package_path = package_dir yaml_file = os.path.join(csar_package_path, vnfd_path) with open(yaml_file, 'r', encoding='utf-8') as f: config_content = yaml.safe_load(f.read()) nodes = (config_content .get('topology_template', {}) .get('node_templates', {})) types = ['tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.Vdu.VirtualBlockStorage'] sw_data = {} for name, data in nodes.items(): if (data['type'] in types and data.get('properties', {}).get('sw_image_data')): image_data = data['properties']['sw_image_data'] sw_data[name] = image_data return sw_data