Add lcm op occ to instantiate vnf
[vfc/gvnfm/vnflcm.git] / lcm / lcm / nf / biz / instantiate_vnf.py
1 # Copyright 2017 ZTE Corporation.
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
21 from lcm.pub.exceptions import NFLCMException
22 from lcm.pub.exceptions import NFLCMExceptionConflict
23 from lcm.pub.msapi.gvnfmdriver import prepare_notification_data
24 from lcm.pub.msapi.gvnfmdriver import notify_lcm_to_nfvo
25 from lcm.pub.msapi.sdc_run_catalog import query_vnfpackage_by_id
26 from lcm.pub.utils.jobutil import JobUtil
27 from lcm.pub.utils.timeutil import now_time
28 from lcm.pub.utils.notificationsutil import NotificationsUtil
29 from lcm.pub.utils.values import ignore_case_get
30 from lcm.pub.vimapi import adaptor
31 from lcm.nf.biz.grant_vnf import grant_resource
32 from lcm.nf.const import CHANGE_TYPE, GRANT_TYPE, OPERATION_TYPE
33 from lcm.nf.const import OPERATION_TASK
34 from lcm.nf.const import OPERATION_STATE_TYPE
35 from lcm.nf.const import SUB_OPERATION_TASK
36 from lcm.nf.biz import common
37 from .operate_vnf_lcm_op_occ import VnfLcmOpOcc
38
39 logger = logging.getLogger(__name__)
40
41
42 class InstantiateVnf(Thread):
43     def __init__(self, data, nf_inst_id, job_id):
44         super(InstantiateVnf, self).__init__()
45         self.data = data
46         self.nf_inst_id = nf_inst_id
47         self.job_id = job_id
48         self.vim_id = ignore_case_get(
49             ignore_case_get(
50                 self.data,
51                 "additionalParams"
52             ),
53             "vimId"
54         )
55         self.grant_type = GRANT_TYPE.INSTANTIATE
56         self.lcm_op_occ = VnfLcmOpOcc(
57             vnf_inst_id=nf_inst_id,
58             lcm_op_id=job_id,
59             operation=OPERATION_TYPE.INSTANTIATE,
60             task=OPERATION_TASK.INSTANTIATE
61         )
62         self.pre_deal()
63
64     def run(self):
65         try:
66             self.inst_pre()
67             self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.STARTING)
68             self.apply_grant()
69             self.lcm_op_occ.upd(
70                 sub_operation=SUB_OPERATION_TASK.GRANTED,
71                 operation_state=OPERATION_STATE_TYPE.PROCESSING
72             )
73             self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.PROCESSING)
74             self.create_res()
75             self.lcm_notify()
76             JobUtil.add_job_status(
77                 self.job_id,
78                 100,
79                 "Instantiate Vnf success."
80             )
81             self.lcm_op_occ.upd(
82                 sub_operation=SUB_OPERATION_TASK.SUCCESS,
83                 operation_state=OPERATION_STATE_TYPE.COMPLETED
84             )
85         except NFLCMException as e:
86             self.vnf_inst_failed_handle(e.message)
87         except Exception as e:
88             logger.error(e.message)
89             logger.error(traceback.format_exc())
90             self.vnf_inst_failed_handle('unexpected exception')
91
92     def pre_deal(self):
93         logger.debug("Start pre deal for VNF instantiate_vnf task")
94
95         vnf_is_in_processing, vnf_op = self.lcm_op_occ.is_in_processing()
96         if vnf_is_in_processing:
97             raise NFLCMExceptionConflict('VNF(%s) %s in processing.' % (
98                 self.nf_inst_id, vnf_op
99             ))
100         self.lcm_op_occ.add()
101
102     def inst_pre(self):
103         vnf_insts = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
104         if not vnf_insts.exists():
105             raise NFLCMException('VNF nf_inst_id is not exist.')
106
107         if vnf_insts[0].status != 'NOT_INSTANTIATED':
108             raise NFLCMException('VNF instantiationState is not NOT_INSTANTIATED.')
109
110         JobUtil.add_job_status(self.job_id, 5, 'Get packageinfo by vnfd_id')
111         self.vnfd_id = vnf_insts[0].vnfdid
112         JobUtil.add_job_status(self.job_id, 10, 'Get vnf package info from catalog by csar_id')
113         input_parameters = []
114         inputs = ignore_case_get(self.data, "additionalParams")
115         if inputs:
116             if isinstance(inputs, (str, unicode)):
117                 inputs = json.loads(inputs)
118             for key, val in inputs.items():
119                 input_parameters.append({"key": key, "value": val})
120         vnf_package = query_vnfpackage_by_id(self.vnfd_id)
121         pkg_info = ignore_case_get(vnf_package, "packageInfo")
122         self.vnfd_info = json.loads(ignore_case_get(pkg_info, "vnfdModel"))
123
124         self.update_cps()
125         metadata = ignore_case_get(self.vnfd_info, "metadata")
126         csar_id = ignore_case_get(metadata, "id")
127         version = ignore_case_get(metadata, "vnfdVersion")
128         vendor = ignore_case_get(metadata, "vendor")
129         netype = ignore_case_get(metadata, "type")
130         vnfsoftwareversion = ignore_case_get(metadata, "version")
131         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).\
132             update(package_id=csar_id,
133                    flavour_id=ignore_case_get(self.data, "flavourId"),
134                    version=version,
135                    vendor=vendor,
136                    netype=netype,
137                    vnfd_model=json.dumps(self.vnfd_info),
138                    status='NOT_INSTANTIATED',
139                    vnfdid=self.vnfd_id,
140                    localizationLanguage=ignore_case_get(self.data, 'localizationLanguage'),
141                    input_params=input_parameters,
142                    vnfSoftwareVersion=vnfsoftwareversion,
143                    lastuptime=now_time())
144
145         logger.info("VimId = %s" % self.vim_id)
146         '''
147         is_exist = NfvoRegInfoModel.objects.filter(nfvoid=self.nf_inst_id).exists()
148         if not is_exist:
149             NfvoRegInfoModel.objects.create(
150                 nfvoid=self.nf_inst_id,
151                 vnfminstid=ignore_case_get(self.data, "vnfmId"),
152                 apiurl=self.vim_id)
153         '''
154         JobUtil.add_job_status(self.job_id, 15, 'Nf instancing pre-check finish')
155         logger.info("Nf instancing pre-check finish")
156
157     def apply_grant(self):
158         vdus = ignore_case_get(self.vnfd_info, "vdus")
159         apply_result = grant_resource(data=self.data,
160                                       nf_inst_id=self.nf_inst_id,
161                                       job_id=self.job_id,
162                                       grant_type=self.grant_type,
163                                       vdus=vdus)
164         self.set_location(apply_result)
165
166         logger.info('VnfdInfo = %s' % self.vnfd_info)
167         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
168             status='INSTANTIATED',
169             lastuptime=now_time()
170         )
171         JobUtil.add_job_status(self.job_id, 20, 'Nf instancing apply grant finish')
172         logger.info("Nf instancing apply grant finish")
173
174     def create_res(self):
175         logger.info("Create resource start")
176         vim_cache, res_cache = {}, {}
177         adaptor.create_vim_res(
178             self.vnfd_info,
179             self.do_notify,
180             vim_cache=vim_cache,
181             res_cache=res_cache
182         )
183         JobUtil.add_job_status(self.job_id, 70, '[NF instantiation] create resource finish')
184         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).\
185             update(vimInfo=json.dumps(vim_cache),
186                    resInfo=json.dumps(res_cache))
187         logger.info("Create resource finish")
188
189     def lcm_notify(self):
190         notification_content = prepare_notification_data(
191             self.nf_inst_id,
192             self.job_id,
193             CHANGE_TYPE.ADDED,
194             OPERATION_TYPE.INSTANTIATE
195         )
196         logger.info('Notify request data = %s' % notification_content)
197         try:
198             resp = notify_lcm_to_nfvo(json.dumps(notification_content))
199             logger.info('Lcm notify end, response %s' % resp)
200         except Exception as e:
201             logger.error("Lcm instantiate notify failed: %s", e.message)
202         NotificationsUtil().send_notification(notification_content)
203
204     def vnf_inst_failed_handle(self, error_msg):
205         logger.error('VNF instantiation failed, detail message: %s' % error_msg)
206         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
207             status='NOT_INSTANTIATED',
208             lastuptime=now_time()
209         )
210         self.lcm_op_occ.notify_lcm(OPERATION_STATE_TYPE.FAILED, error_msg)
211         JobUtil.add_job_status(self.job_id, 255, error_msg)
212         self.lcm_op_occ.upd(
213             sub_operation=SUB_OPERATION_TASK.ERROR,
214             operation_state=OPERATION_STATE_TYPE.FAILED,
215             error={
216                 "status": 500,
217                 "detail": error_msg
218             }
219         )
220
221     def do_notify(self, res_type, ret):
222         logger.info('Creating [%s] resource' % res_type)
223         resource_save_method = getattr(common, res_type + '_save')
224         resource_save_method(self.job_id, self.nf_inst_id, ret)
225
226     def update_cps(self):
227         for extlink in ignore_case_get(self.data, "extVirtualLinks"):
228             for ext_cp in ignore_case_get(extlink, "extCps"):
229                 cpdid = ignore_case_get(ext_cp, "cpdId")
230                 for cp in ignore_case_get(self.vnfd_info, "cps"):
231                     if cpdid == ignore_case_get(cp, "cp_id"):
232                         cp["networkId"] = ignore_case_get(extlink, "resourceId")
233                         cp["subnetId"] = ignore_case_get(extlink, "resourceSubnetId")
234                         break
235
236     def set_location(self, apply_result):
237         vim_connections = ignore_case_get(apply_result, "vimConnections")
238         vnfid = ignore_case_get(apply_result, "vnfInstanceId")
239         vim_assets = ignore_case_get(apply_result, "vimAssets")
240         access_info = ignore_case_get(vim_connections[0], "accessInfo")
241         tenant = ignore_case_get(access_info, "tenant")
242         vimid = ignore_case_get(vim_connections[0], "vimId")
243         cloud_owner, cloud_regionid = vimid.split("_")
244         vdu_info = []
245
246         for flavor in ignore_case_get(vim_assets, "computeResourceFlavours"):
247             oof_vimid = flavor["vimConnectionId"]
248             if oof_vimid and oof_vimid != "none":
249                 vimid = oof_vimid
250             vdu_info.append({"vduName": flavor["resourceProviderId"],
251                              "flavorId": flavor["vimFlavourId"],
252                              "vimid": vimid})
253
254         for resource_type in ['vdus', 'vls', 'cps', 'volume_storages']:
255             for resource in ignore_case_get(self.vnfd_info, resource_type):
256                 if "location_info" in resource["properties"]:
257                     resource["properties"]["location_info"]["vimid"] = vimid
258                     resource["properties"]["location_info"]["tenant"] = tenant
259                     resource["properties"]["location_info"]["vnfId"] = vnfid
260                     resource["properties"]["location_info"]["cloudOwner"] = cloud_owner
261                     resource["properties"]["location_info"]["cloudRegionId"] = cloud_regionid
262                     resource["properties"]["location_info"]["vduInfo"] = vdu_info
263                 else:
264                     resource["properties"]["location_info"] = {
265                         "vimid": vimid,
266                         "tenant": tenant,
267                         "vnfId": vnfid,
268                         "cloudOwner": cloud_owner,
269                         "cloudRegionId": cloud_regionid,
270                         "vduInfo": vdu_info}
271
272     '''
273     def get_subnet_ids(self, ext_cp):
274         subnet_ids = []
275         for cp_conf in ignore_case_get(ext_cp, "cpConfig"):
276             for cp_protocol in ignore_case_get(ext_cp, "cpProtocolData"):
277                 ip_over_ethernet = ignore_case_get(cp_protocol, "ipOverEthernet")
278                 for ip_address in ignore_case_get(ip_over_ethernet, "ipAddresses"):
279                     subnet_ids.append(ignore_case_get(ip_address, "subnetId"))
280         return subnet_ids
281     '''