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