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
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 by VNFMID
61 ret = req_by_msb("api/extsys/v1/vnfms/%s" % vnfmid, "GET")
65 def vnfd_get(vnfpackageid):
66 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
70 def vnfpackage_get(csarid):
71 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % csarid, "GET")
75 # ==================================================
76 create_vnf_url = "v1/vnfs"
77 create_vnf_param_mapping = {
80 "instantiationLevel": "",
81 "vnfInstanceName": "",
83 "vnfDescriptorId": "",
85 "vnfInstanceDescription": "",
87 "additionalParam": ""}
88 create_vnf_resp_mapping = {
89 "VNFInstanceID": "vnfInstanceId",
93 @api_view(http_method_names=['POST'])
94 def instantiate_vnf(request, *args, **kwargs):
96 logger.debug("[%s] request.data=%s", fun_name(), request.data)
97 vnfm_id = ignorcase_get(kwargs, "vnfmid")
98 ret = vnfm_get(vnfm_id)
100 return Response(data={'error': ret[1]}, status=ret[2])
101 vnfm_info = json.JSONDecoder().decode(ret[1])
102 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
103 vnf_package_id = ignorcase_get(request.data, "vnfPackageId")
104 ret = vnfd_get(vnf_package_id)
106 return Response(data={'error': ret[1]}, status=ret[2])
107 vnfd_info = json.JSONDecoder().decode(ret[1])
108 logger.debug("[%s] vnfd_info=%s", fun_name(), vnfd_info)
109 csar_id = ignorcase_get(vnfd_info, "csarId")
110 ret = vnfpackage_get(csar_id)
112 return Response(data={'error': ret[1]}, status=ret[2])
113 vnf_package_info = json.JSONDecoder().decode(ret[1])
114 packageInfo = ignorcase_get(vnf_package_info, "packageInfo")
115 logger.debug("[%s] packageInfo=%s", fun_name(), packageInfo)
118 data["VNFMID"] = vnfm_id
119 vnfdId = ignorcase_get(packageInfo, "vnfdId")
120 from urlparse import urlparse
121 vnfm_ip = urlparse(ignorcase_get(vnfm_info, "url")).netloc.split(':')[0]
122 VNFS = ["SPGW", "MME"]
124 data["VNFD"] = "ftp://VMVERSION:vmversion@" + vnfm_ip + ":21/" + vnfdId
125 data["VNFURL"] = "ftp://VMVERSION:vmversion@" + vnfm_ip + ":21/" + vnfdId
127 data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
128 data["VNFURL"] = ignorcase_get(packageInfo, "downloadUri")
130 data["extension"] = {}
132 for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
133 inputs.append({"name": name, "value": value})
136 "ignorcase_get(request.data, \"additionalParam\") = %s" % ignorcase_get(request.data, "additionalParam"))
137 data["extension"]["inputs"] = json.dumps(inputs)
138 data["extension"]["extVirtualLinks"] = ignorcase_get(
139 ignorcase_get(request.data, "additionalParam"), "extVirtualLinks")
140 data["extension"]["vnfinstancename"] = ignorcase_get(request.data, "vnfInstanceName")
141 data["extension"]["vnfid"] = data["VNFD"]
142 data["extension"]["multivim"] = 0
143 logger.debug("[%s] call_req data=%s", fun_name(), data)
144 ret = restcall.call_req(
145 base_url=ignorcase_get(vnfm_info, "url"),
146 user=ignorcase_get(vnfm_info, "userName"),
147 passwd=ignorcase_get(vnfm_info, "password"),
148 auth_type=restcall.rest_no_auth,
149 resource=create_vnf_url,
151 content=json.JSONEncoder().encode(data))
152 logger.debug("[%s] call_req ret=%s", fun_name(), ret)
154 return Response(data={'error': ret[1]}, status=ret[2])
155 resp = json.JSONDecoder().decode(ret[1])
156 resp_data = mapping_conv(create_vnf_resp_mapping, resp)
157 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
158 except Exception as e:
159 logger.error("Error occurred when instantiating VNF")
161 return Response(data=resp_data, status=ret[2])
164 # ==================================================
165 vnf_delete_url = "v1/vnfs/%s"
166 vnf_delete_param_mapping = {
167 "terminationType": "terminationType",
168 "gracefulTerminationTimeout": "gracefulTerminationTimeout"}
169 vnf_delete_resp_mapping = {
170 "vnfInstanceId": "vnfInstanceId",
174 @api_view(http_method_names=['POST'])
175 def terminate_vnf(request, *args, **kwargs):
177 logger.debug("[%s] request.data=%s", fun_name(), request.data)
178 vnfm_id = ignorcase_get(kwargs, "vnfmid")
179 ret = vnfm_get(vnfm_id)
181 return Response(data={'error': ret[1]}, status=ret[2])
182 vnfm_info = json.JSONDecoder().decode(ret[1])
183 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
185 logger.debug("[%s]req_data=%s", fun_name(), data)
186 ret = restcall.call_req(
187 base_url=ignorcase_get(vnfm_info, "url"),
188 user=ignorcase_get(vnfm_info, "userName"),
189 passwd=ignorcase_get(vnfm_info, "password"),
190 auth_type=restcall.rest_no_auth,
191 resource=vnf_delete_url % (ignorcase_get(kwargs, "vnfInstanceID")),
193 content=json.JSONEncoder().encode(data))
195 return Response(data={'error': ret[1]}, status=ret[2])
196 resp = json.JSONDecoder().decode(ret[1])
197 resp_data = mapping_conv(vnf_delete_resp_mapping, resp)
198 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
199 except Exception as e:
200 logger.error("Error occurred when terminating VNF")
202 return Response(data=resp_data, status=ret[2])
205 # ==================================================
208 vnf_detail_url = "v1/vnfs/%s"
209 vnf_detail_resp_mapping = {
210 "VNFInstanseStatus": "status",}
213 @api_view(http_method_names=['GET'])
214 def query_vnf(request, *args, **kwargs):
216 logger.debug("[%s] request.data=%s", fun_name(), request.data)
217 vnfm_id = ignorcase_get(kwargs, "vnfmid")
218 ret = vnfm_get(vnfm_id)
220 return Response(data={'error': ret[1]}, status=ret[2])
221 vnfm_info = json.JSONDecoder().decode(ret[1])
222 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
224 ret = restcall.call_req(
225 base_url=ignorcase_get(vnfm_info, "url"),
226 user=ignorcase_get(vnfm_info, "userName"),
227 passwd=ignorcase_get(vnfm_info, "password"),
228 auth_type=restcall.rest_no_auth,
229 resource=vnf_detail_url % (ignorcase_get(kwargs, "vnfInstanceID")),
231 content=json.JSONEncoder().encode(data))
233 return Response(data={'error': ret[1]}, status=ret[2])
234 resp = json.JSONDecoder().decode(ret[1])
235 vnf_status = ignorcase_get(resp, "vnfinstancestatus")
236 resp_data = {"vnfInfo": {"vnfStatus": vnf_status}}
237 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
238 except Exception as e:
239 logger.error("Error occurred when querying VNF information.")
241 return Response(data=resp_data, status=ret[2])
244 # Get Operation Status
245 operation_status_url = '/v1/jobs/{jobId}?NFVOID={nfvoId}&VNFMID={vnfmId}&ResponseID={responseId}'
246 operation_status_resp_map = {
249 "Progress": "progress",
250 "StatusDescription": "currentStep",
251 "ErrorCode": "errorCode",
252 "ResponseId": "responseId",
253 "ResponseHistoryList": "responseHistoryList",
254 "ResponseDescriptor": "responseDescriptor",}
257 @api_view(http_method_names=['GET'])
258 def operation_status(request, *args, **kwargs):
261 logger.debug("[%s] request.data=%s", fun_name(), request.data)
262 vnfm_id = ignorcase_get(kwargs, "vnfmid")
263 ret = vnfm_get(vnfm_id)
265 return Response(data={'error': ret[1]}, status=ret[2])
266 vnfm_info = json.JSONDecoder().decode(ret[1])
267 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
268 ret = restcall.call_req(
269 base_url=ignorcase_get(vnfm_info, 'url'),
270 user=ignorcase_get(vnfm_info, 'userName'),
271 passwd=ignorcase_get(vnfm_info, 'password'),
272 auth_type=restcall.rest_no_auth,
273 resource=operation_status_url.format(jobId=ignorcase_get(kwargs, 'jobid'), nfvoId=1,
274 vnfmId=ignorcase_get(kwargs, 'vnfmid'),
275 responseId=ignorcase_get(request.GET, 'responseId')),
277 content=json.JSONEncoder().encode(data))
280 return Response(data={'error': ret[1]}, status=ret[2])
281 resp_data = json.JSONDecoder().decode(ret[1])
282 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
283 except Exception as e:
284 logger.error("Error occurred when getting operation status information.")
286 return Response(data=resp_data, status=ret[2])
289 # Grant VNF Lifecycle Operation
290 grant_vnf_url = 'api/nslcm/v1/ns/grantvnf'
291 grant_vnf_param_map = {
298 "VNFInstanceID": "vnfInstanceId",
299 "OperationRight": "",
305 @api_view(http_method_names=['PUT'])
306 def grantvnf(request, *args, **kwargs):
307 logger.info("=====grantvnf=====")
310 logger.info("req_data = %s", request.data)
311 data = mapping_conv(grant_vnf_param_map, request.data)
312 logger.info("grant_vnf_url = %s", grant_vnf_url)
313 data["vnfDescriptorId"] = ""
314 if ignorcase_get(request.data, "operationright") == 0:
315 data["lifecycleOperation"] = "Instantiate"
316 data["addresource"] = []
317 for vm in ignorcase_get(request.data, "vmlist"):
318 for i in range(int(ignorcase_get(vm, "vmnumber"))):
319 data["addresource"].append(
321 "resourceDefinitionId": i,
322 "vdu": ignorcase_get(vm, "vmflavor"),
323 "vimid": ignorcase_get(vm, "vimid"),
324 "tenant": ignorcase_get(vm, "tenant")
327 data["additionalparam"] = {}
328 data["additionalparam"]["vnfmid"] = ignorcase_get(request.data, "vnfmid")
329 data["additionalparam"]["vimid"] = ignorcase_get(request.data, "vimid")
330 data["additionalparam"]["tenant"] = ignorcase_get(request.data, "tenant")
332 logger.info("data = %s", data)
333 ret = req_by_msb(grant_vnf_url, "POST", content=json.JSONEncoder().encode(data))
334 logger.info("ret = %s", ret)
336 return Response(data={'error': ret[1]}, status=ret[2])
337 resp = json.JSONDecoder().decode(ret[1])
339 resp_data['vimid'] = ignorcase_get(resp['vim'], 'vimid')
340 resp_data['tenant'] = ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
342 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
343 except Exception as e:
344 logger.error("Error occurred in Grant VNF.")
346 return Response(data=resp_data, status=ret[2])
350 notify_url = 'api/nslcm/v1/ns/{vnfmid}/vnfs/{vnfInstanceId}/Notify'
355 "VNFInstanceID": "vnfInstanceId",
357 "EventType": "operation",
365 @api_view(http_method_names=['POST'])
366 def notify(request, *args, **kwargs):
368 logger.info("[%s]req_data = %s", fun_name(), request.data)
369 data = mapping_conv(notify_param_map, request.data)
370 logger.info("[%s]data = %s", fun_name(), data)
372 data["status"] = "result"
373 data["jobId"] = "notMust"
374 data["affectedVnfc"] = []
375 data["affectedVl"] = []
376 data["affectedVirtualStorage"] = []
377 data["affectedCp"] = []
379 affectedvnfcs = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvnfc")
380 affectedvls = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvl")
381 affectedcps = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedcp")
382 vnfdmodule = ignorcase_get(ignorcase_get(request.data, "extension"), "vnfdmodule")
384 data["vnfdmodule"] = vnfdmodule
386 for affectedvnfc in affectedvnfcs:
387 data["affectedVnfc"].append({
388 "vnfcInstanceId": ignorcase_get(affectedvnfc, "vnfcinstanceid"),
389 "vduId": ignorcase_get(affectedvnfc, "vduId"),
390 "changeType": ignorcase_get(affectedvnfc, "changeType"),
391 "vimid": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "vimid"),
392 "vmId": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourceid"),
393 "vmName": ignorcase_get(ignorcase_get(affectedvnfc, "computeresource"), "resourcename")
396 for affectedvl in affectedvls:
397 data["affectedVl"].append({
398 "vlInstanceId": ignorcase_get(affectedvl, "virtuallinkinstanceid"),
399 "vimid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "vimid"),
400 "vldid": ignorcase_get(affectedvl, "virtuallinkdescid"),
401 "vllid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
402 "vlName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
405 for affectedcp in affectedcps:
406 data["affectedCp"].append(affectedcp)
408 # "virtualLinkInstanceId": ignorcase_get(affectedcp, "virtuallinkinstanceid"),
409 # "ownerId": ignorcase_get(affectedcp, "ownerId"),
410 # "ownerType": ignorcase_get(affectedcp, "ownerType")
412 ret = req_by_msb(notify_url.format(vnfmid=ignorcase_get(data, 'VNFMID'),
413 vnfInstanceId=ignorcase_get(data, 'vnfinstanceid')),
414 "POST", content=json.JSONEncoder().encode(data))
416 logger.info("[%s]data = %s", fun_name(), ret)
418 return Response(data={'error': ret[1]}, status=ret[2])
419 except Exception as e:
420 logger.error("Error occurred in LCM notification.")
422 return Response(data=None, status=ret[2])
425 nf_scaling_url = '/v1/vnfs/{vnfInstanceID}/scale'
428 @api_view(http_method_names=['POST'])
429 def scale(request, *args, **kwargs):
430 logger.info("====scale_vnf===")
432 logger.info("request.data = %s", request.data)
433 logger.info("requested_url = %s", request.get_full_path())
434 vnfm_id = ignorcase_get(kwargs, "vnfmid")
435 nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
436 ret = vnfm_get(vnfm_id)
438 return Response(data={'error': ret[1]}, status=ret[2])
439 vnfm_info = json.JSONDecoder().decode(ret[1])
440 scale_type = ignorcase_get(request.data, "type")
441 aspect_id = ignorcase_get(request.data, "aspectId")
442 number_of_steps = ignorcase_get(request.data, "numberOfSteps")
443 extension = ignorcase_get(request.data, "additionalParam")
444 vnfd_model = ignorcase_get(extension, "vnfdModel")
448 'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
449 'vmlist': [{'VMNumber':number_of_steps,'VMFlavor':aspect_id}],
453 for vdu_id in get_vdus(vnfd_model, aspect_id):
454 data['vmlist'].append({
456 "VMNumber": number_of_steps
459 logger.info("data = %s", data)
460 ret = restcall.call_req(
461 base_url=ignorcase_get(vnfm_info, "url"),
462 user=ignorcase_get(vnfm_info, "userName"),
463 passwd=ignorcase_get(vnfm_info, "password"),
464 auth_type=restcall.rest_no_auth,
465 resource=nf_scaling_url.format(vnfInstanceID=nf_instance_id),
467 content=json.JSONEncoder().encode(data))
468 logger.info("ret=%s", ret)
470 return Response(data={'error':'scale error'}, status=ret[2])
471 resp_data = json.JSONDecoder().decode(ret[1])
472 # jobId = resp_data["jobid"]
473 logger.info("resp_data=%s", resp_data)
474 except Exception as e:
475 logger.error("Error occurred when scaling VNF")
476 logger.error(traceback.format_exc())
477 return Response(data={'error':'scale expection'}, status='500')
478 return Response(data=resp_data, status=ret[2])
481 nf_healing_url = '/api/v1/nf_m_i/nfs/{vnfInstanceID}/vms/operation'
483 @api_view(http_method_names=['POST'])
484 def heal(request, *args, **kwargs):
485 logger.info("====heal_vnf===")
487 logger.info("request.data = %s", request.data)
488 logger.info("requested_url = %s", request.get_full_path())
489 vnfm_id = ignorcase_get(kwargs, "vnfmid")
490 nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
491 ret = vnfm_get(vnfm_id)
493 return Response(data={'error': ret[1]}, status=ret[2])
494 vnfm_info = json.JSONDecoder().decode(ret[1])
496 data['lifecycleoperation'] = 'operate'
497 data['isgrace'] = 'force'
499 logger.info("data = %s", data)
500 ret = restcall.call_req(
501 base_url=ignorcase_get(vnfm_info, "url"),
502 user=ignorcase_get(vnfm_info, "userName"),
503 passwd=ignorcase_get(vnfm_info, "password"),
504 auth_type=restcall.rest_no_auth,
505 resource=nf_healing_url.format(vnfInstanceID=nf_instance_id),
507 content=json.JSONEncoder().encode(data))
508 logger.info("ret=%s", ret)
510 return Response(data={'error': 'heal error'}, status=ret[2])
511 resp_data = json.JSONDecoder().decode(ret[1])
512 # jobId = resp_data["jobid"]
513 logger.info("resp_data=%s", resp_data)
514 except Exception as e:
515 logger.error("Error occurred when healing VNF")
516 logger.error(traceback.format_exc())
517 return Response(data={'error': 'heal expection'}, status='500')
518 return Response(data=resp_data, status=ret[2])
521 def get_vdus(nf_model, aspect_id):
522 associated_group = ''
524 vnf_flavours = nf_model['vnf_flavours']
525 for vnf_flaour in vnf_flavours:
526 scaling_aspects = vnf_flaour['scaling_aspects']
527 for aspect in scaling_aspects:
528 if aspect_id == aspect['id']:
529 associated_group = aspect['associated_group']
531 if not associated_group:
532 logger.error('Cannot find the corresponding element group')
533 raise Exception('Cannot find the corresponding element group')
534 for element_group in nf_model['element_groups']:
535 if element_group['group_id'] == associated_group:
536 members = element_group['members']
538 logger.error('Cannot find the corresponding members')
539 raise Exception('Cannot find the corresponding members')
543 @api_view(http_method_names=['GET'])
544 def samples(request, *args, **kwargs):
545 return Response(data={"status": "ok"})