1 # Copyright 2016 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.
18 from threading import Thread
20 from lcm.ns.const import OWNER_TYPE
21 from lcm.pub.config.config import REPORT_TO_AAI
22 from lcm.pub.database.models import NfInstModel, NSInstModel, VmInstModel, VNFFGInstModel, VLInstModel, OOFDataModel
23 from lcm.pub.exceptions import NSLCMException
24 from lcm.pub.msapi.aai import create_vnf_aai
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.sdc_run_catalog import query_vnfpackage_by_id
28 from lcm.pub.msapi.vnfmdriver import send_nf_init_request
29 from lcm.pub.utils.jobutil import JOB_MODEL_STATUS, JobUtil, JOB_TYPE
30 from lcm.pub.utils.share_lock import do_biz_with_share_lock
31 from lcm.pub.utils.timeutil import now_time
32 from lcm.pub.utils.values import ignore_case_get
33 from lcm.pub.utils import restcall
34 from lcm.ns_vnfs.const import VNF_STATUS, NFVO_VNF_INST_TIMEOUT_SECOND, INST_TYPE, INST_TYPE_NAME
35 from lcm.ns_vnfs.biz.wait_job import wait_job_finish
36 from lcm.pub.config.config import REG_TO_MSB_REG_PARAM, OOF_BASE_URL, OOF_PASSWD, OOF_USER
37 from lcm.ns_vnfs.biz.subscribe import Subscription
39 logger = logging.getLogger(__name__)
42 def prepare_create_params():
43 nf_inst_id = str(uuid.uuid4())
44 NfInstModel(nfinstid=nf_inst_id, status=VNF_STATUS.INSTANTIATING, create_time=now_time(),
45 lastuptime=now_time()).save()
46 job_id = JobUtil.create_job(INST_TYPE_NAME.VNF, JOB_TYPE.CREATE_VNF, nf_inst_id)
47 JobUtil.add_job_status(job_id, 0, 'create vnf record in database.', 0)
48 return nf_inst_id, job_id
51 class CreateVnfs(Thread):
52 def __init__(self, data, nf_inst_id, job_id):
53 super(CreateVnfs, self).__init__()
55 self.nf_inst_id = nf_inst_id
60 self.ns_inst_name = ''
63 self.vnf_inst_name = ''
64 self.vnfm_inst_id = ''
66 self.nf_package_info = ''
67 self.vnfm_nf_inst_id = ''
69 self.vnfm_inst_name = ''
75 self.check_nf_name_exist()
78 self.create_vnf_in_aai()
79 self.check_nf_package_valid()
80 self.send_nf_init_request_to_vnfm()
81 self.send_homing_request_to_OOF()
82 self.send_get_vnfm_request_to_extsys()
83 self.send_create_vnf_request_to_resmgr()
84 self.wait_vnfm_job_finish()
86 self.write_vnf_creation_info()
87 self.save_info_to_db()
88 JobUtil.add_job_status(self.job_id, 100, 'vnf instantiation success', 0)
89 except NSLCMException as e:
90 self.vnf_inst_failed_handle(e.message)
92 logger.error(traceback.format_exc())
93 self.vnf_inst_failed_handle('unexpected exception')
96 self.ns_inst_id = self.data['ns_instance_id']
97 vnf_index = int(float(self.data['vnf_index'])) - 1
98 additional_vnf_info = self.data['additional_param_for_vnf'][vnf_index]
99 self.vnf_id = ignore_case_get(additional_vnf_info, 'vnfProfileId')
100 additional_param = ignore_case_get(additional_vnf_info, 'additionalParam')
101 self.properties = ignore_case_get(additional_param, 'properties')
102 self.vnfm_inst_id = ignore_case_get(additional_param, 'vnfmInstanceId')
103 para = ignore_case_get(additional_param, 'inputs')
104 self.inputs = json.loads(para) if isinstance(para, (str, unicode)) else para
105 self.vim_id = ignore_case_get(additional_param, 'vimId')
106 self.vnfd_id = ignore_case_get(additional_param, 'vnfdId')
108 def check_nf_name_exist(self):
109 is_exist = NfInstModel.objects.filter(nf_name=self.vnf_inst_name).exists()
111 logger.error('The name of NF instance already exists.')
112 raise NSLCMException('The name of NF instance already exists.')
114 def get_vnfd_id(self):
116 logger.debug("need not get vnfd_id")
117 self.nsd_model = {'ns_vnfs': [], 'ns_vls': [], 'vnffgs': []}
118 self.vnf_inst_name = self.vnfd_id + str(uuid.uuid4())
119 self.vnf_inst_name = self.vnf_inst_name[:30]
121 ns_inst_info = NSInstModel.objects.get(id=self.ns_inst_id)
122 self.ns_inst_name = ns_inst_info.name
123 self.nsd_model = json.loads(ns_inst_info.nsd_model)
124 for vnf_info in self.nsd_model['ns_vnfs']:
125 if self.vnf_id == vnf_info['vnf_id']:
126 self.vnfd_id = vnf_info['properties']['id']
127 if 'name' not in vnf_info['properties']:
128 # HW vnf instance name must start with alphabet
129 self.vnf_inst_name = 'vnf' + self.vnfd_id[:10] + str(uuid.uuid4())
131 self.vnf_inst_name = vnf_info['properties']['name'] + str(uuid.uuid4())
132 self.vnf_inst_name = self.vnf_inst_name[:30]
133 self.vnf_inst_name = self.vnf_inst_name.replace("-", "_")
135 logger.error('Can not found vnf in nsd model')
136 raise NSLCMException('Can not found vnf in nsd model')
138 def check_nf_package_valid(self):
139 nfpackage_info = query_vnfpackage_by_id(self.vnfd_id)
140 self.nf_package_info = nfpackage_info["packageInfo"]
141 self.vnfd_model = ignore_case_get(self.nf_package_info, "vnfdModel")
142 self.vnfd_model = json.loads(self.vnfd_model)
144 def get_virtual_link_info(self, vnf_id):
145 virtual_link_list, ext_virtual_link = [], []
146 for vnf_info in self.nsd_model['ns_vnfs']:
147 if vnf_info['vnf_id'] != vnf_id:
149 for network_info in vnf_info['networks']:
150 vl_instance = VLInstModel.objects.get(
151 vldid=network_info['vl_id'],
152 ownertype=OWNER_TYPE.NS,
153 ownerid=self.ns_inst_id)
154 vl_instance_id = vl_instance.vlinstanceid
155 network_name, subnet_name = self.get_network_info_of_vl(network_info['vl_id'])
156 virtual_link_list.append({
157 'network_name': network_name,
158 'key_name': network_info['key_name'],
159 'subnetwork_name': subnet_name,
160 'vl_instance_id': vl_instance_id
162 ext_virtual_link.append({
163 "vlInstanceId": vl_instance_id,
164 "resourceId": vl_instance.relatednetworkid,
165 "resourceSubnetId": vl_instance.relatedsubnetworkid,
166 "cpdId": self.get_cpd_id_of_vl(network_info['key_name']),
168 "vimid": vl_instance.vimid
171 return virtual_link_list, ext_virtual_link
173 def get_cpd_id_of_vl(self, vl_key):
174 for cpd in self.vnfd_model["vnf_exposed"]["external_cps"]:
175 if vl_key == cpd["key_name"]:
179 def get_network_info_of_vl(self, vl_id):
180 for vnf_info in self.nsd_model['ns_vls']:
181 if vnf_info['vl_id'] == vl_id:
182 return vnf_info['properties']['vl_profile']['networkName'], vnf_info['properties']['vl_profile']['initiationParameters']['name']
185 def send_nf_init_request_to_vnfm(self):
186 virtual_link_list, ext_virtual_link = self.get_virtual_link_info(self.vnf_id)
187 req_param = json.JSONEncoder().encode({
188 'vnfInstanceName': self.vnf_inst_name,
189 'vnfPackageId': ignore_case_get(self.nf_package_info, "vnfPackageId"),
190 'vnfDescriptorId': self.vnfd_id,
191 'extVirtualLink': ext_virtual_link,
193 "properties": self.properties,
194 "inputs": self.inputs,
195 "vimId": self.vim_id,
196 "extVirtualLinks": virtual_link_list
199 rsp = send_nf_init_request(self.vnfm_inst_id, req_param)
200 self.vnfm_job_id = ignore_case_get(rsp, 'jobId')
201 self.vnfm_nf_inst_id = ignore_case_get(rsp, 'vnfInstanceId')
203 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(
204 mnfinstid=self.vnfm_nf_inst_id,
205 nf_name=self.vnf_inst_name,
207 package_id=ignore_case_get(self.nf_package_info, "vnfPackageId"),
208 vnfm_inst_id=self.vnfm_inst_id,
209 ns_inst_id=self.ns_inst_id,
210 version=ignore_case_get(self.nf_package_info, "vnfdVersion"),
211 vendor=ignore_case_get(self.nf_package_info, "vnfdProvider"),
212 vnfd_model=self.vnfd_model,
213 input_params=json.JSONEncoder().encode(self.inputs),
214 lastuptime=now_time())
216 def build_homing_request(self):
217 id = str(uuid.uuid4())
218 callback_uri = " {vfcBaseUrl}/api/nslcm/v1/ns/placevnf"
219 IP = REG_TO_MSB_REG_PARAM["nodes"][0]["ip"]
220 PORT = REG_TO_MSB_REG_PARAM["nodes"][0]["port"]
221 vfcBaseUrl = IP + ':' + PORT
222 callback_uri = callback_uri.format(vfcBaseUrl=vfcBaseUrl)
223 modelInvariantId = "no-resourceModelInvariantId"
224 modelVersionId = "no-resourceModelVersionId"
225 nsInfo = NSInstModel.objects.filter(id=self.ns_inst_id)
227 "resourceModuleName": self.vnf_inst_name,
228 "serviceResourceId": self.vnfm_nf_inst_id,
229 "resourceModelInfo": {
230 "modelInvariantId": modelInvariantId,
231 "modelVersionId": modelVersionId
238 "callbackUrl": callback_uri,
240 "requestType": "create",
242 "optimizers": ["placement"],
246 "placementDemands": []
249 "serviceInstanceId": self.ns_inst_id,
250 "serviceName": self.ns_inst_name,
252 "modelInvariantId": nsInfo[0].nsd_invariant_id,
253 "modelVersionId": nsInfo[0].nsd_id
257 req_body["placementInfo"]["placementDemands"].append(placementDemand)
258 # Stored the init request info inside DB
259 OOFDataModel.objects.create(
262 request_status="init",
263 request_module_name=self.vnfm_nf_inst_id,
264 service_resource_id=self.vnf_inst_name,
272 def send_homing_request_to_OOF(self):
273 req_body = self.build_homing_request()
274 base_url = OOF_BASE_URL
275 resources = "/api/oof/v1/placement"
276 resp = restcall.call_req(base_url=base_url, user=OOF_USER, passwd=OOF_PASSWD,
277 auth_type=restcall.rest_oneway_auth, resource=resources,
278 method="POST", content=req_body, additional_headers="")
280 resp_status = resp[-1]
282 logger.debug("Got OOF sync response")
284 logger.warn("Missing OOF sync response")
285 logger.debug(("OOF sync response code is %s") % resp_status)
286 if str(resp_status) != '202' or resp[0] != 0:
287 OOFDataModel.objects.filter(request_id=req_body["requestInfo"]["requestId"],
288 transaction_id=req_body["requestInfo"]["transactionId"]).update(
289 request_status="failed",
292 cloud_region_id="none",
295 raise Exception("Received a Bad Sync from OOF with response code %s" % resp_status)
296 logger.info("Completed Homing request to OOF")
298 def send_get_vnfm_request_to_extsys(self):
299 resp_body = get_vnfm_by_id(self.vnfm_inst_id)
300 self.vnfm_inst_name = ignore_case_get(resp_body, 'name')
302 def send_create_vnf_request_to_resmgr(self):
303 pkg_vnfd = self.vnfd_model
305 'nf_inst_id': self.nf_inst_id,
306 'vnfm_nf_inst_id': self.vnfm_nf_inst_id,
307 'vnf_inst_name': self.vnf_inst_name,
308 'ns_inst_id': self.ns_inst_id,
309 'ns_inst_name': self.ns_inst_name,
310 'nf_inst_name': self.vnf_inst_name,
311 'vnfm_inst_id': self.vnfm_inst_id,
312 'vnfm_inst_name': self.vnfm_inst_name,
313 'vnfd_name': pkg_vnfd['metadata'].get('name', 'undefined'),
314 'vnfd_id': self.vnfd_id,
315 'job_id': self.job_id,
316 'nf_inst_status': VNF_STATUS.INSTANTIATING,
317 'vnf_type': pkg_vnfd['metadata'].get('vnf_type', 'undefined'),
318 'nf_package_id': ignore_case_get(self.nf_package_info, "vnfPackageId")
322 def wait_vnfm_job_finish(self):
323 ret = wait_job_finish(vnfm_id=self.vnfm_inst_id,
324 vnfo_job_id=self.job_id,
325 vnfm_job_id=self.vnfm_job_id,
326 progress_range=[10, 90],
327 timeout=NFVO_VNF_INST_TIMEOUT_SECOND)
329 if ret != JOB_MODEL_STATUS.FINISHED:
330 logger.error('VNF instantiation failed on VNFM side. ret=[%s]', ret)
331 raise NSLCMException('VNF instantiation failed on VNFM side.')
335 'vnfInstanceId': self.vnfm_nf_inst_id,
336 'vnfmId': self.vnfm_inst_id
338 Subscription(data).do_biz()
340 def write_vnf_creation_info(self):
341 logger.debug("write_vnf_creation_info start")
342 vm_inst_infos = VmInstModel.objects.filter(insttype=INST_TYPE.VNF, instid=self.nf_inst_id)
344 'nf_inst_id': self.nf_inst_id,
345 'ns_inst_id': self.ns_inst_id,
346 'vnfm_inst_id': self.vnfm_inst_id,
347 'vms': [{'vmId': vm_inst_info.resouceid, 'vmName': vm_inst_info.vmname, 'vmStatus': 'ACTIVE'} for
348 vm_inst_info in vm_inst_infos]}
349 create_vnf_creation_info(data)
350 logger.debug("write_vnf_creation_info end")
352 def save_info_to_db(self):
353 logger.debug("save_info_to_db start")
354 do_biz_with_share_lock("set-vnflist-in-vnffginst-%s" % self.ns_inst_id, self.save_vnf_inst_id_in_vnffg)
355 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.ACTIVE, lastuptime=now_time())
356 logger.debug("save_info_to_db end")
358 def vnf_inst_failed_handle(self, error_msg):
359 logger.error('VNF instantiation failed, detail message: %s' % error_msg)
360 NfInstModel.objects.filter(nfinstid=self.nf_inst_id).update(status=VNF_STATUS.FAILED,
361 lastuptime=now_time())
362 JobUtil.add_job_status(self.job_id, 255, 'VNF instantiation failed, detail message: %s' % error_msg, 0)
364 def save_vnf_inst_id_in_vnffg(self):
365 vnffgs = self.nsd_model['vnffgs']
367 if self.vnf_id not in vnffg['members']:
369 vnffg_inst_infos = VNFFGInstModel.objects.filter(vnffgdid=vnffg['vnffg_Id'], nsinstid=self.ns_inst_id)
370 if not vnffg_inst_infos:
371 logger.error('Vnffg instance not exist.')
372 raise NSLCMException('Vnffg instance not exist.')
373 vnf_list = vnffg_inst_infos[0].vnflist
374 vnffg_inst_infos.update(vnf_list=vnf_list + ',' + self.nf_inst_id if vnf_list else self.nf_inst_id)
376 def create_vnf_in_aai(self):
377 logger.debug("CreateVnfs::create_vnf_in_aai::report vnf instance[%s] to aai." % self.nf_inst_id)
379 ns_insts = NSInstModel.objects.filter(id=self.ns_inst_id)
380 self.global_customer_id = ns_insts[0].global_customer_id
381 self.service_type = ns_insts[0].service_type
383 "vnf-id": self.nf_inst_id,
384 "vnf-name": self.vnf_inst_name,
385 "vnf-type": "vnf-type-test111",
386 "service-id": self.ns_inst_id,
388 "is-closed-loop-disabled": False,
389 "relationship-list": {
392 "related-to": "service-instance",
393 "relationship-data": [
395 "relationship-key": "customer.global-customer-id",
396 "relationship-value": self.global_customer_id
399 "relationship-key": "service-subscription.service-type",
400 "relationship-value": self.service_type
403 "relationship-key": "service-instance.service-instance-id",
404 "relationship-value": self.ns_inst_id
411 resp_data, resp_status = create_vnf_aai(self.nf_inst_id, data)
412 logger.debug("Success to create vnf[%s] to aai, ns instance=[%s], resp_status: [%s]."
413 % (self.nf_inst_id, self.ns_inst_id, resp_status))
414 except NSLCMException as e:
415 logger.debug("Fail to create vnf[%s] to aai, ns instance=[%s], detail message: %s"
416 % (self.nf_inst_id, self.ns_inst_id, e.message))
418 logger.error(traceback.format_exc())