diff options
author | dyh <dengyuanhong@chinamobile.com> | 2019-03-28 10:02:38 +0800 |
---|---|---|
committer | dyh <dengyuanhong@chinamobile.com> | 2019-03-28 10:02:50 +0800 |
commit | 9737bb0c33deae190beff671fb35132ab4934b12 (patch) | |
tree | d1030a5cd3965a088aace648fd88b34365a96059 | |
parent | 50baae0e33075cd8751c0a15afa9342beec9ac85 (diff) |
1.Implement parser RESTAPI. 2.Add UT cases.
Change-Id: I33cd9dc53a00d955d7be3e1cff510aa9dfa263a7
Issue-ID: VFC-1318
Signed-off-by: dyh <dengyuanhong@chinamobile.com>
-rw-r--r-- | catalog/packages/biz/sdc_service_package.py | 12 | ||||
-rw-r--r-- | catalog/packages/biz/sdc_vnf_package.py | 2 | ||||
-rw-r--r-- | catalog/packages/biz/service_descriptor.py | 9 | ||||
-rw-r--r-- | catalog/packages/serializers/catalog_serializers.py | 1 | ||||
-rw-r--r-- | catalog/packages/tests/test_service_descriptor.py | 90 | ||||
-rw-r--r-- | catalog/packages/tests/test_servicepackage.py | 81 | ||||
-rwxr-xr-x | catalog/packages/urls.py | 4 | ||||
-rw-r--r-- | catalog/packages/views/catalog_views.py | 61 |
8 files changed, 243 insertions, 17 deletions
diff --git a/catalog/packages/biz/sdc_service_package.py b/catalog/packages/biz/sdc_service_package.py index bae1f71d..713ab056 100644 --- a/catalog/packages/biz/sdc_service_package.py +++ b/catalog/packages/biz/sdc_service_package.py @@ -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) diff --git a/catalog/packages/biz/sdc_vnf_package.py b/catalog/packages/biz/sdc_vnf_package.py index 71eee499..d1ee4c7d 100644 --- a/catalog/packages/biz/sdc_vnf_package.py +++ b/catalog/packages/biz/sdc_vnf_package.py @@ -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__) diff --git a/catalog/packages/biz/service_descriptor.py b/catalog/packages/biz/service_descriptor.py index 72a561ae..4b9a2aad 100644 --- a/catalog/packages/biz/service_descriptor.py +++ b/catalog/packages/biz/service_descriptor.py @@ -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) diff --git a/catalog/packages/serializers/catalog_serializers.py b/catalog/packages/serializers/catalog_serializers.py index 0e830e5e..4007c34a 100644 --- a/catalog/packages/serializers/catalog_serializers.py +++ b/catalog/packages/serializers/catalog_serializers.py @@ -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 index 00000000..d0dc83fd --- /dev/null +++ b/catalog/packages/tests/test_service_descriptor.py @@ -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) diff --git a/catalog/packages/tests/test_servicepackage.py b/catalog/packages/tests/test_servicepackage.py index 86d513e0..9365c295 100644 --- a/catalog/packages/tests/test_servicepackage.py +++ b/catalog/packages/tests/test_servicepackage.py @@ -11,13 +11,19 @@ # 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) diff --git a/catalog/packages/urls.py b/catalog/packages/urls.py index 3a3426e5..16301d30 100755 --- a/catalog/packages/urls.py +++ b/catalog/packages/urls.py @@ -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'), diff --git a/catalog/packages/views/catalog_views.py b/catalog/packages/views/catalog_views.py index 5496c6e0..f9cc4803 100644 --- a/catalog/packages/views/catalog_views.py +++ b/catalog/packages/views/catalog_views.py @@ -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 @@ -391,6 +392,66 @@ def nf_rd_csar(request, *args, **kwargs): @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", request_body=ParseModelRequestSerializer, responses={ |