From: Hashir Mohammed Date: Wed, 8 Mar 2017 06:25:18 +0000 (-0500) Subject: * YANG to TOSCA VNFFG Support X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=a94a81cc5320aee3cbe05bbdbf3b6f0b244fb19f;p=osm%2FSO.git * YANG to TOSCA VNFFG Support Signed-off-by: Hashir Mohammed --- diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_graph.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_graph.py index 715ddc33..7b8657d5 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_graph.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_graph.py @@ -13,7 +13,7 @@ class ToscaForwardingGraph(ManoResource): type_="vnfgd", metadata=metadata) self.name = group.name - self.type_ = 'vnffg' + self.type_ = 'vnfgd' self.metadata = metadata self.group = group self.properties = {} diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_path.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_path.py index 4e392363..12b7062b 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_path.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_path.py @@ -18,6 +18,7 @@ class ToscaForwardingPath(ManoResource): self.properties = {} def handle_forwarding_path_dependencies(self, nodes, vnf_type_to_capability_substitution_mapping): + def get_classifier(specs): classifier_prop = {} classifier_prop['name'] = 'VNFFG -' + str(self.name) @@ -60,23 +61,27 @@ class ToscaForwardingPath(ManoResource): fp_connection_point = [] vnf_index = 1 order_index = 1 + visited_cps = [] for rsp_item in specs['path']: vnf_node_name = rsp_item['forwarder'] conn_forwarder = rsp_item['capability'] - vnf_node = self.get_node_with_name(vnf_node_name, nodes) + vnf_node = self.get_node_with_name(vnf_node_name, nodes) + for subs_mapping in vnf_type_to_capability_substitution_mapping[vnf_node.vnf_type]: prop = {} if conn_forwarder in subs_mapping: fp_connection_point.append(subs_mapping[conn_forwarder]) cp_node_name = subs_mapping[conn_forwarder] cp_node = self.get_node_with_name(cp_node_name, nodes) - prop['vnfd_connection_point_ref'] = cp_node.cp_name - prop['vnfd_id_ref'] = vnf_node.id - prop['member_vnf_index_ref'] = vnf_index - prop['order'] = order_index - rsp['vnfd_connection_point_ref'].append(prop) - vnf_index = vnf_index + 1 - order_index = order_index + 1 + if cp_node.cp_name not in visited_cps: + prop['vnfd_connection_point_ref'] = cp_node.cp_name + prop['vnfd_id_ref'] = vnf_node.id + prop['member_vnf_index_ref'] = vnf_node.get_member_vnf_index() + prop['order'] = order_index + rsp['vnfd_connection_point_ref'].append(prop) + vnf_index = vnf_index + 1 + order_index = order_index + 1 + visited_cps.append(cp_node.cp_name) return rsp tosca_props = self.get_tosca_props() diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py index a94624de..a9f9c778 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py @@ -89,7 +89,7 @@ class ToscaNetwork(ManoResource): ip_profile_param['gateway-address'] = specs['gateway_ip'] if 'ip_version' in specs: ip_profile_param['ip-version'] = 'ipv' + str(specs['ip_version']) - if 'ip_version' in specs: + if 'cidr' in specs: ip_profile_param['subnet-address'] = specs['cidr'] ip_profile_prop['ip-profile-params'] = ip_profile_param diff --git a/common/python/rift/mano/yang_translator/riftiotypes.yaml b/common/python/rift/mano/yang_translator/riftiotypes.yaml index 2fea0e33..18a07286 100644 --- a/common/python/rift/mano/yang_translator/riftiotypes.yaml +++ b/common/python/rift/mano/yang_translator/riftiotypes.yaml @@ -250,10 +250,10 @@ data_types: - in_range: [ 1, 254 ] required: false destination_port_range: - type: string + type: integer required: false source_port_range: - type: string + type: integer required: false network_src_port_id: type: string diff --git a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py index 7143e675..57b0a31e 100644 --- a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py +++ b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py @@ -43,7 +43,7 @@ class ToscaResource(object): MEM_VNF_INDEX_REF, VNFD_ID_REF, MEM_VNF_INDEX, VNF_CONFIG, TYPE_Y, USER_DEF_SCRIPT, SEQ, PARAM, - VALUE, START_BY_DFLT,) = \ + VALUE, START_BY_DFLT, VNFFGD, ) = \ ('vld', 'nsd', 'vnfd', 'vdu', 'dashboard_params', 'config_attributes', 'config_template', 'config_type', 'config_details', 'external_interface', @@ -51,7 +51,7 @@ class ToscaResource(object): 'member_vnf_index_ref', 'vnfd_id_ref', 'member_vnf_index', 'vnf_configuration', 'type_yang', 'user_defined_script', 'seq', 'parameter', - 'value', 'start_by_default',) + 'value', 'start_by_default', 'vnffgd',) TOSCA_FIELDS = (DERIVED_FROM, PROPERTIES, DEFAULT, REQUIRED, NO, CONSTRAINTS, REALTIONSHIPS, @@ -95,7 +95,9 @@ class ToscaResource(object): T_INITIAL_CFG, T_ARTF_CLOUD_INIT, T_PLACEMENT, - T_ELAN + T_ELAN, + T_VNFFG, + T_FP, ) = \ ('tosca.policies.nfv.riftio.vnf_configuration', 'tosca.capabilities.riftio.http_endpoint_type', @@ -111,7 +113,9 @@ class ToscaResource(object): 'tosca.policies.nfv.riftio.initial_config_primitive', 'tosca.artifacts.Deployment.riftio.cloud_init_file', 'tosca.policies.nfv.riftio.placement', - 'tosca.nodes.nfv.riftio.ELAN' + 'tosca.nodes.nfv.riftio.ELAN', + 'tosca.groups.nfv.VNFFG', + 'tosca.nodes.nfv.riftio.FP1', ) SUPPORT_FILES = ( SRC, DEST, EXISTING) = \ 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 4e421d1f..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' @@ -68,6 +69,10 @@ class YangNsd(ToscaResource): 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}"). @@ -182,7 +187,7 @@ class YangNsd(ToscaResource): if ip_profile_name == ip_prof['name']: ip_profile_vld = ip_prof if 'name' in vld: - vld_name = vld['name'] + vld_name = vld['name'].replace('-','_').replace(' ','') if 'description' in vld: vld_conf['description'] = vld['description'] if 'vendor' in vld: @@ -245,6 +250,168 @@ class YangNsd(ToscaResource): } 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: for key in self.REQUIRED_FIELDS: @@ -263,10 +430,17 @@ class YangNsd(ToscaResource): 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) @@ -427,12 +601,24 @@ class YangNsd(ToscaResource): for vnf_vld in vnf_vld_list: vnfd.generate_vld_link(vld_link_name, vnf_vld[1]) + 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): if self.GROUPS not in tosca[self.TOPOLOGY_TMPL]: @@ -451,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 @@ -493,6 +679,13 @@ class YangNsd(ToscaResource): 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): diff --git a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vdu.py b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vdu.py index 3786d86c..2d828723 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vdu.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vdu.py @@ -87,6 +87,7 @@ class YangVdu(ToscaResource): self.cp_name_to_cp_node = {} self.pinning_epa_prop = {} self.mem_page_guest_epa = None + self.conn_point_to_conection_node = {} def process_vdu(self): self.log.debug(_("Process VDU desc {0}: {1}").format(self.name, @@ -223,6 +224,11 @@ class YangVdu(ToscaResource): self.remove_ignored_fields(vdu_dic) + for cp in self.ext_cp: + cp_name = cp[self.NAME].replace('/', '_') + self.conn_point_to_conection_node[cp[self.NAME]] = cp_name + + if len(vdu_dic): self.log.warn(_("{0}, Did not process the following in " "VDU: {1}"). diff --git a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py index 1094c141..ec21e3c5 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py @@ -56,6 +56,7 @@ class YangVnfd(ToscaResource): self.vnf_type = None self.tosca = None self.script_files = [] + self.service_function_type = None def handle_yang(self): self.log.debug(_("Process VNFD desc {0}: {1}").format(self.name, @@ -197,6 +198,9 @@ class YangVnfd(ToscaResource): "connection-point {1}: {2}"). format(self, name, cp_dic)) + def process_service_type(dic): + self.service_function_type = dic['service_function_type'] + ENDPOINTS_MAP = { self.MGMT_INTF: process_mgmt_intf, self.HTTP_EP: process_http_ep, @@ -224,6 +228,9 @@ class YangVnfd(ToscaResource): if self.VNF_CONFIG in dic: process_vnf_config(dic.pop(self.VNF_CONFIG)) + if 'service_function_type' in dic: + process_service_type(dic) + self.remove_ignored_fields(dic) if len(dic): self.log.warn(_("{0}, Did not process the following for " @@ -243,7 +250,8 @@ class YangVnfd(ToscaResource): vdu.set_vld(cp_name, vld_name) break def _generate_vnf_type(self, tosca): - name = self.name.split('_', 1)[0] + name = self.name.replace("_","") + name = name.split('_', 1)[0] self.vnf_type = "{0}{1}{2}".format(self.vnf_prefix_type, name, 'VNF') if self.NODE_TYPES not in tosca and self.vnf_type: tosca[self.NODE_TYPES] = {} @@ -362,7 +370,28 @@ class YangVnfd(ToscaResource): self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS] = [] self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS].append({virtualLink : { "type": "tosca.nodes.nfv.VL"}}) + def generate_forwarder_sub_mapping(self, sub_link): + if self.CAPABILITIES not in self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING]: + self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.CAPABILITIES] = {} + self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.CAPABILITIES] + self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.CAPABILITIES][sub_link[1]] = \ + "[{}, forwarder]".format(sub_link[2]) + + def generate_sfc_link(self, sfs_conn_point_name): + for vdu in self.vdus: + if sfs_conn_point_name in vdu.cp_name_to_cp_node: + conn_point_node_name = vdu.cp_name_to_cp_node[sfs_conn_point_name] + if conn_point_node_name in self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL]: + if self.CAPABILITIES not in self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL]: + self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][conn_point_node_name][self.CAPABILITIES] = {} + self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][conn_point_node_name][self.CAPABILITIES]['sfc'] = {self.PROPERTIES: {}} + self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][conn_point_node_name] \ + [self.CAPABILITIES]['sfc'][self.PROPERTIES]['sfc_type'] = 'sf' + + if self.service_function_type: + self.tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][conn_point_node_name] \ + [self.CAPABILITIES]['sfc'][self.PROPERTIES]['sf_type'] = self.service_function_type def generate_tosca(self): tosca = {}