summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--catalog/pub/utils/toscaparser/__init__.py3
-rw-r--r--catalog/pub/utils/toscaparser/basemodel.py34
-rw-r--r--catalog/pub/utils/toscaparser/graph.py74
-rw-r--r--catalog/pub/utils/toscaparser/nsdmodel.py6
-rw-r--r--catalog/pub/utils/toscaparser/servicemodel.py19
-rw-r--r--catalog/pub/utils/toscaparser/testdata/ns/ran.csarbin2804 -> 3067 bytes
-rw-r--r--catalog/pub/utils/toscaparser/testdata/ns/service-vIMS.csarbin0 -> 54472 bytes
-rw-r--r--catalog/pub/utils/toscaparser/tests.py37
-rw-r--r--catalog/pub/utils/toscaparser/vnfdmodel.py4
9 files changed, 150 insertions, 27 deletions
diff --git a/catalog/pub/utils/toscaparser/__init__.py b/catalog/pub/utils/toscaparser/__init__.py
index 12df6e89..b94ff4df 100644
--- a/catalog/pub/utils/toscaparser/__init__.py
+++ b/catalog/pub/utils/toscaparser/__init__.py
@@ -25,7 +25,6 @@ def parse_nsd(path, input_parameters=[], isETSI=True):
tosca_obj = EtsiNsdInfoModel(path, input_parameters)
else:
tosca_obj = SdcServiceModel(path, input_parameters)
-
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
return strResponse
@@ -35,7 +34,6 @@ def parse_vnfd(path, input_parameters=[], isETSI=True):
if isETSI:
tosca_obj = EtsiVnfdInfoModel(path, input_parameters)
else:
- # SDC VF Model TBD
tosca_obj = {}
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
@@ -46,7 +44,6 @@ def parse_pnfd(path, input_parameters=[], isETSI=True):
if isETSI:
tosca_obj = PnfdInfoModel(path, input_parameters)
else:
- # SDC PNF Model TBD
tosca_obj = {}
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
diff --git a/catalog/pub/utils/toscaparser/basemodel.py b/catalog/pub/utils/toscaparser/basemodel.py
index f45f7469..7df59ff8 100644
--- a/catalog/pub/utils/toscaparser/basemodel.py
+++ b/catalog/pub/utils/toscaparser/basemodel.py
@@ -24,6 +24,7 @@ import paramiko
from toscaparser.tosca_template import ToscaTemplate
from toscaparser.properties import Property
from toscaparser.functions import Function, Concat, GetInput, get_function, function_mappings
+from catalog.pub.utils.toscaparser.graph import Graph
from catalog.pub.utils.toscaparser.dataentityext import DataEntityExt
@@ -58,7 +59,8 @@ class BaseInfoModel(object):
pass
def buildInputs(self, tosca):
- return tosca.tpl.get(TOPOLOGY_TEMPLATE, '').get(INPUTS, {})
+ topo = tosca.tpl.get(TOPOLOGY_TEMPLATE, None)
+ return topo.get(INPUTS, {}) if topo else {}
def buildToscaTemplate(self, path, params):
file_name = None
@@ -455,9 +457,37 @@ class BaseInfoModel(object):
return False
return True
- def setTargetValues(dict_target, target_keys, dict_source, source_keys):
+ def setTargetValues(self, dict_target, target_keys, dict_source, source_keys):
i = 0
for item in source_keys:
dict_target[target_keys[i]] = dict_source.get(item, "")
i += 1
return dict_target
+
+ def get_deploy_graph(self, tosca, relations):
+ nodes = tosca.graph.nodetemplates
+ graph = Graph()
+ for node in nodes:
+ self._build_deploy_path(node, [], graph, relations)
+ return graph.to_dict()
+
+ def _build_deploy_path(self, node, node_parent, graph, relations):
+ graph.add_node(node.name, node_parent)
+ type_require_set = {}
+ type_requires = node.type_definition.requirements
+ for type_require in type_requires:
+ type_require_set.update(type_require)
+ for requirement in node.requirements:
+ for k in requirement.keys():
+ if type_require_set[k].get('relationship', None) in relations[0] or type_require_set[k].get('capability', None) in relations[0]:
+ if isinstance(requirement[k], dict):
+ next_node = requirement[k].get('node', None)
+ else:
+ next_node = requirement[k]
+ graph.add_node(next_node, [node.name])
+ if type_require_set[k].get('relationship', None) in relations[1]:
+ if isinstance(requirement[k], dict):
+ next_node = requirement[k].get('node', None)
+ else:
+ next_node = requirement[k]
+ graph.add_node(next_node, [node.name])
diff --git a/catalog/pub/utils/toscaparser/graph.py b/catalog/pub/utils/toscaparser/graph.py
new file mode 100644
index 00000000..6d38d12f
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/graph.py
@@ -0,0 +1,74 @@
+# Copyright 2018 ZTE Corporation.
+#
+# 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.
+
+from collections import deque
+from collections import OrderedDict
+
+
+class Graph(object):
+
+ def __init__(self, graph_dict=None):
+ self.graph = OrderedDict()
+ if graph_dict:
+ for node, dep_nodes in graph_dict.iteritems():
+ self.add_node(node, dep_nodes)
+
+ def add_node(self, node, dep_nodes):
+ if node not in self.graph:
+ self.graph[node] = set()
+ if isinstance(dep_nodes, list):
+ for dep_node in dep_nodes:
+ if dep_node not in self.graph:
+ self.graph[dep_node] = set()
+ if dep_node not in self.graph[node]:
+ self.graph[node].add(dep_node)
+
+ def get_pre_nodes(self, node):
+ return [k for k in self.graph if node in self.graph[k]]
+
+ def topo_sort(self):
+ degree = {}
+ for node in self.graph:
+ degree[node] = 0
+
+ for node in self.graph:
+ for dependent in self.graph[node]:
+ degree[dependent] += 1
+
+ queue = deque()
+ for node in degree:
+ if degree[node] == 0:
+ queue.appendleft(node)
+
+ sort_list = []
+ while queue:
+ node = queue.pop()
+ sort_list.append(node)
+ for dependent in self.graph[node]:
+ degree[dependent] -= 1
+ if degree[dependent] == 0:
+ queue.appendleft(dependent)
+
+ if len(sort_list) == len(self.graph):
+ return sort_list
+ else:
+ return None
+
+ def to_dict(self):
+ dict = {}
+ for node, dependents in self.graph.iteritems():
+ dict[node] = []
+ for dep in dependents:
+ dict[node].append(dep)
+ return dict
diff --git a/catalog/pub/utils/toscaparser/nsdmodel.py b/catalog/pub/utils/toscaparser/nsdmodel.py
index 9d72642f..22a75b94 100644
--- a/catalog/pub/utils/toscaparser/nsdmodel.py
+++ b/catalog/pub/utils/toscaparser/nsdmodel.py
@@ -15,6 +15,7 @@
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) = \
@@ -25,6 +26,8 @@ SECTIONS = (NS_TYPE, NS_VNF_TYPE, NS_VL_TYPE, NS_PNF_TYPE, NS_NFP_TYPE, NS_VNFFG
'tosca.nodes.nfv.NFP',
'tosca.nodes.nfv.VNFFG')
+NFV_NS_RELATIONSHIPS = [["tosca.relationships.nfv.VirtualLinksTo", "tosca.relationships.DependsOn"], []]
+
class EtsiNsdInfoModel(BaseInfoModel):
@@ -44,6 +47,7 @@ class EtsiNsdInfoModel(BaseInfoModel):
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)
+ self.graph = self.get_deploy_graph(tosca, NFV_NS_RELATIONSHIPS)
def _get_all_vnf(self, nodeTemplates, node_types):
vnfs = []
@@ -159,7 +163,7 @@ class EtsiNsdInfoModel(BaseInfoModel):
ns['ns_id'] = node['name']
ns['description'] = node['description']
ns['properties'] = node['properties']
- ns['networks'] = self._get_networks(node)
+ ns['networks'] = self._get_networks(node, node_types)
nss.append(ns)
return nss
diff --git a/catalog/pub/utils/toscaparser/servicemodel.py b/catalog/pub/utils/toscaparser/servicemodel.py
index 249710d9..bccd417d 100644
--- a/catalog/pub/utils/toscaparser/servicemodel.py
+++ b/catalog/pub/utils/toscaparser/servicemodel.py
@@ -40,6 +40,8 @@ SDC_PNF_METADATA_SECTIONS = (SDC_PNF_UUID, SDC_PNF_INVARIANTUUID, SDC_PNF_NAME,
SDC_PNF_SECTIONS = (SDC_PNF_ID, SDC_PNF_METADATA, SDC_PNF_PROPERTIES, SDC_PNF_DESCRIPTION) = \
("name", "metadata", "properties", "description")
+SERVICE_RELATIONSHIPS = [["tosca.relationships.network.LinksTo", "tosca.relationships.nfv.VirtualLinksTo", "tosca.capabilities.nfv.VirtualLinkable", "tosca.relationships.DependsOn"], []]
+
class SdcServiceModel(BaseInfoModel):
@@ -49,12 +51,14 @@ class SdcServiceModel(BaseInfoModel):
def parseModel(self, tosca):
self.metadata = self._buildServiceMetadata(tosca)
self.inputs = self.buildInputs(tosca)
- 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)
+ if hasattr(tosca, '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.graph = self.get_deploy_graph(tosca, SERVICE_RELATIONSHIPS)
def _buildServiceMetadata(self, tosca):
""" SDC service Meta Format
@@ -71,7 +75,8 @@ class SdcServiceModel(BaseInfoModel):
namingPolicy: ''
"""
metadata_temp = self.buildMetadata(tosca)
- self.setTargetValues(self.metadata, NS_METADATA_SECTIONS, metadata_temp, SDC_SERVICE_METADATA_SECTIONS)
+ metadata = {}
+ return self.setTargetValues(metadata, NS_METADATA_SECTIONS, metadata_temp, SDC_SERVICE_METADATA_SECTIONS)
def _get_all_vnf(self, nodeTemplates, node_types):
""" SDC Resource Metadata
diff --git a/catalog/pub/utils/toscaparser/testdata/ns/ran.csar b/catalog/pub/utils/toscaparser/testdata/ns/ran.csar
index acd49093..ad9c7d96 100644
--- a/catalog/pub/utils/toscaparser/testdata/ns/ran.csar
+++ b/catalog/pub/utils/toscaparser/testdata/ns/ran.csar
Binary files differ
diff --git a/catalog/pub/utils/toscaparser/testdata/ns/service-vIMS.csar b/catalog/pub/utils/toscaparser/testdata/ns/service-vIMS.csar
new file mode 100644
index 00000000..754dfbc3
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/testdata/ns/service-vIMS.csar
Binary files differ
diff --git a/catalog/pub/utils/toscaparser/tests.py b/catalog/pub/utils/toscaparser/tests.py
index cc99991f..0d90e581 100644
--- a/catalog/pub/utils/toscaparser/tests.py
+++ b/catalog/pub/utils/toscaparser/tests.py
@@ -20,6 +20,7 @@ import shutil
from django.test import TestCase
from catalog.pub.utils.toscaparser import parse_vnfd, parse_pnfd, parse_nsd
+from catalog.pub.utils.toscaparser.graph import Graph
logger = logging.getLogger(__name__)
@@ -31,11 +32,11 @@ class TestToscaparser(TestCase):
def tearDown(self):
pass
- def test_vnf_parse(self):
+ def test_vnfd_parse(self):
self.remove_temp_dir()
csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/vnf"
input_parameters = [{"value": "222222", "key": "sdncontroller"}]
- vcpe = ["infra", "vbng", "vbrgemu", "vgmux", "vgw"]
+ vcpe = ["vgw"]
for vcpe_part in vcpe:
csar_file = ("%s/%s.csar" % (csar_path, vcpe_part))
logger.debug("csar_file:%s", csar_file)
@@ -53,20 +54,17 @@ class TestToscaparser(TestCase):
def test_nsd_parse(self):
self.remove_temp_dir()
- pnf_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/pnf/ran-du.csar"
- nsd_json = parse_nsd(pnf_csar)
+ 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.assertNotEqual("RAN-NS", metadata.get("template_name", ""))
+ self.assertEqual("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", ""))
-
- # 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", ""))
+ def test_service_descriptor_parse(self):
+ self.remove_temp_dir()
+ service_test_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/ns/service-vIMS.csar"
+ test_json = parse_nsd(service_test_csar, [], False)
+ metadata = json.loads(test_json).get("metadata")
+ self.assertEqual("vIMS_v2", metadata.get("name", ""))
def remove_temp_dir(self):
tempdir = tempfile.gettempdir()
@@ -75,3 +73,14 @@ class TestToscaparser(TestCase):
path = tempfile.tempdir + "/" + dir
if (not os.path.isfile(path)) and os.path.exists(path):
shutil.rmtree(tempfile.tempdir + "/" + dir)
+
+ def test_graph(self):
+ data = {
+ "cucp": [],
+ "du": [],
+ "vl_flat_net": ["cucp", "cuup"],
+ "vl_ext_net": ["cucp", "cuup"],
+ "cuup": []
+ }
+ graph = Graph(data)
+ self.assertEqual(['vl_ext_net', 'vl_flat_net'].sort(), graph.get_pre_nodes("cucp").sort())
diff --git a/catalog/pub/utils/toscaparser/vnfdmodel.py b/catalog/pub/utils/toscaparser/vnfdmodel.py
index de29d605..0b6609b8 100644
--- a/catalog/pub/utils/toscaparser/vnfdmodel.py
+++ b/catalog/pub/utils/toscaparser/vnfdmodel.py
@@ -21,6 +21,9 @@ 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')
+NFV_VNF_RELATIONSHIPS = [["tosca.relationships.nfv.VirtualLinksTo", "tosca.relationships.nfv.VduAttachesTo", "tosca.relationships.nfv.AttachesTo", "tosca.relationships.nfv.Vdu.AttachedTo", "tosca.relationships.DependsOn"],
+ ["tosca.nodes.relationships.VirtualBindsTo", "tosca.relationships.nfv.VirtualBindsTo"]]
+
class EtsiVnfdInfoModel(BaseInfoModel):
@@ -39,6 +42,7 @@ class EtsiVnfdInfoModel(BaseInfoModel):
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)
+ self.graph = self.get_deploy_graph(tosca, NFV_VNF_RELATIONSHIPS)
def _get_all_volume_storage(self, nodeTemplates, node_types):
rets = []