update function of ns_heal
[vfc/nfvo/lcm.git] / lcm / ns / biz / ns_heal.py
1 # Copyright 2017 Intel 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 datetime
15 import logging
16 import threading
17 import time
18 import traceback
19
20 from lcm.ns.const import NS_INST_STATUS
21 from lcm.pub.database.models import JobModel, NSInstModel, NfInstModel, VNFCInstModel, VmInstModel
22 from lcm.pub.exceptions import NSLCMException
23 from lcm.pub.utils.jobutil import JobUtil, JOB_MODEL_STATUS
24 from lcm.pub.utils.values import ignore_case_get
25 from lcm.ns_vnfs.biz.heal_vnfs import NFHealService
26
27 JOB_ERROR = 255
28 logger = logging.getLogger(__name__)
29
30
31 class NSHealService(threading.Thread):
32     def __init__(self, ns_instance_id, request_data, job_id):
33         super(NSHealService, self).__init__()
34         self.ns_instance_id = ns_instance_id
35         self.request_data = request_data
36         self.job_id = job_id
37
38         self.heal_vnf_data = ''
39         self.heal_ns_data = ''
40
41     def run(self):
42         try:
43             self.do_biz()
44         except NSLCMException as e:
45             JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
46         except:
47             logger.error(traceback.format_exc())
48             JobUtil.add_job_status(self.job_id, JOB_ERROR, 'ns heal fail')
49
50     def do_biz(self):
51         self.update_job(1, desc='ns heal start')
52         self.get_and_check_params()
53         self.update_ns_status(NS_INST_STATUS.HEALING)
54         self.do_heal()
55         self.update_ns_status(NS_INST_STATUS.ACTIVE)
56         self.update_job(100, desc='ns heal success')
57
58     def get_and_check_params(self):
59         ns_info = NSInstModel.objects.filter(id=self.ns_instance_id)
60         if not ns_info:
61             logger.error('NS [id=%s] does not exist' % self.ns_instance_id)
62             raise NSLCMException(
63                 'NS [id=%s] does not exist' % self.ns_instance_id)
64         self.heal_ns_data = ignore_case_get(self.request_data, 'healNsData')
65         self.heal_vnf_data = ignore_case_get(self.request_data, 'healVnfData')
66         if self.heal_ns_data and self.heal_vnf_data:
67             logger.error('healNsData and healVnfData can not exist together')
68             raise NSLCMException(
69                 'healNsData and healVnfData can not exist together')
70         if not self.heal_ns_data and not self.heal_vnf_data:
71             logger.error(
72                 'healNsData and healVnfData parameters does not exist or value is incorrect.')
73             raise NSLCMException(
74                 'healNsData and healVnfData parameters does not exist or value is incorrect.')
75
76     def do_heal(self):
77         if self.heal_vnf_data:
78             vnf_heal_params = self.prepare_vnf_heal_params(self.heal_vnf_data)
79             status = self.do_vnf_or_ns_heal(vnf_heal_params, 15)
80             if status is JOB_MODEL_STATUS.FINISHED:
81                 logger.info('nf[%s] heal handle end' %
82                             vnf_heal_params.get('vnfInstanceId'))
83                 self.update_job(90,
84                                 desc='nf[%s] heal handle end' % vnf_heal_params.get('vnfInstanceId'))
85             else:
86                 logger.error('nf heal failed')
87                 raise NSLCMException('nf heal failed')
88         else:
89             ns_heal_params = self.prepare_ns_heal_params(self.heal_ns_data)
90             for ns_heal_param in ns_heal_params:
91                 status = self.do_vnf_or_ns_heal(ns_heal_param, 15)
92                 if status is JOB_MODEL_STATUS.FINISHED:
93                     logger.info('nf[%s] heal handle end' %
94                                 ns_heal_param.get('vnfInstanceId'))
95                     self.update_job(90,
96                                     desc='nf[%s] heal handle end' % ns_heal_param.get('vnfInstanceId'))
97                 else:
98                     logger.error('nf heal failed')
99                     raise NSLCMException('nf heal failed')
100
101     def do_vnf_or_ns_heal(self, heal_param, progress):
102         instance_id = heal_param.get('vnfInstanceId')
103         nf_service = NFHealService(instance_id, heal_param)
104         nf_service.start()
105         self.update_job(
106             progress, desc='nf[%s] heal handle start' % instance_id)
107         status = self.wait_job_finish(nf_service.job_id)
108         return status
109
110     def prepare_ns_heal_params(self, ns_data):
111         degree_healing = ignore_case_get(ns_data, 'degreeHealing')
112         if not degree_healing:
113             logger.error('degreeHealing does not exist.')
114             raise NSLCMException('degreeHealing does not exist.')
115         ns_instance_id = self.ns_instance_id
116         cause = ''
117         action = ignore_case_get(ns_data, 'actionsHealing')
118         if degree_healing == "HEAL_RESTORE":
119             ns_inst_infos = NfInstModel.objects.filter(
120                 ns_inst_id=self.ns_instance_id)
121             if not ns_inst_infos.exists():
122                 raise NSLCMException(
123                     'NSInsts(%s) does not exist' % self.ns_instance_id)
124
125             result_arr = []
126             for ns_inst_info in ns_inst_infos:
127                 vnfc_insts = VNFCInstModel.objects.filter(
128                     nfinstid=ns_inst_info.nfinstid)
129                 # If a condition is not met, will it all terminate?
130                 if not vnfc_insts.exists():
131                     raise NSLCMException(
132                         'vnfcinsts(%s) does not exist' % ns_inst_info.nfinstid)
133                 for vnfc_inst in vnfc_insts:
134                     vm_id = vnfc_inst.vmid
135                     vdu_id = vnfc_inst.vduid
136                     vm_inst_info = VmInstModel.objects.filter(vmid=vm_id)
137                     if not vm_inst_info.exists():
138                         raise NSLCMException(
139                             'vminstinfo(%s) does not exist' % vm_id)
140                     vm_name = vm_inst_info[0].vmname
141
142                     result = {
143                         "vnfInstanceId": ns_instance_id,
144                         "cause": cause,
145                         "additionalParams": {
146                             "action": action,
147                             "actionvminfo": {
148                                 "vmid": vm_id,
149                                 "vduid": vdu_id,
150                                 "vmname": vm_name
151                             }
152                         }
153                     }
154                     result_arr.append(result)
155             return result_arr
156         else:
157             logger.error(
158                 'The degree of healing dose not exist or value is incorrect.')
159             raise NSLCMException(
160                 'The degree of healing dose not exist or value is incorrect.')
161
162     def prepare_vnf_heal_params(self, vnf_data):
163         vnf_instance_id = ignore_case_get(vnf_data, 'vnfInstanceId')
164         if not vnf_instance_id:
165             logger.error('vnfinstanceid does not exist or value is incorrect.')
166             raise NSLCMException(
167                 'vnfinstanceid does not exist or value is incorrect.')
168         cause = ignore_case_get(vnf_data, 'cause')
169         additional_params = ignore_case_get(vnf_data, 'additionalParams')
170         action = ignore_case_get(additional_params, 'action')
171         action_vm_info = ignore_case_get(additional_params, 'actionvminfo')
172         vm_id = ignore_case_get(action_vm_info, 'vmid')
173         vdu_id = ignore_case_get(action_vm_info, 'vduid')
174         vm_name = ignore_case_get(action_vm_info, 'vmname')
175
176         result = {
177             "vnfInstanceId": vnf_instance_id,
178             "cause": cause,
179             "additionalParams": {
180                 "action": action,
181                 "actionvminfo": {
182                     "vmid": vm_id,
183                     "vduid": vdu_id,
184                     "vmname": vm_name
185                 }
186             }
187         }
188         return result
189
190     @staticmethod
191     def wait_job_finish(sub_job_id, timeout=3600):
192         query_interval = 2
193         start_time = end_time = datetime.datetime.now()
194         while (end_time - start_time).seconds < timeout:
195             job_result = JobModel.objects.get(jobid=sub_job_id)
196             time.sleep(query_interval)
197             end_time = datetime.datetime.now()
198             if job_result.progress == 100:
199                 return JOB_MODEL_STATUS.FINISHED
200             elif job_result.progress > 100:
201                 return JOB_MODEL_STATUS.ERROR
202             else:
203                 continue
204         return JOB_MODEL_STATUS.TIMEOUT
205
206     def update_job(self, progress, desc=''):
207         JobUtil.add_job_status(self.job_id, progress, desc)
208
209     def update_ns_status(self, status):
210         NSInstModel.objects.filter(
211             id=self.ns_instance_id).update(status=status)