0a23ad5b6454853058061076e5531ba31808c5a9
[vfc/nfvo/lcm.git] / lcm / ns / vnfs / create_vnfs.py
1 # Copyright 2016 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 import json
15 import logging
16 import traceback
17 import uuid
18 from threading import Thread
19
20 from lcm.ns.const import OWNER_TYPE
21 from lcm.ns.vnfs.const import VNF_STATUS, NFVO_VNF_INST_TIMEOUT_SECOND, INST_TYPE, INST_TYPE_NAME
22 from lcm.ns.vnfs.wait_job import wait_job_finish
23 from lcm.pub.config.config import REPORT_TO_AAI
24 from lcm.pub.database.models import NfPackageModel, NfInstModel, NSInstModel, VmInstModel, VNFFGInstModel, VLInstModel
25 from lcm.pub.exceptions import NSLCMException
26 from lcm.pub.msapi.aai import create_vnf_aai, create_vserver_aai
27 from lcm.pub.msapi.extsys import get_vnfm_by_id, split_vim_to_owner_region, get_vim_by_id
28 from lcm.pub.msapi.resmgr import create_vnf, create_vnf_creation_info
29 from lcm.pub.msapi.sdc_run_catalog import query_vnfpackage_by_id
30 from lcm.pub.msapi.vnfmdriver import send_nf_init_request
31 from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil, JOB_TYPE
32 from lcm.pub.utils.share_lock import do_biz_with_share_lock
33 from lcm.pub.utils.timeutil import now_time
34 from lcm.pub.utils.values import ignore_case_get
35
36 logger = logging.getLogger(__name__)
37
38
39 def prepare_create_params():
40     nf_inst_id = str(uuid.uuid4())
41     NfInstModel(nfinstid=nf_inst_id, status=VNF_STATUS.INSTANTIATING, create_time=now_time(),
42                 lastuptime=now_time()).save()
43     job_id = JobUtil.create_job(INST_TYPE_NAME.VNF, JOB_TYPE.CREATE_VNF, nf_inst_id)
44     JobUtil.add_job_status(job_id, 0, 'create vnf record in database.', 0)
45     return nf_inst_id, job_id
46
47
48 class CreateVnfs(Thread):
49     def __init__(self, data, nf_inst_id, job_id):
50         super(CreateVnfs, self).__init__()
51         self.data = data
52         self.nf_inst_id = nf_inst_id
53         self.job_id = job_id
54         self.ns_inst_id = ''
55         self.vnf_id = ''
56         self.vnfd_id = ''
57         self.ns_inst_name = ''
58         self.nsd_model = ''
59         self.vnfd_model = ''
60         self.vnf_inst_name = ''
61         self.vnfm_inst_id = ''
62         self.inputs = ''
63         self.nf_package_info = ''
64         self.vnfm_nf_inst_id = ''
65         self.vnfm_job_id = ''
66         self.vnfm_inst_name = ''
67         self.vim_id = ''
68
69     def run(self):
70         try:
71             self.get_params()
72             self.check_nf_name_exist()
73             self.get_vnfd_id()
74             self.check_nf_package_valid()
75             self.send_nf_init_request_to_vnfm()
76             self.send_get_vnfm_request_to_extsys()
77             self.send_create_vnf_request_to_resmgr()
78             self.wait_vnfm_job_finish()
79             self.write_vnf_creation_info()
80             self.save_info_to_db()
81             if REPORT_TO_AAI:
82                 self.create_vnf_in_aai()
83                 self.create_vserver_in_aai()
84         except NSLCMException as e:
85             self.vnf_inst_failed_handle(e.message)
86         except Exception:
87             logger.error(traceback.format_exc())
88             self.vnf_inst_failed_handle('unexpected exception')
89
90     def get_params(self):
91         self.ns_inst_id = self.data['ns_instance_id']
92         vnf_index = int(float(self.data['vnf_index'])) - 1
93         additional_vnf_info = self.data['additional_param_for_vnf'][vnf_index]
94         self.vnf_id = ignore_case_get(additional_vnf_info, 'vnfProfileId')
95         additional_param = ignore_case_get(additional_vnf_info, 'additionalParam')
96         self.vnfm_inst_id = ignore_case_get(additional_param, 'vnfmInstanceId')
97         para = ignore_case_get(additional_param, 'inputs')
98         self.inputs = json.loads(para) if isinstance(para, (str, unicode)) else para
99         self.vim_id = ignore_case_get(additional_param, 'vimId')
100         self.vnfd_id = ignore_case_get(additional_param, 'vnfdId')
101
102     def check_nf_name_exist(self):
103         is_exist = NfInstModel.objects.filter(nf_name=self.vnf_inst_name).exists()
104         if is_exist:
105             logger.error('The name of NF instance already exists.')
106             raise NSLCMException('The name of NF instance already exists.')
107
108     def get_vnfd_id(self):
109         if self.vnfd_id:
110             logger.debug("need not get vnfd_id")
111             self.nsd_model = {'vnfs': [], 'vls': [], 'vnffgs': []}
112             self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
113             self.vnf_inst_name = self.vnf_inst_name[:30]
114             return
115         ns_inst_info = NSInstModel.objects.get(id=self.ns_inst_id)
116         self.ns_inst_name = ns_inst_info.name
117         self.nsd_model = json.loads(ns_inst_info.nsd_model)
118         for vnf_info in self.nsd_model['vnfs']:
119             if self.vnf_id == vnf_info['vnf_id']:
120                 self.vnfd_id = vnf_info['properties']['id']
121                 if 'name' not in vnf_info['properties']:
122                     self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
123                 else:
124                     self.vnf_inst_name = vnf_info['properties']['name'] + str(uuid.uuid4())
125                 self.vnf_inst_name = self.vnf_inst_name[:30]
126                 return
127         logger.error('Can not found vnf in nsd model')
128         raise NSLCMException('Can not found vnf in nsd model')
129
130     def check_nf_package_valid(self):
131         nf_package_info = query_vnfpackage_by_id(self.vnfd_id)
132         self.nf_package_info = nf_package_info["packageInfo"]
133         self.vnfd_model = ignore_case_get(self.nf_package_info, "vnfdModel")
134
135     def get_virtual_link_info(self, vnf_id):
136         virtual_link_list, ext_virtual_link = [], []
137         for vnf_info in self.nsd_model['vnfs']:
138             if vnf_info['vnf_id'] != vnf_id:
139                 continue
140             for network_info in vnf_info['networks']:
141                 vl_instance = VLInstModel.objects.get(
142                     vldid=network_info['vl_id'], 
143                     ownertype=OWNER_TYPE.NS,
144                     ownerid=self.ns_inst_id)
145                 vl_instance_id = vl_instance.vlinstanceid
146                 network_name, subnet_name = self.get_network_info_of_vl(network_info['vl_id'])
147                 virtual_link_list.append({
148                     'network_name': network_name, 
149                     'key_name': network_info['key_name'],
150                     'subnetwork_name': subnet_name, 
151                     'vl_instance_id': vl_instance_id
152                 })
153                 ext_virtual_link.append({
154                     "vlInstanceId": vl_instance_id,
155                     "resourceId": vl_instance.relatednetworkid,
156                     "resourceSubnetId": vl_instance.relatedsubnetworkid,
157                     "cpdId": self.get_cpd_id_of_vl(network_info['key_name']),
158                     "vim": {
159                         "vimid": vl_instance.vimid
160                     }
161                 })
162         return virtual_link_list, ext_virtual_link
163
164     def get_cpd_id_of_vl(self, vl_key):
165         for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
166             if vl_key == cpd["key_name"]:
167                 return cpd["cpd_id"]
168         return ""
169
170     def get_network_info_of_vl(self, vl_id):
171         for vnf_info in self.nsd_model['vls']:
172             if vnf_info['vl_id'] == vl_id:
173                 return vnf_info['properties']['network_name'], vnf_info['properties']['name']
174         return '', ''
175
176     def send_nf_init_request_to_vnfm(self):
177         virtual_link_list, ext_virtual_link = self.get_virtual_link_info(self.vnf_id)
178         req_param = json.JSONEncoder().encode({
179             'vnfInstanceName': self.vnf_inst_name, 
180             'vnfPackageId': ignore_case_get(self.nf_package_info, "vnfPackageId"),
181             'vnfDescriptorId': self.vnfd_id,
182             'extVirtualLink': ext_virtual_link,
183             'additionalParam': {"inputs": self.inputs, 
184                 "vimId": self.vim_id,
185                 "extVirtualLinks": virtual_link_list}})
186         rsp = send_nf_init_request(self.vnfm_inst_id, req_param)
187         self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
188         self.vnfm_nf_inst_id = ignore_case_get(rsp, 'vnfInstanceId')
189
190         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
191             mnfinstid=self.vnfm_nf_inst_id,
192             nf_name=self.vnf_inst_name,
193             vnf_id=self.vnf_id,
194             package_id=ignore_case_get(self.nf_package_info, "vnfPackageId"),
195             vnfm_inst_id=self.vnfm_inst_id,
196             ns_inst_id=self.ns_inst_id,
197             version=ignore_case_get(self.nf_package_info, "vnfdVersion"),
198             vendor=ignore_case_get(self.nf_package_info, "vnfdProvider"),
199             vnfd_model=self.vnfd_model,
200             input_params=json.JSONEncoder().encode(self.inputs),
201             lastuptime=now_time())
202
203     def send_get_vnfm_request_to_extsys(self):
204         resp_body = get_vnfm_by_id(self.vnfm_inst_id)
205         self.vnfm_inst_name = ignore_case_get(resp_body, 'name')
206
207     def send_create_vnf_request_to_resmgr(self):
208         pkg_vnfd = self.vnfd_model
209         data = {
210             'nf_inst_id': self.nf_inst_id,
211             'vnfm_nf_inst_id': self.vnfm_nf_inst_id,
212             'vnf_inst_name': self.vnf_inst_name,
213             'ns_inst_id': self.ns_inst_id,
214             'ns_inst_name': self.ns_inst_name,
215             'nf_inst_name': self.vnf_inst_name,
216             'vnfm_inst_id': self.vnfm_inst_id,
217             'vnfm_inst_name': self.vnfm_inst_name,
218             'vnfd_name': pkg_vnfd['metadata'].get('name', 'undefined'),
219             'vnfd_id': self.vnfd_id,
220             'job_id': self.job_id,
221             'nf_inst_status': VNF_STATUS.INSTANTIATING,
222             'vnf_type': pkg_vnfd['metadata'].get('vnf_type', 'undefined'),
223             'nf_package_id': ignore_case_get(self.nf_package_info, "vnfPackageId")
224         }
225         create_vnf(data)
226
227     def wait_vnfm_job_finish(self):
228         ret = wait_job_finish(vnfm_id=self.vnfm_inst_id, vnfo_job_id=self.job_id, 
229             vnfm_job_id=self.vnfm_job_id, progress_range=[10, 90],
230             timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
231
232         if ret != JOB_MODEL_STATUS.FINISHED:
233             logger.error('VNF instantiation failed on VNFM side.')
234             raise NSLCMException('VNF instantiation failed on VNFM side.')
235
236     def write_vnf_creation_info(self):
237         logger.debug("write_vnf_creation_info start")
238         vm_inst_infos = VmInstModel.objects.filter(insttype=INST_TYPE.VNF, instid=self.nf_inst_id)
239         data = {
240             'nf_inst_id': self.nf_inst_id,
241             'ns_inst_id': self.ns_inst_id,
242             'vnfm_inst_id': self.vnfm_inst_id,
243             'vms': [{'vmId': vm_inst_info.resouceid, 'vmName': vm_inst_info.vmname, 'vmStatus': 'ACTIVE'} for
244                     vm_inst_info in vm_inst_infos]}
245         create_vnf_creation_info(data)
246         logger.debug("write_vnf_creation_info end")
247
248     def save_info_to_db(self):
249         logger.debug("save_info_to_db start")
250         do_biz_with_share_lock("set-vnflist-in-vnffginst-%s" % self.ns_inst_id, self.save_vnf_inst_id_in_vnffg)
251         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.ACTIVE, lastuptime=now_time())
252         JobUtil.add_job_status(self.job_id, 100, 'vnf instantiation success', 0)
253         logger.debug("save_info_to_db end")
254
255     def vnf_inst_failed_handle(self, error_msg):
256         logger.error('VNF instantiation failed, detail message: %s' % error_msg)
257         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED,
258                                                                     lastuptime=now_time())
259         JobUtil.add_job_status(self.job_id, 255, 'VNF instantiation failed, detail message: %s' % error_msg, 0)
260
261     def save_vnf_inst_id_in_vnffg(self):
262         vnffgs = self.nsd_model['vnffgs']
263         for vnffg in vnffgs:
264             if self.vnf_id not in vnffg['members']:
265                 continue
266             vnffg_inst_infos = VNFFGInstModel.objects.filter(vnffgdid=vnffg['vnffg_Id'], nsinstid=self.ns_inst_id)
267             if not vnffg_inst_infos:
268                 logger.error('Vnffg instance not exist.')
269                 raise NSLCMException('Vnffg instance not exist.')
270             vnf_list = vnffg_inst_infos[0].vnflist
271             vnffg_inst_infos.update(vnf_list=vnf_list + ',' + self.nf_inst_id if vnf_list else self.nf_inst_id)
272
273     def create_vnf_in_aai(self):
274         logger.debug("CreateVnfs::create_vnf_in_aai::report vnf instance[%s] to aai." % self.nf_inst_id)
275         data = {
276             "vnf-id": self.nf_inst_id,
277             "vnf-name": self.vnf_inst_name,
278             "vnf-type": "vnf-type-test111",
279             "service-id": self.ns_inst_id,
280             "in-maint": True,
281             "is-closed-loop-disabled": False,
282             "relationship-list": {
283                 "relationship": [
284                     {
285                         "related-to": "service-instance",
286                         "relationship-data": [
287                             {
288                                 "relationship-key": "customer.global-customer-id",
289                                 "relationship-value": "global-customer-id-" + self.ns_inst_id
290                             },
291                             {
292                                 "relationship-key": "service-subscription.service-type",
293                                 "relationship-value": "service-type-" + self.ns_inst_id
294                             },
295                             {
296                                 "relationship-key": "service-instance.service-instance-id",
297                                 "relationship-value": self.ns_inst_id
298                             }
299                         ]
300                     }
301                 ]
302             }
303         }
304         resp_data, resp_status = create_vnf_aai(self.nf_inst_id, data)
305         if resp_data:
306             logger.debug("Fail to create vnf instance[%s] to aai, vnf instance=[%s], resp_status: [%s]."
307                          % (self.nf_inst_id, self.ns_inst_id, resp_status))
308         else:
309             logger.debug("Success to create vnf instance[%s] to aai, vnf instance=[%s], resp_status: [%s]."
310                          % (self.nf_inst_id, self.ns_inst_id, resp_status))
311
312     def create_vserver_in_aai(self):
313         logger.debug("CreateVnfs::create_vserver_in_aai::report vserver instance to aai.")
314         cloud_owner, cloud_region_id = split_vim_to_owner_region(self.vim_id)
315
316         # query vim_info from aai
317         vim_info = get_vim_by_id(self.vim_id)
318         tenant_id = vim_info["tenant"]
319         vm_inst_infos = VmInstModel.objects.filter(insttype=INST_TYPE.VNF, instid=self.nf_inst_id)
320         for vm_inst_info in vm_inst_infos:
321             vserver_id = vm_inst_info.resouceid
322             data = {
323                 "vserver-id": vm_inst_info.resouceid,
324                 "vserver-name": vm_inst_info.vmname,
325                 "prov-status": "ACTIVE",
326                 "vserver-selflink": "",
327                 "in-maint": True,
328                 "is-closed-loop-disabled": False,
329                 "relationship-list": {
330                     "relationship": [
331                         {
332                             "related-to": "generic-vnf",
333                             "relationship-data": [
334                                 {
335                                     "relationship-key": "generic-vnf.vnf-id",
336                                     "relationship-value": self.nf_inst_id
337                                 }
338                             ]
339                         }
340                     ]
341                 }
342             }
343
344             # create vserver instance in aai
345             resp_data, resp_status = create_vserver_aai(cloud_owner, cloud_region_id, tenant_id, vserver_id, data)
346             if resp_data:
347                 logger.debug("Fail to create vserver instance[%s] to aai, vnf instance=[%s], resp_status: [%s]."
348                              % (vserver_id, self.nf_inst_id, resp_status))
349             else:
350                 logger.debug("Success to create vserver instance[%s] to aai, vnf instance=[%s], resp_status: [%s]."
351                              % (vserver_id, self.nf_inst_id, resp_status))