5e013042dc9c35e78581290ee16687b914d694f6
[vfc/gvnfm/vnflcm.git] / lcm / lcm / nf / biz / heal_vnf.py
1 # Copyright (C) 2018 Verizon. All Rights Reserved.
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 json
16 import logging
17 import traceback
18 from threading import Thread
19
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
30 import uuid
31 from lcm.pub.utils.notificationsutil import NotificationsUtil
32
33
34 logger = logging.getLogger(__name__)
35
36
37 class HealVnf(Thread):
38     def __init__(self, data, nf_inst_id, job_id):
39         super(HealVnf, self).__init__()
40         self.data = data
41         self.nf_inst_id = nf_inst_id
42         self.job_id = job_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")
46         self.grant_type = ""
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
51
52     def run(self):
53         try:
54             self.heal_pre()
55             self.lcm_notify(LCM_NOTIFICATION_STATUS.START, OPERATION_STATE_TYPE.STARTING)
56             self.apply_grant()
57             self.lcm_notify(LCM_NOTIFICATION_STATUS.RESULT, OPERATION_STATE_TYPE.PROCESSING)
58             self.heal_resource()
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())
70
71     def heal_pre(self):
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))
74
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.")
80
81         self.vnf_insts = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
82         self.vnfd_info = json.loads(self.vnf_insts[0].vnfd_model)
83
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)
87             if not self.vdu:
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')
93             return
94
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]
97         if not self.vdu:
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)
101
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')
106
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')
112
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)
117
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)
122
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')
128
129     def prepareNotificationData(self, status, opState, err=None):
130         affected_vnfcs = []
131         if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
132             chtype = ""
133             if self.action == HEAL_ACTION_TYPE.START:
134                 chtype = CHANGE_TYPE.ADDED
135             else:
136                 chtype = CHANGE_TYPE.MODIFIED
137             vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
138             vm_resource = {}
139             vm = VmInstModel.objects.filter(instid=self.nf_inst_id, resourceid=self.vm_id)
140             if vm:
141                 vm_resource = {
142                     'vimConnectionId': vm[0].vimid,
143                     'resourceId': vm[0].resourceid,
144                     'vimLevelResourceType': 'vm'
145                 }
146             if vnfcs:
147                 affected_vnfcs.append({
148                     'id': vnfcs[0].vnfcinstanceid,
149                     'vduId': vnfcs[0].vduid,
150                     'changeType': chtype,
151                     'computeResource': vm_resource
152                 })
153
154         notification_content = {
155             "id": str(uuid.uuid4()),
156             "notificationType": "VnfLcmOperationOccurrenceNotification",
157             "subscriptionId": "",
158             "timeStamp": now_time(),
159             "notificationStatus": status,
160             "operationState": opState,
161             "vnfInstanceId": self.nf_inst_id,
162             "operation": OPERATION_TYPE.HEAL,
163             "isAutomaticInvocation": "false",
164             "vnfLcmOpOccId": self.job_id,
165             "affectedVnfcs": affected_vnfcs,
166             "affectedVirtualLinks": [],
167             "affectedVirtualStorages": [],
168             "changedInfo": {},
169             "changedExtConnectivity": [],
170             "_links": {"vnfInstance": {"href": ""},
171                        "subscription": {"href": ""},
172                        "vnfLcmOpOcc": {"href": ""}}
173         }
174         if opState in (OPERATION_STATE_TYPE.FAILED, OPERATION_STATE_TYPE.FAILED_TEMP):
175             notification_content["error"] = {"status": 500, "detail": err}
176         notification_content["_links"]["vnfInstance"]["href"] = "/vnf_instances/%s" % self.nf_inst_id
177         notification_content["_links"]["vnfLcmOpOcc"]["href"] = "/vnf_lc_ops/%s" % self.job_id
178         return notification_content