Implement Service package management RESTAPIs 79/82879/3
authordyh <dengyuanhong@chinamobile.com>
Thu, 21 Mar 2019 03:39:41 +0000 (11:39 +0800)
committerdeng yuanhong <dengyuanhong@chinamobile.com>
Fri, 22 Mar 2019 06:21:47 +0000 (06:21 +0000)
Change-Id: Iee7a3c94cb6091baddf7a44ef92b70e64f8045dd
Issue-ID: VFC-1308
Signed-off-by: dyh <dengyuanhong@chinamobile.com>
catalog/packages/biz/sdc_service_package.py [new file with mode: 0644]
catalog/packages/biz/service_descriptor.py [new file with mode: 0644]
catalog/packages/serializers/catalog_serializers.py
catalog/packages/tests/test_servicepackage.py [new file with mode: 0644]
catalog/packages/urls.py
catalog/packages/views/catalog_views.py
catalog/packages/views/common.py
catalog/pub/database/models.py
catalog/pub/exceptions.py

diff --git a/catalog/packages/biz/sdc_service_package.py b/catalog/packages/biz/sdc_service_package.py
new file mode 100644 (file)
index 0000000..bae1f71
--- /dev/null
@@ -0,0 +1,116 @@
+# 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
+import traceback
+
+from coverage.xmlreport import os
+
+from catalog.packages.biz.service_descriptor import ServiceDescriptor
+from catalog.pub.config.config import CATALOG_ROOT_PATH, REG_TO_MSB_REG_PARAM, CATALOG_URL_PATH
+from catalog.pub.database.models import ServicePackageModel
+from catalog.pub.exceptions import CatalogException, PackageNotFoundException, \
+    PackageHasExistsException
+from catalog.pub.msapi import sdc
+from catalog.pub.utils import fileutil, toscaparser
+
+logger = logging.getLogger(__name__)
+
+
+class ServicePackage(object):
+    """
+    Actions for sdc service package.
+    """
+
+    def __init__(self):
+        pass
+
+    def on_distribute(self, csar_id):
+        if ServicePackageModel.objects.filter(servicePackageId=csar_id):
+            raise PackageHasExistsException("Service CSAR(%s) already exists." % csar_id)
+
+        try:
+            artifact = sdc.get_artifact(sdc.ASSETTYPE_SERVICES, csar_id)
+            local_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
+            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
+
+            data = {
+                'userDefinedData': {}
+            }
+            serviced = ServiceDescriptor()
+            serviced.create(data, csar_id)
+            serviced.parse_serviced_and_save(csar_id, local_file_name)
+
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            if ServicePackageModel.objects.filter(servicePackageId=csar_id):
+                ServicePackage().delete_csar(csar_id)
+            raise e
+
+    def delete_csar(self, csar_id):
+        serviced = ServiceDescriptor()
+        serviced.delete_single(csar_id)
+
+    def get_csars(self):
+        csars = []
+        packages = ServicePackageModel.objects.filter()
+        for package in packages:
+            csar = self.get_csar(package.servicePackageId)
+            csars.append(csar)
+        return csars
+
+    def get_csar(self, csar_id):
+        package_info = {}
+        csars = ServicePackageModel.objects.filter(servicePackageId=csar_id)
+        if csars:
+            package_info["servicedId"] = csars[0].servicedId
+            package_info["servicePackageId"] = csars[0].servicePackageId
+            package_info["servicedProvider"] = csars[0].servicedDesigner
+            package_info["servicedVersion"] = csars[0].servicedVersion
+            package_info["csarName"] = csars[0].servicePackageUri
+            package_info["servicedModel"] = csars[0].servicedModel
+            package_info["servicedInvariantId"] = csars[0].invariantId
+            package_info["downloadUrl"] = "http://%s:%s/%s/%s/%s" % (
+                REG_TO_MSB_REG_PARAM[0]["nodes"][0]["ip"],
+                REG_TO_MSB_REG_PARAM[0]["nodes"][0]["port"],
+                CATALOG_URL_PATH,
+                csar_id,
+                csars[0].servicePackageUri)
+        else:
+            raise PackageNotFoundException("Service package[%s] not Found." % csar_id)
+
+        return {"csarId": csar_id, "packageInfo": package_info}
+
+    def parse_serviced(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)
+
+        try:
+            csar_path = service_pkg[0].localFilePath
+            ret = {"model": toscaparser.parse_nsd(csar_path, inputs)}
+            return ret
+        except CatalogException as e:
+            logger.error(e.message)
+            raise e
+        except Exception as e:
+            logger.error(e.message)
+            logger.error(traceback.format_exc())
+            raise e
diff --git a/catalog/packages/biz/service_descriptor.py b/catalog/packages/biz/service_descriptor.py
new file mode 100644 (file)
index 0000000..72a561a
--- /dev/null
@@ -0,0 +1,127 @@
+# 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 json
+import logging
+import os
+import uuid
+
+from catalog.packages.const import PKG_STATUS
+from catalog.pub.config.config import CATALOG_ROOT_PATH
+from catalog.pub.database.models import ServicePackageModel
+from catalog.pub.exceptions import CatalogException, PackageNotFoundException
+from catalog.pub.utils import toscaparser, fileutil
+from catalog.pub.utils.values import ignore_case_get
+
+logger = logging.getLogger(__name__)
+
+
+class ServiceDescriptor(object):
+
+    def __init__(self):
+        pass
+
+    def create(self, data, csar_id):
+        logger.info('Start to create a ServiceD...')
+        user_defined_data = ignore_case_get(data, 'userDefinedData', {})
+        data = {
+            'id': id if id else str(uuid.uuid4()),
+            'servicedOnboardingState': PKG_STATUS.CREATED,
+            'servicedOperationalState': PKG_STATUS.DISABLED,
+            'servicedUsageState': PKG_STATUS.NOT_IN_USE,
+            'userDefinedData': user_defined_data,
+            '_links': None  # TODO
+        }
+        ServicePackageModel.objects.create(
+            servicePackageId=data['id'],
+            onboardingState=data['servicedOnboardingState'],
+            operationalState=data['servicedOperationalState'],
+            usageState=data['servicedUsageState'],
+            userDefinedData=json.dumps(user_defined_data)
+        )
+        logger.info('A ServiceD(%s) has been created.' % data['id'])
+        return data
+
+    def parse_serviced_and_save(self, serviced_info_id, local_file_name):
+        logger.info('Start to process ServiceD(%s)...' % serviced_info_id)
+        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
+        logger.debug("%s", serviced_json)
+        serviced = json.JSONDecoder().decode(serviced_json)
+
+        serviced_id = serviced.get("ns", {}).get("properties", {}).get("descriptor_id", "")
+        serviced_name = serviced.get("ns", {}).get("properties", {}).get("name", "")
+        serviced_version = serviced.get("ns", {}).get("properties", {}).get("version", "")
+        serviced_designer = serviced.get("ns", {}).get("properties", {}).get("designer", "")
+        invariant_id = serviced.get("ns", {}).get("properties", {}).get("invariant_id", "")
+        if serviced_id == "":
+            raise CatalogException("serviced_id(%s) does not exist in metadata." % serviced_id)
+        other_nspkg = ServicePackageModel.objects.filter(nsdId=serviced_id)
+        if other_nspkg and other_nspkg[0].servicePackageId != serviced_info_id:
+            logger.warn("ServiceD(%s,%s) already exists.", serviced_id, other_nspkg[0].servicePackageId)
+            raise CatalogException("ServiceD(%s) already exists." % serviced_id)
+
+        for vnf in serviced["vnfs"]:
+            vnfd_id = vnf["properties"].get("descriptor_id", "undefined")
+            if vnfd_id == "undefined":
+                vnfd_id = vnf["properties"].get("id", "undefined")
+            pkg = ServicePackageModel.objects.filter(vnfdId=vnfd_id)
+            if not pkg:
+                pkg = ServicePackageModel.objects.filter(vnfPackageId=vnfd_id)
+            if not pkg:
+                vnfd_name = vnf.get("vnf_id", "undefined")
+                logger.error("[%s] is not distributed.", vnfd_name)
+                raise CatalogException("VNF package(%s) is not distributed." % vnfd_id)
+
+        for pnf in serviced["pnfs"]:
+            pnfd_id = pnf["properties"].get("descriptor_id", "undefined")
+            if pnfd_id == "undefined":
+                pnfd_id = pnf["properties"].get("id", "undefined")
+            pkg = ServicePackageModel.objects.filter(pnfdId=pnfd_id)
+            if not pkg:
+                pkg = ServicePackageModel.objects.filter(pnfPackageId=pnfd_id)
+            if not pkg:
+                pnfd_name = pnf.get("pnf_id", "undefined")
+                logger.error("[%s] is not distributed.", pnfd_name)
+                raise CatalogException("PNF package(%s) is not distributed." % pnfd_name)
+
+        service_pkgs.update(
+            servicedId=serviced_id,
+            servicedName=serviced_name,
+            servicedDesginer=serviced_designer,
+            servicedDescription=serviced.get("description", ""),
+            servicedVersion=serviced_version,
+            invariantId=invariant_id,
+            onboardingState=PKG_STATUS.ONBOARDED,
+            operationalState=PKG_STATUS.ENABLED,
+            usageState=PKG_STATUS.NOT_IN_USE,
+            servicePackageUri=local_file_name,
+            sdcCsarId=serviced_info_id,
+            localFilePath=local_file_name,
+            servicedModel=serviced_json
+        )
+        logger.info('ServiceD(%s) has been processed.' % serviced_info_id)
+
+    def delete_single(self, serviced_info_id):
+        logger.info('Start to delete ServiceD(%s)...' % serviced_info_id)
+        service_pkgs = ServicePackageModel.objects.filter(servicePackageId=serviced_info_id)
+        if not service_pkgs.exists():
+            logger.warn('ServiceD(%s) not found.' % serviced_info_id)
+            raise PackageNotFoundException("Service package[%s] not Found." % serviced_info_id)
+        service_pkgs.delete()
+        service_pkg_path = os.path.join(CATALOG_ROOT_PATH, serviced_info_id)
+        fileutil.delete_dirs(service_pkg_path)
+        logger.info('ServiceD(%s) has been deleted.' % serviced_info_id)
index 90006c9..0e830e5 100644 (file)
@@ -132,6 +132,70 @@ class NsPackagesSerializer(serializers.ListSerializer):
     child = NsPackageSerializer()
 
 
+class ServicePackageDistributeRequestSerializer(serializers.Serializer):
+    csarId = serializers.CharField(help_text="csarId", required=True)
+
+
+class ServicePackageInfoSerializer(serializers.Serializer):
+    servicedId = serializers.CharField(
+        help_text="ServiceD ID",
+        required=False,
+        allow_null=True
+    )
+    servicePackageId = serializers.CharField(
+        help_text="Service Package ID",
+        allow_blank=True,
+        required=False,
+        allow_null=True
+    )
+    servicedProvider = serializers.CharField(
+        help_text="ServiceD Provider",
+        allow_blank=True,
+        required=False,
+        allow_null=True
+    )
+    servicedVersion = serializers.CharField(
+        help_text="ServiceD Version",
+        allow_blank=True,
+        required=False,
+        allow_null=True
+    )
+    csarName = serializers.CharField(
+        help_text="CSAR name",
+        allow_blank=True,
+        required=False,
+        allow_null=True
+    )
+    servicedModel = serializers.CharField(
+        help_text="ServiceD Model",
+        allow_blank=True,
+        required=False,
+        allow_null=True
+    )
+    downloadUrl = serializers.CharField(
+        help_text="URL to download ServiceD Model",
+        required=False,
+        allow_null=True
+    )
+
+
+class ServicePackageSerializer(serializers.Serializer):
+    csarId = serializers.CharField(
+        help_text="CSAR ID",
+        required=False,
+        allow_null=True
+    )
+    packageInfo = ServicePackageInfoSerializer(
+        help_text="Service Package Info",
+        required=False,
+        allow_null=True
+    )
+
+
+class ServicePackagesSerializer(serializers.ListSerializer):
+    child = ServicePackageSerializer()
+
+
 class NfPackageDistributeRequestSerializer(serializers.Serializer):
     csarId = serializers.CharField(help_text="CSAR ID", required=True)
     vimIds = serializers.ListField(
diff --git a/catalog/packages/tests/test_servicepackage.py b/catalog/packages/tests/test_servicepackage.py
new file mode 100644 (file)
index 0000000..86d513e
--- /dev/null
@@ -0,0 +1,143 @@
+# 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.
+
+from django.test import TestCase, Client
+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
+
+
+class TestServicePackage(TestCase):
+    """ Test case for Service Package operations"""
+
+    def setUp(self):
+        self.client = Client()
+        ServicePackageModel.objects.filter().delete()
+
+    def tearDown(self):
+        pass
+
+    ###############################################################
+
+    def test_service_pkg_distribute_when_pkg_exists(self):
+        ServicePackageModel(servicePackageId="1", servicedId="2").save()
+        csar_id = 1
+        try:
+            ServicePackage().on_distribute(csar_id)
+        except PackageHasExistsException as e:
+            self.assertEqual("Service CSAR(1) already exists.", 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')
+        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",
+            servicedId="2",
+            servicedDesigner="2",
+            servicedVersion="2",
+            servicePackageUri="13.csar",
+            servicedModel="").save()
+        ServicePackageModel(
+            servicePackageId="14",
+            servicedId="3",
+            servicedDesigner="3",
+            servicedVersion="3",
+            servicePackageUri="14.csar",
+            servicedModel="").save()
+        csars = ServicePackage().get_csars()
+        self.assertEqual(2, len(csars))
+
+    def test_api_service_pkg_get_all(self):
+        ServicePackageModel(
+            servicePackageId="13",
+            servicedId="2",
+            servicedDesigner="2",
+            servicedVersion="2",
+            servicePackageUri="13.csar",
+            servicedModel="").save()
+        ServicePackageModel(
+            servicePackageId="14",
+            servicedId="3",
+            servicedDesigner="3",
+            servicedVersion="3",
+            servicePackageUri="14.csar",
+            servicedModel="").save()
+        resp = self.client.get("/api/parser/v1/service_packages")
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+
+    ###############################################################
+
+    def test_service_pkg_get_one(self):
+        ServicePackageModel(
+            servicePackageId="14",
+            servicedId="2",
+            servicedDesigner="3",
+            servicedVersion="4",
+            servicePackageUri="14.csar",
+            servicedModel="").save()
+        csar = ServicePackage().get_csar(14)
+        self.assertEqual(14, csar['csarId'])
+
+    def test_service_pkg_get_one_not_found(self):
+        try:
+            ServicePackage().get_csar(1000)
+        except PackageNotFoundException as e:
+            self.assertEqual("Service package[1000] not Found.", e.message)
+
+    def test_api_service_pkg_get_one(self):
+        ServicePackageModel(
+            servicePackageId="14",
+            servicedId="2",
+            servicedDesigner="3",
+            servicedVersion="4",
+            servicePackageUri="14.csar",
+            servicedModel="").save()
+        resp = self.client.get("/api/parser/v1/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")
+        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
+        self.assertEqual(
+            {"errorMessage": "Service package[22] not Found.", 'error': 404},
+            resp.data)
+
+    ###############################################################
+
+    def test_service_pkg_normal_delete(self):
+        ServicePackageModel(servicePackageId="8", servicedId="2").save()
+        sp = ServicePackageModel.objects.filter(servicePackageId=8)
+        self.assertEqual(1, len(sp))
+        ServicePackage().delete_csar("8")
+        sp = ServicePackageModel.objects.filter(servicePackageId=8)
+        self.assertEqual(0, len(sp))
+
+    def test_service_pkg_normal_delete_not_found(self):
+        try:
+            ServicePackage().delete_csar("8000")
+        except PackageNotFoundException as e:
+            self.assertEqual("Service package[8000] not Found.", e.message)
+
+    def test_api_service_pkg_normal_delete(self):
+        ServicePackageModel(servicePackageId="8", servicedId="2").save()
+        resp = self.client.delete("/api/parser/v1/service_packages/8")
+        self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
index dfd1326..3a3426e 100755 (executable)
@@ -27,6 +27,8 @@ urlpatterns = [
     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'),
+    url(r'^api/parser/v1/service_packages$', catalog_views.servicepackages_rc, name='servicepackages_rc'),
+    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/catalog/v1/parsernsd$', catalog_views.ns_model_parser, name='nsmodelparser_rc'),
index fd7f5d4..5496c6e 100644 (file)
@@ -21,7 +21,9 @@ 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.serializers.catalog_serializers import InternalErrorRequestSerializer
+from catalog.packages.biz.sdc_service_package import ServicePackage
+from catalog.packages.serializers.catalog_serializers import InternalErrorRequestSerializer, \
+    ServicePackageDistributeRequestSerializer, ServicePackagesSerializer, ServicePackageSerializer
 from catalog.packages.serializers.catalog_serializers import NfPackageDistributeRequestSerializer
 from catalog.packages.serializers.catalog_serializers import NfPackageSerializer
 from catalog.packages.serializers.catalog_serializers import NfPackagesSerializer
@@ -32,6 +34,8 @@ from catalog.packages.serializers.catalog_serializers import NsPackagesSerialize
 from catalog.packages.serializers.catalog_serializers import ParseModelRequestSerializer
 from catalog.packages.serializers.catalog_serializers import ParseModelResponseSerializer
 from catalog.packages.serializers.catalog_serializers import PostJobResponseSerializer
+from catalog.packages.views.common import fmt_error_rsp
+from catalog.pub.exceptions import PackageNotFoundException, PackageHasExistsException
 from catalog.pub.utils.syscomm import fun_name
 from catalog.pub.utils.values import ignore_case_get
 
@@ -208,6 +212,117 @@ def ns_rd_csar(request, *args, **kwargs):
     return Response(data=ret[1], status=normal_status)
 
 
+@swagger_auto_schema(
+    method='POST',
+    operation_description="On distribute Service package",
+    request_body=ServicePackageDistributeRequestSerializer,
+    responses={
+        status.HTTP_202_ACCEPTED: "",
+        status.HTTP_400_BAD_REQUEST: InternalErrorRequestSerializer,
+        status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@swagger_auto_schema(
+    method='GET',
+    operation_description="Query Service packages",
+    request_body=no_body,
+    responses={
+        status.HTTP_200_OK: ServicePackagesSerializer,
+        status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@api_view(http_method_names=['POST', 'GET'])
+def servicepackages_rc(request, *args, **kwargs):
+    logger.debug("Enter %s, method is %s", fun_name(), request.method)
+
+    if request.method == 'GET':
+        # Gets service package list
+        try:
+            csar_list = ServicePackage().get_csars()
+            response_serializer = ServicePackagesSerializer(data=csar_list)
+            validation_error = handleValidatonError(response_serializer, False)
+            if validation_error:
+                return validation_error
+            return Response(data=csar_list, status=status.HTTP_200_OK)
+        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 request.method == 'POST':
+        # Distributes the package according to the given csarId
+        request_serializer = ServicePackageDistributeRequestSerializer(data=request.data)
+        validation_error = handleValidatonError(request_serializer, True)
+        if validation_error:
+            return validation_error
+
+        csar_id = ignore_case_get(request.data, "csarId")
+        logger.debug("csar_id is %s", csar_id)
+        try:
+            ServicePackage().on_distribute(csar_id)
+            return Response(status=status.HTTP_202_ACCEPTED)
+        except PackageHasExistsException as e:
+            error_status = status.HTTP_400_BAD_REQUEST
+            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)
+
+
+@swagger_auto_schema(
+    method='DELETE',
+    operation_description="Delete one Service package",
+    request_body=no_body,
+    manual_parameters=[
+        openapi.Parameter(
+            'csarId',
+            openapi.IN_QUERY,
+            "csarId",
+            type=openapi.TYPE_STRING)],
+    responses={
+        status.HTTP_204_NO_CONTENT: "",
+        status.HTTP_404_NOT_FOUND: InternalErrorRequestSerializer,
+        status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@swagger_auto_schema(
+    method='GET',
+    operation_description="Query one Service package",
+    request_body=no_body,
+    manual_parameters=[
+        openapi.Parameter(
+            'csarId',
+            openapi.IN_QUERY,
+            "csarId",
+            type=openapi.TYPE_STRING)],
+    responses={
+        status.HTTP_200_OK: ServicePackageSerializer,
+        status.HTTP_404_NOT_FOUND: InternalErrorRequestSerializer,
+        status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@api_view(http_method_names=['DELETE', 'GET'])
+def service_rd_csar(request, *args, **kwargs):
+    csar_id = ignore_case_get(kwargs, "csarId")
+    logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
+
+    if request.method == 'GET':
+        try:
+            ret = ServicePackage().get_csar(csar_id)
+            response_serializer = ServicePackageSerializer(data=ret)
+            validation_error = handleValidatonError(response_serializer, False)
+            if validation_error:
+                return validation_error
+            return Response(data=ret, status=status.HTTP_200_OK)
+        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 request.method == 'DELETE':
+        try:
+            ServicePackage().delete_csar(csar_id)
+            return Response(status=status.HTTP_204_NO_CONTENT)
+        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)
+
+
 @swagger_auto_schema(
     method='DELETE',
     operation_description="Delete one Nf package",
index 5dacb77..94566eb 100644 (file)
@@ -25,3 +25,7 @@ def validate_data(data, serializer):
         logger.error('Data validation failed.')
         raise CatalogException(serialized_data.errors)
     return serialized_data
+
+
+def fmt_error_rsp(error_message, status):
+    return {"errorMessage": error_message, "error": status}
index ef95dea..9f0b498 100644 (file)
@@ -38,6 +38,29 @@ class NSPackageModel(models.Model):
         db_table = 'CATALOG_NSPACKAGE'
 
 
+class ServicePackageModel(models.Model):
+    servicePackageId = models.CharField(db_column='SERVICEPACKAGEID', primary_key=True, max_length=50)
+    servicePackageUri = models.CharField(db_column='SERVICEPACKAGEURI', max_length=300, null=True, blank=True)
+    checksum = models.CharField(db_column='CHECKSUM', max_length=50, null=True, blank=True)  # checksum
+    sdcCsarId = models.CharField(db_column='SDCCSARID', max_length=50, null=True, blank=True)  # SdcCSARUri
+    onboardingState = models.CharField(db_column='ONBOARDINGSTATE', max_length=20, blank=True, null=True)
+    operationalState = models.CharField(db_column='OPERATIONALSTATE', max_length=20, blank=True, null=True)  # operationalState
+    usageState = models.CharField(db_column='USAGESTATE', max_length=20, blank=True, null=True)  # usageState
+    deletionPending = models.CharField(db_column='DELETIONPENDING', max_length=20, blank=True, null=True)  # deletionPending
+    servicedId = models.CharField(db_column='SERVICEDID', max_length=50, blank=True, null=True)
+    invariantId = models.CharField(db_column='INVARIANTID', max_length=50, blank=True, null=True)  # servicedInvariantId
+    servicedName = models.CharField(db_column='SERVICEDNAME', max_length=50, blank=True, null=True)
+    servicedDesigner = models.CharField(db_column='SERVICEDDESIGNER', max_length=50, null=True, blank=True)
+    servicedDescription = models.CharField(db_column='SERVICEDDESCRIPTION', max_length=100, null=True, blank=True)
+    servicedVersion = models.CharField(db_column='SERVICEDVERSION', max_length=20, null=True, blank=True)
+    userDefinedData = models.TextField(db_column='USERDEFINEDDATA', max_length=1024, blank=True, null=True)  # userDefinedData
+    localFilePath = models.CharField(db_column='LOCALFILEPATH', max_length=300, null=True, blank=True)
+    servicedModel = models.TextField(db_column='SERVICEDMODEL', max_length=65535, null=True, blank=True)
+
+    class Meta:
+        db_table = 'CATALOG_SERVICEPACKAGE'
+
+
 class VnfPackageModel(models.Model):
     # uuid = models.CharField(db_column='UUID', primary_key=True, max_length=255)
     vnfPackageId = models.CharField(db_column='VNFPACKAGEID', primary_key=True, max_length=50)   # onboardedVnfPkgInfoId
index afe45d1..a935420 100644 (file)
@@ -21,6 +21,14 @@ class ResourceNotFoundException(CatalogException):
     pass
 
 
+class PackageNotFoundException(CatalogException):
+    pass
+
+
+class PackageHasExistsException(CatalogException):
+    pass
+
+
 class VnfPkgSubscriptionException(CatalogException):
     pass