1 # Copyright 2016-2017 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.
20 from rest_framework.decorators import api_view
21 from rest_framework.response import Response
23 from driver.pub.utils import restcall
24 from driver.pub.utils.restcall import req_by_msb, call_aai
26 logger = logging.getLogger(__name__)
30 return "=================%s==================" % inspect.stack()[1][3]
33 def ignorcase_get(args, key):
41 if old_key.upper() == key.upper():
46 def mapping_conv(keyword_map, rest_return):
48 for param in keyword_map:
49 if keyword_map[param]:
50 resp_data[keyword_map[param]] = ignorcase_get(rest_return, param)
54 query_vnfd_url = "api/nslcm/v1/vnfpackage/%s"
55 query_vnfm_url = "api/extsys/v1/vnfms/%s"
56 query_package_url = "api/nslcm/v1/vnfpackage/%s"
59 # Query vnfm_info from nslcm
60 def get_vnfminfo_from_nslcm(vnfmid):
61 ret = req_by_msb("api/nslcm/v1/vnfms/%s" % vnfmid, "GET")
65 # Query vnfm_info from esr
67 ret = call_aai("api/aai-esr-server/v1/vnfms/%s" % vnfmid, "GET")
71 # Query vnfd_info from nslcm
72 def vnfd_get(vnfpackageid):
73 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
77 # Query vnfpackage_info from nslcm
78 def vnfpackage_get(csarid):
79 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % csarid, "GET")
83 # ==================================================
84 create_vnf_url = "v1/vnfs"
85 create_vnf_param_mapping = {
88 "instantiationLevel": "",
89 "vnfInstanceName": "",
91 "vnfDescriptorId": "",
93 "vnfInstanceDescription": "",
95 "additionalParam": ""}
96 create_vnf_resp_mapping = {
97 "VNFInstanceID": "vnfInstanceId",
102 @api_view(http_method_names=['POST'])
103 def instantiate_vnf(request, *args, **kwargs):
105 logger.debug("[%s] request.data=%s", fun_name(), request.data)
106 vnfm_id = ignorcase_get(kwargs, "vnfmid")
107 ret = get_vnfminfo_from_nslcm(vnfm_id)
109 return Response(data={'error': ret[1]}, status=ret[2])
110 vnfm_info = json.JSONDecoder().decode(ret[1])
111 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
112 vnf_package_id = ignorcase_get(request.data, "vnfPackageId")
113 ret = vnfd_get(vnf_package_id)
115 return Response(data={'error': ret[1]}, status=ret[2])
116 vnfd_info = json.JSONDecoder().decode(ret[1])
117 logger.debug("[%s] vnfd_info=%s", fun_name(), vnfd_info)
118 csar_id = ignorcase_get(vnfd_info, "csarId")
119 ret = vnfpackage_get(csar_id)
121 return Response(data={'error': ret[1]}, status=ret[2])
122 vnf_package_info = json.JSONDecoder().decode(ret[1])
123 packageInfo = ignorcase_get(vnf_package_info, "packageInfo")
124 logger.debug("[%s] packageInfo=%s", fun_name(), packageInfo)
127 data["VNFMID"] = vnfm_id
128 vnfdId = ignorcase_get(packageInfo, "vnfdId")
129 # TODO convert sdc vnf package to vnf vender package
130 from urlparse import urlparse
131 vnfm_ip = urlparse(ignorcase_get(vnfm_info, "url")).netloc.split(':')[0]
132 VNFS = ["SPGW", "MME"]
134 data["VNFD"] = "ftp://VMVERSION:vmversion@" + vnfm_ip + ":21/" + vnfdId
135 data["VNFURL"] = "ftp://VMVERSION:vmversion@" + vnfm_ip + ":21/" + vnfdId
137 data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
138 data["VNFURL"] = ignorcase_get(packageInfo, "downloadUri")
140 data["extension"] = {}
142 for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
143 inputs.append({"name": name, "value": value})
146 "ignorcase_get(request.data, \"additionalParam\") = %s" % ignorcase_get(request.data, "additionalParam"))
147 data["extension"]["inputs"] = json.dumps(inputs)
148 data["extension"]["extVirtualLinks"] = ignorcase_get(
149 ignorcase_get(request.data, "additionalParam"), "extVirtualLinks")
150 data["extension"]["vnfinstancename"] = ignorcase_get(request.data, "vnfInstanceName")
151 data["extension"]["vnfid"] = data["VNFD"]
152 data["extension"]["multivim"] = 0
153 logger.debug("[%s] call_req data=%s", fun_name(), data)
155 ret = restcall.call_req(
156 base_url=ignorcase_get(vnfm_info, "url"),
157 user=ignorcase_get(vnfm_info, "userName"),
158 passwd=ignorcase_get(vnfm_info, "password"),
159 auth_type=restcall.rest_no_auth,
160 resource=create_vnf_url,
162 content=json.JSONEncoder().encode(data))
164 logger.debug("[%s] call_req ret=%s", fun_name(), ret)
166 return Response(data={'error': ret[1]}, status=ret[2])
167 resp = json.JSONDecoder().decode(ret[1])
168 resp_data = mapping_conv(create_vnf_resp_mapping, resp)
169 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
170 except Exception as e:
171 logger.error("Error occurred when instantiating VNF")
173 return Response(data=resp_data, status=ret[2])
176 # ==================================================
177 vnf_delete_url = "v1/vnfs/%s"
178 vnf_delete_param_mapping = {
179 "terminationType": "terminationType",
180 "gracefulTerminationTimeout": "gracefulTerminationTimeout"}
181 vnf_delete_resp_mapping = {
182 "vnfInstanceId": "vnfInstanceId",
186 @api_view(http_method_names=['POST'])
187 def terminate_vnf(request, *args, **kwargs):
189 logger.debug("[%s] request.data=%s", fun_name(), request.data)
190 vnfm_id = ignorcase_get(kwargs, "vnfmid")
191 ret = get_vnfminfo_from_nslcm(vnfm_id)
193 return Response(data={'error': ret[1]}, status=ret[2])
194 vnfm_info = json.JSONDecoder().decode(ret[1])
195 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
197 logger.debug("[%s]req_data=%s", fun_name(), data)
198 ret = restcall.call_req(
199 base_url=ignorcase_get(vnfm_info, "url"),
200 user=ignorcase_get(vnfm_info, "userName"),
201 passwd=ignorcase_get(vnfm_info, "password"),
202 auth_type=restcall.rest_no_auth,
203 resource=vnf_delete_url % (ignorcase_get(kwargs, "vnfInstanceID")),
205 content=json.JSONEncoder().encode(data))
207 return Response(data={'error': ret[1]}, status=ret[2])
208 resp = json.JSONDecoder().decode(ret[1])
209 resp_data = mapping_conv(vnf_delete_resp_mapping, resp)
210 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
211 except Exception as e:
212 logger.error("Error occurred when terminating VNF")
214 return Response(data=resp_data, status=ret[2])
217 # ==================================================
220 vnf_detail_url = "v1/vnfs/%s"
221 vnf_detail_resp_mapping = {
222 "VNFInstanseStatus": "status"
226 @api_view(http_method_names=['GET'])
227 def query_vnf(request, *args, **kwargs):
229 logger.debug("[%s] request.data=%s", fun_name(), request.data)
230 vnfm_id = ignorcase_get(kwargs, "vnfmid")
231 ret = get_vnfminfo_from_nslcm(vnfm_id)
233 return Response(data={'error': ret[1]}, status=ret[2])
234 vnfm_info = json.JSONDecoder().decode(ret[1])
235 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
237 ret = restcall.call_req(
238 base_url=ignorcase_get(vnfm_info, "url"),
239 user=ignorcase_get(vnfm_info, "userName"),
240 passwd=ignorcase_get(vnfm_info, "password"),
241 auth_type=restcall.rest_no_auth,
242 resource=vnf_detail_url % (ignorcase_get(kwargs, "vnfInstanceID")),
244 content=json.JSONEncoder().encode(data))
246 return Response(data={'error': ret[1]}, status=ret[2])
247 resp = json.JSONDecoder().decode(ret[1])
248 vnf_status = ignorcase_get(resp, "vnfinstancestatus")
249 resp_data = {"vnfInfo": {"vnfStatus": vnf_status}}
250 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
251 except Exception as e:
252 logger.error("Error occurred when querying VNF information.")
254 return Response(data=resp_data, status=ret[2])
257 # Get Operation Status
258 operation_status_url = '/v1/jobs/{jobId}?NFVOID={nfvoId}&VNFMID={vnfmId}&ResponseID={responseId}'
259 operation_status_resp_map = {
262 "Progress": "progress",
263 "StatusDescription": "currentStep",
264 "ErrorCode": "errorCode",
265 "ResponseId": "responseId",
266 "ResponseHistoryList": "responseHistoryList",
267 "ResponseDescriptor": "responseDescriptor"
271 @api_view(http_method_names=['GET'])
272 def operation_status(request, *args, **kwargs):
275 logger.debug("[%s] request.data=%s", fun_name(), request.data)
276 vnfm_id = ignorcase_get(kwargs, "vnfmid")
277 ret = get_vnfminfo_from_nslcm(vnfm_id)
279 return Response(data={'error': ret[1]}, status=ret[2])
280 vnfm_info = json.JSONDecoder().decode(ret[1])
281 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
282 ret = restcall.call_req(
283 base_url=ignorcase_get(vnfm_info, 'url'),
284 user=ignorcase_get(vnfm_info, 'userName'),
285 passwd=ignorcase_get(vnfm_info, 'password'),
286 auth_type=restcall.rest_no_auth,
287 resource=operation_status_url.format(jobId=ignorcase_get(kwargs, 'jobid'), nfvoId=1,
288 vnfmId=ignorcase_get(kwargs, 'vnfmid'),
289 responseId=ignorcase_get(request.GET, 'responseId')),
291 content=json.JSONEncoder().encode(data))
294 return Response(data={'error': ret[1]}, status=ret[2])
295 resp_data = json.JSONDecoder().decode(ret[1])
296 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
297 except Exception as e:
298 logger.error("Error occurred when getting operation status information.")
300 return Response(data=resp_data, status=ret[2])
303 # Grant VNF Lifecycle Operation
304 grant_vnf_url = 'api/nslcm/v1/ns/grantvnf'
305 grant_vnf_param_map = {
312 "VNFInstanceID": "vnfInstanceId",
313 "OperationRight": "",
319 @api_view(http_method_names=['PUT'])
320 def grantvnf(request, *args, **kwargs):
321 logger.info("=====grantvnf=====")
324 logger.info("req_data = %s", request.data)
325 data = mapping_conv(grant_vnf_param_map, request.data)
326 logger.info("grant_vnf_url = %s", grant_vnf_url)
327 data["vnfDescriptorId"] = ""
328 if ignorcase_get(request.data, "operationright") == 0:
329 data["lifecycleOperation"] = "Instantiate"
330 data["addresource"] = []
331 for vm in ignorcase_get(request.data, "vmlist"):
332 for i in range(int(ignorcase_get(vm, "vmnumber"))):
333 data["addresource"].append(
335 "resourceDefinitionId": i,
336 "vdu": ignorcase_get(vm, "vmflavor"),
337 "vimid": ignorcase_get(vm, "vimid"),
338 "tenant": ignorcase_get(vm, "tenant")
341 data["additionalparam"] = {}
342 data["additionalparam"]["vnfmid"] = ignorcase_get(request.data, "vnfmid")
343 data["additionalparam"]["vimid"] = ignorcase_get(request.data, "vimid")
344 data["additionalparam"]["tenant"] = ignorcase_get(request.data, "tenant")
346 logger.info("data = %s", data)
347 ret = req_by_msb(grant_vnf_url, "POST", content=json.JSONEncoder().encode(data))
348 logger.info("ret = %s", ret)
350 return Response(data={'error': ret[1]}, status=ret[2])
351 resp = json.JSONDecoder().decode(ret[1])
353 resp_data['vimid'] = ignorcase_get(resp['vim'], 'vimid')
354 resp_data['tenant'] = ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
356 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
357 except Exception as e:
358 logger.error("Error occurred in Grant VNF.")
360 return Response(data=resp_data, status=ret[2])
364 notify_url = 'api/nslcm/v1/ns/{vnfmid}/vnfs/{vnfInstanceId}/Notify'
369 "VNFInstanceID": "vnfInstanceId",
371 "EventType": "operation",
380 @api_view(http_method_names=['POST'])
381 def notify(request, *args, **kwargs):
383 logger.info("[%s]req_data = %s", fun_name(), request.data)
384 data = mapping_conv(notify_param_map, request.data)
385 logger.info("[%s]data = %s", fun_name(), data)
387 data["status"] = "result"
388 data["jobId"] = "notMust"
389 data["affectedVnfc"] = []
390 data["affectedVl"] = []
391 data["affectedVirtualStorage"] = []
392 data["affectedCp"] = []
394 affectedvnfcs = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvnfc")
395 affectedvls = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvl")
396 affectedcps = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedcp")
397 vnfdmodule = ignorcase_get(ignorcase_get(request.data, "extension"), "vnfdmodule")
399 data["vnfdmodule"] = vnfdmodule
401 for affectedvnfc in affectedvnfcs:
402 data["affectedVnfc"].append({
403 "vnfcInstanceId": ignorcase_get(affectedvnfc, "vnfcinstanceid"),
404 "vduId": ignorcase_get(affectedvnfc, "vduId"),
405 "changeType": ignorcase_get(affectedvnfc, "changeType"),
406 "vimid": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "vimid"),
407 "vmId": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourceid"),
408 "vmName": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourcename")
411 for affectedvl in affectedvls:
412 data["affectedVl"].append({
413 "vlInstanceId": ignorcase_get(affectedvl, "virtuallinkinstanceid"),
414 "vimid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "vimid"),
415 "vldid": ignorcase_get(affectedvl, "virtuallinkdescid"),
416 "vllid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
417 "vlName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
420 for affectedcp in affectedcps:
421 data["affectedCp"].append(affectedcp)
423 # "virtualLinkInstanceId": ignorcase_get(affectedcp, "virtuallinkinstanceid"),
424 # "ownerId": ignorcase_get(affectedcp, "ownerId"),
425 # "ownerType": ignorcase_get(affectedcp, "ownerType")
427 ret = req_by_msb(notify_url.format(vnfmid=ignorcase_get(data, 'VNFMID'),
428 vnfInstanceId=ignorcase_get(data, 'vnfinstanceid')),
429 "POST", content=json.JSONEncoder().encode(data))
431 logger.info("[%s]data = %s", fun_name(), ret)
433 return Response(data={'error': ret[1]}, status=ret[2])
434 except Exception as e:
435 logger.error("Error occurred in LCM notification.")
437 return Response(data=None, status=ret[2])
440 nf_scaling_url = '/v1/vnfs/{vnfInstanceID}/scale'
443 @api_view(http_method_names=['POST'])
444 def scale(request, *args, **kwargs):
445 logger.info("====scale_vnf===")
447 logger.info("request.data = %s", request.data)
448 logger.info("requested_url = %s", request.get_full_path())
449 vnfm_id = ignorcase_get(kwargs, "vnfmid")
450 nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
451 ret = get_vnfminfo_from_nslcm(vnfm_id)
453 return Response(data={'error': ret[1]}, status=ret[2])
454 vnfm_info = json.JSONDecoder().decode(ret[1])
455 scale_type = ignorcase_get(request.data, "type")
456 aspect_id = ignorcase_get(request.data, "aspectId")
457 number_of_steps = ignorcase_get(request.data, "numberOfSteps")
458 # extension = ignorcase_get(request.data, "additionalParam")
459 # vnfd_model = ignorcase_get(extension, "vnfdModel")
463 'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
464 'vmlist': [{'VMNumber': number_of_steps, 'VMFlavor': aspect_id}],
468 for vdu_id in get_vdus(vnfd_model, aspect_id):
469 data['vmlist'].append({
471 "VMNumber": number_of_steps
474 logger.info("data = %s", data)
475 ret = restcall.call_req(
476 base_url=ignorcase_get(vnfm_info, "url"),
477 user=ignorcase_get(vnfm_info, "userName"),
478 passwd=ignorcase_get(vnfm_info, "password"),
479 auth_type=restcall.rest_no_auth,
480 resource=nf_scaling_url.format(vnfInstanceID=nf_instance_id),
482 content=json.JSONEncoder().encode(data))
483 logger.info("ret=%s", ret)
485 return Response(data={'error': 'scale error'}, status=ret[2])
486 resp_data = json.JSONDecoder().decode(ret[1])
487 # jobId = resp_data["jobid"]
488 logger.info("resp_data=%s", resp_data)
489 except Exception as e:
490 logger.error("Error occurred when scaling VNF,error:%s", e.message)
491 logger.error(traceback.format_exc())
492 return Response(data={'error': 'scale expection'}, status='500')
493 return Response(data=resp_data, status=ret[2])
496 nf_healing_url = '/api/v1/nf_m_i/nfs/{vnfInstanceID}/vms/operation'
499 @api_view(http_method_names=['POST'])
500 def heal(request, *args, **kwargs):
501 logger.info("====heal_vnf===")
503 logger.info("request.data = %s", request.data)
504 logger.info("requested_url = %s", request.get_full_path())
505 vnfm_id = ignorcase_get(kwargs, "vnfmid")
506 nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
507 ret = get_vnfminfo_from_nslcm(vnfm_id)
509 return Response(data={'error': ret[1]}, status=ret[2])
510 vnfm_info = json.JSONDecoder().decode(ret[1])
512 data['lifecycleoperation'] = 'operate'
513 data['isgrace'] = 'force'
515 logger.info("data = %s", data)
516 ret = restcall.call_req(
517 base_url=ignorcase_get(vnfm_info, "url"),
518 user=ignorcase_get(vnfm_info, "userName"),
519 passwd=ignorcase_get(vnfm_info, "password"),
520 auth_type=restcall.rest_no_auth,
521 resource=nf_healing_url.format(vnfInstanceID=nf_instance_id),
523 content=json.JSONEncoder().encode(data))
524 logger.info("ret=%s", ret)
526 return Response(data={'error': 'heal error'}, status=ret[2])
527 resp_data = json.JSONDecoder().decode(ret[1])
528 # jobId = resp_data["jobid"]
529 logger.info("resp_data=%s", resp_data)
530 except Exception as e:
531 logger.error("Error occurred when healing VNF,error:%s", e.message)
532 logger.error(traceback.format_exc())
533 return Response(data={'error': 'heal expection'}, status='500')
534 return Response(data=resp_data, status=ret[2])
537 def get_vdus(nf_model, aspect_id):
538 associated_group = ''
540 vnf_flavours = nf_model['vnf_flavours']
541 for vnf_flaour in vnf_flavours:
542 scaling_aspects = vnf_flaour['scaling_aspects']
543 for aspect in scaling_aspects:
544 if aspect_id == aspect['id']:
545 associated_group = aspect['associated_group']
547 if not associated_group:
548 logger.error('Cannot find the corresponding element group')
549 raise Exception('Cannot find the corresponding element group')
550 for element_group in nf_model['element_groups']:
551 if element_group['group_id'] == associated_group:
552 members = element_group['members']
554 logger.error('Cannot find the corresponding members')
555 raise Exception('Cannot find the corresponding members')
559 @api_view(http_method_names=['GET'])
560 def samples(request, *args, **kwargs):
561 return Response(data={"status": "ok"})