diff options
author | fengyuanxing <feng.yuanxing@zte.com.cn> | 2017-08-26 20:11:31 +0800 |
---|---|---|
committer | fengyuanxing <feng.yuanxing@zte.com.cn> | 2017-08-26 20:11:31 +0800 |
commit | fe5fd27c1fb55eca78c6a9f17c86dff3188c3eba (patch) | |
tree | 11792d73ee9aa41b3e0ac7e20488fd74ff17b731 | |
parent | ac2a906339f71be109f3426087a7048ab7e09299 (diff) |
Add code related to sdc
Change-Id: If4ddb9c10e654b04b033b63005f99ddf1adc599b
Issue-Id: VFC-152
Signed-off-by: fengyuanxing <feng.yuanxing@zte.com.cn>
-rw-r--r-- | catalog/packages/sdc_nf_package.py | 228 | ||||
-rw-r--r-- | catalog/packages/sdc_ns_package.py | 174 | ||||
-rw-r--r-- | catalog/packages/tests.py | 39 | ||||
-rw-r--r-- | catalog/packages/views.py | 71 | ||||
-rw-r--r-- | requirements.txt | 3 |
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 |