Implement read VNFD API
[modeling/etsicatalog.git] / catalog / packages / biz / sdc_vnf_package.py
1 # Copyright 2017 ZTE Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import json
16 import logging
17 import os
18 import sys
19 import threading
20 import traceback
21 import zipfile
22
23 from catalog.packages.biz.vnf_package import VnfPackage
24 from catalog.packages.const import PKG_STATUS
25 from catalog.pub.config.config import CATALOG_ROOT_PATH, CATALOG_URL_PATH
26 from catalog.pub.config.config import REG_TO_MSB_REG_PARAM
27 from catalog.pub.database.models import VnfPackageModel
28 from catalog.pub.exceptions import CatalogException
29 from catalog.pub.msapi import sdc
30 from catalog.pub.utils import fileutil
31 from catalog.pub.utils import toscaparser
32 from catalog.pub.utils.jobutil import JobUtil
33
34 logger = logging.getLogger(__name__)
35
36 JOB_ERROR = 255
37
38
39 def nf_get_csars():
40     ret = None
41     try:
42         ret = NfPackage().get_csars()
43     except CatalogException as e:
44         return [1, e.args[0]]
45     except Exception as e:
46         logger.error(e.args[0])
47         logger.error(traceback.format_exc())
48         return [1, str(sys.exc_info())]
49     return ret
50
51
52 def nf_get_csar(csar_id):
53     ret = None
54     try:
55         ret = NfPackage().get_csar(csar_id)
56     except CatalogException as e:
57         return [1, e.args[0]]
58     except Exception as e:
59         logger.error(e.args[0])
60         logger.error(traceback.format_exc())
61         return [1, str(sys.exc_info())]
62     return ret
63
64
65 def parse_vnfd(csar_id, inputs):
66     ret = None
67     try:
68         nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=csar_id)
69         if not nf_pkg:
70             raise CatalogException("VNF CSAR(%s) does not exist." % csar_id)
71         csar_path = nf_pkg[0].localFilePath
72         ret = {"model": toscaparser.parse_vnfd(csar_path, inputs)}
73     except CatalogException as e:
74         return [1, e.args[0]]
75     except Exception as e:
76         logger.error(e.args[0])
77         logger.error(traceback.format_exc())
78         return [1, str(sys.exc_info())]
79     return [0, ret]
80
81
82 class NfDistributeThread(threading.Thread):
83     """
84     Sdc NF Package Distribute
85     """
86
87     def __init__(self, csar_id, vim_ids, lab_vim_id, job_id):
88         threading.Thread.__init__(self)
89         self.csar_id = csar_id
90         self.vim_ids = vim_ids
91         self.lab_vim_id = lab_vim_id
92         self.job_id = job_id
93
94         self.csar_save_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
95
96     def run(self):
97         try:
98             self.on_distribute()
99         except CatalogException as e:
100             self.rollback_distribute()
101             JobUtil.add_job_status(self.job_id, JOB_ERROR, e.args[0])
102         except Exception as e:
103             logger.error(e.args[0])
104             logger.error(traceback.format_exc())
105             logger.error(str(sys.exc_info()))
106             self.rollback_distribute()
107             JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to distribute CSAR(%s)" % self.csar_id)
108
109     def on_distribute(self):
110         JobUtil.create_job(
111             inst_type='nf',
112             jobaction='on_distribute',
113             inst_id=self.csar_id,
114             job_id=self.job_id)
115         JobUtil.add_job_status(self.job_id, 5, "Start CSAR(%s) distribute." % self.csar_id)
116
117         if VnfPackageModel.objects.filter(vnfPackageId=self.csar_id):
118             err_msg = "NF CSAR(%s) already exists." % self.csar_id
119             JobUtil.add_job_status(self.job_id, JOB_ERROR, err_msg)
120             return
121
122         artifact = sdc.get_artifact(sdc.ASSETTYPE_RESOURCES, self.csar_id)
123         local_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
124         csar_name = "%s.csar" % artifact.get("name", self.csar_id)
125         local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path, csar_name)
126         if local_file_name.endswith(".csar") or local_file_name.endswith(".zip"):
127             fileutil.unzip_csar(local_file_name, local_path)
128             vendor_vnf_file = ''
129             # find original vendor ETSI package under the ONBOARDING_PACKAGE directory
130             onboarding_package_dir = os.path.join(local_path, "Artifacts/Deployment/ONBOARDED_PACKAGE")
131             if os.path.exists(onboarding_package_dir):
132                 files = os.listdir(onboarding_package_dir)
133                 for file_name in files:
134                     a_file = os.path.join(onboarding_package_dir, file_name)
135                     if os.path.isfile(a_file) & file_name.endswith(".csar"):
136                         vendor_vnf_file = a_file
137                         break
138
139             # find original vendor ETSI package under Artifacts/Deployment/OTHER directory
140             if vendor_vnf_file.strip() == '':
141                 vendor_vnf_file = os.path.join(local_path, "Artifacts/Deployment/OTHER/vnf.csar")
142                 if os.path.exists(vendor_vnf_file):
143                     local_file_name = vendor_vnf_file
144             else:
145                 local_file_name = vendor_vnf_file
146
147         # create VNFD zip file
148         self.create_vnfd_zip(self.csar_id, vendor_vnf_file)
149
150         vnfd_json = toscaparser.parse_vnfd(local_file_name)
151         vnfd = json.JSONDecoder().decode(vnfd_json)
152
153         if not vnfd.get("vnf"):
154             raise CatalogException("VNF properties and metadata in VNF Package(id=%s) are empty." % self.csar_id)
155
156         vnfd_id = vnfd["vnf"]["properties"].get("descriptor_id", "")
157         if VnfPackageModel.objects.filter(vnfdId=vnfd_id):
158             logger.error("VNF package(%s) already exists.", vnfd_id)
159             raise CatalogException("VNF package(%s) already exists." % vnfd_id)
160         JobUtil.add_job_status(self.job_id, 30, "Save CSAR(%s) to database." % self.csar_id)
161         vnfd_ver = vnfd["vnf"]["properties"].get("descriptor_version", "")
162         vnf_provider = vnfd["vnf"]["properties"].get("provider", "")
163         vnf_software_version = vnfd["vnf"]["properties"].get("software_version", "")
164         vnfd_product_name = vnfd["vnf"]["properties"].get("product_name", "")
165         VnfPackageModel(
166             vnfPackageId=self.csar_id,
167             vnfdId=vnfd_id,
168             vnfVendor=vnf_provider,
169             vnfdProductName=vnfd_product_name,
170             vnfdVersion=vnfd_ver,
171             vnfSoftwareVersion=vnf_software_version,
172             vnfdModel=vnfd_json,
173             localFilePath=local_file_name,
174             vnfPackageUri=csar_name,
175             onboardingState=PKG_STATUS.ONBOARDED,
176             operationalState=PKG_STATUS.ENABLED,
177             usageState=PKG_STATUS.NOT_IN_USE
178         ).save()
179         JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) distribute successfully." % self.csar_id)
180
181     def create_vnfd_zip(self, csar_id, vendor_vnf_file):
182         """
183         Create VNFD zip file.
184         :param csar_id: CSAR Id
185         :param vendor_vnf_file: the vendor original package(csar)
186         :return:
187         """
188         if os.path.exists(vendor_vnf_file):
189             # create VNFD from vendor original package
190             VnfPackage().creat_vnfd(csar_id, vendor_vnf_file)
191         else:
192             try:
193                 vnf_package_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
194                 vnfd_zip_file = os.path.join(vnf_package_path, 'VNFD.zip')
195                 with zipfile.ZipFile(vnfd_zip_file, 'w', zipfile.ZIP_DEFLATED) as vnfd_zip:
196                     def_path = os.path.join(vnf_package_path, "Definitions")
197                     if os.path.exists(def_path):
198                         def_files = os.listdir(def_path)
199                         for def_file in def_files:
200                             full_path = os.path.join(def_path, def_file)
201                             vnfd_zip.write(full_path, def_file)
202             except Exception as e:
203                 logger.error(e)
204                 if os.path.exists(vnfd_zip_file):
205                     os.remove(vnfd_zip_file)
206
207     def rollback_distribute(self):
208         try:
209             VnfPackageModel.objects.filter(vnfPackageId=self.csar_id).delete()
210             fileutil.delete_dirs(self.csar_save_path)
211         except Exception as e:
212             logger.error(e.args[0])
213             logger.error(traceback.format_exc())
214             logger.error(str(sys.exc_info()))
215
216
217 class NfPkgDeleteThread(threading.Thread):
218     """
219     Sdc NF Package Deleting
220     """
221
222     def __init__(self, csar_id, job_id):
223         threading.Thread.__init__(self)
224         self.csar_id = csar_id
225         self.job_id = job_id
226
227     def run(self):
228         try:
229             self.delete_csar()
230         except CatalogException as e:
231             JobUtil.add_job_status(self.job_id, JOB_ERROR, e.args[0])
232         except Exception as e:
233             logger.error(e.args[0])
234             logger.error(traceback.format_exc())
235             logger.error(str(sys.exc_info()))
236             JobUtil.add_job_status(self.job_id, JOB_ERROR, "Failed to delete CSAR(%s)" % self.csar_id)
237
238     def delete_csar(self):
239         JobUtil.create_job(
240             inst_type='nf',
241             jobaction='delete',
242             inst_id=self.csar_id,
243             job_id=self.job_id)
244         JobUtil.add_job_status(self.job_id, 5, "Start to delete CSAR(%s)." % self.csar_id)
245
246         VnfPackageModel.objects.filter(vnfPackageId=self.csar_id).delete()
247
248         JobUtil.add_job_status(self.job_id, 50, "Delete local CSAR(%s) file." % self.csar_id)
249
250         csar_save_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
251         fileutil.delete_dirs(csar_save_path)
252
253         JobUtil.add_job_status(self.job_id, 100, "Delete CSAR(%s) successfully." % self.csar_id)
254
255
256 class NfPackage(object):
257     """
258     Actions for sdc nf package.
259     """
260
261     def __init__(self):
262         pass
263
264     def get_csars(self):
265         csars = []
266         nf_pkgs = VnfPackageModel.objects.filter()
267         for nf_pkg in nf_pkgs:
268             ret = self.get_csar(nf_pkg.vnfPackageId)
269             csars.append(ret[1])
270         return [0, csars]
271
272     def get_csar(self, csar_id):
273         pkg_info = {}
274         nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=csar_id)
275         if not nf_pkg:
276             nf_pkg = VnfPackageModel.objects.filter(vnfdId=csar_id)
277
278         if nf_pkg:
279             db_csar_id = nf_pkg[0].vnfPackageId
280             pkg_info["vnfdId"] = nf_pkg[0].vnfdId
281             pkg_info["vnfPackageId"] = nf_pkg[0].vnfPackageId
282             pkg_info["vnfdProvider"] = nf_pkg[0].vnfVendor
283             pkg_info["vnfdVersion"] = nf_pkg[0].vnfdVersion
284             pkg_info["vnfVersion"] = nf_pkg[0].vnfSoftwareVersion
285             pkg_info["csarName"] = nf_pkg[0].vnfPackageUri
286             pkg_info["vnfdModel"] = nf_pkg[0].vnfdModel
287             pkg_info["downloadUrl"] = "http://%s:%s/%s/%s/%s" % (
288                 REG_TO_MSB_REG_PARAM[0]["nodes"][0]["ip"],
289                 REG_TO_MSB_REG_PARAM[0]["nodes"][0]["port"],
290                 CATALOG_URL_PATH,
291                 db_csar_id,
292                 nf_pkg[0].vnfPackageUri)
293         else:
294             raise CatalogException("Vnf package[%s] not Found." % csar_id)
295
296         csar_info = {
297             "csarId": db_csar_id,
298             "packageInfo": pkg_info,
299             "imageInfo": []
300         }
301         return [0, csar_info]