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.
20 from lcm.jobs.const import JOB_INSTANCE_RESPONSE_ID_URI
21 from lcm.pub.database.models import NSInstModel, VLInstModel, FPInstModel, NfInstModel
22 from lcm.pub.exceptions import NSLCMException
23 from lcm.pub.msapi.nslcm import call_from_ns_cancel_resource
24 from lcm.pub.msapi import sdc_run_catalog
25 from lcm.pub.utils.jobutil import JobUtil
26 from lcm.pub.utils.values import ignore_case_get
27 from lcm.pub.utils import restcall
28 from lcm.ns.enum import OWNER_TYPE
29 from lcm.pub.database.models import PNFInstModel
30 from lcm.ns.biz.ns_lcm_op_occ import NsLcmOpOcc
31 from lcm.jobs.enum import JOB_PROGRESS
32 from lcm.ns.enum import NS_INST_STATUS
33 from lcm.workflows import build_in
35 logger = logging.getLogger(__name__)
38 class TerminateNsService(threading.Thread):
40 Terminate the NS instance
43 def __init__(self, ns_inst_id, job_id, request_data):
44 threading.Thread.__init__(self)
45 self.terminate_type = request_data.get('terminationType', 'GRACEFUL')
46 self.terminate_timeout = request_data.get('gracefulTerminationTimeout', 600)
48 self.ns_inst_id = ns_inst_id
49 self.occ_id = NsLcmOpOcc.create(ns_inst_id, "TERMINATE", "PROCESSING", False, request_data)
53 if not NSInstModel.objects.filter(id=self.ns_inst_id):
54 JobUtil.add_job_status(self.job_id, JOB_PROGRESS.FINISHED, "Need not terminate.", '')
55 NsLcmOpOcc.update(self.occ_id, "COMPLETED")
57 JobUtil.add_job_status(self.job_id, 10, "Starting terminate...", '')
58 NSInstModel.objects.filter(id=self.ns_inst_id).update(status=NS_INST_STATUS.TERMINATING)
60 self.cancel_sfc_list()
61 self.cancel_vnf_list()
63 self.cancel_pnf_list()
65 self.modify_package_state()
66 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='NOT_INSTANTIATED')
67 JobUtil.add_job_status(self.job_id, JOB_PROGRESS.FINISHED, "ns terminate ends.", '')
68 NsLcmOpOcc.update(self.occ_id, "COMPLETED")
69 except NSLCMException as e:
70 JobUtil.add_job_status(self.job_id, JOB_PROGRESS.ERROR, e.args[0])
71 NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.args[0])
72 build_in.post_deal(self.ns_inst_id, "false")
73 except Exception as e:
74 logger.error(e.args[0])
75 logger.error(traceback.format_exc())
76 JobUtil.add_job_status(self.job_id, JOB_PROGRESS.ERROR, "ns terminate fail.")
77 NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.args[0])
78 build_in.post_deal(self.ns_inst_id, "false")
80 def modify_package_state(self):
82 Update the state of NS instance model
85 ns_inst = NSInstModel.objects.filter(id=self.ns_inst_id)
86 ns_insts = NSInstModel.objects.filter(nspackage_id=ns_inst[0].nspackage_id)
87 if len(ns_insts) == 1:
88 sdc_run_catalog.modify_nsd_state(ns_inst[0].nspackage_id, 0)
90 def cancel_vl_list(self):
92 Delete list of VL related
95 array_vlinst = VLInstModel.objects.filter(ownertype=OWNER_TYPE.NS, ownerid=self.ns_inst_id)
97 logger.info("[cancel_vl_list] no vlinst attatch to ns_inst_id: %s" % self.ns_inst_id)
99 step_progress = 20 / len(array_vlinst)
101 for vlinst in array_vlinst:
102 delete_result = "failed"
103 cur_progress += step_progress
105 ret = call_from_ns_cancel_resource('vl', vlinst.vlinstanceid)
107 result = json.JSONDecoder().decode(ret[1]).get("result", "")
108 if str(result) == '0':
109 delete_result = "success"
110 except Exception as e:
111 logger.error("[cancel_vl_list] error[%s]!" % e.args[0])
112 logger.error(traceback.format_exc())
113 job_msg = "Delete vlinst:[%s] %s." % (vlinst.vlinstanceid, delete_result)
114 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
116 def cancel_sfc_list(self):
121 array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
122 if not array_sfcinst:
123 logger.info("[cancel_sfc_list] no sfcinst attatch to ns_inst_id: %s" % self.ns_inst_id)
125 step_progress = 20 / len(array_sfcinst)
127 for sfcinst in array_sfcinst:
128 cur_progress += step_progress
129 delete_result = "failed"
131 ret = call_from_ns_cancel_resource('sfc', sfcinst.sfcid)
133 result = json.JSONDecoder().decode(ret[1]).get("result", "")
134 if str(result) == '0':
135 delete_result = "success"
136 except Exception as e:
137 logger.error("[cancel_sfc_list] error[%s]!" % e.args[0])
138 logger.error(traceback.format_exc())
139 job_msg = "Delete sfcinst:[%s] %s." % (sfcinst.sfcid, delete_result)
140 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
142 def cancel_vnf_list(self):
144 Delete VNF instance list
147 array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
148 if not array_vnfinst:
149 logger.info("[cancel_vnf_list] no vnfinst attatch to ns_inst_id: %s" % self.ns_inst_id)
151 step_progress = 10 / len(array_vnfinst)
154 for vnfinst in array_vnfinst:
155 cur_progress += step_progress
156 delete_result = "failed"
159 vnf_job_id = self.delete_vnf(vnfinst.nfinstid)
161 delete_result = "deleting"
162 except Exception as e:
163 logger.error("[cancel_vnf_list] error[%s]!" % e.args[0])
164 logger.error(traceback.format_exc())
165 job_msg = "Delete vnfinst:[%s] %s." % (vnfinst.nfinstid, delete_result)
166 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
167 vnf_jobs.append((vnfinst.nfinstid, vnf_job_id))
168 self.wait_delete_vnfs(vnf_jobs, cur_progress, step_progress)
170 def wait_delete_vnfs(self, vnf_jobs, cur_progress, step_progress):
171 for vnfinstid, vnfjobid in vnf_jobs:
173 cur_progress += step_progress
176 is_job_ok = self.wait_delete_vnf_job_finish(vnfjobid)
177 msg = "%s to delete VNF(%s)" % \
178 ("Succeed" if is_job_ok else "Failed", vnfinstid)
180 JobUtil.add_job_status(self.job_id, cur_progress, msg)
181 except Exception as e:
182 msg = "Exception occurs(%s) when delete VNF(%s)" % (e, vnfinstid)
184 JobUtil.add_job_status(self.job_id, cur_progress, msg)
186 def delete_vnf(self, nf_instid):
193 "terminationType": self.terminate_type
195 if self.terminate_timeout:
196 term_param["gracefulTerminationTimeout"] = int(self.terminate_timeout)
197 ret = call_from_ns_cancel_resource('vnf', nf_instid, term_param)
199 logger.error("Terminate VNF(%s) failed: %s", nf_instid, ret[1])
201 job_info = json.JSONDecoder().decode(ret[1])
202 vnf_job_id = ignore_case_get(job_info, "jobId")
205 def wait_delete_vnf_job_finish(self, vnf_job_id):
209 response_id, new_response_id = 0, 0
210 job_end_normal, job_timeout = False, True
211 while count < retry_count:
213 time.sleep(interval_second)
214 uri = JOB_INSTANCE_RESPONSE_ID_URI % (vnf_job_id, response_id)
215 ret = restcall.req_by_msb(uri, "GET")
217 logger.error("Failed to query job: %s:%s", ret[2], ret[1])
219 job_result = json.JSONDecoder().decode(ret[1])
220 if "responseDescriptor" not in job_result:
221 logger.debug("No new progress after response_id(%s) in job(%s)", response_id, vnf_job_id)
223 progress = job_result["responseDescriptor"]["progress"]
224 new_response_id = job_result["responseDescriptor"]["responseId"]
225 job_desc = job_result["responseDescriptor"]["statusDescription"]
226 if new_response_id != response_id:
227 logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
228 response_id = new_response_id
230 if progress == JOB_PROGRESS.ERROR:
232 logger.error("Job(%s) failed: %s", vnf_job_id, job_desc)
234 elif progress == JOB_PROGRESS.FINISHED:
235 job_end_normal, job_timeout = True, False
236 logger.info("Job(%s) ended normally", vnf_job_id)
239 logger.error("Job(%s) timeout", vnf_job_id)
240 return job_end_normal
242 def cancel_pnf_list(self):
247 pnfinst_list = PNFInstModel.objects.filter(nsInstances__contains=self.ns_inst_id)
248 if len(pnfinst_list) > 0:
250 step_progress = 5 / len(pnfinst_list)
251 for pnfinst in pnfinst_list:
252 delete_result = "fail"
254 ret = call_from_ns_cancel_resource('pnf', pnfinst.pnfId)
256 delete_result = "success"
257 except Exception as e:
258 logger.error("[cancel_pnf_list] error[%s]!" % e.args[0])
259 logger.error(traceback.format_exc())
260 job_msg = "Delete pnfinst:[%s] %s" % (pnfinst.pnfId, delete_result)
261 cur_progress += step_progress
262 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)