775def3074f08a7321e9c4b4a9c5ccc6c225342e
[vfc/gvnfm/vnflcm.git] / lcm / lcm / nf / biz / operate_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.notificationsutil import NotificationsUtil
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
32 from lcm.nf.const import RESOURCE_MAP
33 from lcm.nf.const import GRANT_TYPE
34 from lcm.nf.const import OPERATION_STATE_TYPE
35 from lcm.nf.const import LCM_NOTIFICATION_STATUS
36 from lcm.nf.const import CHANGE_TYPE
37 from lcm.nf.const import OPERATION_TYPE
38 from lcm.nf.const import OPERATION_TASK
39 from .operate_vnf_lcm_op_occ import VnfLcmOpOcc
40
41 logger = logging.getLogger(__name__)
42
43
44 class OperateVnf(Thread):
45     def __init__(self, data, nf_inst_id, job_id):
46         super(OperateVnf, self).__init__()
47         self.data = data
48         self.nf_inst_id = nf_inst_id
49         self.job_id = job_id
50         self.grant_type = GRANT_TYPE.OPERATE
51         self.changeStateTo = ignore_case_get(self.data, "changeStateTo")
52         self.stopType = ignore_case_get(self.data, "stopType")
53         self.gracefulStopTimeout = ignore_case_get(self.data, "gracefulStopTimeout")
54         self.inst_resource = {'vm': []}
55         self.lcm_op_occ = VnfLcmOpOcc(
56             vnf_inst_id=nf_inst_id,
57             lcm_op_id=job_id,
58             operation=OPERATION_TYPE.OPERATE,
59             task=OPERATION_TASK.OPERATE
60         )
61
62     def run(self):
63         try:
64             self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.STARTING)
65             self.apply_grant()
66             self.query_inst_resource()
67             self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.PROCESSING)
68             self.operate_resource()
69             JobUtil.add_job_status(self.job_id, 100, "Operate 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             self.vnf_operate_failed_handle(e.message)
80         except Exception as e:
81             logger.error(e.message)
82             logger.error(traceback.format_exc())
83             self.vnf_operate_failed_handle(e.message)
84
85     def apply_grant(self):
86         vdus = VmInstModel.objects.filter(instid=self.nf_inst_id)
87         apply_result = grant_resource(data=self.data,
88                                       nf_inst_id=self.nf_inst_id,
89                                       job_id=self.job_id,
90                                       grant_type=self.grant_type,
91                                       vdus=vdus)
92         logger.info("Grant resource, response: %s" % apply_result)
93         JobUtil.add_job_status(self.job_id, 20, 'Nf Operate grant_resource finish')
94
95     def query_inst_resource(self):
96         logger.info('Query resource begin')
97         # Querying only vm resources now
98         resource_type = "Vm"
99         resource_table = globals().get(resource_type + 'InstModel')
100         resource_insts = resource_table.objects.filter(instid=self.nf_inst_id)
101         for resource_inst in resource_insts:
102             if not resource_inst.resourceid:
103                 continue
104             self.inst_resource[RESOURCE_MAP.get(resource_type)].append(self.get_resource(resource_inst))
105         logger.info('Query resource end, resource=%s' % self.inst_resource)
106
107     def get_resource(self, resource):
108         return {
109             "vim_id": resource.vimid,
110             "tenant_id": resource.tenant,
111             "id": resource.resourceid
112         }
113
114     def operate_resource(self):
115         logger.info('Operate resource begin')
116         adaptor.operate_vim_res(self.inst_resource,
117                                 self.changeStateTo,
118                                 self.stopType,
119                                 self.gracefulStopTimeout,
120                                 self.do_notify_op)
121         logger.info('Operate resource complete')
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 vnf_operate_failed_handle(self, error_msg):
130         logger.error('VNF Operation 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 do_notify_op(self, status, resid):
139         logger.error('VNF resource %s updated to: %s' % (resid, status))
140
141     def prepareNotificationData(self, status, opState, err=None):
142         affected_vnfcs = []
143         if status == LCM_NOTIFICATION_STATUS.RESULT and opState == OPERATION_STATE_TYPE.COMPLETED:
144             vnfcs = VNFCInstModel.objects.filter(instid=self.nf_inst_id)
145             for vnfc in vnfcs:
146                 vm_resource = {}
147                 if vnfc.vmid:
148                     vm = VmInstModel.objects.filter(vmid=vnfc.vmid)
149                     if vm:
150                         vm_resource = {
151                             'vimConnectionId': vm[0].vimid,
152                             'resourceId': vm[0].resourceid,
153                             'vimLevelResourceType': 'vm'
154                         }
155                 affected_vnfcs.append({
156                     'id': vnfc.vnfcinstanceid,
157                     'vduId': vnfc.vduid,
158                     'changeType': CHANGE_TYPE.MODIFIED,
159                     'computeResource': vm_resource
160                 })
161         notification_content = {
162             "id": str(uuid.uuid4()),
163             "notificationType": "VnfLcmOperationOccurrenceNotification",
164             "subscriptionId": "",
165             "timeStamp": now_time(),
166             "notificationStatus": status,
167             "operationState": opState,
168             "vnfInstanceId": self.nf_inst_id,
169             "operation": OPERATION_TYPE.OPERATE,
170             "isAutomaticInvocation": "false",
171             "vnfLcmOpOccId": self.job_id,
172             "affectedVnfcs": affected_vnfcs,
173             "affectedVirtualLinks": [],
174             "affectedVirtualStorages": [],
175             "changedInfo": {},
176             "changedExtConnectivity": [],
177             "_links": {"vnfInstance": {"href": ""},
178                        "subscription": {"href": ""},
179                        "vnfLcmOpOcc": {"href": ""}}
180         }
181         if opState in (OPERATION_STATE_TYPE.FAILED, OPERATION_STATE_TYPE.FAILED_TEMP):
182             notification_content["error"] = {"status": 500, "detail": err}
183         notification_content["_links"]["vnfInstance"]["href"] = "/vnf_instances/%s" % self.nf_inst_id
184         notification_content["_links"]["vnfLcmOpOcc"]["href"] = "/vnf_lc_ops/%s" % self.job_id
185         return notification_content