1 # Copyright 2016 ZTE Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
22 from lcm.ns.vnfs.wait_job import wait_job_finish
23 from lcm.pub.database.models import NSInstModel, VLInstModel, FPInstModel, NfInstModel
24 from lcm.pub.exceptions import NSLCMException
25 from lcm.pub.msapi.nslcm import call_from_ns_cancel_resource
26 from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil
27 from lcm.pub.utils.values import ignore_case_get
30 # [delete vnf try times]
32 logger = logging.getLogger(__name__)
35 class TerminateNsService(threading.Thread):
36 def __init__(self, ns_inst_id, terminate_type, terminate_timeout, job_id):
37 threading.Thread.__init__(self)
38 self.ns_inst_id = ns_inst_id
39 self.terminate_type = terminate_type
40 self.terminate_timeout = terminate_timeout
42 self.vnfm_inst_id = ''
47 except NSLCMException as e:
48 JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
50 logger.error(traceback.format_exc())
51 JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.", '')
54 if not self.check_data():
55 JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
58 self.cancel_sfc_list()
59 self.cancel_vnf_list()
66 JobUtil.add_job_status(self.job_id, 0, "TERMINATING...", '')
67 ns_inst = NSInstModel.objects.filter(id=self.ns_inst_id)
68 if not ns_inst.exists():
69 logger.warn('ns instance [%s] does not exist.' % self.ns_inst_id)
71 JobUtil.add_job_status(self.job_id, 10, "Ns cancel: check ns_inst_id success", '')
75 def cancel_vl_list(self):
76 array_vlinst = VLInstModel.objects.filter(ownertype='2', ownerid=self.ns_inst_id)
78 logger.error("[cancel_vl_list] no vlinst attatch to ns_inst_id:%s" % self.ns_inst_id)
80 step_progress = 20 / len(array_vlinst)
82 for vlinst in array_vlinst:
83 tmp_msg = vlinst.vlinstanceid
85 ret = self.delete_vl(tmp_msg)
87 cur_progress += step_progress
88 result = json.JSONDecoder().decode(ret[1]).get("result", "")
89 if str(result) == '0':
90 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] success." % tmp_msg, '')
92 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] failed." % tmp_msg, '')
95 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
97 except Exception as e:
98 logger.error("[cancel_vl_list] error[%s]!" % e.message)
99 logger.error(traceback.format_exc())
100 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] Failed." % tmp_msg, '')
105 def cancel_sfc_list(self):
106 array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
107 if not array_sfcinst:
108 logger.error("[cancel_sfc_list] no sfcinst attatch to ns_inst_id:%s" % self.ns_inst_id)
110 step_progress = 20 / len(array_sfcinst)
112 for sfcinst in array_sfcinst:
113 tmp_msg = sfcinst.sfcid
115 ret = self.delete_sfc(tmp_msg)
117 cur_progress += step_progress
118 result = json.JSONDecoder().decode(ret[1]).get("result", "")
119 if str(result) == '0':
120 JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] success." % tmp_msg, '')
122 JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] failed." % tmp_msg, '')
125 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
127 except Exception as e:
128 logger.error("[cancel_sfc_list] error[%s]!" % e.message)
129 logger.error(traceback.format_exc())
130 JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] Failed." % tmp_msg, '')
135 def cancel_vnf_list(self):
136 array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
137 if not array_vnfinst:
138 logger.error("[cancel_vnf_list] no vnfinst attatch to ns_inst_id:%s" % self.ns_inst_id)
140 step_progress = 20 / len(array_vnfinst)
142 for vnfinst in array_vnfinst:
143 tmp_msg = vnfinst.nfinstid
145 self.delete_vnf(tmp_msg)
146 cur_progress += step_progress
147 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] success." % tmp_msg, '')
148 except Exception as e:
149 logger.error("[cancel_vnf_list] error[%s]!" % e.message)
150 logger.error(traceback.format_exc())
151 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vnfinst:[%s] Failed." % tmp_msg, '')
155 def delete_vnf(self, nf_instid):
156 ret = call_from_ns_cancel_resource('vnf', nf_instid)
157 self.delete_resource(ret)
159 def delete_sfc(self, sfc_instid):
160 ret = call_from_ns_cancel_resource('sfc', sfc_instid)
163 def delete_vl(self, vl_instid):
164 ret = call_from_ns_cancel_resource('vl', vl_instid)
167 def delete_resource(self, result):
168 logger.debug("terminate_type=%s, result=%s", self.terminate_type, result)
170 job_info = json.JSONDecoder().decode(result[1])
171 vnfm_job_id = ignore_case_get(job_info, "jobid")
172 self.add_progress(5, "SEND_TERMINATE_REQ_SUCCESS")
173 if self.terminate_type == 'forceful':
174 ret = wait_job_finish(self.vnfm_inst_id, self.job_id, vnfm_job_id,
175 progress_range=[10, 50],
176 timeout=self.terminate_timeout,
177 job_callback=TerminateNsService.wait_job_mode_callback, mode='1')
178 if ret != JOB_MODEL_STATUS.FINISHED:
179 logger.error('[NS terminate] VNFM terminate ns failed')
180 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
181 raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
183 logger.error('[NS terminate] VNFM terminate ns failed')
184 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
185 raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
188 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
189 raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
192 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
193 JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
196 def call_vnfm_to_cancel_resource(res_type, instid):
197 ret = call_from_ns_cancel_resource(res_type, instid)
200 def add_progress(self, progress, status_decs, error_code=""):
201 JobUtil.add_job_status(self.job_id, progress, status_decs, error_code)
204 def wait_job_mode_callback(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
206 progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
207 if 255 == progress and '1' == kwargs['mode']:
209 JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ''), job.get('errorcode', ''))
211 latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
212 if 255 == latest_progress and '1' == kwargs['mode']:
213 JobUtil.add_job_status(vnfo_job_id, progress_range[1], job_status.get('statusdescription', ''),
214 job_status.get('errorcode', ''))
216 JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ''),
217 job_status.get('errorcode', ''))
218 if job_status['status'] in ('error', 'finished'):
219 return True, job_status['status']
220 return False, 'processing'
223 def wait_job_finish_common_call_back(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
226 progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
228 logger.debug("=========254==============")
231 JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ""), job.get('errorcode', ""))
232 latest_progress = TerminateNsService.calc_progress_over_100(job_status['progress'], progress_range)
233 if 254 == latest_progress:
234 logger.debug("=========254==============")
235 latest_progress = 255
237 JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ""),
238 job_status.get('errorcode', ""))
241 logger.debug("return 254")
242 return True, 'error_254'
243 if job_status['status'] in ('error', 'finished'):
244 return True, job_status['status']
245 return False, 'processing'
248 def calc_progress_over_100(vnfm_progress, target_range=None):
249 if target_range is None:
250 target_range = [0, 100]
251 progress = int(vnfm_progress)
254 floor_progress = int(math.floor(float(target_range[1] - target_range[0]) / 100 * progress))
255 target_range = floor_progress + target_range[0]