1 # Copyright (C) 2018 Verizon. All Rights Reserved.
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.
19 from threading import Thread
21 from lcm.pub.database.models import NfInstModel
22 from lcm.pub.database.models import VmInstModel
23 from lcm.pub.database.models import VNFCInstModel
24 from lcm.pub.exceptions import NFLCMException
25 from lcm.pub.exceptions import NFLCMExceptionConflict
26 from lcm.pub.utils.jobutil import JobUtil
27 from lcm.pub.utils.notificationsutil import NotificationsUtil
28 from lcm.pub.utils.timeutil import now_time
29 from lcm.pub.utils.values import ignore_case_get
30 from lcm.pub.vimapi import adaptor
31 from lcm.nf.biz.grant_vnf import grant_resource
32 from lcm.nf.const import VNF_STATUS, GRANT_TYPE
33 from lcm.nf.const import OPERATION_STATE_TYPE, LCM_NOTIFICATION_STATUS
34 from lcm.nf.const import CHANGE_TYPE, OPERATION_TYPE, HEAL_ACTION_TYPE
35 from lcm.nf.const import OPERATION_TASK
36 from lcm.nf.const import SUB_OPERATION_TASK
37 from lcm.nf.biz import common
38 from .operate_vnf_lcm_op_occ import VnfLcmOpOcc
41 logger = logging.getLogger(__name__)
44 class HealVnf(Thread):
45 def __init__(self, data, nf_inst_id, job_id):
46 super(HealVnf, self).__init__()
48 self.nf_inst_id = nf_inst_id
50 self.affectedvm = ignore_case_get(
57 # TODO: Check if we could move the action param into the list of affectedvm structure
58 self.action = ignore_case_get(
66 if self.action == HEAL_ACTION_TYPE.START:
67 self.grant_type = GRANT_TYPE.HEAL_CREATE
68 elif self.action == HEAL_ACTION_TYPE.RESTART:
69 self.grant_type = GRANT_TYPE.HEAL_RESTART
70 self.lcm_op_occ = VnfLcmOpOcc(
71 vnf_inst_id=nf_inst_id,
73 operation=OPERATION_TYPE.HEAL,
74 task=OPERATION_TASK.HEAL
81 self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.STARTING)
84 sub_operation=SUB_OPERATION_TASK.GRANTED,
85 operation_state=OPERATION_STATE_TYPE.PROCESSING
87 self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.PROCESSING)
89 JobUtil.add_job_status(self.job_id, 100, "Heal Vnf success.")
90 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
91 status='INSTANTIATED',
95 LCM_NOTIFICATION_STATUS.RESULT,
96 OPERATION_STATE_TYPE.COMPLETED
99 sub_operation=SUB_OPERATION_TASK.SUCCESS,
100 operation_state=OPERATION_STATE_TYPE.COMPLETED
102 except NFLCMException as e:
103 logger.error(e.args[0])
104 self.vnf_heal_failed_handle(e.args[0])
105 except Exception as e:
106 logger.error(e.args[0])
107 logger.error(traceback.format_exc())
108 self.vnf_heal_failed_handle(e.args[0])
111 logger.debug("Start pre deal for VNF heal_vnf task")
113 vnf_is_in_processing, vnf_op = self.lcm_op_occ.is_in_processing()
114 if vnf_is_in_processing:
115 raise NFLCMExceptionConflict('VNF(%s) %s in processing.' % (
116 self.nf_inst_id, vnf_op
118 self.lcm_op_occ.add()
121 if self.action not in (HEAL_ACTION_TYPE.START, HEAL_ACTION_TYPE.RESTART):
122 raise NFLCMException("Action should be %s or %s" % (HEAL_ACTION_TYPE.START, HEAL_ACTION_TYPE.RESTART))
124 self.vm_id = ignore_case_get(self.affectedvm, "vmid")
125 self.vdu_id = ignore_case_get(self.affectedvm, "vduid")
126 self.vm_name = ignore_case_get(self.affectedvm, "vmname")
127 if not (self.vm_id and self.vdu_id and self.vm_name):
128 raise NFLCMException("VM identifiers is not present in request.")
130 self.vnf_insts = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
131 self.vnfd_info = json.loads(self.vnf_insts[0].vnfd_model)
133 def apply_grant(self):
134 if self.action == HEAL_ACTION_TYPE.RESTART:
135 self.vdu = VmInstModel.objects.filter(instid=self.nf_inst_id, resourceid=self.vm_id)
137 raise NFLCMException("VNF Vm(%s) does not exist." % self.vm_id)
138 self.vimid = self.vdu[0].vimid
139 self.tenant = self.vdu[0].tenant
140 logger.debug("Get heal vnf vm(%s,%s) info successfully.", self.vm_id, self.vm_name)
141 JobUtil.add_job_status(self.job_id, 20, 'Nf Healing get vnf vm info finish')
144 vdus = ignore_case_get(self.vnfd_info, "vdus")
145 self.vdu = [elem for elem in vdus if ignore_case_get(elem, "vdu_id") == self.vdu_id]
147 raise NFLCMException("VNF Vdu(%s) does not exist." % self.vdu_id)
148 apply_result = grant_resource(data=self.data, nf_inst_id=self.nf_inst_id, job_id=self.job_id,
149 grant_type=self.grant_type, vdus=self.vdu)
151 self.vimid = ignore_case_get(apply_result, "vimid"),
152 self.tenant = ignore_case_get(apply_result, "tenant")
153 logger.info("Grant resource, response: %s" % apply_result)
154 JobUtil.add_job_status(self.job_id, 20, 'Nf Healing grant_resource finish')
156 def heal_resource(self):
157 logger.info('Heal resource begin')
158 data = {'action': self.action, 'vimid': self.vimid, 'tenant': self.tenant}
159 adaptor.heal_vim_res(self.vdu, self.vnfd_info, self.do_notify, data, json.loads(self.vnf_insts[0].vimInfo), json.loads(self.vnf_insts[0].resInfo))
160 logger.info('Heal resource complete')
162 def do_notify(self, res_type, ret):
163 logger.info('Creating [%s] resource' % res_type)
164 resource_save_method = getattr(common, res_type + '_save')
165 resource_save_method(self.job_id, self.nf_inst_id, ret)
167 def vnf_heal_failed_handle(self, error_msg):
168 logger.error('VNF Healing failed, detail message: %s' % error_msg)
169 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
170 status=VNF_STATUS.FAILED,
171 lastuptime=now_time()
173 self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.FAILED, error_msg)
174 JobUtil.add_job_status(self.job_id, 255, error_msg)
176 sub_operation=SUB_OPERATION_TASK.ERROR,
177 operation_state=OPERATION_STATE_TYPE.FAILED,
184 def lcm_notify(self, status, opState, err=None):
185 notification_content = self.prepareNotificationData(status, opState, err)
186 logger.info('Notify data = %s' % notification_content)
187 NotificationsUtil().send_notification(notification_content)
188 logger.info('Notify end')
190 def prepareNotificationData(self, status, opState, err=None):
192 if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
194 if self.action == HEAL_ACTION_TYPE.START:
195 chtype = CHANGE_TYPE.ADDED
197 chtype = CHANGE_TYPE.MODIFIED
198 vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
200 vm = VmInstModel.objects.filter(instid=self.nf_inst_id, resourceid=self.vm_id)
203 'vimConnectionId': vm[0].vimid,
204 'resourceId': vm[0].resourceid,
205 'vimLevelResourceType': 'vm'
208 affected_vnfcs.append({
209 'id': vnfcs[0].vnfcinstanceid,
210 'vduId': vnfcs[0].vduid,
211 'changeType': chtype,
212 'computeResource': vm_resource
215 notification_content = {
216 "id": str(uuid.uuid4()),
217 "notificationType": "VnfLcmOperationOccurrenceNotification",
218 "subscriptionId": "",
219 "timeStamp": now_time(),
220 "notificationStatus": status,
221 "operationState": opState,
222 "vnfInstanceId": self.nf_inst_id,
223 "operation": OPERATION_TYPE.HEAL,
224 "isAutomaticInvocation": "false",
225 "vnfLcmOpOccId": self.job_id,
226 "affectedVnfcs": affected_vnfcs,
227 "affectedVirtualLinks": [],
228 "affectedVirtualStorages": [],
230 "changedExtConnectivity": [],
231 "_links": {"vnfInstance": {"href": ""},
232 "subscription": {"href": ""},
233 "vnfLcmOpOcc": {"href": ""}}
235 if opState in (OPERATION_STATE_TYPE.FAILED, OPERATION_STATE_TYPE.FAILED_TEMP):
236 notification_content["error"] = {"status": 500, "detail": err}
237 notification_content["_links"]["vnfInstance"]["href"] = "/vnf_instances/%s" % self.nf_inst_id
238 notification_content["_links"]["vnfLcmOpOcc"]["href"] = "/vnf_lc_ops/%s" % self.job_id
239 return notification_content