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.
18 from threading import Thread
20 from lcm.pub.database.models import NfInstModel, VmInstModel, VNFCInstModel
21 from lcm.pub.exceptions import NFLCMException
22 from lcm.pub.utils.jobutil import JobUtil
23 from lcm.pub.utils.timeutil import now_time
24 from lcm.pub.utils.values import ignore_case_get
25 from lcm.pub.vimapi import adaptor
26 from lcm.nf.biz.grant_vnf import grant_resource
27 from lcm.nf.const import VNF_STATUS, GRANT_TYPE, OPERATION_STATE_TYPE, LCM_NOTIFICATION_STATUS
28 from lcm.nf.const import CHANGE_TYPE, OPERATION_TYPE, HEAL_ACTION_TYPE
29 from lcm.nf.biz import common
31 from lcm.pub.utils.notificationsutil import NotificationsUtil
34 logger = logging.getLogger(__name__)
37 class HealVnf(Thread):
38 def __init__(self, data, nf_inst_id, job_id):
39 super(HealVnf, self).__init__()
41 self.nf_inst_id = nf_inst_id
43 self.affectedvm = ignore_case_get(ignore_case_get(self.data, "additionalParams"), "affectedvm")
44 # TODO: Check if we could move the action param into the list of affectedvm structure
45 self.action = ignore_case_get(ignore_case_get(self.data, "additionalParams"), "action")
47 if self.action == HEAL_ACTION_TYPE.START:
48 self.grant_type = GRANT_TYPE.HEAL_CREATE
49 elif self.action == HEAL_ACTION_TYPE.RESTART:
50 self.grant_type = GRANT_TYPE.HEAL_RESTART
55 self.lcm_notify(LCM_NOTIFICATION_STATUS.START, OPERATION_STATE_TYPE.STARTING)
57 self.lcm_notify(LCM_NOTIFICATION_STATUS.RESULT, OPERATION_STATE_TYPE.PROCESSING)
59 JobUtil.add_job_status(self.job_id, 100, "Heal Vnf success.")
60 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status='INSTANTIATED', lastuptime=now_time())
61 self.lcm_notify(LCM_NOTIFICATION_STATUS.RESULT, OPERATION_STATE_TYPE.COMPLETED)
62 except NFLCMException as e:
63 logger.error(e.message)
64 self.lcm_notify(LCM_NOTIFICATION_STATUS.RESULT, OPERATION_STATE_TYPE.FAILED, str(e))
65 self.vnf_heal_failed_handle(e.message)
66 except Exception as e:
67 logger.error(e.message)
68 self.lcm_notify(LCM_NOTIFICATION_STATUS.RESULT, OPERATION_STATE_TYPE.FAILED, str(e))
69 self.vnf_heal_failed_handle(traceback.format_exc())
72 if self.action not in (HEAL_ACTION_TYPE.START, HEAL_ACTION_TYPE.RESTART):
73 raise NFLCMException("Action should be %s or %s" % (HEAL_ACTION_TYPE.START, HEAL_ACTION_TYPE.RESTART))
75 self.vm_id = ignore_case_get(self.affectedvm, "vmid")
76 self.vdu_id = ignore_case_get(self.affectedvm, "vduid")
77 self.vm_name = ignore_case_get(self.affectedvm, "vmname")
78 if not (self.vm_id and self.vdu_id and self.vm_name):
79 raise NFLCMException("VM identifiers is not present in request.")
81 self.vnf_insts = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
82 self.vnfd_info = json.loads(self.vnf_insts[0].vnfd_model)
84 def apply_grant(self):
85 if self.action == HEAL_ACTION_TYPE.RESTART:
86 self.vdu = VmInstModel.objects.filter(instid=self.nf_inst_id, resourceid=self.vm_id)
88 raise NFLCMException("VNF Vm(%s) does not exist." % self.vm_id)
89 self.vimid = self.vdu[0].vimid
90 self.tenant = self.vdu[0].tenant
91 logger.debug("Get heal vnf vm(%s,%s) info successfully.", self.vm_id, self.vm_name)
92 JobUtil.add_job_status(self.job_id, 20, 'Nf Healing get vnf vm info finish')
95 vdus = ignore_case_get(self.vnfd_info, "vdus")
96 self.vdu = [elem for elem in vdus if ignore_case_get(elem, "vdu_id") == self.vdu_id]
98 raise NFLCMException("VNF Vdu(%s) does not exist." % self.vdu_id)
99 apply_result = grant_resource(data=self.data, nf_inst_id=self.nf_inst_id, job_id=self.job_id,
100 grant_type=self.grant_type, vdus=self.vdu)
102 self.vimid = ignore_case_get(apply_result, "vimid"),
103 self.tenant = ignore_case_get(apply_result, "tenant")
104 logger.info("Grant resource, response: %s" % apply_result)
105 JobUtil.add_job_status(self.job_id, 20, 'Nf Healing grant_resource finish')
107 def heal_resource(self):
108 logger.info('Heal resource begin')
109 data = {'action': self.action, 'vimid': self.vimid, 'tenant': self.tenant}
110 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))
111 logger.info('Heal resource complete')
113 def do_notify(self, res_type, ret):
114 logger.info('Creating [%s] resource' % res_type)
115 resource_save_method = getattr(common, res_type + '_save')
116 resource_save_method(self.job_id, self.nf_inst_id, ret)
118 def vnf_heal_failed_handle(self, error_msg):
119 logger.error('VNF Healing failed, detail message: %s' % error_msg)
120 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED, lastuptime=now_time())
121 JobUtil.add_job_status(self.job_id, 255, error_msg)
123 def lcm_notify(self, status, opState, err=None):
124 notification_content = self.prepareNotificationData(status, opState, err)
125 logger.info('Notify data = %s' % notification_content)
126 NotificationsUtil().send_notification(notification_content)
127 logger.info('Notify end')
129 def prepareNotificationData(self, status, opState, err=None):
131 if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
133 if self.action == HEAL_ACTION_TYPE.START:
134 chtype = CHANGE_TYPE.ADDED
136 chtype = CHANGE_TYPE.MODIFIED
137 vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
139 vm = VmInstModel.objects.filter(instid=self.nf_inst_id, resourceid=self.vm_id)
142 'vimConnectionId': vm[0].vimid,
143 'resourceId': vm[0].resourceid,
144 'vimLevelResourceType': 'vm'
146 affected_vnfcs.append({
147 'id': vnfcs[0].vnfcinstanceid,
148 'vduId': vnfcs[0].vduid,
149 'changeType': chtype,
150 'computeResource': vm_resource
153 notification_content = {
154 "id": str(uuid.uuid4()),
155 "notificationType": "VnfLcmOperationOccurrenceNotification",
156 "subscriptionId": "",
157 "timeStamp": now_time(),
158 "notificationStatus": status,
159 "operationState": opState,
160 "vnfInstanceId": self.nf_inst_id,
161 "operation": OPERATION_TYPE.HEAL,
162 "isAutomaticInvocation": "false",
163 "vnfLcmOpOccId": self.job_id,
164 "affectedVnfcs": affected_vnfcs,
165 "affectedVirtualLinks": [],
166 "affectedVirtualStorages": [],
168 "changedExtConnectivity": [],
169 "_links": {"vnfInstance": {"href": ""},
170 "subscription": {"href": ""},
171 "vnfLcmOpOcc": {"href": ""}}
173 if opState in (OPERATION_STATE_TYPE.FAILED, OPERATION_STATE_TYPE.FAILED_TEMP):
174 notification_content["error"] = {"status": 500, "detail": err}
175 notification_content["_links"]["vnfInstance"]["href"] = "/vnf_instances/%s" % self.nf_inst_id
176 notification_content["_links"]["vnfLcmOpOcc"]["href"] = "/vnf_lc_ops/%s" % self.job_id
177 return notification_content