X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=common%2Fpython%2Frift%2Fmano%2Fyang_translator%2Frwmano%2Fyang%2Fyang_nsd.py;h=d28b3e1d98546bd6df06eab5a3752f1472c167d2;hb=a94a81cc5320aee3cbe05bbdbf3b6f0b244fb19f;hp=491bd86db4ee23b52ca16473cd3f94609fdd44f5;hpb=6f07e6f33f751ab4ffe624f6037f887b243bece2;p=osm%2FSO.git diff --git a/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py b/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py index 491bd86d..d28b3e1d 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py @@ -21,6 +21,7 @@ from rift.mano.yang_translator.common.utils import _ from rift.mano.yang_translator.rwmano.syntax.tosca_resource \ import ToscaResource from rift.mano.yang_translator.rwmano.yang.yang_vld import YangVld +from collections import OrderedDict TARGET_CLASS_NAME = 'YangNsd' @@ -49,7 +50,8 @@ class YangNsd(ToscaResource): log, name, type_, - yang): + yang, + vnfd_files): super(YangNsd, self).__init__(log, name, type_, @@ -57,10 +59,20 @@ class YangNsd(ToscaResource): self.props = {} self.inputs = [] self.vnfds = {} - self.vlds = [] + self.vlds = {} self.conf_prims = [] self.scale_grps = [] self.initial_cfg = [] + self.placement_groups = [] + self.vnf_id_to_vnf_map = {} + self.vnfd_files = vnfd_files + self.vld_to_vnf_map = {} + self.vnf_to_vld_map = {} + self._vnf_vld_conn_point_map = {} + self.vnffgds = {} + self.forwarding_paths = {} + self.substitution_mapping_forwarder = [] + self.vnfd_sfc_map = None def handle_yang(self, vnfds): self.log.debug(_("Process NSD desc {0}: {1}"). @@ -85,6 +97,7 @@ class YangNsd(ToscaResource): vnfd_id = cvnfd.pop(self.VNFD_ID_REF) for vnfd in vnfds: if vnfd.type == self.VNFD and vnfd.id == vnfd_id: + self.vnf_id_to_vnf_map[vnfd_id] = vnfd.name self.vnfds[cvnfd.pop(self.MEM_VNF_INDEX)] = vnfd if self.START_BY_DFLT in cvnfd: vnfd.props[self.START_BY_DFLT] = \ @@ -160,7 +173,244 @@ class YangNsd(ToscaResource): self.log.warn(_("{0}, Did not process all fields for {1}"). format(self, dic)) self.log.debug(_("{0}, Initial config {1}").format(self, icp)) - self.initial_cfg.append(icp) + self.initial_cfg.append({self.PROPERTIES : icp}) + + def process_vld(vld, dic): + vld_conf = {} + vld_prop = {} + ip_profile_vld = None + vld_name = None + if 'ip_profile_ref' in vld: + ip_profile_name = vld['ip_profile_ref'] + if 'ip_profiles' in dic: + for ip_prof in dic['ip_profiles']: + if ip_profile_name == ip_prof['name']: + ip_profile_vld = ip_prof + if 'name' in vld: + vld_name = vld['name'].replace('-','_').replace(' ','') + if 'description' in vld: + vld_conf['description'] = vld['description'] + if 'vendor' in vld: + vld_conf['vendor'] = vld['vendor'] + if ip_profile_vld: + if 'ip_profile_params' in ip_profile_vld: + ip_param = ip_profile_vld['ip_profile_params'] + if 'gateway_address' in ip_param: + vld_conf['gateway_ip'] = ip_param['gateway_address'] + if 'subnet_address' in ip_param: + vld_conf['cidr'] = ip_param['subnet_address'] + if 'ip_version' in ip_param: + vld_conf['ip_version'] = ip_param['ip_version'].replace('ipv','') + + if vld_name: + vld_prop = {vld_name : + { + 'type': self.T_ELAN, + self.PROPERTIES : vld_conf + }} + self.vlds[vld_name] = { 'type': self.T_ELAN, + self.PROPERTIES : vld_conf + } + + self.vld_to_vnf_map[vld_name] = [] + if 'vnfd_connection_point_ref' in vld: + for vnfd_ref in vld['vnfd_connection_point_ref']: + vnf_name = self.vnf_id_to_vnf_map[vnfd_ref['vnfd_id_ref']] + if vnf_name in self.vnf_to_vld_map: + self.vnf_to_vld_map[vnf_name].append(vld_name) + self._vnf_vld_conn_point_map[vnf_name].\ + append((vld_name ,vnfd_ref['vnfd_connection_point_ref'])) + else: + self.vnf_to_vld_map[vnf_name] = [] + self._vnf_vld_conn_point_map[vnf_name] = [] + self.vnf_to_vld_map[vnf_name].append(vld_name) + self._vnf_vld_conn_point_map[vnf_name].\ + append((vld_name ,vnfd_ref['vnfd_connection_point_ref'])) + + def process_placement_group(placement_groups): + for i in range(0, len(placement_groups)): + placement_group = placement_groups[i] + pg_name = "placement_{0}".format(i) + pg_config = {} + targets = [] + if 'name' in placement_group: + pg_config['name'] = placement_group['name'] + if 'requirement' in placement_group: + pg_config['requirement'] = placement_group['requirement'] + if 'strategy' in placement_group: + pg_config['strategy'] = placement_group['strategy'] + if 'member_vnfd' in placement_group: + for member_vnfd in placement_group['member_vnfd']: + targets.append(self.vnf_id_to_vnf_map[member_vnfd['vnfd_id_ref']]) + placement = { pg_name : { + 'type': self.T_PLACEMENT, + self.PROPERTIES: pg_config, + self.TARGETS : str(targets) + } + } + self.placement_groups.append(placement) + + def process_vnffgd(vnffgs, dic): + associated_cp_names = [] + all_cp_names = [] + vnfd_sfc_map = {} + + conn_point_to_conection_node = {} + conn_point_to_vnf_name_map = {} + + unigue_id_forwarder_path_map = OrderedDict() + forwarder_name_to_constitent_vnf_map = OrderedDict() + unique_id_classifier_map = OrderedDict() + fp_path_count = 1 + forwarder_count = 1 + + vnffg_to_unique_id_rsp_map = OrderedDict() + vnffg_to_unique_id_classifier_map = OrderedDict() + vnffg_to_associated_cp_names = OrderedDict() + rsp_associated_cp_names = OrderedDict() + vnffg_to_forwarder_map = OrderedDict() + for vnffg in vnffgs: + unique_id_rsp_map = {} + for rs in vnffg['rsp']: + unique_id_rsp_map[str(rs['id'])] = rs + for class_identifier in vnffg['classifier']: + unique_id_classifier_map[str(class_identifier['rsp_id_ref'])] = class_identifier + associated_cp_names.append(class_identifier['vnfd_connection_point_ref']) + all_cp_names.append(class_identifier['vnfd_connection_point_ref']) + conn_point_to_vnf_name_map[class_identifier['vnfd_connection_point_ref']] = self.vnf_id_to_vnf_map[class_identifier['vnfd_id_ref']] + vnfd_sfc_map[self.vnf_id_to_vnf_map[class_identifier['vnfd_id_ref']]] = class_identifier['vnfd_connection_point_ref'] + + rsp_associated_cp_names[str(class_identifier['rsp_id_ref'])] = class_identifier['vnfd_connection_point_ref'] + + vnffg_to_unique_id_rsp_map[vnffg['name']] = unique_id_rsp_map + vnffg_to_forwarder_map[vnffg['name']] = [] + + for vnffg in vnffgs: + prop = {} + fp_members = [] + + + prop['type'] = self.T_VNFFG + prop[self.DESC] = "Test" + prop[self.PROPERTIES] = {} + if 'vendor' in vnffg: + prop[self.PROPERTIES]['vendor'] = vnffg['vendor'] + if 'name' in vnffg: + self.vnffgds[vnffg['name']] = prop + + for rs_id, rs in vnffg_to_unique_id_rsp_map[vnffg['name']].items(): + associated_cp_node_names = [] + associated_vnf_names = [] + number_of_endpoints = 0 + if 'vnfd_connection_point_ref' in rs: + number_of_endpoints = number_of_endpoints + len(rs['vnfd_connection_point_ref']) + for vnf in rs['vnfd_connection_point_ref']: + associated_vnf_names.append(str(self.vnf_id_to_vnf_map[vnf['vnfd_id_ref']])) + associated_cp_names.append(vnf['vnfd_connection_point_ref']) + all_cp_names.append(vnf['vnfd_connection_point_ref']) + conn_point_to_vnf_name_map[vnf['vnfd_connection_point_ref']] = self.vnf_id_to_vnf_map[vnf['vnfd_id_ref']] + if "forwarder{}".format(fp_path_count) not in forwarder_name_to_constitent_vnf_map: + forwarder_name_to_constitent_vnf_map["forwarder{}".format(fp_path_count)] = associated_vnf_names + vnffg_to_forwarder_map[vnffg['name']].append("forwarder{}".format(fp_path_count)) + fp_path_count = fp_path_count + 1 + + associated_cp_names = list(set(associated_cp_names)) + for cp_name in associated_cp_names: + for idx, vnfd in self.vnfds.items(): + for vdu in vnfd.vdus: + if cp_name == rsp_associated_cp_names[rs_id]: + if cp_name in vdu.conn_point_to_conection_node: + associated_cp_node_names.append(vdu.conn_point_to_conection_node[cp_name]) + #conn_point_to_conection_node[cp_name] = vdu.conn_point_to_conection_node[cp_name] + + for cp_name in all_cp_names: + for idx, vnfd in self.vnfds.items(): + for vdu in vnfd.vdus: + if cp_name in vdu.conn_point_to_conection_node: + conn_point_to_conection_node[cp_name] = vdu.conn_point_to_conection_node[cp_name] + + if len(associated_vnf_names) > 0: + associated_vnf_names = list(set(associated_vnf_names)) + vnf_str = ", ".join(associated_vnf_names) + prop[self.PROPERTIES]['constituent_vnfs'] = "[{}]".format(vnf_str) + if len(associated_cp_node_names) > 0: + associated_cp_node_names = list(set(associated_cp_node_names)) + connection_point_str = ", ".join(associated_cp_node_names) + prop[self.PROPERTIES]['connection_point'] = "[{}]".format(", ".join(associated_cp_node_names)) + + prop[self.PROPERTIES]['number_of_endpoints'] = number_of_endpoints + fp_name = "Forwarding_path{}".format(forwarder_count) + unigue_id_forwarder_path_map[fp_name] = rs_id + fp_members.append(fp_name) + forwarder_count = forwarder_count + 1 + + if len(fp_members) > 0: + prop['members'] = [] + for fp in fp_members: + prop['members'].append(fp) + + fp_count = 1 + for fp, idx in unigue_id_forwarder_path_map.items(): + for vnffg_name, unique_id_rsp_map in vnffg_to_unique_id_rsp_map.items(): + if idx in unique_id_rsp_map: + prop = {} + prop['type'] = self.T_FP + prop[self.PROPERTIES] = {} + prop[self.PROPERTIES][self.DESC] = "Forwarder" + prop[self.PROPERTIES]['policy'] = {} + prop[self.PROPERTIES]['policy']['type'] = 'ACL' + prop[self.PROPERTIES]['policy']['criteria'] = [] + + prop[self.PROPERTIES]['path'] = [] + + rsp = unique_id_rsp_map[idx] + classifier = unique_id_classifier_map[idx] + + for match in classifier['match_attributes']: + match_prop = {} + if 'source_port' in match: + port = "'{}'".format((match['source_port'])) + prop[self.PROPERTIES]['policy']['criteria'].append({'source_port_range': port}) + if 'destination_port' in match: + port = "'f'{}''".format((match['destination_port'])) + prop[self.PROPERTIES]['policy']['criteria'].append({'destination_port_range': '5006'}) + if 'ip_proto' in match: + port = match['ip_proto'] + prop[self.PROPERTIES]['policy']['criteria'].append({'ip_proto': port}) + if 'destination_ip_address' in match: + port = "'{}'".format((match['destination_ip_address'])) + prop[self.PROPERTIES]['policy']['criteria'].append({'ip_dst_prefix': port}) + + if 'vnfd_connection_point_ref' in classifier: + if classifier['vnfd_connection_point_ref'] in conn_point_to_vnf_name_map: + if 'cp' not in prop[self.PROPERTIES]: + prop[self.PROPERTIES]['cp'] = {} + prop[self.PROPERTIES]['cp']['forwarder'] = conn_point_to_vnf_name_map[classifier['vnfd_connection_point_ref']] + prop[self.PROPERTIES]['cp']['capability'] = conn_point_to_conection_node[classifier['vnfd_connection_point_ref']] + + for fp, vnf_list in forwarder_name_to_constitent_vnf_map.items(): + for vnf in vnf_list: + for cp, vnf_name in conn_point_to_vnf_name_map.items(): + if vnf == vnf_name: + self.substitution_mapping_forwarder.append((vnf, fp, conn_point_to_conection_node[cp])) + + visited_forwarder = [] + visited_path = None + for path, vnfs in forwarder_name_to_constitent_vnf_map.items(): + for vnf in vnfs: + if (vnf not in visited_forwarder) and (path in vnffg_to_forwarder_map[vnffg_name]): + path_prop = {} + path_prop['forwarder'] = vnf + path_prop['capability'] = path + prop[self.PROPERTIES]['path'].append(path_prop) + visited_forwarder.append(vnf) + visited_path = path + forwarder_name_to_constitent_vnf_map.pop(visited_path) + + self.forwarding_paths["Forwarding_path{}".format(fp_count)] = prop + fp_count = fp_count +1 + + self.vnfd_sfc_map = vnfd_sfc_map dic = deepcopy(self.yang) try: @@ -177,15 +427,20 @@ class YangNsd(ToscaResource): # Process VLDs if self.VLD in dic: for vld_dic in dic.pop(self.VLD): - vld = YangVld(self.log, vld_dic.pop(self.NAME), - self.VLD, vld_dic) - vld.process_vld(self.vnfds) - self.vlds.append(vld) + process_vld(vld_dic, dic) + #self.vlds.append(vld) + + #Process VNFFG + if self.VNFFGD in dic: + process_vnffgd(dic[self.VNFFGD], dic) + + + #if self. # Process config primitives if self.CONF_PRIM in dic: for cprim in dic.pop(self.CONF_PRIM): - conf_prim = {self.NAME: cprim.pop(self.NAME)} + conf_prim = {self.NAME: cprim.pop(self.NAME), self.DESC : 'TestDescription'} if self.USER_DEF_SCRIPT in cprim: conf_prim[self.USER_DEF_SCRIPT] = \ cprim.pop(self.USER_DEF_SCRIPT) @@ -212,6 +467,10 @@ class YangNsd(ToscaResource): for param in dic.pop(self.INPUT_PARAM_XPATH): process_input_param(param) + if 'placement_groups' in dic: + process_placement_group(dic['placement_groups']) + + self.remove_ignored_fields(dic) if len(dic): self.log.warn(_("{0}, Did not process the following for " @@ -226,13 +485,14 @@ class YangNsd(ToscaResource): raise ValidationError(message=err_msg) def generate_tosca_type(self): + self.log.debug(_("{0} Generate tosa types"). format(self)) tosca = {} - tosca[self.DATA_TYPES] = {} - tosca[self.NODE_TYPES] = {} - + #tosca[self.DATA_TYPES] = {} + #tosca[self.NODE_TYPES] = {} + return tosca for idx, vnfd in self.vnfds.items(): tosca = vnfd.generate_tosca_type(tosca) @@ -287,20 +547,25 @@ class YangNsd(ToscaResource): def generate_tosca_template(self, tosca): self.log.debug(_("{0}, Generate tosca template"). format(self, tosca)) - # Add the standard entries tosca['tosca_definitions_version'] = \ - 'tosca_simple_profile_for_nfv_1_0_0' + 'tosca_simple_profile_for_nfv_1_0' tosca[self.DESC] = self.props[self.DESC] tosca[self.METADATA] = { 'ID': self.name, self.VENDOR: self.props[self.VENDOR], self.VERSION: self.props[self.VERSION], } + if len(self.vnfd_files) > 0: + tosca[self.IMPORT] = [] + imports = [] + for vnfd_file in self.vnfd_files: + tosca[self.IMPORT].append('"{0}.yaml"'.format(vnfd_file)) tosca[self.TOPOLOGY_TMPL] = {} # Add input params + ''' if len(self.inputs): if self.INPUTS not in tosca[self.TOPOLOGY_TMPL]: tosca[self.TOPOLOGY_TMPL][self.INPUTS] = {} @@ -309,15 +574,50 @@ class YangNsd(ToscaResource): self.DESC: 'Translated from YANG'}} tosca[self.TOPOLOGY_TMPL][self.INPUTS] = entry - + ''' tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL] = {} # Add the VNFDs and VLDs for idx, vnfd in self.vnfds.items(): - vnfd.generate_vnf_template(tosca, idx) + #vnfd.generate_vnf_template(tosca, idx) + node = { + 'type' : vnfd.vnf_type, + self.PROPERTIES : { + self.ID : idx, + self.VENDOR : self.props[self.VENDOR], + self.VERSION : self.props[self.VERSION] + } + } + if vnfd.name in self.vnf_to_vld_map: + vld_list = self.vnf_to_vld_map[vnfd.name] + node[self.REQUIREMENTS] = [] + for vld_idx in range(0, len(vld_list)): + vld_link_name = "{0}{1}".format("virtualLink", vld_idx + 1) + vld_prop = {} + vld_prop[vld_link_name] = vld_list[vld_idx] + node[self.REQUIREMENTS].append(vld_prop) + if vnfd.name in self._vnf_vld_conn_point_map: + vnf_vld_list = self._vnf_vld_conn_point_map[vnfd.name] + for vnf_vld in vnf_vld_list: + vnfd.generate_vld_link(vld_link_name, vnf_vld[1]) - for vld in self.vlds: - vld.generate_tosca_template(tosca) + for sub_mapping in self.substitution_mapping_forwarder: + if sub_mapping[0] == vnfd.name: + vnfd.generate_forwarder_sub_mapping(sub_mapping) + + for vnfd_name, cp_name in self.vnfd_sfc_map.items(): + if vnfd.name == vnfd_name: + vnfd.generate_sfc_link(cp_name) + + + + tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vnfd.name] = node + + for vld_node_name in self.vlds: + tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vld_node_name] = self.vlds[vld_node_name] + + for fp_name, fp in self.forwarding_paths.items(): + tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][fp_name] = fp # add the config primitives if len(self.conf_prims): @@ -337,8 +637,8 @@ class YangNsd(ToscaResource): conf_prims[self.PROPERTIES] = { self.PRIMITIVES: prims } - - tosca[self.TOPOLOGY_TMPL][self.GROUPS][self.CONF_PRIM] = conf_prims + conf_prims[self.DESC] = 'Test' + #tosca[self.TOPOLOGY_TMPL][self.GROUPS][self.CONF_PRIM] = conf_prims # Add the scale group @@ -361,33 +661,45 @@ class YangNsd(ToscaResource): tosca[self.TOPOLOGY_TMPL][self.POLICIES] = [] for icp in self.initial_cfg: - icpt = { - self.TYPE: self.T_INITIAL_CFG, - } - icpt.update(icp) - tosca[self.TOPOLOGY_TMPL][self.POLICIES].append({ - self.INITIAL_CFG: icpt - }) + if len(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL]) > 0: + node_name = list(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL].keys())[0] + icpt = { + self.TYPE: self.T_INITIAL_CFG, + self.TARGETS : "[{0}]".format(node_name) + } + icpt.update(icp) + tosca[self.TOPOLOGY_TMPL][self.POLICIES].append({ + self.INITIAL_CFG: icpt + }) + + if len(self.placement_groups) > 0: + if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]: + tosca[self.TOPOLOGY_TMPL][self.POLICIES] = [] + + for placment_group in self.placement_groups: + tosca[self.TOPOLOGY_TMPL][self.POLICIES].append(placment_group) + + if len(self.vnffgds) > 0: + if self.GROUPS not in tosca[self.TOPOLOGY_TMPL]: + tosca[self.TOPOLOGY_TMPL][self.GROUPS] = {} + for vnffgd_name in self.vnffgds: + tosca[self.TOPOLOGY_TMPL][self.GROUPS][vnffgd_name] = self.vnffgds[vnffgd_name] + return tosca def get_supporting_files(self): files = [] - - for vnfd in self.vnfds.values(): - f = vnfd.get_supporting_files() - if f and len(f): - files.extend(f) - # Get the config files for initial config for icp in self.initial_cfg: - if self.USER_DEF_SCRIPT in icp: - script = os.path.basename(icp[self.USER_DEF_SCRIPT]) - files.append({ - self.TYPE: 'script', - self.NAME: script, - self.DEST: "{}/{}".format(self.SCRIPT_DIR, script), - }) + if 'properties' in icp: + if 'user_defined_script' in icp['properties']: + script = os.path.basename(icp['properties']['user_defined_script']) + files.append({ + self.TYPE: 'script', + self.NAME: script, + self.DEST: "{}/{}".format(self.SCRIPT_DIR, script), + }) # TODO (pjoseph): Add support for config scripts, # charms, etc