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