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.
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
29 # [delete vnf try times]
31 logger = logging.getLogger(__name__)
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
41 self.vnfm_inst_id = ''
46 except NSLCMException as e:
47 JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
49 logger.error(traceback.format_exc())
50 JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.", '')
53 if not self.check_data():
54 JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
57 self.cancel_sfc_list()
58 self.cancel_vnf_list()
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)
70 JobUtil.add_job_status(self.job_id, 10, "Ns cancel: check ns_inst_id success", '')
74 def cancel_vl_list(self):
75 array_vlinst = VLInstModel.objects.filter(ownertype='2', ownerid=self.ns_inst_id)
77 logger.error("[cancel_vl_list] no vlinst attatch to ns_inst_id:%s" % self.ns_inst_id)
79 step_progress = 20 / len(array_vlinst)
81 for vlinst in array_vlinst:
82 tmp_msg = vlinst.vlinstanceid
84 ret = self.delete_vl(tmp_msg)
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, '')
91 JobUtil.add_job_status(self.job_id, cur_progress, "Delete vlinst:[%s] failed." % tmp_msg, '')
94 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
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, '')
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)
109 step_progress = 20 / len(array_sfcinst)
111 for sfcinst in array_sfcinst:
112 tmp_msg = sfcinst.sfcid
114 ret = self.delete_sfc(tmp_msg)
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, '')
121 JobUtil.add_job_status(self.job_id, cur_progress, "Delete sfcinst:[%s] failed." % tmp_msg, '')
124 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
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, '')
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)
139 step_progress = 20 / len(array_vnfinst)
141 for vnfinst in array_vnfinst:
142 tmp_msg = vnfinst.nfinstid
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, '')
154 def delete_vnf(self, nf_instid):
155 ret = call_from_ns_cancel_resource('vnf', nf_instid)
156 self.delete_resource(ret)
158 def delete_sfc(self, sfc_instid):
159 ret = call_from_ns_cancel_resource('sfc', sfc_instid)
162 def delete_vl(self, vl_instid):
163 ret = call_from_ns_cancel_resource('vl', vl_instid)
166 def delete_resource(self, result):
167 logger.debug("terminate_type=%s, result=%s", self.terminate_type, result)
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")
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")
187 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='FAILED')
188 raise NSLCMException("DELETE_NS_RESOURCE_FAILED")
191 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
192 JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
195 def call_vnfm_to_cancel_resource(res_type, instid):
196 ret = call_from_ns_cancel_resource(res_type, instid)
199 def add_progress(self, progress, status_decs, error_code=""):
200 JobUtil.add_job_status(self.job_id, progress, status_decs, error_code)
203 def wait_job_mode_callback(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
205 progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
206 if 255 == progress and '1' == kwargs['mode']:
208 JobUtil.add_job_status(vnfo_job_id, progress, job.get('statusdescription', ''), job.get('errorcode', ''))
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', ''))
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'
222 def wait_job_finish_common_call_back(vnfo_job_id, vnfm_job_id, job_status, jobs, progress_range, **kwargs):
225 progress = TerminateNsService.calc_progress_over_100(job['progress'], progress_range)
227 logger.debug("=========254==============")
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
236 JobUtil.add_job_status(vnfo_job_id, latest_progress, job_status.get('statusdescription', ""),
237 job_status.get('errorcode', ""))
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'
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)
253 floor_progress = int(math.floor(float(target_range[1] - target_range[0]) / 100 * progress))
254 target_range = floor_progress + target_range[0]