aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--catalog/packages/sdc_nf_package.py228
-rw-r--r--catalog/packages/sdc_ns_package.py174
-rw-r--r--catalog/packages/tests.py39
-rw-r--r--catalog/packages/views.py71
-rw-r--r--requirements.txt3
5 files changed, 487 insertions, 28 deletions
diff --git a/catalog/packages/sdc_nf_package.py b/catalog/packages/sdc_nf_package.py
new file mode 100644
index 00000000..f95baf57
--- /dev/null
+++ b/catalog/packages/sdc_nf_package.py
@@ -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
index 00000000..5c42959f
--- /dev/null
+++ b/catalog/packages/sdc_ns_package.py
@@ -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
diff --git a/catalog/packages/tests.py b/catalog/packages/tests.py
index e27bbb3a..ca95c50a 100644
--- a/catalog/packages/tests.py
+++ b/catalog/packages/tests.py
@@ -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
diff --git a/catalog/packages/views.py b/catalog/packages/views.py
index e6ca9fe9..99a49fd5 100644
--- a/catalog/packages/views.py
+++ b/catalog/packages/views.py
@@ -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)
diff --git a/requirements.txt b/requirements.txt
index c98aff71..e0114780 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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