1.Implement parser RESTAPI. 2.Add UT cases. 41/83541/1
authordyh <dengyuanhong@chinamobile.com>
Thu, 28 Mar 2019 02:02:38 +0000 (10:02 +0800)
committerdyh <dengyuanhong@chinamobile.com>
Thu, 28 Mar 2019 02:02:50 +0000 (10:02 +0800)
Change-Id: I33cd9dc53a00d955d7be3e1cff510aa9dfa263a7
Issue-ID: VFC-1318
Signed-off-by: dyh <dengyuanhong@chinamobile.com>
catalog/packages/biz/sdc_service_package.py
catalog/packages/biz/sdc_vnf_package.py
catalog/packages/biz/service_descriptor.py
catalog/packages/serializers/catalog_serializers.py
catalog/packages/tests/test_service_descriptor.py [new file with mode: 0644]
catalog/packages/tests/test_servicepackage.py
catalog/packages/urls.py
catalog/packages/views/catalog_views.py

index bae1f71..713ab05 100644 (file)
@@ -46,11 +46,7 @@ class ServicePackage(object):
             csar_name = "%s.csar" % artifact.get("name", csar_id)
             local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path, csar_name)
             if local_file_name.endswith(".csar") or local_file_name.endswith(".zip"):
-                artifact_vnf_file = fileutil.unzip_file(local_file_name, local_path,
-                                                        "Artifacts/Deployment/OTHER/ns.csar")
-                if os.path.exists(artifact_vnf_file):
-                    local_file_name = artifact_vnf_file
-
+                fileutil.unzip_file(local_file_name, local_path, "")
             data = {
                 'userDefinedData': {}
             }
@@ -94,11 +90,13 @@ class ServicePackage(object):
                 csar_id,
                 csars[0].servicePackageUri)
         else:
-            raise PackageNotFoundException("Service package[%s] not Found." % csar_id)
+            error_message = "Service package[%s] not Found." % csar_id
+            logger.error(error_message)
+            raise PackageNotFoundException(error_message)
 
         return {"csarId": csar_id, "packageInfo": package_info}
 
-    def parse_serviced(csar_id, inputs):
+    def parse_serviced(self, csar_id, inputs):
         service_pkg = ServicePackageModel.objects.filter(servicePackageId=csar_id)
         if not service_pkg:
             raise PackageNotFoundException("Service CSAR(%s) does not exist." % csar_id)
index 71eee49..d1ee4c7 100644 (file)
@@ -19,6 +19,7 @@ import sys
 import threading
 import traceback
 
+from catalog.packages.const import PKG_STATUS
 from catalog.pub.config.config import CATALOG_ROOT_PATH, CATALOG_URL_PATH
 from catalog.pub.config.config import REG_TO_MSB_REG_PARAM
 from catalog.pub.database.models import VnfPackageModel
@@ -27,7 +28,6 @@ from catalog.pub.msapi import sdc
 from catalog.pub.utils import fileutil
 from catalog.pub.utils import toscaparser
 from catalog.pub.utils.jobutil import JobUtil
-from catalog.packages.const import PKG_STATUS
 
 logger = logging.getLogger(__name__)
 
index 72a561a..4b9a2aa 100644 (file)
@@ -28,15 +28,18 @@ logger = logging.getLogger(__name__)
 
 
 class ServiceDescriptor(object):
+    """
+    Action for Service Descriptor
+    """
 
     def __init__(self):
         pass
 
-    def create(self, data, csar_id):
+    def create(self, data, csar_id=None):
         logger.info('Start to create a ServiceD...')
         user_defined_data = ignore_case_get(data, 'userDefinedData', {})
         data = {
-            'id': id if id else str(uuid.uuid4()),
+            'id': csar_id if csar_id else str(uuid.uuid4()),
             'servicedOnboardingState': PKG_STATUS.CREATED,
             'servicedOperationalState': PKG_STATUS.DISABLED,
             'servicedUsageState': PKG_STATUS.NOT_IN_USE,
@@ -58,7 +61,7 @@ class ServiceDescriptor(object):
         service_pkgs = ServicePackageModel.objects.filter(servicePackageId=serviced_info_id)
         service_pkgs.update(onboardingState=PKG_STATUS.PROCESSING)
 
-        serviced_json = toscaparser.parse_nsd(local_file_name)  # TODO
+        serviced_json = toscaparser.parse_nsd(local_file_name)
         logger.debug("%s", serviced_json)
         serviced = json.JSONDecoder().decode(serviced_json)
 
index 0e830e5..4007c34 100644 (file)
@@ -282,6 +282,7 @@ class PostJobResponseSerializer(serializers.Serializer):
 
 class ParseModelRequestSerializer(serializers.Serializer):
     csarId = serializers.CharField(help_text="CSAR ID", required=True)
+    packageType = serializers.CharField(help_text="Package type: VNF, PNF, NS, Service", required=False)
     inputs = serializers.JSONField(help_text="Inputs", required=False)
 
 
diff --git a/catalog/packages/tests/test_service_descriptor.py b/catalog/packages/tests/test_service_descriptor.py
new file mode 100644 (file)
index 0000000..d0dc83f
--- /dev/null
@@ -0,0 +1,90 @@
+# Copyright (c) 2019, CMCC Technologies. Co., Ltd.
+#
+# 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 logging
+
+from django.test import TestCase
+
+from catalog.packages.biz.service_descriptor import ServiceDescriptor
+from catalog.packages.const import PKG_STATUS
+from catalog.pub.database.models import ServicePackageModel
+from catalog.pub.exceptions import PackageNotFoundException
+
+logger = logging.getLogger(__name__)
+
+
+class TestServiceDescription(TestCase):
+
+    def setUp(self):
+        self.user_defined_data = {
+            'key1': 'value1',
+            'key2': 'value2',
+            'key3': 'value3',
+        }
+        self.data = {
+            'userDefinedData': self.user_defined_data,
+        }
+        ServicePackageModel.objects.filter().delete()
+
+    def tearDown(self):
+        pass
+
+    def test_create(self):
+        result_data = ServiceDescriptor().create(self.data)
+        self.assertIsNotNone(result_data['id'])
+        service_package = ServicePackageModel.objects.filter(servicePackageId=result_data['id'])[0]
+        self.assertIsNotNone(service_package)
+        self.assertEqual(PKG_STATUS.DISABLED, service_package.operationalState)
+        self.assertEqual(PKG_STATUS.CREATED, service_package.onboardingState)
+        self.assertEqual(PKG_STATUS.NOT_IN_USE, service_package.usageState)
+
+    def test_create_with_csarid(self):
+        csar_id = '0b667470-e6b3-4ee8-8f08-186317a04dc2'
+        result_data = ServiceDescriptor().create(self.data, csar_id)
+        self.assertEqual(csar_id, result_data['id'])
+        service_package = ServicePackageModel.objects.filter(servicePackageId=csar_id)[0]
+        self.assertIsNotNone(service_package)
+        self.assertEqual(PKG_STATUS.DISABLED, service_package.operationalState)
+        self.assertEqual(PKG_STATUS.CREATED, service_package.onboardingState)
+        self.assertEqual(PKG_STATUS.NOT_IN_USE, service_package.usageState)
+
+    def test_parse_serviced_and_save(self):
+        try:
+            servcie_desc = ServiceDescriptor()
+            csar_id = '0b667470-e6b3-4ee8-8f08-186317a04dc2'
+            servcie_desc.create(self.data, csar_id)
+
+            local_file_name = "C:\\work\\onap\\api_test_data\\service\\service-Sotnvpninfraservice-csar.csar"
+            servcie_desc.parse_serviced_and_save(csar_id, local_file_name)
+
+            service_package = ServicePackageModel.objects.filter(servicePackageId=csar_id)[0]
+            self.assertIsNotNone(service_package)
+        except Exception as e:
+            logger.error(e.message)
+
+    def test_delete_single(self):
+        servcie_desc = ServiceDescriptor()
+        csar_id = '0b667470-e6b3-4ee8-8f08-186317a04dc2'
+        servcie_desc.create(self.data, csar_id)
+
+        servcie_desc.delete_single(csar_id)
+        self.assertTrue(len(ServicePackageModel.objects.filter(servicePackageId=csar_id)) == 0)
+        self.assertFalse(ServicePackageModel.objects.filter(servicePackageId=csar_id).exists())
+
+    def test_delete_single_not_exists(self):
+        csar_id = "8000"
+        try:
+            ServiceDescriptor().delete_single(csar_id)
+        except Exception as e:
+            self.assertTrue(isinstance(e, PackageNotFoundException))
+            self.assertEqual("Service package[8000] not Found.", e.message)
index 86d513e..9365c29 100644 (file)
 # 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 json
 
 from django.test import TestCase, Client
+from mock import mock
 from rest_framework import status
 
 from catalog.packages.biz.sdc_service_package import ServicePackage
 from catalog.pub.database.models import ServicePackageModel
-from catalog.pub.exceptions import PackageNotFoundException, PackageHasExistsException
+from catalog.pub.exceptions import PackageNotFoundException, PackageHasExistsException, CatalogException
+from catalog.pub.msapi import sdc
+from catalog.pub.utils import toscaparser
+
+PARSER_BASE_URL = "/api/parser/v1"
 
 
 class TestServicePackage(TestCase):
@@ -40,14 +46,49 @@ class TestServicePackage(TestCase):
         except PackageHasExistsException as e:
             self.assertEqual("Service CSAR(1) already exists.", e.message)
 
+    @mock.patch.object(sdc, 'get_artifact')
+    def test_service_pkg_distribute_when_fail_get_artifacts(self, mock_get_artifact):
+        mock_get_artifact.side_effect = CatalogException("Failed to query artifact(services,1) from sdc.")
+        csar_id = 1
+        try:
+            ServicePackage().on_distribute(csar_id)
+        except Exception as e:
+            self.assertTrue(isinstance(e, CatalogException))
+            self.assertEqual("Failed to query artifact(services,1) from sdc.", e.message)
+
+    @mock.patch.object(sdc, 'get_artifact')
+    @mock.patch.object(sdc, 'download_artifacts')
+    def test_api_service_pkg_distribute_when_fail_download_artifacts(self, mock_get_artifact, mock_download_artifacts):
+        mock_get_artifact.return_value = {
+            "uuid": "1",
+            "invariantUUID": "63eaec39-ffbe-411c-a838-448f2c73f7eb",
+            "name": "underlayvpn",
+            "version": "2.0",
+            "toscaModelURL": "/sdc/v1/catalog/resources/c94490a0-f7ef-48be-b3f8-8d8662a37236/toscaModel",
+            "category": "Volte",
+            "subCategory": "VolteVNF",
+            "resourceType": "VF",
+            "lifecycleState": "CERTIFIED",
+            "distributionStatus": "DISTRIBUTION_APPROVED",
+            "lastUpdaterUserId": "jh0003"
+        }
+        mock_download_artifacts.side_effect = CatalogException("Failed to download 1 from sdc.")
+        csar_id = 1
+        try:
+            ServicePackage().on_distribute(csar_id)
+        except Exception as e:
+            self.assertTrue(isinstance(e, CatalogException))
+            self.assertEqual("Failed to download 1 from sdc.", e.message)
+
     def test_api_service_pkg_distribute_when_pkg_exists(self):
         ServicePackageModel(servicePackageId="1", servicedId="2").save()
         resp = self.client.post(
-            "/api/parser/v1/service_packages", {"csarId": "1"}, format='json')
+            PARSER_BASE_URL + "/service_packages", {"csarId": "1"}, format='json')
         self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertEqual("Service CSAR(1) already exists.", resp.data["errorMessage"])
 
     ###############################################################
+
     def test_service_pkg_get_all(self):
         ServicePackageModel(
             servicePackageId="13",
@@ -81,7 +122,7 @@ class TestServicePackage(TestCase):
             servicedVersion="3",
             servicePackageUri="14.csar",
             servicedModel="").save()
-        resp = self.client.get("/api/parser/v1/service_packages")
+        resp = self.client.get(PARSER_BASE_URL + "/service_packages")
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
 
     ###############################################################
@@ -111,11 +152,11 @@ class TestServicePackage(TestCase):
             servicedVersion="4",
             servicePackageUri="14.csar",
             servicedModel="").save()
-        resp = self.client.get("/api/parser/v1/service_packages/14")
+        resp = self.client.get(PARSER_BASE_URL + "/service_packages/14")
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
 
     def test_api_service_pkg_get_one_not_found(self):
-        resp = self.client.get("/api/parser/v1/service_packages/22")
+        resp = self.client.get(PARSER_BASE_URL + "/service_packages/22")
         self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
         self.assertEqual(
             {"errorMessage": "Service package[22] not Found.", 'error': 404},
@@ -139,5 +180,33 @@ class TestServicePackage(TestCase):
 
     def test_api_service_pkg_normal_delete(self):
         ServicePackageModel(servicePackageId="8", servicedId="2").save()
-        resp = self.client.delete("/api/parser/v1/service_packages/8")
+        resp = self.client.delete(PARSER_BASE_URL + "/service_packages/8")
         self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
+
+    ###############################################################
+
+    @mock.patch.object(toscaparser, 'parse_nsd')
+    def test_service_pkg_parser(self, mock_parse_nsd):
+        ServicePackageModel(servicePackageId="8", servicedId="2").save()
+        mock_parse_nsd.return_value = json.JSONEncoder().encode({"a": "b"})
+
+        inputs = []
+        ret = ServicePackage().parse_serviced(8, inputs)
+        self.assertTrue({"model": '{"c": "d"}'}, ret)
+
+    def test_service_pkg_parser_not_found(self):
+        try:
+            csar_id = 8000
+            inputs = []
+            ServicePackage().parse_serviced(csar_id, inputs)
+        except PackageNotFoundException as e:
+            self.assertEqual("Service CSAR(8000) does not exist.", e.message)
+
+    def test_api_service_pkg_parser_not_found(self):
+        query_data = {
+            "csarId": "1",
+            "packageType": "Service",
+            "inputs": "string"
+        }
+        resp = self.client.post(PARSER_BASE_URL + "/parser", query_data, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
index 3a3426e..16301d3 100755 (executable)
@@ -31,6 +31,10 @@ urlpatterns = [
     url(r'^api/parser/v1/service_packages/(?P<csarId>[0-9a-zA-Z\-\_]+)$', catalog_views.service_rd_csar, name='servicepackage_rd'),
 
     # NFV Model Parser
+    url(r'^api/parser/v1/parser$', catalog_views.model_parser, name='modelparser_rc'),
+    url(r'^api/parser/v1/parsernsd$', catalog_views.ns_model_parser, name='nsmodelparser_rc'),
+    url(r'^api/parser/v1/parservnfd$', catalog_views.vnf_model_parser, name='vnfmodelparser_rc'),
+    url(r'^api/parser/v1/parserpnfd$', pnf_descriptor_views.pnf_model_parser, name='pnfmodelparser_rc'),
     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'),
index 5496c6e..f9cc480 100644 (file)
@@ -21,6 +21,7 @@ from rest_framework import status
 from rest_framework.decorators import api_view
 from rest_framework.response import Response
 from catalog.packages.biz import sdc_vnf_package, sdc_ns_package
+from catalog.packages.biz.pnf_descriptor import PnfDescriptor
 from catalog.packages.biz.sdc_service_package import ServicePackage
 from catalog.packages.serializers.catalog_serializers import InternalErrorRequestSerializer, \
     ServicePackageDistributeRequestSerializer, ServicePackagesSerializer, ServicePackageSerializer
@@ -389,6 +390,66 @@ def nf_rd_csar(request, *args, **kwargs):
     return Response(data=response_serializer.data, status=normal_status)
 
 
+@swagger_auto_schema(
+    method='POST',
+    operation_description="Parse model(NS, Service, VNF, PNF)",
+    request_body=ParseModelRequestSerializer,
+    responses={
+        status.HTTP_202_ACCEPTED: ParseModelResponseSerializer,
+        status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@api_view(http_method_names=['POST'])
+def model_parser(request, *args, **kwargs):
+    csar_id = ignore_case_get(request.data, "csarId")
+    package_type = ignore_case_get(request.data, "packageType")
+    inputs = ignore_case_get(request.data, "inputs")
+    logger.debug(
+        "Enter %s, csar_id=%s, package_type=%s, inputs=%s",
+        fun_name(),
+        csar_id,
+        package_type,
+        inputs)
+
+    if package_type.lower().__eq__("service"):
+        try:
+            ret = ServicePackage().parse_serviced(csar_id, inputs)
+            response_serializer = ParseModelResponseSerializer(data=ret)
+            validation_error = handleValidatonError(
+                response_serializer, False)
+            if validation_error:
+                return validation_error
+            return Response(data=response_serializer.data, status=status.HTTP_202_ACCEPTED)
+        except PackageNotFoundException as e:
+            error_status = status.HTTP_404_NOT_FOUND
+            return Response(data=fmt_error_rsp(e.message, error_status), status=error_status)
+        except Exception as e:
+            error_status = status.HTTP_500_INTERNAL_SERVER_ERROR
+            return Response(data=fmt_error_rsp(e.message, error_status), status=error_status)
+    elif package_type.lower().__eq__("ns"):
+        ret = sdc_ns_package.parse_nsd(csar_id, inputs)
+    elif package_type.lower().__eq__("vnf"):
+        ret = sdc_vnf_package.parse_vnfd(csar_id, inputs)
+    elif package_type.lower().__eq__("pnf"):
+        ret = PnfDescriptor().parse_pnfd(csar_id, inputs)
+    else:
+        error_status = status.HTTP_400_BAD_REQUEST
+        error_message = "Invalid package type, it should be one of [VNF, PNF, NS, Service]"
+        return Response(data=fmt_error_rsp(error_message, error_status), status=error_status)
+
+    if ret[0] != 0:
+        return Response(
+            data={
+                'error': ret[1]},
+            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+    response_serializer = ParseModelResponseSerializer(data=ret[1])
+    validation_error = handleValidatonError(
+        response_serializer, False)
+    if validation_error:
+        return validation_error
+
+    return Response(data=response_serializer.data, status=status.HTTP_202_ACCEPTED)
+
+
 @swagger_auto_schema(
     method='POST',
     operation_description="Parse NS model",