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 type in Request in invalid. 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, vmid=self.vm_id, vmname=self.vm_name)
88 raise NFLCMException("VNF Vm does not exist.")
89 self.vimid = self.vdu[0].vimid
90 self.tenant = self.vdu[0].tenant
91 elif self.action == HEAL_ACTION_TYPE.START:
92 vdus = ignore_case_get(self.vnfd_info, "vdus")
93 self.vdu = [elem for elem in vdus if ignore_case_get(elem, "vdu_id") == self.vdu_id]
95 raise NFLCMException("VNF Vm does not exist.")
96 apply_result = grant_resource(data=self.data, nf_inst_id=self.nf_inst_id, job_id=self.job_id,
97 grant_type=self.grant_type, vdus=self.vdu)
98 if self.action == HEAL_ACTION_TYPE.START:
99 self.vimid = ignore_case_get(apply_result, "vimid"),
100 self.tenant = ignore_case_get(apply_result, "tenant")
101 logger.info("Grant resource, response: %s" % apply_result)
102 JobUtil.add_job_status(self.job_id, 20, 'Nf Healing grant_resource finish')
104 def heal_resource(self):
105 logger.info('Heal resource begin')
106 data = {'action': self.action, 'vimid': self.vimid, 'tenant': self.tenant}
107 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))
108 logger.info('Heal resource complete')
110 def do_notify(self, res_type, ret):
111 logger.info('Creating [%s] resource' % res_type)
112 resource_save_method = getattr(common, res_type + '_save')
113 resource_save_method(self.job_id, self.nf_inst_id, ret)
115 def vnf_heal_failed_handle(self, error_msg):
116 logger.error('VNF Healing failed, detail message: %s' % error_msg)
117 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED, lastuptime=now_time())
118 JobUtil.add_job_status(self.job_id, 255, error_msg)
120 def lcm_notify(self, status, opState, err=None):
121 notification_content = self.prepareNotificationData(status, opState, err)
122 logger.info('Notify data = %s' % notification_content)
123 NotificationsUtil().send_notification(notification_content)
124 logger.info('Notify end')
126 def prepareNotificationData(self, status, opState, err=None):
128 if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
130 if self.action == HEAL_ACTION_TYPE.START:
131 chtype = CHANGE_TYPE.ADDED
133 chtype = CHANGE_TYPE.MODIFIED
134 vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
136 vm = VmInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
139 'vimConnectionId': vm[0].vimid,
140 'resourceId': vm[0].resourceid,
141 'vimLevelResourceType': 'vm'
143 affected_vnfcs.append({
144 'id': vnfcs[0].vnfcinstanceid,
145 'vduId': vnfcs[0].vduid,
146 'changeType': chtype,
147 'computeResource': vm_resource
150 notification_content = {
151 "id": str(uuid.uuid4()),
152 "notificationType": "VnfLcmOperationOccurrenceNotification",
153 "subscriptionId": "",
154 "timeStamp": now_time(),
155 "notificationStatus": status,
156 "operationState": opState,
157 "vnfInstanceId": self.nf_inst_id,
158 "operation": OPERATION_TYPE.HEAL,
159 "isAutomaticInvocation": "false",
160 "vnfLcmOpOccId": self.job_id,
161 "affectedVnfcs": affected_vnfcs,
162 "affectedVirtualLinks": [],
163 "affectedVirtualStorages": [],
165 "changedExtConnectivity": [],
166 "_links": {"vnfInstance": {"href": ""},
167 "subscription": {"href": ""},
168 "vnfLcmOpOcc": {"href": ""}}
170 if opState in (OPERATION_STATE_TYPE.FAILED, OPERATION_STATE_TYPE.FAILED_TEMP):
171 notification_content["error"] = {"status": 500, "detail": err}
172 notification_content["_links"]["vnfInstance"]["href"] = "/vnf_instances/%s" % self.nf_inst_id
173 notification_content["_links"]["vnfLcmOpOcc"]["href"] = "/vnf_lc_ops/%s" % self.job_id
174 return notification_content