83bb4443db9df91a21a7711cac3a6b3a4cd12d16
[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 from lcm.ns.const import OWNER_TYPE
20
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.database.models import NfPackageModel, NfInstModel, NSInstModel, VmInstModel, VNFFGInstModel, VLInstModel
24 from lcm.pub.exceptions import NSLCMException
25 from lcm.pub.msapi.extsys import get_vnfm_by_id
26 from lcm.pub.msapi.resmgr import create_vnf, create_vnf_creation_info
27 from lcm.pub.msapi.vnfmdriver import send_nf_init_request
28 from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil, JOB_TYPE
29 from lcm.pub.utils.share_lock import do_biz_with_share_lock
30 from lcm.pub.utils.timeutil import now_time
31 from lcm.pub.utils.values import ignore_case_get
32
33 logger = logging.getLogger(__name__)
34
35
36 def prepare_create_params():
37     nf_inst_id = str(uuid.uuid4())
38     NfInstModel(nfinstid=nf_inst_id, status=VNF_STATUS.INSTANTIATING, create_time=now_time(),
39                 lastuptime=now_time()).save()
40     job_id = JobUtil.create_job(INST_TYPE_NAME.VNF, JOB_TYPE.CREATE_VNF, nf_inst_id)
41     JobUtil.add_job_status(job_id, 0, 'create vnf record in database.', 0)
42     return nf_inst_id, job_id
43
44
45 class CreateVnfs(Thread):
46     def __init__(self, data, nf_inst_id, job_id):
47         super(CreateVnfs, self).__init__()
48         self.data = data
49         self.nf_inst_id = nf_inst_id
50         self.job_id = job_id
51         self.ns_inst_id = ''
52         self.vnf_id = ''
53         self.vnfd_id = ''
54         self.ns_inst_name = ''
55         self.nsd_model = ''
56         self.vnfd_model = ''
57         self.vnf_inst_name = ''
58         self.vnfm_inst_id = ''
59         self.inputs = ''
60         self.nf_package_info = ''
61         self.vnfm_nf_inst_id = ''
62         self.vnfm_job_id = ''
63         self.vnfm_inst_name = ''
64         self.vim_id = ''
65
66     def run(self):
67         try:
68             self.get_params()
69             self.check_nf_name_exist()
70             self.get_vnfd_id()
71             self.check_nf_package_valid()
72             self.send_nf_init_request_to_vnfm()
73             self.send_get_vnfm_request_to_extsys()
74             self.send_create_vnf_request_to_resmgr()
75             self.wait_vnfm_job_finish()
76             self.write_vnf_creation_info()
77             self.save_info_to_db()
78         except NSLCMException as e:
79             self.vnf_inst_failed_handle(e.message)
80         except Exception:
81             logger.error(traceback.format_exc())
82             self.vnf_inst_failed_handle('unexpected exception')
83
84     def get_params(self):
85         self.ns_inst_id = self.data['ns_instance_id']
86         vnf_index = int(float(self.data['vnf_index'])) - 1
87         additional_vnf_info = self.data['additional_param_for_vnf'][vnf_index]
88         self.vnf_id = ignore_case_get(additional_vnf_info, 'vnfProfileId')
89         additional_param = ignore_case_get(additional_vnf_info, 'additionalParam')
90         self.vnfm_inst_id = ignore_case_get(additional_param, 'vnfmInstanceId')
91         para = ignore_case_get(additional_param, 'inputs')
92         self.inputs = json.loads(para) if isinstance(para, (str, unicode)) else para
93         self.vim_id = ignore_case_get(additional_param, 'vimId')
94         self.vnfd_id = ignore_case_get(additional_param, 'vnfdId')
95
96     def check_nf_name_exist(self):
97         is_exist = NfInstModel.objects.filter(nf_name=self.vnf_inst_name).exists()
98         if is_exist:
99             logger.error('The name of NF instance already exists.')
100             raise NSLCMException('The name of NF instance already exists.')
101
102     def get_vnfd_id(self):
103         if self.vnfd_id:
104             logger.debug("need not get vnfd_id")
105             self.nsd_model={'vnfs': [], 'vls': [], 'vnffgs': []}
106             self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
107             self.vnf_inst_name = self.vnf_inst_name[:30]
108             return
109         ns_inst_info = NSInstModel.objects.get(id=self.ns_inst_id)
110         self.ns_inst_name = ns_inst_info.name
111         self.nsd_model = json.loads(ns_inst_info.nsd_model)
112         for vnf_info in self.nsd_model['vnfs']:
113             if self.vnf_id == vnf_info['vnf_id']:
114                 self.vnfd_id = vnf_info['properties']['id']
115                 if 'name' not in vnf_info['properties']:
116                     self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
117                 else:
118                     self.vnf_inst_name = vnf_info['properties']['name'] + str(uuid.uuid4())
119                 self.vnf_inst_name = self.vnf_inst_name[:30]
120                 return
121         logger.error('Can not found vnf in nsd model')
122         raise NSLCMException('Can not found vnf in nsd model')
123
124     def check_nf_package_valid(self):
125         nf_package_info = NfPackageModel.objects.filter(vnfdid=self.vnfd_id)
126         if not nf_package_info:
127             logger.info('NF package not exist.')
128             raise NSLCMException('NF package not exist.')
129         self.nf_package_info = nf_package_info[0]
130         self.vnfd_model = json.loads(self.nf_package_info.vnfdmodel)
131
132     def get_virtual_link_info(self, vnf_id):
133         virtual_link_list, ext_virtual_link = [], []
134         for vnf_info in self.nsd_model['vnfs']:
135             if vnf_info['vnf_id'] != vnf_id:
136                 continue
137             for network_info in vnf_info['networks']:
138                 vl_instance = VLInstModel.objects.get(
139                     vldid=network_info['vl_id'], 
140                     ownertype=OWNER_TYPE.NS,
141                     ownerid=self.ns_inst_id)
142                 vl_instance_id = vl_instance.vlinstanceid
143                 network_name, subnet_name = self.get_network_info_of_vl(network_info['vl_id'])
144                 virtual_link_list.append({
145                     'network_name': network_name, 
146                     'key_name': network_info['key_name'],
147                     'subnetwork_name': subnet_name, 
148                     'vl_instance_id': vl_instance_id
149                 })
150                 ext_virtual_link.append({
151                     "vlInstanceId": vl_instance_id,
152                     "resourceId": vl_instance.relatednetworkid,
153                     "resourceSubnetId": vl_instance.relatedsubnetworkid,
154                     "cpdId": self.get_cpd_id_of_vl(network_info['key_name']),
155                     "vim": {
156                         "vimid": vl_instance.vimid
157                     }
158                 })
159         return virtual_link_list, ext_virtual_link
160
161     def get_cpd_id_of_vl(self, vl_key):
162         for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
163             if vl_key == cpd["key_name"]:
164                 return cpd["cpd_id"]
165         return ""
166
167     def get_network_info_of_vl(self, vl_id):
168         for vnf_info in self.nsd_model['vls']:
169             if vnf_info['vl_id'] == vl_id:
170                 return vnf_info['properties']['network_name'], vnf_info['properties']['name']
171         return '', ''
172
173     def send_nf_init_request_to_vnfm(self):
174         virtual_link_list, ext_virtual_link = self.get_virtual_link_info(self.vnf_id)
175         req_param = json.JSONEncoder().encode({
176             'vnfInstanceName': self.vnf_inst_name, 
177             'vnfPackageId': self.nf_package_info.nfpackageid, 
178             'vnfDescriptorId': self.vnfd_id,
179             'extVirtualLink': ext_virtual_link,
180             'additionalParam': {"inputs": self.inputs, 
181                 "vimId": self.vim_id,
182                 "extVirtualLinks": virtual_link_list}})
183         rsp = send_nf_init_request(self.vnfm_inst_id, req_param)
184         self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
185         self.vnfm_nf_inst_id = ignore_case_get(rsp, 'vnfInstanceId')
186
187         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
188             mnfinstid=self.vnfm_nf_inst_id,
189             nf_name=self.vnf_inst_name,
190             vnf_id=self.vnf_id,
191             package_id=self.nf_package_info.nfpackageid,
192             vnfm_inst_id=self.vnfm_inst_id,
193             ns_inst_id=self.ns_inst_id,
194             version=self.nf_package_info.vnfversion,
195             vendor=self.nf_package_info.vendor,
196             vnfd_model=self.vnfd_model,
197             input_params=json.JSONEncoder().encode(self.inputs),
198             lastuptime=now_time())
199
200     def send_get_vnfm_request_to_extsys(self):
201         resp_body = get_vnfm_by_id(self.vnfm_inst_id)
202         self.vnfm_inst_name = ignore_case_get(resp_body, 'name')
203
204     def send_create_vnf_request_to_resmgr(self):
205         pkg_vnfd = json.loads(self.nf_package_info.vnfdmodel)
206         data = {
207             'nf_inst_id': self.nf_inst_id,
208             'vnfm_nf_inst_id': self.vnfm_nf_inst_id,
209             'vnf_inst_name': self.vnf_inst_name,
210             'ns_inst_id': self.ns_inst_id,
211             'ns_inst_name': self.ns_inst_name,
212             'nf_inst_name': self.vnf_inst_name,
213             'vnfm_inst_id': self.vnfm_inst_id,
214             'vnfm_inst_name': self.vnfm_inst_name,
215             'vnfd_name': pkg_vnfd['metadata'].get('name', 'undefined'),
216             'vnfd_id': self.vnfd_id,
217             'job_id': self.job_id,
218             'nf_inst_status': VNF_STATUS.INSTANTIATING,
219             'vnf_type': pkg_vnfd['metadata'].get('vnf_type', 'undefined'),
220             'nf_package_id': self.nf_package_info.nfpackageid}
221         create_vnf(data)
222
223     def wait_vnfm_job_finish(self):
224         ret = wait_job_finish(vnfm_id=self.vnfm_inst_id, vnfo_job_id=self.job_id, 
225             vnfm_job_id=self.vnfm_job_id, progress_range=[10, 90],
226             timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
227
228         if ret != JOB_MODEL_STATUS.FINISHED:
229             logger.error('VNF instantiation failed on VNFM side.')
230             raise NSLCMException('VNF instantiation failed on VNFM side.')
231
232     def write_vnf_creation_info(self):
233         logger.debug("write_vnf_creation_info start")
234         vm_inst_infos = VmInstModel.objects.filter(insttype=INST_TYPE.VNF, instid=self.nf_inst_id)
235         data = {
236             'nf_inst_id': self.nf_inst_id,
237             'ns_inst_id': self.ns_inst_id,
238             'vnfm_inst_id': self.vnfm_inst_id,
239             'vms': [{'vmId': vm_inst_info.resouceid, 'vmName': vm_inst_info.vmname, 'vmStatus': 'ACTIVE'} for
240                     vm_inst_info in vm_inst_infos]}
241         create_vnf_creation_info(data)
242         logger.debug("write_vnf_creation_info end")
243
244     def save_info_to_db(self):
245         logger.debug("save_info_to_db start")
246         do_biz_with_share_lock("set-vnflist-in-vnffginst-%s" % self.ns_inst_id, self.save_vnf_inst_id_in_vnffg)
247         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.ACTIVE, lastuptime=now_time())
248         JobUtil.add_job_status(self.job_id, 100, 'vnf instantiation success', 0)
249         logger.debug("save_info_to_db end")
250
251     def vnf_inst_failed_handle(self, error_msg):
252         logger.error('VNF instantiation failed, detail message: %s' % error_msg)
253         NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED,
254                                                                     lastuptime=now_time())
255         JobUtil.add_job_status(self.job_id, 255, 'VNF instantiation failed, detail message: %s' % error_msg, 0)
256
257     def save_vnf_inst_id_in_vnffg(self):
258         vnffgs = self.nsd_model['vnffgs']
259         for vnffg in vnffgs:
260             if self.vnf_id not in vnffg['members']:
261                 continue
262             vnffg_inst_infos = VNFFGInstModel.objects.filter(vnffgdid=vnffg['vnffg_Id'], nsinstid=self.ns_inst_id)
263             if not vnffg_inst_infos:
264                 logger.error('Vnffg instance not exist.')
265                 raise NSLCMException('Vnffg instance not exist.')
266             vnf_list = vnffg_inst_infos[0].vnflist
267             vnffg_inst_infos.update(vnf_list=vnf_list + ',' + self.nf_inst_id if vnf_list else self.nf_inst_id)