fix but for ETSI Catalog Manager needs to trigger a notification after storing ETSI...
[modeling/etsicatalog.git] / catalog / packages / biz / sdc_vnf_package.py
index 571c3bb..3bfc533 100644 (file)
@@ -18,16 +18,19 @@ import os
 import sys
 import threading
 import traceback
+import zipfile
 
-from catalog.packages.const import PKG_STATUS
+from catalog.packages.biz.vnf_package import VnfPackage
+from catalog.packages import const
 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
-from catalog.pub.exceptions import CatalogException
+from catalog.pub.exceptions import CatalogException, PackageHasExistsException
 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.pub.utils.jobutil import JobUtil, JOB_ERROR_CODE
+from catalog.packages.biz.notificationsutil import PkgNotifications
 
 logger = logging.getLogger(__name__)
 
@@ -94,15 +97,19 @@ class NfDistributeThread(threading.Thread):
     def run(self):
         try:
             self.on_distribute()
+        except PackageHasExistsException as e:
+            self.rollback_distribute()
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.args[0], error_code=JOB_ERROR_CODE.PACKAGE_EXIST)
         except CatalogException as e:
             self.rollback_distribute()
-            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.args[0])
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, e.args[0], error_code=JOB_ERROR_CODE.CATALOG_EXCEPTION)
         except Exception as e:
             logger.error(e.args[0])
             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)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to distribute CSAR(%s)" % self.csar_id,
+                                   error_code=JOB_ERROR_CODE.SYSTEM_ERROR)
 
     def on_distribute(self):
         JobUtil.create_job(
@@ -114,7 +121,7 @@ class NfDistributeThread(threading.Thread):
 
         if VnfPackageModel.objects.filter(vnfPackageId=self.csar_id):
             err_msg = "NF CSAR(%s) already exists." % self.csar_id
-            JobUtil.add_job_status(self.job_id, JOB_ERROR, err_msg)
+            JobUtil.add_job_status(self.job_id, JOB_ERROR, err_msg, error_code=JOB_ERROR_CODE.PACKAGE_EXIST)
             return
 
         artifact = sdc.get_artifact(sdc.ASSETTYPE_RESOURCES, self.csar_id)
@@ -122,9 +129,28 @@ class NfDistributeThread(threading.Thread):
         csar_name = "%s.csar" % artifact.get("name", self.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/vnf.csar")
-            if os.path.exists(artifact_vnf_file):
-                local_file_name = artifact_vnf_file
+            fileutil.unzip_csar(local_file_name, local_path)
+            vendor_vnf_file = ''
+            # find original vendor ETSI package under the ONBOARDING_PACKAGE directory
+            onboarding_package_dir = os.path.join(local_path, "Artifacts/Deployment/ONBOARDED_PACKAGE")
+            if os.path.exists(onboarding_package_dir):
+                files = os.listdir(onboarding_package_dir)
+                for file_name in files:
+                    a_file = os.path.join(onboarding_package_dir, file_name)
+                    if os.path.isfile(a_file) & file_name.endswith(".csar"):
+                        vendor_vnf_file = a_file
+                        break
+
+            # find original vendor ETSI package under Artifacts/Deployment/OTHER directory
+            if vendor_vnf_file.strip() == '':
+                vendor_vnf_file = os.path.join(local_path, "Artifacts/Deployment/OTHER/vnf.csar")
+                if os.path.exists(vendor_vnf_file):
+                    local_file_name = vendor_vnf_file
+            else:
+                local_file_name = vendor_vnf_file
+
+        # create VNFD zip file
+        self.create_vnfd_zip(self.csar_id, vendor_vnf_file)
 
         vnfd_json = toscaparser.parse_vnfd(local_file_name)
         vnfd = json.JSONDecoder().decode(vnfd_json)
@@ -135,7 +161,7 @@ class NfDistributeThread(threading.Thread):
         vnfd_id = vnfd["vnf"]["properties"].get("descriptor_id", "")
         if VnfPackageModel.objects.filter(vnfdId=vnfd_id):
             logger.error("VNF package(%s) already exists.", vnfd_id)
-            raise CatalogException("VNF package(%s) already exists." % vnfd_id)
+            raise PackageHasExistsException("VNF package(%s) already exists." % vnfd_id)
         JobUtil.add_job_status(self.job_id, 30, "Save CSAR(%s) to database." % self.csar_id)
         vnfd_ver = vnfd["vnf"]["properties"].get("descriptor_version", "")
         vnf_provider = vnfd["vnf"]["properties"].get("provider", "")
@@ -151,11 +177,39 @@ class NfDistributeThread(threading.Thread):
             vnfdModel=vnfd_json,
             localFilePath=local_file_name,
             vnfPackageUri=csar_name,
-            onboardingState=PKG_STATUS.ONBOARDED,
-            operationalState=PKG_STATUS.ENABLED,
-            usageState=PKG_STATUS.NOT_IN_USE
+            onboardingState=const.PKG_STATUS.ONBOARDED,
+            operationalState=const.PKG_STATUS.ENABLED,
+            usageState=const.PKG_STATUS.NOT_IN_USE
         ).save()
         JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) distribute successfully." % self.csar_id)
+        send_notification(self.csar_id, const.PKG_NOTIFICATION_TYPE.ONBOARDING,
+                          const.PKG_CHANGE_TYPE.OP_STATE_CHANGE)
+
+    def create_vnfd_zip(self, csar_id, vendor_vnf_file):
+        """
+        Create VNFD zip file.
+        :param csar_id: CSAR Id
+        :param vendor_vnf_file: the vendor original package(csar)
+        :return:
+        """
+        if os.path.exists(vendor_vnf_file):
+            # create VNFD from vendor original package
+            VnfPackage().creat_vnfd(csar_id, vendor_vnf_file)
+        else:
+            try:
+                vnf_package_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
+                vnfd_zip_file = os.path.join(vnf_package_path, 'VNFD.zip')
+                with zipfile.ZipFile(vnfd_zip_file, 'w', zipfile.ZIP_DEFLATED) as vnfd_zip:
+                    def_path = os.path.join(vnf_package_path, "Definitions")
+                    if os.path.exists(def_path):
+                        def_files = os.listdir(def_path)
+                        for def_file in def_files:
+                            full_path = os.path.join(def_path, def_file)
+                            vnfd_zip.write(full_path, def_file)
+            except Exception as e:
+                logger.error(e)
+                if os.path.exists(vnfd_zip_file):
+                    os.remove(vnfd_zip_file)
 
     def rollback_distribute(self):
         try:
@@ -195,7 +249,8 @@ class NfPkgDeleteThread(threading.Thread):
             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)
-
+        send_notification(self.csar_id, const.PKG_NOTIFICATION_TYPE.CHANGE,
+                          const.PKG_CHANGE_TYPE.PKG_DELETE)
         VnfPackageModel.objects.filter(vnfPackageId=self.csar_id).delete()
 
         JobUtil.add_job_status(self.job_id, 50, "Delete local CSAR(%s) file." % self.csar_id)
@@ -252,3 +307,9 @@ class NfPackage(object):
             "imageInfo": []
         }
         return [0, csar_info]
+
+
+def send_notification(pkg_id, type, pkg_change_type, operational_state=None):
+    notify = PkgNotifications(type, pkg_id, change_type=pkg_change_type,
+                              operational_state=operational_state)
+    notify.send_notification()