diff options
author | 2018-09-10 22:53:26 +0800 | |
---|---|---|
committer | 2018-09-11 16:09:25 +0800 | |
commit | 438606259fca179b732eeba350ba95f04f5ba838 (patch) | |
tree | dacdf51aa862455c79d55af89a50482805f19f80 | |
parent | cd97933abdb647a19a76d1e4916e18ecda43aa9c (diff) |
Support PNFD in NSD
Support to parser PNFD in NSD
Change-Id: I6cdcb5ca275ca532c10e47107a635685e62cfacc
Issue-ID: VFC-1102
Signed-off-by: maopengzhang <zhang.maopeng1@zte.com.cn>
-rw-r--r-- | catalog/packages/urls.py | 10 | ||||
-rw-r--r-- | catalog/pub/utils/toscaparser/basemodel.py | 102 | ||||
-rw-r--r-- | catalog/pub/utils/toscaparser/nsdmodel.py | 314 | ||||
-rw-r--r-- | catalog/pub/utils/toscaparser/pnfmodel.py | 8 | ||||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/ns/ran.csar | bin | 0 -> 2977 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar | bin | 34326 -> 0 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/vnf/infra.csar (renamed from catalog/pub/utils/toscaparser/testdata/vcpe/infra.csar) | bin | 10751 -> 10751 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/vnf/vbng.csar (renamed from catalog/pub/utils/toscaparser/testdata/vcpe/vbng.csar) | bin | 10754 -> 10754 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/vnf/vbrgemu.csar (renamed from catalog/pub/utils/toscaparser/testdata/vcpe/vbrgemu.csar) | bin | 10460 -> 10460 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/vnf/vgmux.csar (renamed from catalog/pub/utils/toscaparser/testdata/vcpe/vgmux.csar) | bin | 10723 -> 10723 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/testdata/vnf/vgw.csar (renamed from catalog/pub/utils/toscaparser/testdata/vcpe/vgw.csar) | bin | 10579 -> 10579 bytes | |||
-rw-r--r-- | catalog/pub/utils/toscaparser/tests.py | 29 | ||||
-rw-r--r-- | catalog/pub/utils/toscaparser/vnfdmodel.py | 334 |
13 files changed, 224 insertions, 573 deletions
diff --git a/catalog/packages/urls.py b/catalog/packages/urls.py index ca090c74..e62bc76a 100644 --- a/catalog/packages/urls.py +++ b/catalog/packages/urls.py @@ -19,27 +19,31 @@ from catalog.packages.views import catalog_views, ns_descriptor_views, pnf_descr urlpatterns = [ + + # Sync package from SDC url(r'^api/catalog/v1/nspackages$', catalog_views.nspackages_rc, name='nspackages_rc'), url(r'^api/catalog/v1/nspackages/(?P<csarId>[0-9a-zA-Z\-\_]+)$', catalog_views.ns_rd_csar, name='nspackage_rd'), url(r'^api/catalog/v1/vnfpackages$', catalog_views.nfpackages_rc, name='nfpackages_rc'), url(r'^api/catalog/v1/vnfpackages/(?P<csarId>[0-9a-zA-Z\-\_]+)$', catalog_views.nf_rd_csar, name='nfpackage_rd'), + + # NFV Model Parser url(r'^api/catalog/v1/parsernsd$', catalog_views.ns_model_parser, name='nsmodelparser_rc'), url(r'^api/catalog/v1/parservnfd$', catalog_views.vnf_model_parser, name='vnfmodelparser_rc'), url(r'^api/catalog/v1/parserpnfd$', pnf_descriptor_views.pnf_model_parser, name='pnfmodelparser_rc'), - # NSPakcage& NSD + # ETSI SOL005 NSD API url(r'^api/nsd/v1/ns_descriptors$', ns_descriptor_views.ns_descriptors_rc, name='ns_descriptors_rc'), url(r'^api/nsd/v1/ns_descriptors/(?P<nsdInfoId>[0-9a-zA-Z\-\_]+)$', ns_descriptor_views.ns_info_rd, name='ns_info_rd'), url(r'^api/nsd/v1/ns_descriptors/(?P<nsdInfoId>[0-9a-zA-Z\-\_]+)/nsd_content$', ns_descriptor_views.nsd_content_ru, name='nsd_content_ru'), # url(r'^api/nsd/v1/subscriptions', nsd_subscriptions.as_view(), name='subscriptions_rc'), # url(r'^api/nsd/v1/subscriptions/(?P<subscriptionId>[0-9a-zA-Z\-\_]+)$', nsd_subscription.as_view(), name='subscription_rd'), - # PNF Package and PNFD + # ETSI SOL005 PNFD url(r'^api/nsd/v1/pnf_descriptors$', pnf_descriptor_views.pnf_descriptors_rc, name='pnf_descriptors_rc'), url(r'^api/nsd/v1/pnf_descriptors/(?P<pnfdInfoId>[0-9a-zA-Z\-\_]+)$', pnf_descriptor_views.pnfd_info_rd, name='pnfd_info_rd'), url(r'^api/nsd/v1/pnf_descriptors/(?P<pnfdInfoId>[0-9a-zA-Z\-\_]+)/pnfd_content$', pnf_descriptor_views.pnfd_content_ru, name='pnfd_content_ru'), - # VNFD + # ETSI SOL005&SOL003 VNF Package url(r'^api/vnfpkgm/v1/vnf_packages$', vnf_package_views.vnf_packages_rc, name='vnf_packages_rc'), url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)$', vnf_package_views.vnf_package_rd, name='vnf_package_rd'), url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/package_content$', vnf_package_views.package_content_ru, name='package_content_ru'), diff --git a/catalog/pub/utils/toscaparser/basemodel.py b/catalog/pub/utils/toscaparser/basemodel.py index 192e44b6..54e1fd97 100644 --- a/catalog/pub/utils/toscaparser/basemodel.py +++ b/catalog/pub/utils/toscaparser/basemodel.py @@ -30,10 +30,6 @@ from catalog.pub.utils.toscaparser.dataentityext import DataEntityExt logger = logging.getLogger(__name__) -# TOSCA template key names -SECTIONS = (VDU_TYPE, VL_TYPE, CP_TYPE) = \ - ('tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.VnfVirtualLink', 'tosca.nodes.nfv.Cp') - class BaseInfoModel(object): @@ -354,22 +350,6 @@ class BaseInfoModel(object): return False return True - def isVnf(self, node): - # return node['nodeType'].upper().find('.VNF.') >= 0 or node['nodeType'].upper().endswith('.VNF') - return node['nodeType'].upper().find('.VF.') >= 0 or node['nodeType'].upper().endswith('.VF') - - def isPnf(self, node): - return node['nodeType'].upper().find('.PNF.') >= 0 or node['nodeType'].upper().endswith('.PNF') - - def isCp(self, node, node_types): - return node['nodeType'].upper().find('TOSCA.NODES.NFV.VDUCP') >= 0 - - def isVl(self, node, node_types): - return node['nodeType'].upper().find('TOSCA.NODES.NFV.VNFVIRTUALLINK') >= 0 - - def isService(self, node): - return node['nodeType'].upper().find('.SERVICE.') >= 0 or node['nodeType'].upper().endswith('.SERVICE') - def get_requirement_node_name(self, req_value): return self.get_prop_from_obj(req_value, 'node') @@ -389,12 +369,6 @@ class BaseInfoModel(object): def getNodeDependencys(self, node): return self.getRequirementByName(node, 'dependency') - def getVirtualLinks(self, node): - return self.getRequirementByName(node, 'virtual_link') - - def getVirtualbindings(self, node): - return self.getRequirementByName(node, 'virtual_binding') - def getRequirementByName(self, node, requirementName): requirements = [] if 'requirements' in node: @@ -404,15 +378,6 @@ class BaseInfoModel(object): requirements.append(value) return requirements - def get_networks(self, node): - rets = [] - if 'requirements' in node: - for item in node['requirements']: - for key, value in item.items(): - if key.upper().find('VIRTUAL_LINK') >= 0 or key.upper().find('VIRTUALLINK') >= 0: - rets.append({"key_name": key, "vl_id": self.get_requirement_node_name(value)}) - return rets - def _verify_value(self, value, inputs, parsed_params): if value == '{}': return '' @@ -443,44 +408,51 @@ class BaseInfoModel(object): value = value.replace(getInput, json.dumps(input_def.default)) return value - def get_node_vl_id(self, node): - vl_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualLinks(node)) - if len(vl_ids) > 0: - return vl_ids[0] - return "" - def get_node_by_name(self, node_templates, name): for node in node_templates: if node['name'] == name: return node return None - def get_all_nested_ns(self, nodes): - nss = [] - for node in nodes: - if self.is_nested_ns(node): - ns = {} - ns['ns_id'] = node['name'] - ns['description'] = node['description'] - ns['properties'] = node['properties'] - ns['networks'] = self.get_networks(node) - - nss.append(ns) - return nss - - def is_nested_ns(self, node): - return node['nodeType'].upper().find('.NS.') >= 0 or node['nodeType'].upper().endswith('.NS') - - def isVdu(self, node, node_types): - return node['nodeType'].upper().find('TOSCA.NODES.NFV.VDU.COMPUTE') >= 0 - def getCapabilityByName(self, node, capabilityName): if 'capabilities' in node and capabilityName in node['capabilities']: return node['capabilities'][capabilityName] return None - def get_node_vdu_id(self, node): - vdu_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualbindings(node)) - if len(vdu_ids) > 0: - return vdu_ids[0] - return "" + def get_base_path(self, tosca): + fpath, fname = os.path.split(tosca.path) + return fpath + + def build_artifacts(self, node): + rets = [] + if 'artifacts' in node and len(node['artifacts']) > 0: + artifacts = node['artifacts'] + for name, value in artifacts.items(): + ret = {} + if isinstance(value, dict): + ret['artifact_name'] = name + ret['type'] = value.get('type', '') + ret['file'] = value.get('file', '') + ret['repository'] = value.get('repository', '') + ret['deploy_path'] = value.get('deploy_path', '') + else: + ret['artifact_name'] = name + ret['type'] = '' + ret['file'] = value + ret['repository'] = '' + ret['deploy_path'] = '' + rets.append(ret) + return rets + + def get_node_by_req(self, node_templates, req): + req_node_name = self.get_requirement_node_name(req) + return self.get_node_by_name(node_templates, req_node_name) + + def isGroupTypeX(self, group, groupTypes, x): + group_type = group['groupType'] + while group_type != x: + group_type_derived = group_type + group_type = groupTypes[group_type]['derived_from'] + if group_type == "tosca.groups.Root" or group_type == group_type_derived: + return False + return True diff --git a/catalog/pub/utils/toscaparser/nsdmodel.py b/catalog/pub/utils/toscaparser/nsdmodel.py index c01ea7e4..ae99e9bb 100644 --- a/catalog/pub/utils/toscaparser/nsdmodel.py +++ b/catalog/pub/utils/toscaparser/nsdmodel.py @@ -13,244 +13,89 @@ # limitations under the License. import functools - +import logging from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel +logger = logging.getLogger(__name__) + +SECTIONS = (NS_TYPE, NS_VNF_TYPE, NS_VL_TYPE, NS_PNF_TYPE, NS_NFP_TYPE, NS_VNFFG_TYPE) = \ + ('tosca.nodes.nfv.NS', + 'tosca.nodes.nfv.VNF', + 'tosca.nodes.nfv.NsVirtualLink', + 'tosca.nodes.nfv.PNF', + 'tosca.nodes.nfv.NFP', + 'tosca.nodes.nfv.VNFFG') class EtsiNsdInfoModel(BaseInfoModel): def __init__(self, path, params): - tosca = self.buildToscaTemplate(path, params) - self.parseModel(tosca) + super(EtsiNsdInfoModel, self).__init__(path, params) def parseModel(self, tosca): self.buidMetadata(tosca) if hasattr(tosca, 'topology_template') and hasattr(tosca.topology_template, 'inputs'): self.inputs = self.buildInputs(tosca.topology_template.inputs) - - nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), - tosca.nodetemplates) - node_types = tosca.topology_template.custom_defs - self.vnfs = self._get_all_vnf(nodeTemplates) - self.pnfs = self._get_all_pnf(nodeTemplates) - self.vls = self.get_all_vl(nodeTemplates, node_types) - self.cps = self.get_all_cp(nodeTemplates, node_types) - self.routers = self.get_all_router(nodeTemplates) - self.fps = self._get_all_fp(nodeTemplates, node_types) - self.vnffgs = self._get_all_vnffg(tosca.topology_template.groups) - self.server_groups = self.get_all_server_group(tosca.topology_template.groups) - self.ns_exposed = self.get_all_endpoint_exposed(tosca.topology_template) - self.policies = self._get_policies_scaling(tosca.topology_template.policies) - self.ns_flavours = self.get_all_flavour(tosca.topology_template.groups) - self.nested_ns = self.get_all_nested_ns(nodeTemplates) - - def buildInputs(self, top_inputs): - ret = {} - for tmpinput in top_inputs: - tmp = {} - tmp['type'] = tmpinput.type - tmp['description'] = tmpinput.description - tmp['default'] = tmpinput.default - - ret[tmpinput.name] = tmp - return ret - - def buildNode(self, nodeTemplate, tosca): - inputs = tosca.inputs - parsed_params = tosca.parsed_params - ret = {} - ret['name'] = nodeTemplate.name - ret['nodeType'] = nodeTemplate.type - if 'description' in nodeTemplate.entity_tpl: - ret['description'] = nodeTemplate.entity_tpl['description'] - else: - ret['description'] = '' - if 'metadata' in nodeTemplate.entity_tpl: - ret['metadata'] = nodeTemplate.entity_tpl['metadata'] - else: - ret['metadata'] = '' - props = self.buildProperties_ex(nodeTemplate, tosca.topology_template) - ret['properties'] = self.verify_properties(props, inputs, parsed_params) - ret['requirements'] = self.build_requirements(nodeTemplate) - self.buildCapabilities(nodeTemplate, inputs, ret) - self.buildArtifacts(nodeTemplate, inputs, ret) - interfaces = self.build_interfaces(nodeTemplate) - if interfaces: - ret['interfaces'] = interfaces - return ret - - def _get_all_vnf(self, nodeTemplates): + nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), tosca.nodetemplates) + types = tosca.topology_template.custom_defs + self.basepath = self.get_base_path(tosca) + self.vnfs = self._get_all_vnf(nodeTemplates, types) + self.pnfs = self._get_all_pnf(nodeTemplates, types) + self.vls = self._get_all_vl(nodeTemplates, types) + self.fps = self._get_all_fp(nodeTemplates, types) + self.vnffgs = self._get_all_vnffg(tosca.topology_template.groups, types) + self.ns_exposed = self._get_all_endpoint_exposed(tosca.topology_template) + self.nested_ns = self._get_all_nested_ns(nodeTemplates, types) + + def _get_all_vnf(self, nodeTemplates, node_types): vnfs = [] for node in nodeTemplates: - if self.isVnf(node): + if self.isNodeTypeX(node, node_types, NS_VNF_TYPE): vnf = {} vnf['vnf_id'] = node['name'] vnf['description'] = node['description'] vnf['properties'] = node['properties'] - vnf['properties']['id'] = node['metadata'].get('UUID', 'undefined') - # for key in vnf['properties'].iterkeys(): - # if key.endswith('_version'): - # vnf['properties'].update(version=vnf['properties'].pop(key)) - # if key.endswith('_id'): - # vnf['properties'].update(id=vnf['properties'].pop(key)) - # if key.endswith('_csarProvider'): - # vnf['properties'].update(csarProvider=vnf['properties'].pop(key)) - # if key.endswith('_csarVersion'): - # vnf['properties'].update(csarVersion=vnf['properties'].pop(key)) - # if key.endswith('_vendor'): - # vnf['properties'].update(vendor=vnf['properties'].pop(key)) - # if key.endswith('_csarType'): - # vnf['properties'].update(csarType=vnf['properties'].pop(key)) - # if key.endswith('_vnfm_type') or key.endswith('_vnfmType'): - # vnf['properties'].update(vnfmType=vnf['properties'].pop(key)) - # vnf['dependencies'] = map(lambda x: self.get_requirement_node_name(x), self.getNodeDependencys(node)) - vnf['dependencies'] = self.get_networks(node) - vnf['networks'] = self.get_networks(node) - + if node['metadata']: + vnf['properties']['id'] = node['metadata'].get('UUID', 'undefined') + vnf['dependencies'] = self._get_networks(node, node_types) + vnf['networks'] = self._get_networks(node, node_types) vnfs.append(vnf) return vnfs - def _get_all_pnf(self, nodeTemplates): + def _get_all_pnf(self, nodeTemplates, node_types): pnfs = [] for node in nodeTemplates: - if self.isPnf(node): + if self.isNodeTypeX(node, node_types, NS_PNF_TYPE): pnf = {} pnf['pnf_id'] = node['name'] pnf['description'] = node['description'] pnf['properties'] = node['properties'] - pnf['cps'] = self.getVirtalBindingCpIds(node, nodeTemplates) - + pnf['networks'] = self._get_networks(node, node_types) pnfs.append(pnf) return pnfs - def getVirtalBindingCpIds(self, node, nodeTemplates): - return map(lambda x: x['name'], self.getVirtalBindingCps(node, nodeTemplates)) - - def getVirtalBindingCps(self, node, nodeTemplates): - cps = [] - for tmpnode in nodeTemplates: - if 'requirements' in tmpnode: - for item in tmpnode['requirements']: - for key, value in item.items(): - if key.upper().startswith('VIRTUAL_BINDING'): - req_node_name = self.get_requirement_node_name(value) - if req_node_name is not None and req_node_name == node['name']: - cps.append(tmpnode) - return cps - - def get_all_vl(self, nodeTemplates, node_types): + def _get_all_vl(self, nodeTemplates, node_types): vls = [] for node in nodeTemplates: - if self.isVl(node, node_types) or self._isExternalVL(node): + if self.isNodeTypeX(node, node_types, NS_VL_TYPE): vl = dict() vl['vl_id'] = node['name'] vl['description'] = node['description'] vl['properties'] = node['properties'] - vl['route_external'] = False if self.isVl(node, node_types) else True - # vl['route_id'] = self._get_vl_route_id(node) vls.append(vl) return vls - def _get_vl_route_id(self, node): - route_ids = map(lambda x: self.get_requirement_node_name(x), - self.getRequirementByName(node, 'virtual_route')) - if len(route_ids) > 0: - return route_ids[0] - return "" - - def _isExternalVL(self, node): - return node['nodeType'].upper().find('.ROUTEEXTERNALVL') >= 0 - - def get_all_cp(self, nodeTemplates, node_types): - cps = [] - for node in nodeTemplates: - if self.isCp(node, node_types): - cp = {} - cp['cp_id'] = node['name'] - cp['cpd_id'] = node['name'] - cp['description'] = node['description'] - cp['properties'] = node['properties'] - cp['vl_id'] = self.get_node_vl_id(node) - binding_node_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualbindings(node)) - # cp['vnf_id'] = self._filter_vnf_id(binding_node_ids, nodeTemplates) - cp['pnf_id'] = self._filter_pnf_id(binding_node_ids, nodeTemplates) - vls = self.buil_cp_vls(node) - if len(vls) > 1: - cp['vls'] = vls - cps.append(cp) - return cps - - def buil_cp_vls(self, node): - return map(lambda x: self._build_cp_vl(x), self.getVirtualLinks(node)) - - def _build_cp_vl(self, req): - cp_vl = {} - cp_vl['vl_id'] = self.get_prop_from_obj(req, 'node') - relationship = self.get_prop_from_obj(req, 'relationship') - if relationship is not None: - properties = self.get_prop_from_obj(relationship, 'properties') - if properties is not None and isinstance(properties, dict): - for key, value in properties.items(): - cp_vl[key] = value - return cp_vl - - def _filter_pnf_id(self, node_ids, node_templates): - for node_id in node_ids: - node = self.get_node_by_name(node_templates, node_id) - if self.isPnf(node): - return node_id - return "" - - def get_all_router(self, nodeTemplates): - rets = [] - for node in nodeTemplates: - if self._isRouter(node): - ret = {} - ret['router_id'] = node['name'] - ret['description'] = node['description'] - ret['properties'] = node['properties'] - ret['external_vl_id'] = self._get_router_external_vl_id(node) - ret['external_ip_addresses'] = self._get_external_ip_addresses(node) - - rets.append(ret) - return rets - - def _isRouter(self, node): - return node['nodeType'].upper().find('.ROUTER.') >= 0 or node['nodeType'].upper().endswith('.ROUTER') - - def _get_router_external_vl(self, node): - return self.getRequirementByName(node, 'external_virtual_link') - - def _get_router_external_vl_id(self, node): - ids = map(lambda x: self.get_requirement_node_name(x), self._get_router_external_vl(node)) - if len(ids) > 0: - return ids[0] - return "" - - def _get_external_ip_addresses(self, node): - external_vls = self._get_router_external_vl(node) - if len(external_vls) > 0: - if 'relationship' in external_vls[0] and 'properties' in external_vls[0]['relationship'] and 'router_ip_address' in external_vls[0]['relationship']['properties']: - return external_vls[0]['relationship']['properties']['router_ip_address'] - return [] - def _get_all_fp(self, nodeTemplates, node_types): fps = [] for node in nodeTemplates: - if self._isFp(node): + if self.isNodeTypeX(node, node_types, NS_NFP_TYPE): fp = {} fp['fp_id'] = node['name'] fp['description'] = node['description'] fp['properties'] = node['properties'] fp['forwarder_list'] = self._getForwarderList(node, nodeTemplates, node_types) - fps.append(fp) return fps - def _isFp(self, node): - return node['nodeType'].upper().find('.FP.') >= 0 or node['nodeType'].upper().find('.SFP.') >= 0 or node[ - 'nodeType'].upper().endswith('.FP') or node['nodeType'].upper().endswith('.SFP') - def _getForwarderList(self, node, node_templates, node_types): forwarderList = [] if 'requirements' in node: @@ -258,57 +103,29 @@ class EtsiNsdInfoModel(BaseInfoModel): for key, value in item.items(): if key == 'forwarder': tmpnode = self.get_node_by_req(node_templates, value) - type = 'cp' if self.isCp(tmpnode, node_types) else 'vnf' + type = 'pnf' if self.isNodeTypeX(tmpnode, node_types, NS_PNF_TYPE) else 'vnf' req_node_name = self.get_requirement_node_name(value) if isinstance(value, dict) and 'capability' in value: forwarderList.append( {"type": type, "node_name": req_node_name, "capability": value['capability']}) else: forwarderList.append({"type": type, "node_name": req_node_name, "capability": ""}) - return forwarderList - def get_node_by_req(self, node_templates, req): - req_node_name = self.get_requirement_node_name(req) - return self.get_node_by_name(node_templates, req_node_name) - - def _get_all_vnffg(self, groups): + def _get_all_vnffg(self, groups, group_types): vnffgs = [] for group in groups: - if self._isVnffg(group): + if self.isGroupTypeX(group, group_types, NS_VNFFG_TYPE): vnffg = {} vnffg['vnffg_id'] = group.name vnffg['description'] = group.description if 'properties' in group.tpl: vnffg['properties'] = group.tpl['properties'] vnffg['members'] = group.members - vnffgs.append(vnffg) return vnffgs - def _isVnffg(self, group): - return group.type.upper().find('.VNFFG.') >= 0 or group.type.upper().find( - '.SFC.') >= 0 or group.type.upper().endswith('.VNFFG') or group.type.upper().endswith('.SFC') - - def get_all_server_group(self, groups): - rets = [] - for group in groups: - if self._isServerGroup(group): - ret = {} - ret['group_id'] = group.name - ret['description'] = group.description - if 'properties' in group.tpl: - ret['properties'] = group.tpl['properties'] - ret['members'] = group.members - - rets.append(ret) - return rets - - def _isServerGroup(self, group): - return group.type.upper().find('.AFFINITYORANTIAFFINITYGROUP.') >= 0 or group.type.upper().endswith( - '.AFFINITYORANTIAFFINITYGROUP') - - def get_all_endpoint_exposed(self, topo_tpl): + def _get_all_endpoint_exposed(self, topo_tpl): if 'substitution_mappings' in topo_tpl.tpl: external_cps = self._get_external_cps(topo_tpl.tpl['substitution_mappings']) forward_cps = self._get_forward_cps(topo_tpl.tpl['substitution_mappings']) @@ -335,43 +152,22 @@ class EtsiNsdInfoModel(BaseInfoModel): forward_cps.append({"key_name": key, "cpd_id": value}) return forward_cps - def _get_policies_scaling(self, top_policies): - policies_scaling = [] - scaling_policies = self.get_scaling_policies(top_policies) - if len(scaling_policies) > 0: - policies_scaling.append({"scaling": scaling_policies}) - return policies_scaling - - def get_policies_by_keyword(self, top_policies, keyword): - ret = [] - for policy in top_policies: - if policy.type.upper().find(keyword) >= 0: - tmp = {} - tmp['policy_id'] = policy.name - tmp['description'] = policy.description - if 'properties' in policy.entity_tpl: - tmp['properties'] = policy.entity_tpl['properties'] - tmp['targets'] = policy.targets - ret.append(tmp) - - return ret - - def get_scaling_policies(self, top_policies): - return self.get_policies_by_keyword(top_policies, '.SCALING') - - def get_all_flavour(self, groups): + def _get_all_nested_ns(self, nodes, node_types): + nss = [] + for node in nodes: + if self.isNodeTypeX(node, node_types, NS_TYPE): + ns = {} + ns['ns_id'] = node['name'] + ns['description'] = node['description'] + ns['properties'] = node['properties'] + ns['networks'] = self._get_networks(node) + nss.append(ns) + return nss + + def _get_networks(self, node, node_types): rets = [] - for group in groups: - if self._isFlavour(group): - ret = {} - ret['flavour_id'] = group.name - ret['description'] = group.description - if 'properties' in group.tpl: - ret['properties'] = group.tpl['properties'] - ret['members'] = group.members - - rets.append(ret) + if 'requirements' in node and (self.isNodeTypeX(node, node_types, NS_TYPE) or self.isNodeTypeX(node, node_types, NS_VNF_TYPE)): + for item in node['requirements']: + for key, value in item.items(): + rets.append({"key_name": key, "vl_id": self.get_requirement_node_name(value)}) return rets - - def _isFlavour(self, group): - return group.type.upper().find('FLAVOUR') >= 0 diff --git a/catalog/pub/utils/toscaparser/pnfmodel.py b/catalog/pub/utils/toscaparser/pnfmodel.py index ce531d6d..7dc99d80 100644 --- a/catalog/pub/utils/toscaparser/pnfmodel.py +++ b/catalog/pub/utils/toscaparser/pnfmodel.py @@ -14,7 +14,6 @@ import functools import logging -import os from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel logger = logging.getLogger(__name__) @@ -31,15 +30,10 @@ class PnfdInfoModel(BaseInfoModel): nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), tosca.nodetemplates) - print nodeTemplates - self.basepath = self._get_base_path(tosca) + self.basepath = self.get_base_path(tosca) self.pnf = {} self.get_all_cp(nodeTemplates) - def _get_base_path(self, tosca): - fpath, fname = os.path.split(tosca.path) - return fpath - def get_substitution_mappings(self, tosca): pnf_substitution_mappings = tosca.tpl['topology_template']['substitution_mappings'] if pnf_substitution_mappings: diff --git a/catalog/pub/utils/toscaparser/testdata/ns/ran.csar b/catalog/pub/utils/toscaparser/testdata/ns/ran.csar Binary files differnew file mode 100644 index 00000000..ba78605d --- /dev/null +++ b/catalog/pub/utils/toscaparser/testdata/ns/ran.csar diff --git a/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar b/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar Binary files differdeleted file mode 100644 index 4d7e3984..00000000 --- a/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar +++ /dev/null diff --git a/catalog/pub/utils/toscaparser/testdata/vcpe/infra.csar b/catalog/pub/utils/toscaparser/testdata/vnf/infra.csar Binary files differindex 315b0bfc..315b0bfc 100644 --- a/catalog/pub/utils/toscaparser/testdata/vcpe/infra.csar +++ b/catalog/pub/utils/toscaparser/testdata/vnf/infra.csar diff --git a/catalog/pub/utils/toscaparser/testdata/vcpe/vbng.csar b/catalog/pub/utils/toscaparser/testdata/vnf/vbng.csar Binary files differindex 7180dc19..7180dc19 100644 --- a/catalog/pub/utils/toscaparser/testdata/vcpe/vbng.csar +++ b/catalog/pub/utils/toscaparser/testdata/vnf/vbng.csar diff --git a/catalog/pub/utils/toscaparser/testdata/vcpe/vbrgemu.csar b/catalog/pub/utils/toscaparser/testdata/vnf/vbrgemu.csar Binary files differindex 69fdbde6..69fdbde6 100644 --- a/catalog/pub/utils/toscaparser/testdata/vcpe/vbrgemu.csar +++ b/catalog/pub/utils/toscaparser/testdata/vnf/vbrgemu.csar diff --git a/catalog/pub/utils/toscaparser/testdata/vcpe/vgmux.csar b/catalog/pub/utils/toscaparser/testdata/vnf/vgmux.csar Binary files differindex 4108b696..4108b696 100644 --- a/catalog/pub/utils/toscaparser/testdata/vcpe/vgmux.csar +++ b/catalog/pub/utils/toscaparser/testdata/vnf/vgmux.csar diff --git a/catalog/pub/utils/toscaparser/testdata/vcpe/vgw.csar b/catalog/pub/utils/toscaparser/testdata/vnf/vgw.csar Binary files differindex e23dd27f..e23dd27f 100644 --- a/catalog/pub/utils/toscaparser/testdata/vcpe/vgw.csar +++ b/catalog/pub/utils/toscaparser/testdata/vnf/vgw.csar diff --git a/catalog/pub/utils/toscaparser/tests.py b/catalog/pub/utils/toscaparser/tests.py index 296cb15f..36ceb2a3 100644 --- a/catalog/pub/utils/toscaparser/tests.py +++ b/catalog/pub/utils/toscaparser/tests.py @@ -17,7 +17,7 @@ import logging from django.test import TestCase -from catalog.pub.utils.toscaparser import parse_vnfd, parse_pnfd +from catalog.pub.utils.toscaparser import parse_vnfd, parse_pnfd, parse_nsd logger = logging.getLogger(__name__) @@ -30,17 +30,23 @@ class TestToscaparser(TestCase): pass def test_nsd_parse(self): - # csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/resource-ZteMmeFixVl-csar.csar" - # input_parameters = [{"value": "111111", "key": "sdncontroller"}] - # logger.debug("csar_path:%s", csar_path) - # vnfd_json = parse_vnfd(csar_path, input_parameters) - # metadata = json.loads(vnfd_json).get("metadata") - # self.assertEqual("ZTE-MME-FIX-VL", metadata.get("name", "")) - # TODO - pass + ran_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/ns/ran.csar" + nsd_json = parse_nsd(ran_csar) + metadata = json.loads(nsd_json).get("metadata") + self.assertEqual("RAN-NS", metadata.get("template_name", "")) + + pnf_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/pnf/ran-du.csar" + nsd_json = parse_nsd(pnf_csar) + metadata = json.loads(nsd_json).get("metadata") + self.assertNotEqual("RAN-NS", metadata.get("template_name", "")) + + pnf_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/vnf/vgw.csar" + nsd_json = parse_nsd(pnf_csar) + metadata = json.loads(nsd_json).get("metadata") + self.assertNotEqual("RAN-NS", metadata.get("template_name", "")) - def test_vcpe_parse(self): - csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/vcpe" + def test_vnf_parse(self): + csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/vnf" input_parameters = [{"value": "222222", "key": "sdncontroller"}] vcpe = ["infra", "vbng", "vbrgemu", "vgmux", "vgw"] for vcpe_part in vcpe: @@ -54,6 +60,5 @@ class TestToscaparser(TestCase): def test_pnfd_parse(self): csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/pnf/ran-du.csar" pnfd_json = parse_pnfd(csar_path) - print pnfd_json metadata = json.loads(pnfd_json).get("metadata") self.assertEqual("RAN_DU", metadata.get("template_name", "")) diff --git a/catalog/pub/utils/toscaparser/vnfdmodel.py b/catalog/pub/utils/toscaparser/vnfdmodel.py index c85b7d1b..135963b2 100644 --- a/catalog/pub/utils/toscaparser/vnfdmodel.py +++ b/catalog/pub/utils/toscaparser/vnfdmodel.py @@ -15,11 +15,14 @@ import functools import logging import os -from catalog.pub.utils.toscaparser import EtsiNsdInfoModel +from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel logger = logging.getLogger(__name__) +SECTIONS = (VDU_COMPUTE_TYPE, VNF_VL_TYPE, VDU_CP_TYPE, VDU_STORAGE_TYPE) = \ + ('tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.VnfVirtualLink', 'tosca.nodes.nfv.VduCp', 'tosca.nodes.nfv.Vdu.VirtualStorage') -class EtsiVnfdInfoModel(EtsiNsdInfoModel): + +class EtsiVnfdInfoModel(BaseInfoModel): def __init__(self, path, params): super(EtsiVnfdInfoModel, self).__init__(path, params) @@ -32,148 +35,33 @@ class EtsiVnfdInfoModel(EtsiNsdInfoModel): nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), tosca.nodetemplates) node_types = tosca.topology_template.custom_defs - logger.error("customdefs:%s", node_types) - self.basepath = self._get_base_path(tosca) - self.services = self._get_all_services(nodeTemplates) - self.vcloud = self._get_all_vcloud(nodeTemplates) - self.vcenter = self._get_all_vcenter(nodeTemplates) - self.image_files = self._get_all_image_file(nodeTemplates) - self.local_storages = self._get_all_local_storage(nodeTemplates) - self.volume_storages = self._get_all_volume_storage(nodeTemplates) + self.basepath = self.get_base_path(tosca) + self.volume_storages = self._get_all_volume_storage(nodeTemplates, node_types) self.vdus = self._get_all_vdu(nodeTemplates, node_types) - self.vls = self.get_all_vl(nodeTemplates, node_types) - logger.debug("vls:%s", self.vls) - self.cps = self.get_all_cp(nodeTemplates, node_types) - self.plugins = self.get_all_plugin(nodeTemplates) - self.routers = self.get_all_router(nodeTemplates) - self.server_groups = self.get_all_server_group(tosca.topology_template.groups) - self.element_groups = self._get_all_element_group(tosca.topology_template.groups) - self.policies = self._get_policies(tosca.topology_template.policies) - self.vnf_exposed = self.get_all_endpoint_exposed(tosca.topology_template) - self.vnf_flavours = self.get_all_flavour(tosca.topology_template.groups) - - def _get_base_path(self, tosca): - fpath, fname = os.path.split(tosca.path) - return fpath - - def _get_all_services(self, nodeTemplates): - ret = [] - for node in nodeTemplates: - if self.isService(node): - service = {} - service['serviceId'] = node['name'] - if 'description' in node: - service['description'] = node['description'] - service['properties'] = node['properties'] - service['dependencies'] = map(lambda x: self.get_requirement_node_name(x), - self.getNodeDependencys(node)) - service['networks'] = map(lambda x: self.get_requirement_node_name(x), self.getVirtualLinks(node)) - - ret.append(service) - return ret + self.vls = self._get_all_vl(nodeTemplates, node_types) + self.cps = self._get_all_cp(nodeTemplates, node_types) + self.vnf_exposed = self._get_all_endpoint_exposed(tosca.topology_template) - def _get_all_vcloud(self, nodeTemplates): + def _get_all_volume_storage(self, nodeTemplates, node_types): rets = [] for node in nodeTemplates: - if self._isVcloud(node): - ret = {} - if 'vdc_name' in node['properties']: - ret['vdc_name'] = node['properties']['vdc_name'] - else: - ret['vdc_name'] = "" - if 'storage_clusters' in node['properties']: - ret['storage_clusters'] = node['properties']['storage_clusters'] - else: - ret['storage_clusters'] = [] - - rets.append(ret) - return rets - - def _isVcloud(self, node): - return node['nodeType'].upper().find('.VCLOUD.') >= 0 or node['nodeType'].upper().endswith('.VCLOUD') - - def _get_all_vcenter(self, nodeTemplates): - rets = [] - for node in nodeTemplates: - if self._isVcenter(node): - ret = {} - if 'compute_clusters' in node['properties']: - ret['compute_clusters'] = node['properties']['compute_clusters'] - else: - ret['compute_clusters'] = [] - if 'storage_clusters' in node['properties']: - ret['storage_clusters'] = node['properties']['storage_clusters'] - else: - ret['storage_clusters'] = [] - if 'network_clusters' in node['properties']: - ret['network_clusters'] = node['properties']['network_clusters'] - else: - ret['network_clusters'] = [] - - rets.append(ret) - return rets - - def _isVcenter(self, node): - return node['nodeType'].upper().find('.VCENTER.') >= 0 or node['nodeType'].upper().endswith('.VCENTER') - - def _get_all_image_file(self, nodeTemplates): - rets = [] - for node in nodeTemplates: - if self._isImageFile(node): - ret = {} - ret['image_file_id'] = node['name'] - if 'description' in node: - ret['description'] = node['description'] - ret['properties'] = node['properties'] - - rets.append(ret) - return rets - - def _isImageFile(self, node): - return node['nodeType'].upper().find('.IMAGEFILE.') >= 0 or node['nodeType'].upper().endswith('.IMAGEFILE') - - def _get_all_local_storage(self, nodeTemplates): - rets = [] - for node in nodeTemplates: - if self._isLocalStorage(node): - ret = {} - ret['local_storage_id'] = node['name'] - if 'description' in node: - ret['description'] = node['description'] - ret['properties'] = node['properties'] - - rets.append(ret) - return rets - - def _isLocalStorage(self, node): - return node['nodeType'].upper().find('.LOCALSTORAGE.') >= 0 or node['nodeType'].upper().endswith( - '.LOCALSTORAGE') - - def _get_all_volume_storage(self, nodeTemplates): - rets = [] - for node in nodeTemplates: - if self._isVolumeStorage(node): + if self.isNodeTypeX(node, node_types, VDU_STORAGE_TYPE): ret = {} ret['volume_storage_id'] = node['name'] if 'description' in node: ret['description'] = node['description'] ret['properties'] = node['properties'] - ret['image_file'] = map(lambda x: self.get_requirement_node_name(x), - self.getRequirementByName(node, 'image_file')) - + # image_file should be gotten form artifacts TODO + # ret['artifacts'] = self._build_artifacts(node) rets.append(ret) return rets - def _isVolumeStorage(self, node): - return node['nodeType'].upper().find('.VOLUMESTORAGE.') >= 0 or node['nodeType'].upper().endswith( - '.VOLUMESTORAGE') - def _get_all_vdu(self, nodeTemplates, node_types): rets = [] inject_files = [] for node in nodeTemplates: logger.error("nodeTemplates :%s", node) - if self.isVdu(node, node_types): + if self.isNodeTypeX(node, node_types, VDU_COMPUTE_TYPE): ret = {} ret['vdu_id'] = node['name'] ret['type'] = node['nodeType'] @@ -189,136 +77,128 @@ class EtsiVnfdInfoModel(EtsiNsdInfoModel): source_data = f.read() source_data_base64 = source_data.encode("base64") inject_file["source_data_base64"] = source_data_base64 - - local_storages = self.getRequirementByName(node, 'local_storage') - ret['local_storages'] = map(lambda x: self.get_requirement_node_name(x), local_storages) - volume_storages = self.getRequirementByName(node, 'volume_storage') - ret['volume_storages'] = map(functools.partial(self._trans_volume_storage), volume_storages) + virtual_storages = self.getRequirementByName(node, 'virtual_storage') + ret['virtual_storages'] = map(functools.partial(self._trans_virtual_storage), virtual_storages) ret['dependencies'] = map(lambda x: self.get_requirement_node_name(x), self.getNodeDependencys(node)) - virtual_compute = self.getCapabilityByName(node, 'virtual_compute') if virtual_compute is not None and 'properties' in virtual_compute: ret['virtual_compute'] = virtual_compute['properties'] - - ret['vls'] = self.get_linked_vl_ids(node, nodeTemplates) - - scalable = self.getCapabilityByName(node, 'scalable') - if scalable is not None and 'properties' in scalable: - ret['scalable'] = scalable['properties'] - - ret['cps'] = self.getVirtalBindingCpIds(node, nodeTemplates) - ret['artifacts'] = self._build_artifacts(node) - + ret['vls'] = self._get_linked_vl_ids(node, nodeTemplates) + ret['cps'] = self._get_virtal_binding_cp_ids(node, nodeTemplates) + ret['artifacts'] = self.build_artifacts(node) rets.append(ret) logger.debug("rets:%s", rets) return rets - def get_node_image_file(self, node): - rets = map(lambda x: self.get_requirement_node_name(x), self.getRequirementByName(node, 'guest_os')) - if len(rets) > 0: - return rets[0] - return "" - - def _trans_volume_storage(self, volume_storage): - if isinstance(volume_storage, str): - return {"volume_storage_id": volume_storage} + def _trans_virtual_storage(self, virtual_storage): + if isinstance(virtual_storage, str): + return {"vitual_storage_id": virtual_storage} else: ret = {} - ret['volume_storage_id'] = self.get_requirement_node_name(volume_storage) - if 'relationship' in volume_storage and 'properties' in volume_storage['relationship']: - if 'location' in volume_storage['relationship']['properties']: - ret['location'] = volume_storage['relationship']['properties']['location'] - if 'device' in volume_storage['relationship']['properties']: - ret['device'] = volume_storage['relationship']['properties']['device'] - + ret['vitual_storage_id'] = self.get_requirement_node_name(virtual_storage) return ret - def get_linked_vl_ids(self, node, node_templates): + def _get_linked_vl_ids(self, node, node_templates): vl_ids = [] - cps = self.getVirtalBindingCps(node, node_templates) + cps = self._get_virtal_binding_cps(node, node_templates) for cp in cps: - vl_reqs = self.getVirtualLinks(cp) + vl_reqs = self.getRequirementByName(cp, 'virtual_link') for vl_req in vl_reqs: vl_ids.append(self.get_requirement_node_name(vl_req)) return vl_ids - def _build_artifacts(self, node): - rets = [] - if 'artifacts' in node and len(node['artifacts']) > 0: - artifacts = node['artifacts'] - for name, value in artifacts.items(): - ret = {} - if isinstance(value, dict): - ret['artifact_name'] = name - ret['type'] = value.get('type', '') - ret['file'] = value.get('file', '') - ret['repository'] = value.get('repository', '') - ret['deploy_path'] = value.get('deploy_path', '') - else: - ret['artifact_name'] = name - ret['type'] = '' - ret['file'] = value - ret['repository'] = '' - ret['deploy_path'] = '' - rets.append(ret) - return rets + def _get_virtal_binding_cp_ids(self, node, nodeTemplates): + return map(lambda x: x['name'], self._get_virtal_binding_cps(node, nodeTemplates)) + + def _get_virtal_binding_cps(self, node, nodeTemplates): + cps = [] + for tmpnode in nodeTemplates: + if 'requirements' in tmpnode: + for item in tmpnode['requirements']: + for key, value in item.items(): + if key.upper().startswith('VIRTUAL_BINDING'): + req_node_name = self.get_requirement_node_name(value) + if req_node_name is not None and req_node_name == node['name']: + cps.append(tmpnode) + return cps - def get_all_cp(self, nodeTemplates, node_types): + def _get_all_vl(self, nodeTemplates, node_types): + vls = [] + for node in nodeTemplates: + if self.isNodeTypeX(node, node_types, VNF_VL_TYPE): + vl = dict() + vl['vl_id'] = node['name'] + vl['description'] = node['description'] + vl['properties'] = node['properties'] + vls.append(vl) + return vls + + def _get_all_cp(self, nodeTemplates, node_types): cps = [] for node in nodeTemplates: - if self.isCp(node, node_types): + if self.isNodeTypeX(node, node_types, VDU_CP_TYPE): cp = {} cp['cp_id'] = node['name'] cp['cpd_id'] = node['name'] cp['description'] = node['description'] cp['properties'] = node['properties'] - cp['vl_id'] = self.get_node_vl_id(node) - cp['vdu_id'] = self.get_node_vdu_id(node) - vls = self.buil_cp_vls(node) + cp['vl_id'] = self._get_node_vl_id(node) + cp['vdu_id'] = self._get_node_vdu_id(node) + vls = self._buil_cp_vls(node) if len(vls) > 1: cp['vls'] = vls cps.append(cp) return cps - def get_all_plugin(self, node_templates): - plugins = [] - for node in node_templates: - if self._isPlugin(node): - plugin = {} - plugin['plugin_id'] = node['name'] - plugin['description'] = node['description'] - plugin['properties'] = node['properties'] - if 'interfaces' in node: - plugin['interfaces'] = node['interfaces'] - - plugins.append(plugin) - return plugins - - def _isPlugin(self, node): - return node['nodeType'].lower().find('.plugin.') >= 0 or node['nodeType'].lower().endswith('.plugin') - - def _get_all_element_group(self, groups): - rets = [] - for group in groups: - if self._isVnfdElementGroup(group): - ret = {} - ret['group_id'] = group.name - ret['description'] = group.description - if 'properties' in group.tpl: - ret['properties'] = group.tpl['properties'] - ret['members'] = group.members - rets.append(ret) - return rets - - def _isVnfdElementGroup(self, group): - return group.type.upper().find('.VNFDELEMENTGROUP.') >= 0 or group.type.upper().endswith('.VNFDELEMENTGROUP') + def _get_node_vdu_id(self, node): + vdu_ids = map(lambda x: self.get_requirement_node_name(x), self.getRequirementByName(node, 'virtual_binding')) + if len(vdu_ids) > 0: + return vdu_ids[0] + return "" - def _get_policies(self, top_policies): - policies = [] - scaling_policies = self.get_scaling_policies(top_policies) - healing_policies = self.get_healing_policies(top_policies) - policies.append({"scaling": scaling_policies, 'healing': healing_policies}) - return policies + def _get_node_vl_id(self, node): + vl_ids = map(lambda x: self.get_requirement_node_name(x), self.getRequirementByName(node, 'virtual_link')) + if len(vl_ids) > 0: + return vl_ids[0] + return "" - def get_healing_policies(self, top_policies): - return self.get_policies_by_keyword(top_policies, '.HEALING') + def _buil_cp_vls(self, node): + return map(lambda x: self._build_cp_vl(x), self.getRequirementByName(node, 'virtual_link')) + + def _build_cp_vl(self, req): + cp_vl = {} + cp_vl['vl_id'] = self.get_prop_from_obj(req, 'node') + relationship = self.get_prop_from_obj(req, 'relationship') + if relationship is not None: + properties = self.get_prop_from_obj(relationship, 'properties') + if properties is not None and isinstance(properties, dict): + for key, value in properties.items(): + cp_vl[key] = value + return cp_vl + + def _get_all_endpoint_exposed(self, topo_tpl): + if 'substitution_mappings' in topo_tpl.tpl: + external_cps = self._get_external_cps(topo_tpl.tpl['substitution_mappings']) + forward_cps = self._get_forward_cps(topo_tpl.tpl['substitution_mappings']) + return {"external_cps": external_cps, "forward_cps": forward_cps} + return {} + + def _get_external_cps(self, subs_mappings): + external_cps = [] + if 'requirements' in subs_mappings: + for key, value in subs_mappings['requirements'].items(): + if isinstance(value, list) and len(value) > 0: + external_cps.append({"key_name": key, "cpd_id": value[0]}) + else: + external_cps.append({"key_name": key, "cpd_id": value}) + return external_cps + + def _get_forward_cps(self, subs_mappings): + forward_cps = [] + if 'capabilities' in subs_mappings: + for key, value in subs_mappings['capabilities'].items(): + if isinstance(value, list) and len(value) > 0: + forward_cps.append({"key_name": key, "cpd_id": value[0]}) + else: + forward_cps.append({"key_name": key, "cpd_id": value}) + return forward_cps |