summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--catalog/packages/biz/pnf_descriptor.py15
-rw-r--r--catalog/packages/tests/test_pnf_descriptor.py9
-rw-r--r--catalog/packages/urls.py7
-rw-r--r--catalog/packages/views/pnf_descriptor_views.py29
-rw-r--r--catalog/pub/utils/toscaparser/__init__.py6
-rw-r--r--catalog/pub/utils/toscaparser/basemodel.py42
-rw-r--r--catalog/pub/utils/toscaparser/pnfmodel.py60
-rw-r--r--catalog/pub/utils/toscaparser/testdata/pnf/ran-du.csarbin0 -> 2680 bytes
-rw-r--r--catalog/pub/utils/toscaparser/tests.py9
9 files changed, 172 insertions, 5 deletions
diff --git a/catalog/packages/biz/pnf_descriptor.py b/catalog/packages/biz/pnf_descriptor.py
index e250ba0c..89db9cb9 100644
--- a/catalog/packages/biz/pnf_descriptor.py
+++ b/catalog/packages/biz/pnf_descriptor.py
@@ -172,3 +172,18 @@ class PnfDescriptor(object):
def handle_upload_failed(self, pnf_pkg_id):
pnf_pkg = PnfPackageModel.objects.filter(pnfPackageId=pnf_pkg_id)
pnf_pkg.update(onboardingState=PKG_STATUS.CREATED)
+
+ def parse_pnfd(self, csar_id, inputs):
+ ret = None
+ try:
+ pnf_pkg = PnfPackageModel.objects.filter(pnfPackageId=csar_id)
+ if not pnf_pkg:
+ raise CatalogException("PNF CSAR(%s) does not exist." % csar_id)
+ csar_path = pnf_pkg[0].localFilePath
+ ret = {"model": toscaparser.parse_pnfd(csar_path, inputs)}
+ except CatalogException as e:
+ return [1, e.message]
+ except Exception as e:
+ logger.error(e.message)
+ return [1, e.message]
+ return [0, ret]
diff --git a/catalog/packages/tests/test_pnf_descriptor.py b/catalog/packages/tests/test_pnf_descriptor.py
index e67e35d9..7afdeae1 100644
--- a/catalog/packages/tests/test_pnf_descriptor.py
+++ b/catalog/packages/tests/test_pnf_descriptor.py
@@ -271,3 +271,12 @@ class TestPnfDescriptor(TestCase):
mock_download.side_effect = TypeError("integer type")
response = self.client.get("/api/nsd/v1/pnf_descriptors/22/pnfd_content")
self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ @mock.patch.object(toscaparser, 'parse_pnfd')
+ def test_pnfd_parse_normal(self, mock_parse_pnfd):
+ PnfPackageModel(pnfPackageId="8", pnfdId="10").save()
+ mock_parse_pnfd.return_value = json.JSONEncoder().encode({"c": "d"})
+ req_data = {"csarId": "8", "inputs": []}
+ resp = self.client.post("/api/catalog/v1/parserpnfd", req_data, format='json')
+ self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+ self.assertEqual({"model": '{"c": "d"}'}, resp.data)
diff --git a/catalog/packages/urls.py b/catalog/packages/urls.py
index 883c3749..ca090c74 100644
--- a/catalog/packages/urls.py
+++ b/catalog/packages/urls.py
@@ -25,20 +25,21 @@ urlpatterns = [
url(r'^api/catalog/v1/vnfpackages/(?P<csarId>[0-9a-zA-Z\-\_]+)$', catalog_views.nf_rd_csar, name='nfpackage_rd'),
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'),
- # NSD
+ # NSPakcage& NSD
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
+ # PNF Package and 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'),
- # TODO SOL005 & SOL003
+ # VNFD
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/packages/views/pnf_descriptor_views.py b/catalog/packages/views/pnf_descriptor_views.py
index caa7ac23..618e6e05 100644
--- a/catalog/packages/views/pnf_descriptor_views.py
+++ b/catalog/packages/views/pnf_descriptor_views.py
@@ -27,6 +27,11 @@ from catalog.packages.serializers.pnfd_info import PnfdInfoSerializer
from catalog.packages.serializers.pnfd_infos import PnfdInfosSerializer
from catalog.packages.views.common import validate_data
from catalog.pub.exceptions import CatalogException, ResourceNotFoundException
+from catalog.packages.serializers.catalog_serializers import ParseModelRequestSerializer
+from catalog.packages.serializers.catalog_serializers import ParseModelResponseSerializer
+from catalog.packages.serializers.catalog_serializers import InternalErrorRequestSerializer
+from catalog.pub.utils.syscomm import fun_name
+from catalog.pub.utils.values import ignore_case_get
logger = logging.getLogger(__name__)
@@ -186,3 +191,27 @@ def pnfd_content_ru(request, **kwargs):
error_code = status.HTTP_500_INTERNAL_SERVER_ERROR
error_data = {'error': 'Downloading PNFD content failed.'}
return Response(data=error_data, status=error_code)
+
+
+@swagger_auto_schema(
+ method='POST',
+ operation_description="Parse PNF model",
+ request_body=ParseModelRequestSerializer,
+ responses={
+ status.HTTP_202_ACCEPTED: ParseModelResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@api_view(http_method_names=['POST'])
+def pnf_model_parser(request, *args, **kwargs):
+ csar_id = ignore_case_get(request.data, "csarId")
+ inputs = ignore_case_get(request.data, "inputs")
+ logger.debug(
+ "Enter %s, csar_id=%s, inputs=%s",
+ fun_name(),
+ csar_id,
+ inputs)
+ ret = PnfDescriptor().parse_pnfd(csar_id, inputs)
+ logger.info("Leave %s, Return value is %s", fun_name(), ret)
+ if ret[0] != 0:
+ return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ response = validate_data(ret[1], ParseModelResponseSerializer)
+ return Response(data=response.data, status=status.HTTP_202_ACCEPTED)
diff --git a/catalog/pub/utils/toscaparser/__init__.py b/catalog/pub/utils/toscaparser/__init__.py
index 604bb23f..b172d678 100644
--- a/catalog/pub/utils/toscaparser/__init__.py
+++ b/catalog/pub/utils/toscaparser/__init__.py
@@ -16,6 +16,7 @@ import json
from catalog.pub.utils.toscaparser.nsdmodel import EtsiNsdInfoModel
from catalog.pub.utils.toscaparser.vnfdmodel import EtsiVnfdInfoModel
+from catalog.pub.utils.toscaparser.pnfmodel import PnfdInfoModel
def parse_nsd(path, input_parameters=[]):
@@ -33,4 +34,7 @@ def parse_vnfd(path, input_parameters=[]):
def parse_pnfd(path, input_parameters=[]):
- pass
+ tosca_obj = PnfdInfoModel(path, input_parameters)
+ strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
+ strResponse = strResponse.replace(': null', ': ""')
+ return strResponse
diff --git a/catalog/pub/utils/toscaparser/basemodel.py b/catalog/pub/utils/toscaparser/basemodel.py
index 465249d7..192e44b6 100644
--- a/catalog/pub/utils/toscaparser/basemodel.py
+++ b/catalog/pub/utils/toscaparser/basemodel.py
@@ -37,6 +37,24 @@ SECTIONS = (VDU_TYPE, VL_TYPE, CP_TYPE) = \
class BaseInfoModel(object):
+ def __init__(self, path, params):
+ tosca = self.buildToscaTemplate(path, params)
+ self.parseModel(tosca)
+
+ def parseModel(self, tosca):
+ pass
+
+ 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 buildToscaTemplate(self, path, params):
file_name = None
try:
@@ -169,6 +187,30 @@ class BaseInfoModel(object):
if tosca.tpl['metadata'].get('UUID', ''):
self.metadata['id'] = tosca.tpl['metadata']['UUID']
+ 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 buildProperties(self, nodeTemplate, parsed_params):
properties = {}
isMappingParams = parsed_params and len(parsed_params) > 0
diff --git a/catalog/pub/utils/toscaparser/pnfmodel.py b/catalog/pub/utils/toscaparser/pnfmodel.py
new file mode 100644
index 00000000..ce531d6d
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/pnfmodel.py
@@ -0,0 +1,60 @@
+# 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.
+
+import functools
+import logging
+import os
+from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel
+logger = logging.getLogger(__name__)
+
+
+class PnfdInfoModel(BaseInfoModel):
+
+ def __init__(self, path, params):
+ super(PnfdInfoModel, 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)
+ print nodeTemplates
+ 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:
+ self.pnf['type'] = pnf_substitution_mappings['node_type']
+ self.pnf['properties'] = pnf_substitution_mappings['properties']
+
+ def get_all_cp(self, nodeTemplates):
+ self.pnf['ExtPorts'] = []
+ for node in nodeTemplates:
+ if self.isPnfExtPort(node):
+ cp = {}
+ cp['id'] = node['name']
+ cp['type'] = node['nodeType']
+ cp['properties'] = node['properties']
+ self.pnf['ExtPorts'].append(cp)
+
+ def isPnfExtPort(self, node):
+ return node['nodeType'].find('tosca.nodes.nfv.PnfExtPort') >= 0
diff --git a/catalog/pub/utils/toscaparser/testdata/pnf/ran-du.csar b/catalog/pub/utils/toscaparser/testdata/pnf/ran-du.csar
new file mode 100644
index 00000000..77bdedfc
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/testdata/pnf/ran-du.csar
Binary files differ
diff --git a/catalog/pub/utils/toscaparser/tests.py b/catalog/pub/utils/toscaparser/tests.py
index 390929e8..296cb15f 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
+from catalog.pub.utils.toscaparser import parse_vnfd, parse_pnfd
logger = logging.getLogger(__name__)
@@ -50,3 +50,10 @@ class TestToscaparser(TestCase):
metadata = json.loads(vnfd_json).get("metadata")
logger.debug("metadata:%s", metadata)
self.assertEqual(("vCPE_%s" % vcpe_part), metadata.get("template_name", ""))
+
+ 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", ""))