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