Add code related to sdc 69/8869/1
authorfengyuanxing <feng.yuanxing@zte.com.cn>
Sat, 26 Aug 2017 12:11:31 +0000 (20:11 +0800)
committerfengyuanxing <feng.yuanxing@zte.com.cn>
Sat, 26 Aug 2017 12:11:31 +0000 (20:11 +0800)
Change-Id: If4ddb9c10e654b04b033b63005f99ddf1adc599b
Issue-Id: VFC-152
Signed-off-by: fengyuanxing <feng.yuanxing@zte.com.cn>
catalog/packages/sdc_nf_package.py [new file with mode: 0644]
catalog/packages/sdc_ns_package.py [new file with mode: 0644]
catalog/packages/tests.py
catalog/packages/views.py
requirements.txt

diff --git a/catalog/packages/sdc_nf_package.py b/catalog/packages/sdc_nf_package.py
new file mode 100644 (file)
index 0000000..f95baf5
--- /dev/null
@@ -0,0 +1,228 @@
+# Copyright 2017 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 json
+import logging
+import uuid
+import os
+import time
+import threading
+import traceback
+import sys
+
+from catalog.pub.database.models import NfPackageModel, NfInstModel
+from catalog.pub.utils.values import ignore_case_get
+from catalog.pub.utils import fileutil
+from catalog.pub.exceptions import NSLCMException
+from catalog.pub.config.config import CATALOG_ROOT_PATH
+from catalog.pub.msapi.extsys import get_vims
+from catalog.pub.utils.jobutil import JobUtil
+from catalog.pub.utils import toscaparser
+from catalog.pub.msapi import sdc
+
+logger = logging.getLogger(__name__)
+
+JOB_ERROR = 255
+
+def nf_get_csars():
+    ret = None
+    try:
+        ret = SdcNfPackage().get_csars()
+    except NSLCMException as e:
+        return [1, e.message]
+    except:
+        logger.error(traceback.format_exc())
+        return [1, str(sys.exc_info())]
+    return ret
+
+def nf_get_csar(csar_id):
+    ret = None
+    try:
+        ret = SdcNfPackage().get_csar(csar_id)
+    except NSLCMException as e:
+        return [1, e.message]
+    except:
+        logger.error(traceback.format_exc())
+        return [1, str(sys.exc_info())]
+    return ret
+
+#####################################################################################
+
+class SdcNfDistributeThread(threading.Thread):
+    """
+    Sdc NF Package Distribute
+    """
+
+    def __init__(self, csar_id, vim_ids, lab_vim_id, job_id):
+        threading.Thread.__init__(self)
+        self.csar_id = csar_id
+        self.vim_ids = vim_ids
+        self.lab_vim_id = lab_vim_id
+        self.job_id = job_id
+
+        self.csar_save_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
+
+    def run(self):
+        try:
+            self.on_distribute()
+        except NSLCMException as e:
+            self.rollback_distribute()
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+            self.rollback_distribute()
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to distribute CSAR(%s)" % self.csar_id)
+
+    def on_distribute(self):
+        JobUtil.create_job(
+            inst_type='nf',
+            jobaction='on_distribute',
+            inst_id=self.csar_id,
+            job_id=self.job_id)
+        JobUtil.add_job_status(self.job_id, 5, "Start CSAR(%s) distribute." % self.csar_id)
+
+        if NfPackageModel.objects.filter(nfpackageid=self.csar_id):
+            raise NSLCMException("NF CSAR(%s) already exists." % self.csar_id)
+
+        artifact = sdc.get_artifact(sdc.ASSETTYPE_RESOURCES, self.csar_id)
+        local_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
+        local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path)
+        
+        vnfd_json = toscaparser.parse_vnfd(local_file_name)
+        vnfd = json.JSONDecoder().decode(vnfd_json)
+
+        nfd_id = vnfd["metadata"]["id"]
+        if NfPackageModel.objects.filter(vnfdid=nfd_id):
+            raise NSLCMException("NFD(%s) already exists." % nfd_id)
+
+        JobUtil.add_job_status(self.job_id, 30, "Save CSAR(%s) to database." % self.csar_id)
+
+        vnfd_ver = vnfd["metadata"].get("vnfd_version")
+        if not vnfd_ver:
+            vnfd_ver = vnfd["metadata"].get("vnfdVersion", "undefined")
+        NfPackageModel(
+            uuid=self.csar_id,
+            nfpackageid=self.csar_id,
+            vnfdid=nfd_id,
+            vendor=vnfd["metadata"].get("vendor", "undefined"),
+            vnfdversion=vnfd_ver,
+            vnfversion=vnfd["metadata"].get("version", "undefined"),
+            vnfdmodel=vnfd_json,
+            vnfd_path=local_file_name
+            ).save()
+
+        JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) distribute successfully." % self.csar_id)
+
+
+    def rollback_distribute(self):
+        try:
+            NfPackageModel.objects.filter(nfpackageid=self.csar_id).delete()
+            fileutil.delete_dirs(self.csar_save_path)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+
+
+######################################################################################################################
+
+
+class SdcNfPkgDeleteThread(threading.Thread):
+    """
+    Sdc NF Package Deleting
+    """
+
+    def __init__(self, csar_id, job_id, force_delete):
+        threading.Thread.__init__(self)
+        self.csar_id = csar_id
+        self.job_id = job_id
+        self.force_delete = force_delete
+
+    def run(self):
+        try:
+            self.delete_csar()
+        except NSLCMException as e:
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
+        except:
+            logger.error(traceback.format_exc())
+            logger.error(str(sys.exc_info()))
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to delete CSAR(%s)" % self.csar_id)
+
+    def delete_csar(self):
+        JobUtil.create_job(
+            inst_type='nf',
+            jobaction='delete',
+            inst_id=self.csar_id,
+            job_id=self.job_id)
+        JobUtil.add_job_status(self.job_id, 5, "Start to delete CSAR(%s)." % self.csar_id)
+
+        if self.force_delete:
+            NfInstModel.objects.filter(package_id=self.csar_id).delete()
+        else:
+            if NfInstModel.objects.filter(package_id=self.csar_id):
+                raise NSLCMException("NfInst by csar(%s) exists, cannot delete." % self.csar_id)
+
+        JobUtil.add_job_status(self.job_id, 50, "Delete CSAR(%s) from Database." % self.csar_id)
+
+        NfPackageModel.objects.filter(nfpackageid=self.csar_id).delete()
+
+        JobUtil.add_job_status(self.job_id, 80, "Delete local CSAR(%s) file." % self.csar_id)
+
+        csar_save_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
+        fileutil.delete_dirs(csar_save_path)
+
+        JobUtil.add_job_status(self.job_id, 100, "Delete CSAR(%s) successfully." % self.csar_id)
+
+
+######################################################################################################################
+
+class SdcNfPackage(object):
+    """
+    Actions for sdc nf package.
+    """
+
+    def __init__(self):
+        pass
+
+    def get_csars(self):
+        csars = {"csars": []}
+        nf_pkgs = NfPackageModel.objects.filter()
+        for nf_pkg in nf_pkgs:
+            csars["csars"].append({
+                "csarId": nf_pkg.nfpackageid,
+                "vnfdId": nf_pkg.vnfdid
+            })
+        return [0, csars]
+        
+    def get_csar(self, csar_id):
+        pkg_info = {}
+        nf_pkg = NfPackageModel.objects.filter(nfpackageid=csar_id)
+        if nf_pkg:
+            pkg_info["vnfdId"] = nf_pkg[0].vnfdid
+            pkg_info["vnfdProvider"] = nf_pkg[0].vendor
+            pkg_info["vnfdVersion"] = nf_pkg[0].vnfdversion
+            pkg_info["vnfVersion"] = nf_pkg[0].vnfversion
+
+
+        vnf_insts = NfInstModel.objects.filter(package_id=csar_id)
+        vnf_inst_info = [{"vnfInstanceId": vnf_inst.nfinstid,
+                          "vnfInstanceName": vnf_inst.nf_name} for vnf_inst in vnf_insts]
+
+        return [0, {"csarId": csar_id,
+                    "packageInfo": pkg_info,
+                    "imageInfo": [],
+                    "vnfInstanceInfo": vnf_inst_info}]
+
+
+        
diff --git a/catalog/packages/sdc_ns_package.py b/catalog/packages/sdc_ns_package.py
new file mode 100644 (file)
index 0000000..5c42959
--- /dev/null
@@ -0,0 +1,174 @@
+# Copyright 2017 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 json
+import logging
+
+import traceback
+import sys
+import os
+
+from catalog.pub.database.models import NSDModel, NSInstModel, NfPackageModel
+from catalog.pub.utils.values import ignore_case_get
+from catalog.pub.exceptions import NSLCMException
+from catalog.pub.msapi import sdc
+from catalog.pub.config.config import CATALOG_ROOT_PATH
+from catalog.pub.utils import toscaparser
+from catalog.pub.utils import fileutil
+
+logger = logging.getLogger(__name__)
+
+STATUS_SUCCESS, STATUS_FAILED = "success", "failed"
+
+
+def fmt_ns_pkg_rsp(status, desc, error_code="500"):
+    return [0, {"status": status, "statusDescription": desc, "errorCode": error_code}]
+
+
+def ns_on_distribute(csar_id):
+    ret = None
+    try:
+        ret = SdcNsPackage().on_distribute(csar_id)
+    except NSLCMException as e:
+        SdcNsPackage().delete_catalog(csar_id)
+        return fmt_ns_pkg_rsp(STATUS_FAILED, e.message)
+    except:
+        logger.error(traceback.format_exc())
+        SdcNsPackage().delete_catalog(csar_id)
+        return fmt_ns_pkg_rsp(STATUS_FAILED, str(sys.exc_info()))
+    return fmt_ns_pkg_rsp(STATUS_SUCCESS, ret[1], "")
+
+
+def ns_delete_csar(csar_id, force_delete):
+    ret = None
+    try:
+        ret = SdcNsPackage().delete_csar(csar_id, force_delete)
+    except NSLCMException as e:
+        return fmt_ns_pkg_rsp(STATUS_FAILED, e.message)
+    except:
+        logger.error(traceback.format_exc())
+        return fmt_ns_pkg_rsp(STATUS_FAILED, str(sys.exc_info()))
+    return fmt_ns_pkg_rsp(STATUS_SUCCESS, ret[1], "")
+
+def ns_get_csars():
+    ret = None
+    try:
+        ret = SdcNsPackage().get_csars()
+    except NSLCMException as e:
+        return [1, e.message]
+    except:
+        logger.error(traceback.format_exc())
+        return [1, str(sys.exc_info())]
+    return ret
+
+def ns_get_csar(csar_id):
+    ret = None
+    try:
+        ret = SdcNsPackage().get_csar(csar_id)
+    except NSLCMException as e:
+        return [1, e.message]
+    except:
+        logger.error(traceback.format_exc())
+        return [1, str(sys.exc_info())]
+    return ret
+
+
+###############################################################################################################
+
+class SdcNsPackage(object):
+    """
+    Actions for sdc ns package.
+    """
+
+    def __init__(self):
+        pass
+
+    def on_distribute(self, csar_id):
+        if NSDModel.objects.filter(id=csar_id):
+            raise NSLCMException("NS CSAR(%s) already exists." % csar_id)
+
+        artifact = sdc.get_artifact(sdc.ASSETTYPE_SERVICES, csar_id)
+        local_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
+        local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path)
+        
+        nsd_json = toscaparser.parse_nsd(local_file_name)
+        nsd = json.JSONDecoder().decode(nsd_json)
+
+        nsd_id = nsd["metadata"]["id"]
+        if NSDModel.objects.filter(nsd_id=nsd_id):
+            raise NSLCMException("NSD(%s) already exists." % nsd_id)
+
+        for vnf in nsd["vnfs"]:
+            vnfd_id = vnf["properties"]["id"]
+            pkg = NfPackageModel.objects.filter(vnfdid=vnfd_id)
+            if not pkg:
+                raise NSLCMException("VNF package(%s) is not distributed." % vnfd_id)
+
+        NSDModel(
+            id=csar_id,
+            nsd_id=nsd_id,
+            name=nsd["metadata"].get("name", nsd_id),
+            vendor=nsd["metadata"].get("vendor", "undefined"),
+            description=nsd["metadata"].get("description", ""),
+            version=nsd["metadata"].get("version", "undefined"),
+            nsd_path=local_file_name,
+            nsd_model=nsd_json).save()
+
+        return [0, "CSAR(%s) distributed successfully." % csar_id]
+
+
+    def delete_csar(self, csar_id, force_delete):
+        if force_delete:
+            NSInstModel.objects.filter(nspackage_id=csar_id).delete()
+        else:
+            if NSInstModel.objects.filter(nspackage_id=csar_id):
+                raise NSLCMException("CSAR(%s) is in using, cannot be deleted." % csar_id)
+        NSDModel.objects.filter(id=csar_id).delete()
+        return [0, "Delete CSAR(%s) successfully." % csar_id]
+
+
+    def get_csars(self):
+        csars = {"csars": []}
+        nss = NSDModel.objects.filter()
+        for ns in nss:
+            csars["csars"].append({
+                "csarId": ns.id,
+                "nsdId": ns.nsd_id
+            })
+        return [0, csars]
+
+    def get_csar(self, csar_id):
+        package_info = {}
+        csars = NSDModel.objects.filter(id=csar_id)
+        if csars:
+            package_info["nsdId"] = csars[0].nsd_id
+            package_info["nsdProvider"] = csars[0].vendor
+            package_info["nsdVersion"] = csars[0].version
+
+        nss = NSInstModel.objects.filter(nspackage_id=csar_id)
+        ns_instance_info = [{
+            "nsInstanceId": ns.id, 
+            "nsInstanceName": ns.name} for ns in nss]
+
+        return [0, {"csarId": csar_id, 
+            "packageInfo": package_info, 
+            "nsInstanceInfo": ns_instance_info}]
+
+    def delete_catalog(self, csar_id):
+        local_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
+        fileutil.delete_dirs(local_path)
+
+
+
+       
\ No newline at end of file
index e27bbb3..ca95c50 100644 (file)
@@ -21,15 +21,46 @@ from rest_framework import status
 class PackageTest(unittest.TestCase):
     def setUp(self):
         self.client = Client()
+        self.nsdata = None
+        self.nfdata = None
+        self.ns_csarId = 123
+        self.nf_csarId = 456
+
+        self.nsdata = {
+            "csarId": self.ns_csarId
+        }
+
+        self.nfdata = {
+            "csarId": self.nf_csarId
+        }
+
 
     def tearDown(self):
         pass
 
     def test_nspackage_get(self):
-
         response = self.client.get("/api/nfvocatalog/v1/nspackages")
-        #self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+        self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
 
     def test_nfpackage_get(self):
-        response = self.client.get("/api/nfvocatalog/v1/nfpackages")
-        #self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
\ No newline at end of file
+        response = self.client.get("/api/nfvocatalog/v1/vnfpackages")
+        self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+
+    def test_ns_distribute(self):
+        response = self.client.post("/api/nfvocatalog/v1/nspackages",self.nsdata)
+        #self.assertEqual(status.HTTP_200_OK, response.status_code, response.content)
+
+
+    def test_nf_distribute(self):
+        response = self.client.post("/api/nfvocatalog/v1/vnfpackages",self.nfdata)
+        #self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code, response.content)
+        
+
+    def test_ns_package_delete(self):
+        response = self.client.delete("/api/nfvocatalog/v1/nspackages/" + str(self.ns_csarId))
+        self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code, response.content)
+
+    def test_nf_package_delete(self):
+        #response = self.client.delete("/api/nfvocatalog/v1/vnfpackages/" + str(self.nf_csarId))
+        #self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code, response.content)
+        pass
index e6ca9fe..99a49fd 100644 (file)
@@ -19,6 +19,8 @@ from rest_framework.response import Response
 from rest_framework import status
 from rest_framework.decorators import api_view
 from catalog.pub.utils.values import ignore_case_get
+from catalog.packages import sdc_nf_package
+from catalog.packages import sdc_ns_package
 
 
 logger = logging.getLogger(__name__)
@@ -27,13 +29,16 @@ logger = logging.getLogger(__name__)
 def nspackage_get(request, *args, **kwargs):
     logger.debug("Enter %s, method is %s", fun_name(), request.method)
     ret, normal_status = None, None
+
     if request.method == 'GET':
-        ret = get_ns_csars()
+        # Gets ns package list
+        ret = sdc_ns_package.SdcNsPackage().get_csars()
         normal_status = status.HTTP_200_OK
-    else:
+    elif request.method == 'POST':
+        # Distributes the package accroding to the given csarId
         csar_id = ignore_case_get(request.data, "csarId")
         logger.debug("csar_id is %s", csar_id)
-        ret = ns_on_distribute(csar_id)
+        ret = sdc_ns_package.ns_on_distribute(csar_id)
         normal_status = status.HTTP_202_ACCEPTED
     logger.debug("Leave %s, Return value is %s", fun_name(), ret)
     if ret[0] != 0:
@@ -45,14 +50,14 @@ def nfpackage_get(request, *args, **kwargs):
     logger.debug("Enter %s%s, method is %s", fun_name(), request.data, request.method)
     ret, normal_status = None, None
     if request.method == 'GET':
-        ret = get_nf_csars()
+        ret = sdc_nf_package.nf_get_csars()
         normal_status = status.HTTP_200_OK
-    else:
+    elif request.method == 'POST':
         csar_id = ignore_case_get(request.data, "csarId")
         vim_ids = ignore_case_get(request.data, "vimIds")
         lab_vim_id = ignore_case_get(request.data, "labVimId")
         job_id = str(uuid.uuid4())
-        nf_on_distribute(csar_id, vim_ids, lab_vim_id, job_id)
+        sdc_nf_package.SdcNfDistributeThread(csar_id, vim_ids, lab_vim_id, job_id).start()
         ret = [0, {"jobId": job_id}]
         normal_status = status.HTTP_202_ACCEPTED
     logger.debug("Leave %s, Return value is %s", fun_name(), ret)
@@ -61,23 +66,41 @@ def nfpackage_get(request, *args, **kwargs):
     return Response(data=ret[1], status=normal_status)
 
 @api_view(http_method_names=['DELETE', 'GET'])
-def ns_rd_csar():
-    return [0,0]
+def ns_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)
+    ret, normal_status = None, None
+    if request.method == 'GET':
+        ret = sdc_ns_package.ns_get_csar(csar_id)
+        normal_status = status.HTTP_200_OK
+    elif request.method == 'DELETE':
+        force_delete = csar_id.endswith("force")
+        if force_delete:
+            csar_id = csar_id[:-5]
+        ret = sdc_ns_package.ns_delete_csar(csar_id, force_delete)
+        normal_status = status.HTTP_202_ACCEPTED
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=normal_status)
 
 @api_view(http_method_names=['DELETE', 'GET'])
-def nf_rd_csar():
-    return [0,0]
-
-def get_ns_csars():
-    return [0,0]
-
-
-def get_nf_csars():
-    return [0,0]
-
-
-def ns_on_distribute(csarId):
-    return [0,0]
-
-def nf_on_distribute(csar_id, vim_ids, lab_vim_id, job_id):
-    return [0,0]
\ No newline at end of file
+def nf_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)
+    ret, normal_status = None, None
+    if request.method == 'GET':
+        ret = sdc_nf_package.nf_get_csar(csar_id)
+        normal_status = status.HTTP_200_OK
+    elif request.method == 'DELETE':
+        force_delete = csar_id.endswith("force")
+        if force_delete:
+            csar_id = csar_id[:-5]
+        job_id = str(uuid.uuid4())
+        sdc_nf_package.SdcNfPkgDeleteThread(csar_id, job_id, force_delete).start()
+        ret = [0, {"jobId": job_id}]
+        normal_status = status.HTTP_202_ACCEPTED
+    logger.info("Leave %s, Return value is %s", fun_name(), str(ret))
+    if ret[0] != 0:
+        return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+    return Response(data=ret[1], status=normal_status)
index c98aff7..e011478 100644 (file)
@@ -19,3 +19,6 @@ httplib2==0.9.2
 coverage==4.2
 mock==2.0.0
 unittest_xml_reporting==1.12.0
+
+# for parser
+nfv-toscaparser==0.5.0.dev95
\ No newline at end of file