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