Merge "Fix URL in VIM and VNFM query"
[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 threading
17 import time
18 import traceback
19
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.const import OWNER_TYPE
27
28 JOB_ERROR = 255
29
30 logger = logging.getLogger(__name__)
31
32
33 class TerminateNsService(threading.Thread):
34     def __init__(self, ns_inst_id, terminate_type, terminate_timeout, job_id):
35         threading.Thread.__init__(self)
36         self.ns_inst_id = ns_inst_id
37         self.terminate_type = terminate_type
38         self.terminate_timeout = terminate_timeout
39         self.job_id = job_id
40
41     def run(self):
42         try:
43             if not NSInstModel.objects.filter(id=self.ns_inst_id):
44                 JobUtil.add_job_status(self.job_id, 100, "Need not terminate.", '')
45                 return
46             JobUtil.add_job_status(self.job_id, 10, "Starting terminate...", '')
47
48             self.cancel_sfc_list()
49             self.cancel_vnf_list()
50             self.cancel_vl_list()
51
52             NSInstModel.objects.filter(id=self.ns_inst_id).update(status='null')
53             JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
54         except NSLCMException as e:
55             JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
56         except:
57             logger.error(traceback.format_exc())
58             JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.")
59
60     def cancel_vl_list(self):
61         array_vlinst = VLInstModel.objects.filter(ownertype=OWNER_TYPE.NS, ownerid=self.ns_inst_id)
62         if not array_vlinst:
63             logger.info("[cancel_vl_list] no vlinst attatch to ns_inst_id: %s" % self.ns_inst_id)
64             return
65         step_progress = 20 / len(array_vlinst)
66         cur_progress = 70
67         for vlinst in array_vlinst:
68             delete_result = "failed"
69             cur_progress += step_progress
70             try:
71                 ret = call_from_ns_cancel_resource('vl', vlinst.vlinstanceid)
72                 if ret[0] == 0:
73                     result = json.JSONDecoder().decode(ret[1]).get("result", "")
74                     if str(result) == '0':
75                         delete_result = "success"
76             except Exception as e:
77                 logger.error("[cancel_vl_list] error[%s]!" % e.message)
78                 logger.error(traceback.format_exc())
79             job_msg = "Delete vlinst:[%s] %s." % (vlinst.vlinstanceid, delete_result)
80             JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
81
82     def cancel_sfc_list(self):
83         array_sfcinst = FPInstModel.objects.filter(nsinstid=self.ns_inst_id)
84         if not array_sfcinst:
85             logger.info("[cancel_sfc_list] no sfcinst attatch to ns_inst_id: %s" % self.ns_inst_id)
86             return
87         step_progress = 20 / len(array_sfcinst)
88         cur_progress = 30
89         for sfcinst in array_sfcinst:
90             cur_progress += step_progress
91             delete_result = "failed"
92             try:
93                 ret = call_from_ns_cancel_resource('sfc', sfcinst.sfcid)
94                 if ret[0] == 0:
95                     result = json.JSONDecoder().decode(ret[1]).get("result", "")
96                     if str(result) == '0':
97                         delete_result = "success"
98             except Exception as e:
99                 logger.error("[cancel_sfc_list] error[%s]!" % e.message)
100                 logger.error(traceback.format_exc())
101             job_msg = "Delete sfcinst:[%s] %s." % (sfcinst.sfcid, delete_result)
102             JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
103
104     def cancel_vnf_list(self):
105         array_vnfinst = NfInstModel.objects.filter(ns_inst_id=self.ns_inst_id)
106         if not array_vnfinst:
107             logger.info("[cancel_vnf_list] no vnfinst attatch to ns_inst_id: %s" % self.ns_inst_id)
108             return
109         step_progress = 20 / len(array_vnfinst)
110         cur_progress = 50
111         for vnfinst in array_vnfinst:
112             cur_progress += step_progress
113             delete_result = "failed"
114             try:
115                 if self.delete_vnf(vnfinst.nfinstid):
116                     delete_result = "success"
117             except Exception as e:
118                 logger.error("[cancel_vnf_list] error[%s]!" % e.message)
119                 logger.error(traceback.format_exc())
120             job_msg = "Delete vnfinst:[%s] %s." % (vnfinst.nfinstid, delete_result)
121             JobUtil.add_job_status(self.job_id, cur_progress, job_msg)
122
123     def delete_vnf(self, nf_instid):
124         ret = call_from_ns_cancel_resource('vnf', nf_instid)
125         if ret[0] != 0:
126             return False
127         job_info = json.JSONDecoder().decode(ret[1])
128         vnf_job_id = ignore_case_get(job_info, "jobid")
129         return self.wait_delete_vnf_job_finish(vnf_job_id)
130
131     def wait_delete_vnf_job_finish(self, vnf_job_id):
132         count = 0
133         retry_count = 30
134         interval_second = 1
135         response_id, new_response_id = 0, 0
136         job_end_normal, job_timeout = False, True
137         while count < retry_count:
138             count = count + 1
139             time.sleep(interval_second)
140             uri = "/api/nslcm/v1/jobs/%s?responseId=%s" % (vnf_job_id, response_id)
141             ret = restcall.req_by_msb(uri, "GET")
142             if ret[0] != 0:
143                 logger.error("Failed to query job: %s:%s", ret[2], ret[1])
144                 continue
145             job_result = json.JSONDecoder().decode(ret[1])
146             if "responseDescriptor" not in job_result:
147                 logger.error("Job(%s) does not exist.", vnf_job_id)
148                 continue
149             progress = job_result["responseDescriptor"]["progress"]
150             new_response_id = job_result["responseDescriptor"]["responseId"]
151             job_desc = job_result["responseDescriptor"]["statusDescription"]
152             if new_response_id != response_id:
153                 logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
154                 response_id = new_response_id
155                 count = 0
156             if progress == JOB_ERROR:
157                 job_timeout = False
158                 logger.error("Job(%s) failed: %s", vnf_job_id, job_desc)
159                 break
160             elif progress == 100:
161                 job_end_normal, job_timeout = True, False
162                 logger.info("Job(%s) ended normally", vnf_job_id)
163                 break
164         if job_timeout:
165             logger.error("Job(%s) timeout", vnf_job_id)
166         return job_end_normal