Add log and comment
[modeling/etsicatalog.git] / catalog / packages / biz / pnf_descriptor.py
1 # Copyright 2018 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
16 import json
17 import logging
18 import os
19 import uuid
20
21 from catalog.packages.biz.common import read, save
22 from catalog.packages.const import PKG_STATUS
23 from catalog.pub.config.config import CATALOG_ROOT_PATH
24 from catalog.pub.database.models import NSPackageModel, PnfPackageModel
25 from catalog.pub.exceptions import CatalogException, ResourceNotFoundException
26 from catalog.pub.utils import fileutil, toscaparser
27 from catalog.pub.utils.values import ignore_case_get
28 from catalog.packages.biz.notificationsutil import PnfNotifications
29 from catalog.packages import const
30
31 logger = logging.getLogger(__name__)
32
33
34 class PnfDescriptor(object):
35     """
36     PNF package management
37     """
38
39     def __init__(self):
40         pass
41
42     def create(self, data):
43         """
44         Create a PNF package
45         :param data:
46         :return:
47         """
48         logger.info('Start to create a PNFD...')
49         user_defined_data = ignore_case_get(data, 'userDefinedData', {})
50         data = {
51             'id': str(uuid.uuid4()),
52             'pnfdOnboardingState': PKG_STATUS.CREATED,
53             'pnfdUsageState': PKG_STATUS.NOT_IN_USE,
54             'userDefinedData': user_defined_data,
55             '_links': None  # TODO
56         }
57         PnfPackageModel.objects.create(
58             pnfPackageId=data['id'],
59             onboardingState=data['pnfdOnboardingState'],
60             usageState=data['pnfdUsageState'],
61             userDefinedData=json.dumps(user_defined_data)
62         )
63         logger.info('A PNFD(%s) has been created.' % data['id'])
64         return data
65
66     def query_multiple(self, request):
67         """
68         Query PNF packages
69         :param request:
70         :return:
71         """
72         pnfdId = request.query_params.get('pnfdId')
73         if pnfdId:
74             pnf_pkgs = PnfPackageModel.objects.filter(pnfdId=pnfdId)
75         else:
76             pnf_pkgs = PnfPackageModel.objects.all()
77         response_data = []
78         for pnf_pkg in pnf_pkgs:
79             data = self.fill_response_data(pnf_pkg)
80             response_data.append(data)
81         return response_data
82
83     def query_single(self, pnfd_info_id):
84         """
85         Query PNF package by id
86         :param pnfd_info_id:
87         :return:
88         """
89         pnf_pkgs = PnfPackageModel.objects.filter(pnfPackageId=pnfd_info_id)
90         if not pnf_pkgs.exists():
91             logger.error('PNFD(%s) does not exist.' % pnfd_info_id)
92             raise ResourceNotFoundException('PNFD(%s) does not exist.' % pnfd_info_id)
93         return self.fill_response_data(pnf_pkgs[0])
94
95     def upload(self, remote_file, pnfd_info_id):
96         """
97         Upload PNF package file
98         :param remote_file:
99         :param pnfd_info_id:
100         :return:
101         """
102         logger.info('Start to upload PNFD(%s)...' % pnfd_info_id)
103         pnf_pkgs = PnfPackageModel.objects.filter(pnfPackageId=pnfd_info_id)
104         if not pnf_pkgs.exists():
105             details = 'PNFD(%s) is not CREATED.' % pnfd_info_id
106             logger.info(details)
107             send_notification(
108                 type=const.NSD_NOTIFICATION_TYPE.PNFD_ONBOARDING_FAILURE,
109                 pnfd_info_id=pnfd_info_id,
110                 failure_details=details
111             )
112             raise CatalogException(details)
113         pnf_pkgs.update(onboardingState=PKG_STATUS.UPLOADING)
114
115         local_file_name = save(remote_file, pnfd_info_id)
116         logger.info('PNFD(%s) content has been uploaded.' % pnfd_info_id)
117         return local_file_name
118
119     def delete_single(self, pnfd_info_id):
120         """
121         Delete PNF package by id
122         :param pnfd_info_id:
123         :return:
124         """
125         logger.info('Start to delete PNFD(%s)...' % pnfd_info_id)
126         pnf_pkgs = PnfPackageModel.objects.filter(pnfPackageId=pnfd_info_id)
127         if not pnf_pkgs.exists():
128             logger.info('PNFD(%s) has been deleted.' % pnfd_info_id)
129             return
130         '''
131         if pnf_pkgs[0].usageState != PKG_STATUS.NOT_IN_USE:
132             logger.info('PNFD(%s) shall be NOT_IN_USE.' % pnfd_info_id)
133             raise CatalogException('PNFD(%s) shall be NOT_IN_USE.' % pnfd_info_id)
134         '''
135         del_pnfd_id = pnf_pkgs[0].pnfdId
136         ns_pkgs = NSPackageModel.objects.all()
137         for ns_pkg in ns_pkgs:
138             nsd_model = None
139             if ns_pkg.nsdModel:
140                 nsd_model = json.JSONDecoder().decode(ns_pkg.nsdModel)
141             if not nsd_model:
142                 continue
143             for pnf in nsd_model['pnfs']:
144                 if del_pnfd_id == pnf["properties"]["id"]:
145                     logger.warn("PNFD(%s) is referenced in NSD", del_pnfd_id)
146                     raise CatalogException('PNFD(%s) is referenced.' % pnfd_info_id)
147         pnf_pkgs.delete()
148         pnf_pkg_path = os.path.join(CATALOG_ROOT_PATH, pnfd_info_id)
149         fileutil.delete_dirs(pnf_pkg_path)
150         send_notification(const.NSD_NOTIFICATION_TYPE.PNFD_DELETION, pnfd_info_id, del_pnfd_id)
151         logger.debug('PNFD(%s) has been deleted.' % pnfd_info_id)
152
153     def download(self, pnfd_info_id):
154         """
155         Download PNF package file by id
156         :param pnfd_info_id:
157         :return:
158         """
159         logger.info('Start to download PNFD(%s)...' % pnfd_info_id)
160         pnf_pkgs = PnfPackageModel.objects.filter(pnfPackageId=pnfd_info_id)
161         if not pnf_pkgs.exists():
162             logger.error('PNFD(%s) does not exist.' % pnfd_info_id)
163             raise ResourceNotFoundException('PNFD(%s) does not exist.' % pnfd_info_id)
164         if pnf_pkgs[0].onboardingState != PKG_STATUS.ONBOARDED:
165             logger.error('PNFD(%s) is not ONBOARDED.' % pnfd_info_id)
166             raise CatalogException('PNFD(%s) is not ONBOARDED.' % pnfd_info_id)
167
168         local_file_path = pnf_pkgs[0].localFilePath
169         start, end = 0, os.path.getsize(local_file_path)
170         logger.info('PNFD(%s) has been downloaded.' % pnfd_info_id)
171         return read(local_file_path, start, end)
172
173     def parse_pnfd_and_save(self, pnfd_info_id, local_file_name):
174         """
175         Parse PNFD and save the information
176         :param pnfd_info_id:
177         :param local_file_name:
178         :return:
179         """
180         logger.info('Start to process PNFD(%s)...' % pnfd_info_id)
181         pnf_pkgs = PnfPackageModel.objects.filter(pnfPackageId=pnfd_info_id)
182         pnf_pkgs.update(onboardingState=PKG_STATUS.PROCESSING)
183         pnfd_json = toscaparser.parse_pnfd(local_file_name)
184         pnfd = json.JSONDecoder().decode(pnfd_json)
185
186         logger.debug("pnfd_json is %s" % pnfd_json)
187         pnfd_id = ""
188         pnfdVersion = ""
189         pnfdProvider = ""
190         pnfdName = ""
191         if pnfd.get("pnf", "") != "":
192             if pnfd["pnf"].get("properties", "") != "":
193                 pnfd_id = pnfd["pnf"].get("properties", {}).get("descriptor_id", "")
194                 pnfdVersion = pnfd["pnf"].get("properties", {}).get("version", "")
195                 pnfdProvider = pnfd["pnf"].get("properties", {}).get("provider", "")
196                 pnfdName = pnfd["pnf"].get("properties", {}).get("name", "")
197         if pnfd_id == "":
198             pnfd_id = pnfd["metadata"].get("descriptor_id", "")
199             if pnfd_id == "":
200                 pnfd_id = pnfd["metadata"].get("id", "")
201             if pnfd_id == "":
202                 pnfd_id = pnfd["metadata"].get("UUID", "")
203             if pnfd_id == "":
204                 raise CatalogException('pnfd_id is Null.')
205
206         if pnfdVersion == "":
207             pnfdVersion = pnfd["metadata"].get("template_version", "")
208             if pnfdVersion == "":
209                 pnfdVersion = pnfd["metadata"].get("version", "")
210
211         if pnfdProvider == "":
212             pnfdProvider = pnfd["metadata"].get("template_author", "")
213             if pnfdVersion == "":
214                 pnfdVersion = pnfd["metadata"].get("provider", "")
215
216         if pnfdName == "":
217             pnfdName = pnfd["metadata"].get("template_name", "")
218             if pnfdVersion == "":
219                 pnfdName = pnfd["metadata"].get("name", "")
220
221         other_pnf = PnfPackageModel.objects.filter(pnfdId=pnfd_id)
222         if other_pnf and other_pnf[0].pnfPackageId != pnfd_info_id:
223             logger.info('PNFD(%s) already exists.' % pnfd_id)
224             raise CatalogException("PNFD(%s) already exists." % pnfd_id)
225
226         pnf_pkgs.update(
227             pnfdId=pnfd_id,
228             pnfdName=pnfdName,
229             pnfdVersion=pnfdVersion,
230             pnfVendor=pnfdProvider,
231             pnfPackageUri=local_file_name,
232             onboardingState=PKG_STATUS.ONBOARDED,
233             usageState=PKG_STATUS.NOT_IN_USE,
234             localFilePath=local_file_name,
235             pnfdModel=pnfd_json
236         )
237         send_notification(const.NSD_NOTIFICATION_TYPE.PNFD_ONBOARDING, pnfd_info_id, pnfd_id)
238         logger.info('PNFD(%s) has been processed.' % pnfd_info_id)
239
240     def fill_response_data(self, pnf_pkg):
241         """
242         Fill response data
243         :param pnf_pkg:
244         :return:
245         """
246         data = {
247             'id': pnf_pkg.pnfPackageId,
248             'pnfdId': pnf_pkg.pnfdId,
249             'pnfdName': pnf_pkg.pnfdName,
250             'pnfdVersion': pnf_pkg.pnfdVersion,
251             'pnfdProvider': pnf_pkg.pnfVendor,
252             'pnfdInvariantId': None,  # TODO
253             'pnfdOnboardingState': pnf_pkg.onboardingState,
254             'onboardingFailureDetails': None,  # TODO
255             'pnfdUsageState': pnf_pkg.usageState,
256             'userDefinedData': {},
257             '_links': None  # TODO
258         }
259         if pnf_pkg.userDefinedData:
260             user_defined_data = json.JSONDecoder().decode(pnf_pkg.userDefinedData)
261             data['userDefinedData'] = user_defined_data
262
263         return data
264
265     def handle_upload_failed(self, pnf_pkg_id):
266         """
267         Faild process
268         :param pnf_pkg_id:
269         :return:
270         """
271         pnf_pkg = PnfPackageModel.objects.filter(pnfPackageId=pnf_pkg_id)
272         pnf_pkg.update(onboardingState=PKG_STATUS.CREATED)
273
274     def parse_pnfd(self, csar_id, inputs):
275         """
276         Parse PNFD
277         :param csar_id:
278         :param inputs:
279         :return:
280         """
281         try:
282             pnf_pkg = PnfPackageModel.objects.filter(pnfPackageId=csar_id)
283             if not pnf_pkg:
284                 raise CatalogException("PNF CSAR(%s) does not exist." % csar_id)
285             csar_path = pnf_pkg[0].localFilePath
286             ret = {"model": toscaparser.parse_pnfd(csar_path, inputs)}
287         except CatalogException as e:
288             return [1, e.args[0]]
289         except Exception as e:
290             logger.error(e.args[0])
291             return [1, e.args[0]]
292         return [0, ret]
293
294
295 def send_notification(type, pnfd_info_id, pnfd_id=None, failure_details=None):
296     """
297     Send notification
298     :param type:
299     :param pnfd_info_id:
300     :param pnfd_id:
301     :param failure_details:
302     :return:
303     """
304     notify = PnfNotifications(type, pnfd_info_id, pnfd_id, failure_details=failure_details)
305     notify.send_notification()