Modify vfc-lcm variable name to hump
[vfc/nfvo/lcm.git] / lcm / ns / ns_terminate.py
1 # Copyright 2016 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 import json
15 import logging
16 import math
17 import threading
18 import time
19 import traceback
20
21 from lcm.ns.vnfs.wait_job import wait_job_finish
22 from lcm.pub.database.models import NSInstModel, VLInstModel, FPInstModel, NfInstModel
23 from lcm.pub.exceptions import NSLCMException
24 from lcm.pub.msapi.nslcm import call_from_ns_cancel_resource
25 from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil
26 from lcm.pub.utils.values import ignore_case_get
27
28 JOB_ERROR = 255
29 # [delete vnf try times]
30
31 logger = logging.getLogger(__name__)
32
33
34 class TerminateNsService(threading.Thread):
35     def __init__(self, ns_inst_id, terminate_type, terminate_timeout, job_id):
36         threading.Thread.__init__(self)
37         self.ns_inst_id = ns_inst_id
38         self.terminate_type = terminate_type
39         self.terminate_timeout = terminate_timeout
40         self.job_id = job_id
41         self.vnfm_inst_id = ''
42
43     def run(self):
44         try:
45             self.do_biz()
46         except NSLCMException as e:
47             JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
48         except:
49             logger.error(traceback.format_exc())
50             JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.", '')
51
52     def do_biz(self):
53         if not self.check_data():
54             JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
55             return
56
57         self.cancel_sfc_list()
58         self.cancel_vnf_list()
59         time.sleep(4)
60         self.cancel_vl_list()
61
62         self.finaldata()
63
64     def check_data(self):
65         JobUtil.add_job_status(self.job_id, 0, "TERMINATING...", '')
66         ns_inst = NSInstModel.objects.filter(id=self.ns_inst_id)
67         if not ns_inst.exists():
68             logger.warn('ns instance [%s] does not exist.' % self.ns_inst_id)
69             return False
70         JobUtil.add_job_status(self.job_id, 10, "Ns cancel: check ns_inst_id success", '')
71         return True
72
73     # delete VLINST
74     def cancel_vl_list(self):
75         array_vlinst = VLInstModel.objects.filter(ownertype='2', ownerid=self.ns_inst_id)
76         if not array_vlinst:
77             logger.error("[cancel_vl_list] no vlinst attatch to ns_inst_id:%s" % self.ns_inst_id)
78             return
79         step_progress = 20 / len(array_vlinst)
80         cur_progress = 70
81         for vlinst in array_vlinst:
82             tmp_msg = vlinst.vlinstanceid
83             try:
84                 ret = self.delete_vl(tmp_msg)
85                 if ret[0] == 0:
86                     cur_progress += step_progress
87                     result = json.JSONDecoder().decode(ret[1]).get("result", "")
88                     if str(result) == '0':
89                         JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] success." % tmp_msg, '')
90                     else:
91                         JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] failed." % tmp_msg, '')
92                         return 'false'
93                 else:
94                     NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
95                     return 'false'
96             except Exception as e:
97                 logger.error("[cancel_vl_list] error[%s]!" % e.message)
98                 logger.error(traceback.format_exc())
99                 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] Failed." % tmp_msg, '')
100                 return 'false'
101         return 'true'
102
103     # delete SFC
104     def cancel_sfc_list(self):
105         array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
106         if not array_sfcinst:
107             logger.error("[cancel_sfc_list] no sfcinst attatch to ns_inst_id:%s" % self.ns_inst_id)
108             return
109         step_progress = 20 / len(array_sfcinst)
110         cur_progress = 30
111         for sfcinst in array_sfcinst:
112             tmp_msg = sfcinst.sfcid
113             try:
114                 ret = self.delete_sfc(tmp_msg)
115                 if ret[0] == 0:
116                     cur_progress += step_progress
117                     result = json.JSONDecoder().decode(ret[1]).get("result", "")
118                     if str(result) == '0':
119                         JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] success." % tmp_msg, '')
120                     else:
121                         JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] failed." % tmp_msg, '')
122                         return 'false'
123                 else:
124                     NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
125                     return 'false'
126             except Exception as e:
127                 logger.error("[cancel_sfc_list] error[%s]!" % e.message)
128                 logger.error(traceback.format_exc())
129                 JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] Failed." % tmp_msg, '')
130                 return 'false'
131         return 'true'
132
133     # delete Vnf
134     def cancel_vnf_list(self):
135         array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
136         if not array_vnfinst:
137             logger.error("[cancel_vnf_list] no vnfinst attatch to ns_inst_id:%s" % self.ns_inst_id)
138             return
139         step_progress = 20 / len(array_vnfinst)
140         cur_progress = 50
141         for vnfinst in array_vnfinst:
142             tmp_msg = vnfinst.nfinstid
143             try:
144                 self.delete_vnf(tmp_msg)
145                 cur_progress += step_progress
146                 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] success." % tmp_msg, '')
147             except Exception as e:
148                 logger.error("[cancel_vnf_list] error[%s]!" % e.message)
149                 logger.error(traceback.format_exc())
150                 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] Failed." % tmp_msg, '')
151                 return 'false'
152         return 'true'
153
154     def delete_vnf(self, nf_instid):
155         ret = call_from_ns_cancel_resource('vnf', nf_instid)
156         self.delete_resource(ret)
157
158     def delete_sfc(self, sfc_instid):
159         ret = call_from_ns_cancel_resource('sfc', sfc_instid)
160         return ret
161
162     def delete_vl(self, vl_instid):
163         ret = call_from_ns_cancel_resource('vl', vl_instid)
164         return ret
165
166     def delete_resource(self, result):
167         logger.debug("terminate_type=%s, result=%s", self.terminate_type, result)
168         if result[0] == 0:
169             job_info = json.JSONDecoder().decode(result[1])
170             vnfm_job_id = ignore_case_get(job_info, "jobid")
171             self.add_progress(5, "SEND_TERMINATE_REQ_SUCCESS")
172             if self.terminate_type == 'forceful':
173                 ret = wait_job_finish(self.vnfm_inst_id, self.job_id, vnfm_job_id,
174                                       progress_range=[10, 50],
175                                       timeout=self.terminate_timeout,
176                                       job_callback=TerminateNsService.wait_job_mode_callback, mode='1')
177                 if ret != JOB_MODEL_STATUS.FINISHED:
178                     logger.error('[NS terminate] VNFM terminate ns failed')
179                     NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
180                     raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
181         else:
182             logger.error('[NS terminate] VNFM terminate ns failed')
183             NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
184             raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
185
186     def exception(self):
187         NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
188         raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
189
190     def finaldata(self):
191         NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
192         JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
193
194     @staticmethod
195     def call_vnfm_to_cancel_resource(res_type, instid):
196         ret = call_from_ns_cancel_resource(res_type, instid)
197         return ret
198
199     def add_progress(self, progress, status_decs, error_code=""):
200         JobUtil.add_job_status(self.job_id, progress, status_decs, error_code)
201
202     @staticmethod
203     def wait_job_mode_callback(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
204         for job in jobs:
205             progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
206             if 255 == progress and '1' == kwargs['mode']:
207                 break
208             JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ''), job.get('errorcode', ''))
209
210         latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
211         if 255 == latest_progress and '1' == kwargs['mode']:
212             JobUtil.add_job_status(vnfo_job_id, progress_range[1], job_status.get('statusdescription', ''),
213                                    job_status.get('errorcode', ''))
214         else:
215             JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ''),
216                                    job_status.get('errorcode', ''))
217         if job_status['status'] in ('error', 'finished'):
218             return True, job_status['status']
219         return False, 'processing'
220
221     @staticmethod
222     def wait_job_finish_common_call_back(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
223         error_254 = False
224         for job in jobs:
225             progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
226             if 254 == progress:
227                 logger.debug("=========254==============")
228                 progress = 255
229                 error_254 = True
230             JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ""), job.get('errorcode', ""))
231         latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
232         if 254 == latest_progress:
233             logger.debug("=========254==============")
234             latest_progress = 255
235             error_254 = True
236         JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ""),
237                                job_status.get('errorcode', ""))
238         # return error_254
239         if error_254:
240             logger.debug("return 254")
241             return True, 'error_254'
242         if job_status['status'] in ('error', 'finished'):
243             return True, job_status['status']
244         return False, 'processing'
245
246     @staticmethod
247     def calc_progress_over_100(vnfm_progress, target_range=None):
248         if target_range is None:
249             target_range = [0, 100]
250         progress = int(vnfm_progress)
251         if progress > 100:
252             return progress
253         floor_progress = int(math.floor(float(target_range[1] - target_range[0]) / 100 * progress))
254         target_range = floor_progress + target_range[0]
255         return target_range