4b503424eb6879f06eedd5afd07ca57d7d47556d
[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 type in Request in invalid. 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, vmid=self.vm_id, vmname=self.vm_name)
87             if not self.vdu:
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]
94             if not self.vdu:
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')
103
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')
109
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)
114
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)
119
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')
125
126     def prepareNotificationData(self, status, opState, err=None):
127         affected_vnfcs = []
128         if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
129             chtype = ""
130             if self.action == HEAL_ACTION_TYPE.START:
131                 chtype = CHANGE_TYPE.ADDED
132             else:
133                 chtype = CHANGE_TYPE.MODIFIED
134             vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
135             vm_resource = {}
136             vm = VmInstModel.objects.filter(instid=self.nf_inst_id, vmid=self.vm_id)
137             if vm:
138                 vm_resource = {
139                     'vimConnectionId': vm[0].vimid,
140                     'resourceId': vm[0].resourceid,
141                     'vimLevelResourceType': 'vm'
142                 }
143             affected_vnfcs.append({
144                 'id': vnfcs[0].vnfcinstanceid,
145                 'vduId': vnfcs[0].vduid,
146                 'changeType': chtype,
147                 'computeResource': vm_resource
148             })
149
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": [],
164             "changedInfo": {},
165             "changedExtConnectivity": [],
166             "_links": {"vnfInstance": {"href": ""},
167                        "subscription": {"href": ""},
168                        "vnfLcmOpOcc": {"href": ""}}
169         }
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