1 # Copyright 2016-2018 ZTE Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 from threading import Thread
21 from lcm.ns.enum import OWNER_TYPE
22 from lcm.ns_vnfs.const import NFVO_VNF_INST_TIMEOUT_SECOND
23 from lcm.ns_vnfs.biz.subscribe import SubscriptionCreation
24 from lcm.ns_vnfs.biz.wait_job import wait_job_finish
25 from lcm.ns_vnfs.enum import VNF_STATUS
26 from lcm.pub.config.config import REPORT_TO_AAI
27 from lcm.pub.config.config import REG_TO_MSB_REG_PARAM, OOF_BASE_URL, OOF_PASSWD, OOF_USER
28 from lcm.pub.config.config import CUST_NAME, CUST_LAT, CUST_LONG
29 from lcm.pub.database.models import NfInstModel, NSInstModel, VNFFGInstModel, VLInstModel, OOFDataModel
30 from lcm.jobs.enum import JOB_MODEL_STATUS, JOB_ACTION, JOB_PROGRESS, JOB_ERROR_CODE, JOB_TYPE
31 from lcm.pub.exceptions import NSLCMException
32 from lcm.pub.msapi.aai import create_vnf_aai
33 from lcm.pub.msapi.extsys import get_vnfm_by_id
34 from lcm.pub.msapi.sdc_run_catalog import query_vnfpackage_by_id
35 from lcm.pub.msapi.vnfmdriver import send_nf_init_request
36 from lcm.pub.utils import restcall
37 from lcm.pub.utils.jobutil import JobUtil
38 # from lcm.pub.utils.share_lock import do_biz_with_share_lock
39 from lcm.pub.utils.timeutil import now_time
40 from lcm.pub.utils.values import ignore_case_get
43 logger = logging.getLogger(__name__)
46 def prepare_create_params():
47 nf_inst_id = str(uuid.uuid4())
50 status=VNF_STATUS.INSTANTIATING,
51 create_time=now_time(),
54 job_id = JobUtil.create_job(JOB_TYPE.VNF, JOB_ACTION.CREATE, nf_inst_id)
55 JobUtil.add_job_status(job_id, JOB_PROGRESS.STARTED, 'create vnf record in database.', JOB_ERROR_CODE.NO_ERROR)
56 return nf_inst_id, job_id
59 class CreateVnfs(Thread):
60 def __init__(self, data, nf_inst_id, job_id):
61 super(CreateVnfs, self).__init__()
63 self.nf_inst_id = nf_inst_id
68 self.ns_inst_name = ''
71 self.vnf_inst_name = ''
72 self.vnfm_inst_id = ''
74 self.nf_package_info = ''
75 self.vnfm_nf_inst_id = ''
77 self.vnfm_inst_name = ''
83 self.check_nf_name_exist()
86 self.create_vnf_in_aai()
87 self.check_nf_package_valid()
88 self.send_nf_init_request_to_vnfm()
89 self.send_homing_request_to_OOF()
90 self.send_get_vnfm_request_to_extsys()
91 self.wait_vnfm_job_finish()
93 self.save_info_to_db()
94 JobUtil.add_job_status(self.job_id, JOB_PROGRESS.FINISHED, 'vnf instantiation success', JOB_ERROR_CODE.NO_ERROR)
95 except NSLCMException as e:
96 self.vnf_inst_failed_handle(e.args[0])
98 logger.error(traceback.format_exc())
99 self.vnf_inst_failed_handle('unexpected exception')
101 def get_params(self):
102 self.ns_inst_id = self.data['ns_instance_id']
103 vnf_index = int(float(self.data['vnf_index'])) - 1
104 additional_vnf_info = self.data['additional_param_for_vnf'][vnf_index]
105 self.vnf_id = ignore_case_get(additional_vnf_info, 'vnfProfileId')
106 additional_param = ignore_case_get(additional_vnf_info, 'additionalParam')
107 self.properties = ignore_case_get(additional_param, 'properties')
108 self.vnfm_inst_id = ignore_case_get(additional_param, 'vnfmInstanceId')
109 para = ignore_case_get(additional_param, 'inputs')
110 self.inputs = json.loads(para) if isinstance(para, str) else para
111 self.vim_id = ignore_case_get(additional_param, 'vimId')
112 self.vnfd_id = ignore_case_get(additional_param, 'vnfdId')
114 def check_nf_name_exist(self):
115 is_exist = NfInstModel.objects.filter(nf_name=self.vnf_inst_name).exists()
117 raise NSLCMException('The name of VNF instance already exists.')
119 def get_vnfd_id(self):
121 logger.debug("need not get vnfd_id")
122 self.nsd_model = {'vnfs': [], 'vls': [], 'vnffgs': []}
123 self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
124 self.vnf_inst_name = self.vnf_inst_name[:30]
126 ns_inst_info = NSInstModel.objects.get(id=self.ns_inst_id)
127 self.ns_inst_name = ns_inst_info.name
128 self.nsd_model = json.loads(ns_inst_info.nsd_model)
129 for vnf_info in self.nsd_model['vnfs']:
130 if self.vnf_id == vnf_info['vnf_id']:
131 self.vnfd_id = vnf_info['properties']['id']
132 if 'name' not in vnf_info['properties']:
133 # HW vnf instance name must start with alphabet
134 self.vnf_inst_name = 'vnf' + self.vnfd_id[:10] + str(uuid.uuid4())
136 self.vnf_inst_name = vnf_info['properties']['name'] + str(uuid.uuid4())
137 self.vnf_inst_name = self.vnf_inst_name[:30]
138 self.vnf_inst_name = self.vnf_inst_name.replace("-", "_")
140 raise NSLCMException('Can not found vnf in nsd model')
142 def check_nf_package_valid(self):
143 nfpackage_info = query_vnfpackage_by_id(self.vnfd_id)
144 self.nf_package_info = nfpackage_info["packageInfo"]
145 self.vnfd_model = ignore_case_get(self.nf_package_info, "vnfdModel")
146 self.vnfd_model = json.loads(self.vnfd_model)
148 def get_virtual_link_info(self, vnf_id):
149 virtual_link_list, ext_virtual_link = [], []
150 for vnf_info in self.nsd_model['vnfs']:
151 if vnf_info['vnf_id'] != vnf_id:
153 for network_info in vnf_info['networks']:
154 vl_instance = VLInstModel.objects.get(
155 vldid=network_info['vl_id'],
156 ownertype=OWNER_TYPE.NS,
157 ownerid=self.ns_inst_id)
158 vl_instance_id = vl_instance.vlinstanceid
159 network_name, subnet_name = self.get_network_info_of_vl(network_info['vl_id'])
160 virtual_link_list.append({
161 'network_name': network_name,
162 'key_name': network_info['key_name'],
163 'subnetwork_name': subnet_name,
164 'vl_instance_id': vl_instance_id
166 vim_id = json.JSONDecoder().decode(vl_instance.vimid) if isinstance(vl_instance.vimid, str) \
167 else vl_instance.vimid
168 ext_virtual_link.append({
169 "vlInstanceId": vl_instance_id,
170 "resourceId": vl_instance.relatednetworkid,
171 "resourceSubnetId": vl_instance.relatedsubnetworkid,
172 "cpdId": self.get_cpd_id_of_vl(network_info['key_name']),
177 "id": vl_instance_id,
178 "vimConnectionId": vl_instance.vimid,
179 "extCps": self.get_cpds_of_vl(network_info['key_name'])
181 return virtual_link_list, ext_virtual_link
183 def get_cpds_of_vl(self, vl_key):
185 logger.debug("vl_keya; %s" % vl_key)
186 for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
187 logger.debug("exposed_cpd; %s" % cpd)
188 if vl_key == cpd["key_name"]:
189 cp = {"cpdId": cpd["cpd_id"], "cpConfig": []}
193 def get_cpd_id_of_vl(self, vl_key):
194 for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
195 if vl_key == cpd["key_name"]:
199 def get_network_info_of_vl(self, vl_id):
200 for vnf_info in self.nsd_model['vls']:
201 if vnf_info['vl_id'] == vl_id:
202 return vnf_info['properties']['vl_profile']['networkName'], vnf_info['properties']['vl_profile']['networkName'] # ['initiationParameters']['name']
205 def send_nf_init_request_to_vnfm(self):
206 virtual_link_list, ext_virtual_link = self.get_virtual_link_info(self.vnf_id)
207 req_param = json.JSONEncoder().encode({
208 'vnfInstanceName': self.vnf_inst_name,
209 'vnfPackageId': ignore_case_get(self.nf_package_info, "vnfPackageId"),
210 'vnfDescriptorId': self.vnfd_id,
211 'flavourId': "default",
212 'extVirtualLink': ext_virtual_link,
214 "properties": self.properties,
215 "inputs": self.inputs,
216 "vimId": self.vim_id,
217 "extVirtualLinks": virtual_link_list
220 rsp = send_nf_init_request(self.vnfm_inst_id, req_param)
221 self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
222 self.vnfm_nf_inst_id = ignore_case_get(rsp, 'vnfInstanceId')
224 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
225 mnfinstid=self.vnfm_nf_inst_id,
226 nf_name=self.vnf_inst_name,
228 package_id=ignore_case_get(self.nf_package_info, "vnfPackageId"),
229 vnfm_inst_id=self.vnfm_inst_id,
230 ns_inst_id=self.ns_inst_id,
231 version=ignore_case_get(self.nf_package_info, "vnfdVersion"),
232 vendor=ignore_case_get(self.nf_package_info, "vnfdProvider"),
233 vnfd_model=self.vnfd_model,
234 input_params=json.JSONEncoder().encode(self.inputs),
235 lastuptime=now_time())
237 def build_homing_request(self):
238 id = str(uuid.uuid4())
239 callback_uri = "http://{vfcBaseUrl}/api/nslcm/v1/ns/placevnf"
240 IP = REG_TO_MSB_REG_PARAM["nodes"][0]["ip"]
241 PORT = REG_TO_MSB_REG_PARAM["nodes"][0]["port"]
242 vfcBaseUrl = IP + ':' + PORT
243 callback_uri = callback_uri.format(vfcBaseUrl=vfcBaseUrl)
244 modelInvariantId = "no-resourceModelInvariantId"
245 modelVersionId = "no-resourceModelVersionId"
246 nsInfo = NSInstModel.objects.filter(id=self.ns_inst_id)
248 "resourceModuleName": self.vnf_id,
249 "serviceResourceId": self.vnfm_nf_inst_id,
250 "resourceModelInfo": {
251 "modelInvariantId": modelInvariantId,
252 "modelVersionId": modelVersionId
257 # vim_info = self.vim_id.split("_")
258 # identifiers = list()
259 # identifiers.append(vim_info[1])
260 # cloudOwner = vim_info[0]
262 if isinstance(self.vim_id, str):
263 self.vim_id = json.loads(self.vim_id)
264 identifiers.append(self.vim_id['cloud_regionid'])
265 cloudOwner = self.vim_id['cloud_owner']
266 required_candidate = [
268 "identifierType": "vimId",
269 "cloudOwner": cloudOwner,
270 "identifiers": identifiers
273 placementDemand["requiredCandidates"] = required_candidate
279 "callbackUrl": callback_uri,
281 "requestType": "create",
283 "optimizers": ["placement"],
287 "requestParameters": {
288 "customerLatitude": CUST_LAT,
289 "customerLongitude": CUST_LONG,
290 "customerName": CUST_NAME
293 "globalSubscriberId": "",
294 "subscriberName": "",
295 "subscriberCommonSiteId": "",
297 "placementDemands": []
300 "serviceInstanceId": self.ns_inst_id,
301 "serviceName": self.ns_inst_name,
303 "modelInvariantId": nsInfo[0].nsd_invariant_id,
304 "modelVersionId": nsInfo[0].nsd_id
308 req_body["placementInfo"]["placementDemands"].append(placementDemand)
309 # Stored the init request info inside DB
310 OOFDataModel.objects.create(
313 request_status="init",
314 request_module_name=self.vnf_id,
315 service_resource_id=self.vnfm_nf_inst_id,
323 def send_homing_request_to_OOF(self):
324 req_body = self.build_homing_request()
325 base_url = OOF_BASE_URL
326 resources = "/api/oof/v1/placement"
327 resp = restcall.call_req(base_url, OOF_USER, OOF_PASSWD, restcall.rest_no_auth, resources, "POST",
328 json.dumps(req_body), "")
329 # resp = restcall.call_req(
333 # auth_type=restcall.rest_no_auth,
334 # resource=resources,
336 # content=json.dumps(req_body),
337 # additional_headers="")
339 resp_status = resp[-1]
341 logger.debug("Got OOF sync response")
343 logger.warn("Missing OOF sync response")
344 logger.debug(("OOF sync response code is %s") % resp_status)
345 if str(resp_status) != '202' or resp[0] != 0:
346 OOFDataModel.objects.filter(
347 request_id=req_body["requestInfo"]["requestId"],
348 transaction_id=req_body["requestInfo"]["transactionId"]
350 request_status="failed",
353 cloud_region_id="none",
356 logger.error("Received a Bad Sync from OOF with response code %s" % resp_status)
357 logger.info("Completed Homing request to OOF")
359 def send_get_vnfm_request_to_extsys(self):
360 resp_body = get_vnfm_by_id(self.vnfm_inst_id)
361 self.vnfm_inst_name = ignore_case_get(resp_body, 'name')
363 def wait_vnfm_job_finish(self):
364 ret = wait_job_finish(
365 vnfm_id=self.vnfm_inst_id,
366 vnfo_job_id=self.job_id,
367 vnfm_job_id=self.vnfm_job_id,
368 progress_range=[10, 90],
369 timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
371 if ret != JOB_MODEL_STATUS.FINISHED:
372 raise NSLCMException('VNF instantiation failed from VNFM. The job status is %s' % ret)
376 'vnfInstanceId': self.vnfm_nf_inst_id,
377 'vnfmId': self.vnfm_inst_id
380 SubscriptionCreation(data).do_biz()
381 except NSLCMException as e:
382 logger.error("subscribe failed: %s", e.args[0])
383 except Exception as e:
384 logger.error("subscribe failed: %s", e.args[0])
386 def save_info_to_db(self):
387 logger.debug("save_info_to_db start")
388 # do_biz_with_share_lock("set-vnflist-in-vnffginst-%s" % self.ns_inst_id, self.save_vnf_inst_id_in_vnffg)
389 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.ACTIVE, lastuptime=now_time())
390 logger.debug("save_info_to_db end")
392 def vnf_inst_failed_handle(self, error_msg):
393 logger.error('VNF instantiation failed, detail message: %s' % error_msg)
394 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED, lastuptime=now_time())
395 JobUtil.add_job_status(self.job_id, 255, 'VNF instantiation failed, detail message: %s' % error_msg, 0)
397 def save_vnf_inst_id_in_vnffg(self):
398 vnffgs = self.nsd_model['vnffgs']
400 if self.vnf_id not in vnffg['members']:
402 vnffg_inst_infos = VNFFGInstModel.objects.filter(vnffgdid=vnffg['vnffg_Id'], nsinstid=self.ns_inst_id)
403 if not vnffg_inst_infos:
404 raise NSLCMException('Vnffg instance not exist.')
405 vnf_list = vnffg_inst_infos[0].vnflist
406 vnffg_inst_infos.update(vnf_list=vnf_list + ',' + self.nf_inst_id if vnf_list else self.nf_inst_id)
408 def create_vnf_in_aai(self):
409 logger.debug("CreateVnfs::create_vnf_in_aai::report vnf instance[%s] to aai." % self.nf_inst_id)
411 ns_insts = NSInstModel.objects.filter(id=self.ns_inst_id)
412 self.global_customer_id = ns_insts[0].global_customer_id
413 self.service_type = ns_insts[0].service_type
415 "vnf-id": self.nf_inst_id,
416 "vnf-name": self.vnf_inst_name,
417 "vnf-type": "vnf-type-test111",
418 "service-id": self.ns_inst_id,
420 "is-closed-loop-disabled": False,
421 "relationship-list": {
424 "related-to": "service-instance",
425 "relationship-data": [
427 "relationship-key": "customer.global-customer-id",
428 "relationship-value": self.global_customer_id
431 "relationship-key": "service-subscription.service-type",
432 "relationship-value": self.service_type
435 "relationship-key": "service-instance.service-instance-id",
436 "relationship-value": self.ns_inst_id
443 resp_data, resp_status = create_vnf_aai(self.nf_inst_id, data)
444 logger.debug("Success to create vnf[%s] to aai, ns instance=[%s], resp_status: [%s]."
445 % (self.nf_inst_id, self.ns_inst_id, resp_status))
446 except NSLCMException as e:
447 logger.debug("Fail to create vnf[%s] to aai, ns instance=[%s], detail message: %s"
448 % (self.nf_inst_id, self.ns_inst_id, e.args[0]))
450 logger.error(traceback.format_exc())