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.pub.database.models import NSInstModel, VLInstModel, FPInstModel, NfInstModel
21 from lcm.pub.exceptions import NSLCMException
22 from lcm.pub.msapi.nslcm import call_from_ns_cancel_resource
23 from lcm.pub.utils.jobutil import JobUtil
24 from lcm.pub.utils.values import ignore_case_get
25 from lcm.pub.utils import restcall
26 from lcm.ns.enum import OWNER_TYPE
27 from lcm.pub.database.models import PNFInstModel
28 from lcm.ns.biz.ns_lcm_op_occ import NsLcmOpOcc
32 logger = logging.getLogger(__name__)
35 class TerminateNsService(threading.Thread):
36 def __init__(self, ns_inst_id, job_id, request_data):
37 threading.Thread.__init__(self)
38 self.terminate_type = request_data.get('terminationType', 'GRACEFUL')
39 self.terminate_timeout = request_data.get('gracefulTerminationTimeout', 600)
41 self.ns_inst_id = ns_inst_id
42 self.occ_id = NsLcmOpOcc.create(ns_inst_id, "TERMINATE", "PROCESSING", False, request_data)
46 if not NSInstModel.objects.filter(id=self.ns_inst_id):
47 JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
48 NsLcmOpOcc.update(self.occ_id, "COMPLETED")
50 JobUtil.add_job_status(self.job_id, 10, "Starting terminate...", '')
52 self.cancel_sfc_list()
53 self.cancel_vnf_list()
55 self.cancel_pnf_list()
57 NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
58 JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
59 NsLcmOpOcc.update(self.occ_id, "COMPLETED")
60 except NSLCMException as e:
61 JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
62 NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.message)
63 except Exception as e:
64 logger.error(e.message)
65 logger.error(traceback.format_exc())
66 JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.")
67 NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.message)
69 def cancel_vl_list(self):
70 array_vlinst = VLInstModel.objects.filter(ownertype=OWNER_TYPE.NS, ownerid=self.ns_inst_id)
72 logger.info("[cancel_vl_list] no vlinst attatch to ns_inst_id: %s" % self.ns_inst_id)
74 step_progress = 20 / len(array_vlinst)
76 for vlinst in array_vlinst:
77 delete_result = "failed"
78 cur_progress += step_progress
80 ret = call_from_ns_cancel_resource('vl', vlinst.vlinstanceid)
82 result = json.JSONDecoder().decode(ret[1]).get("result", "")
83 if str(result) == '0':
84 delete_result = "success"
85 except Exception as e:
86 logger.error("[cancel_vl_list] error[%s]!" % e.message)
87 logger.error(traceback.format_exc())
88 job_msg = "Delete vlinst:[%s] %s." % (vlinst.vlinstanceid, delete_result)
89 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
91 def cancel_sfc_list(self):
92 array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
94 logger.info("[cancel_sfc_list] no sfcinst attatch to ns_inst_id: %s" % self.ns_inst_id)
96 step_progress = 20 / len(array_sfcinst)
98 for sfcinst in array_sfcinst:
99 cur_progress += step_progress
100 delete_result = "failed"
102 ret = call_from_ns_cancel_resource('sfc', sfcinst.sfcid)
104 result = json.JSONDecoder().decode(ret[1]).get("result", "")
105 if str(result) == '0':
106 delete_result = "success"
107 except Exception as e:
108 logger.error("[cancel_sfc_list] error[%s]!" % e.message)
109 logger.error(traceback.format_exc())
110 job_msg = "Delete sfcinst:[%s] %s." % (sfcinst.sfcid, delete_result)
111 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
113 def cancel_vnf_list(self):
114 array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
115 if not array_vnfinst:
116 logger.info("[cancel_vnf_list] no vnfinst attatch to ns_inst_id: %s" % self.ns_inst_id)
118 step_progress = 10 / len(array_vnfinst)
121 for vnfinst in array_vnfinst:
122 cur_progress += step_progress
123 delete_result = "failed"
126 vnf_job_id = self.delete_vnf(vnfinst.nfinstid)
128 delete_result = "deleting"
129 except Exception as e:
130 logger.error("[cancel_vnf_list] error[%s]!" % e.message)
131 logger.error(traceback.format_exc())
132 job_msg = "Delete vnfinst:[%s] %s." % (vnfinst.nfinstid, delete_result)
133 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
134 vnf_jobs.append((vnfinst.nfinstid, vnf_job_id))
136 for vnfinstid, vnfjobid in vnf_jobs:
138 cur_progress += step_progress
141 is_job_ok = self.wait_delete_vnf_job_finish(vnfjobid)
142 msg = "%s to delete VNF(%s)" % ("Succeed" if is_job_ok else "Failed", vnfinstid)
144 JobUtil.add_job_status(self.job_id, cur_progress, msg)
145 except Exception as e:
146 msg = "Exception occurs when delete VNF(%s)" % vnfinstid
148 JobUtil.add_job_status(self.job_id, cur_progress, msg)
150 def delete_vnf(self, nf_instid):
152 "terminationType": self.terminate_type
154 if self.terminate_timeout:
155 term_param["gracefulTerminationTimeout"] = int(self.terminate_timeout)
156 ret = call_from_ns_cancel_resource('vnf', nf_instid, term_param)
158 logger.error("Terminate VNF(%s) failed: %s", nf_instid, ret[1])
160 job_info = json.JSONDecoder().decode(ret[1])
161 vnf_job_id = ignore_case_get(job_info, "jobId")
164 def wait_delete_vnf_job_finish(self, vnf_job_id):
168 response_id, new_response_id = 0, 0
169 job_end_normal, job_timeout = False, True
170 while count < retry_count:
172 time.sleep(interval_second)
173 uri = "/api/nslcm/v1/jobs/%s?responseId=%s" % (vnf_job_id, response_id)
174 ret = restcall.req_by_msb(uri, "GET")
176 logger.error("Failed to query job: %s:%s", ret[2], ret[1])
178 job_result = json.JSONDecoder().decode(ret[1])
179 if "responseDescriptor" not in job_result:
180 logger.debug("No new progress after response_id(%s) in job(%s)", response_id, vnf_job_id)
182 progress = job_result["responseDescriptor"]["progress"]
183 new_response_id = job_result["responseDescriptor"]["responseId"]
184 job_desc = job_result["responseDescriptor"]["statusDescription"]
185 if new_response_id != response_id:
186 logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
187 response_id = new_response_id
189 if progress == JOB_ERROR:
191 logger.error("Job(%s) failed: %s", vnf_job_id, job_desc)
193 elif progress == 100:
194 job_end_normal, job_timeout = True, False
195 logger.info("Job(%s) ended normally", vnf_job_id)
198 logger.error("Job(%s) timeout", vnf_job_id)
199 return job_end_normal
201 def cancel_pnf_list(self):
202 pnfinst_list = PNFInstModel.objects.filter(nsInstances__contains=self.ns_inst_id)
203 if len(pnfinst_list) > 0:
205 step_progress = 5 / len(pnfinst_list)
206 for pnfinst in pnfinst_list:
207 delete_result = "fail"
209 ret = call_from_ns_cancel_resource('pnf', pnfinst.pnfId)
211 delete_result = "success"
212 except Exception as e:
213 logger.error("[cancel_pnf_list] error[%s]!" % e.message)
214 logger.error(traceback.format_exc())
215 job_msg = "Delete pnfinst:[%s] %s" % (pnfinst.pnfId, delete_result)
216 cur_progress += step_progress
217 JobUtil.add_job_status(self.job_id, cur_progress, job_msg)