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.
21 from drf_yasg.utils import swagger_auto_schema
22 from rest_framework import status
23 from rest_framework.decorators import api_view
24 from rest_framework.response import Response
25 from rest_framework.views import APIView
27 from driver.interfaces.serializers import HealReqSerializer, InstScaleHealRespSerializer
28 from driver.pub.config.config import VNF_FTP
29 from driver.pub.utils import restcall
30 from driver.pub.utils.restcall import req_by_msb
32 logger = logging.getLogger(__name__)
35 def load_json_file(file_name):
36 json_file = os.path.join(os.path.dirname(__file__), "data/" + file_name)
38 json_data = json.JSONDecoder().decode(f.read())
44 return "=================%s==================" % inspect.stack()[1][3]
47 def ignorcase_get(args, key):
55 if old_key.upper() == key.upper():
60 def mapping_conv(keyword_map, rest_return):
62 for param in keyword_map:
63 if keyword_map[param]:
64 resp_data[keyword_map[param]] = ignorcase_get(rest_return, param)
68 # Query vnfm_info from nslcm
69 def get_vnfminfo_from_nslcm(vnfmid):
70 ret = req_by_msb("api/nslcm/v1/vnfms/%s" % vnfmid, "GET")
74 # Query vnfd_info from nslcm
75 def vnfd_get(vnfpackageid):
76 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
80 # Query vnfpackage_info from nslcm
81 def vnfpackage_get(csarid):
82 ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % csarid, "GET")
86 @api_view(http_method_names=['POST'])
87 def instantiate_vnf(request, *args, **kwargs):
89 logger.debug("[%s] request.data=%s", fun_name(), request.data)
90 vnfm_id = ignorcase_get(kwargs, "vnfmid")
91 ret = get_vnfminfo_from_nslcm(vnfm_id)
93 return Response(data={'error': ret[1]}, status=ret[2])
94 vnfm_info = json.JSONDecoder().decode(ret[1])
95 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
96 vnf_package_id = ignorcase_get(request.data, "vnfPackageId")
97 ret = vnfd_get(vnf_package_id)
99 return Response(data={'error': ret[1]}, status=ret[2])
100 vnfd_info = json.JSONDecoder().decode(ret[1])
101 logger.debug("[%s] vnfd_info=%s", fun_name(), vnfd_info)
102 csar_id = ignorcase_get(vnfd_info, "csarId")
103 ret = vnfpackage_get(csar_id)
105 return Response(data={'error': ret[1]}, status=ret[2])
106 vnf_package_info = json.JSONDecoder().decode(ret[1])
107 packageInfo = ignorcase_get(vnf_package_info, "packageInfo")
108 logger.debug("[%s] packageInfo=%s", fun_name(), packageInfo)
111 data["VNFMID"] = vnfm_id
112 vnfdModel = json.loads(ignorcase_get(packageInfo, "vnfdModel"))
113 metadata = ignorcase_get(vnfdModel, "metadata")
114 vnfd_name = ignorcase_get(metadata, "name")
115 # TODO convert sdc vnf package to vnf vender package
117 if "SPGW" in vnfd_name.upper():
118 data["VNFD"] = VNF_FTP + "SPGW"
119 inputs = load_json_file("SPGW" + "_inputs.json")
120 elif "MME" in vnfd_name.upper():
121 data["VNFD"] = VNF_FTP + "MME"
122 inputs = load_json_file("MME" + "_inputs.json")
124 data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
126 data["VNFURL"] = data["VNFD"]
128 data["extension"] = {}
129 for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
130 inputs.append({"name": name, "value": value})
132 data["extension"]["inputs"] = json.dumps(inputs)
133 additionalParam = ignorcase_get(request.data, "additionalParam")
134 data["extension"]["extVirtualLinks"] = ignorcase_get(additionalParam, "extVirtualLinks")
135 data["extension"]["vnfinstancename"] = ignorcase_get(request.data, "vnfInstanceName")
136 data["extension"]["vnfid"] = data["VNFD"]
137 data["extension"]["multivim"] = 0
138 logger.debug("[%s] call_req data=%s", fun_name(), data)
140 ret = restcall.call_req(
141 base_url=ignorcase_get(vnfm_info, "url"),
142 user=ignorcase_get(vnfm_info, "userName"),
143 passwd=ignorcase_get(vnfm_info, "password"),
144 auth_type=restcall.rest_no_auth,
147 content=json.JSONEncoder().encode(data))
149 logger.debug("[%s] call_req ret=%s", fun_name(), ret)
151 return Response(data={'error': ret[1]}, status=ret[2])
152 resp = json.JSONDecoder().decode(ret[1])
154 "vnfInstanceId": ignorcase_get(resp, "VNFInstanceID"),
155 "jobId": ignorcase_get(resp, "JobId")
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 @api_view(http_method_names=['POST'])
165 def terminate_vnf(request, *args, **kwargs):
167 logger.debug("[%s] request.data=%s", fun_name(), request.data)
168 vnfm_id = ignorcase_get(kwargs, "vnfmid")
169 ret = get_vnfminfo_from_nslcm(vnfm_id)
171 return Response(data={'error': ret[1]}, status=ret[2])
172 vnfm_info = json.JSONDecoder().decode(ret[1])
173 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
174 ret = restcall.call_req(
175 base_url=ignorcase_get(vnfm_info, "url"),
176 user=ignorcase_get(vnfm_info, "userName"),
177 passwd=ignorcase_get(vnfm_info, "password"),
178 auth_type=restcall.rest_no_auth,
179 resource="v1/vnfs/%s" % (ignorcase_get(kwargs, "vnfInstanceID")),
181 content=json.JSONEncoder().encode(request.data))
183 return Response(data={'error': ret[1]}, status=ret[2])
184 resp = json.JSONDecoder().decode(ret[1])
186 "vnfInstanceId": ignorcase_get(resp, "VNFInstanceID"),
187 "jobId": ignorcase_get(resp, "JobId")
189 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
190 except Exception as e:
191 logger.error("Error occurred when terminating VNF")
193 return Response(data=resp_data, status=ret[2])
196 @api_view(http_method_names=['GET'])
197 def query_vnf(request, *args, **kwargs):
199 logger.debug("[%s] request.data=%s", fun_name(), request.data)
200 vnfm_id = ignorcase_get(kwargs, "vnfmid")
201 ret = get_vnfminfo_from_nslcm(vnfm_id)
203 return Response(data={'error': ret[1]}, status=ret[2])
204 vnfm_info = json.JSONDecoder().decode(ret[1])
205 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
206 ret = restcall.call_req(
207 base_url=ignorcase_get(vnfm_info, "url"),
208 user=ignorcase_get(vnfm_info, "userName"),
209 passwd=ignorcase_get(vnfm_info, "password"),
210 auth_type=restcall.rest_no_auth,
211 resource="v1/vnfs/%s" % (ignorcase_get(kwargs, "vnfInstanceID")),
213 content=json.JSONEncoder().encode({}))
215 return Response(data={'error': ret[1]}, status=ret[2])
216 resp = json.JSONDecoder().decode(ret[1])
217 vnf_status = ignorcase_get(resp, "vnfinstancestatus")
218 resp_data = {"vnfInfo": {"vnfStatus": vnf_status}}
219 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
220 except Exception as e:
221 logger.error("Error occurred when querying VNF information.")
223 return Response(data=resp_data, status=ret[2])
226 @api_view(http_method_names=['GET'])
227 def operation_status(request, *args, **kwargs):
230 logger.debug("[%s] request.data=%s", fun_name(), request.data)
231 vnfm_id = ignorcase_get(kwargs, "vnfmid")
232 ret = get_vnfminfo_from_nslcm(vnfm_id)
234 return Response(data={'error': ret[1]}, status=ret[2])
235 vnfm_info = json.JSONDecoder().decode(ret[1])
236 logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
237 operation_status_url = '/v1/jobs/{jobId}?NFVOID={nfvoId}&VNFMID={vnfmId}&ResponseID={responseId}'
238 ret = restcall.call_req(
239 base_url=ignorcase_get(vnfm_info, 'url'),
240 user=ignorcase_get(vnfm_info, 'userName'),
241 passwd=ignorcase_get(vnfm_info, 'password'),
242 auth_type=restcall.rest_no_auth,
243 resource=operation_status_url.format(jobId=ignorcase_get(kwargs, 'jobid'), nfvoId=1,
244 vnfmId=ignorcase_get(kwargs, 'vnfmid'),
245 responseId=ignorcase_get(request.GET, 'responseId')),
247 content=json.JSONEncoder().encode(data))
250 return Response(data={'error': ret[1]}, status=ret[2])
251 resp_data = json.JSONDecoder().decode(ret[1])
252 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
253 except Exception as e:
254 logger.error("Error occurred when getting operation status information.")
256 return Response(data=resp_data, status=ret[2])
259 @api_view(http_method_names=['PUT'])
260 def grantvnf(request, *args, **kwargs):
261 logger.info("=====grantvnf=====")
263 logger.info("req_data = %s", request.data)
264 grant_vnf_param_map = {
271 "VNFInstanceID": "vnfInstanceId",
272 "OperationRight": "",
277 data = mapping_conv(grant_vnf_param_map, request.data)
278 data["vnfDescriptorId"] = ""
279 if ignorcase_get(request.data, "operationright") == 0:
280 data["lifecycleOperation"] = "Instantiate"
281 data["addresource"] = []
282 for vm in ignorcase_get(request.data, "vmlist"):
283 for i in range(int(ignorcase_get(vm, "vmnumber"))):
284 data["addresource"].append(
287 "resourceDefinitionId": i,
288 "vdu": ignorcase_get(vm, "vmflavor"),
289 "vimid": ignorcase_get(vm, "vimid"),
290 "tenant": ignorcase_get(vm, "tenant")})
292 data["additionalparam"] = {}
293 data["additionalparam"]["vnfmid"] = ignorcase_get(request.data, "vnfmid")
294 data["additionalparam"]["vimid"] = ignorcase_get(request.data, "vimid")
295 data["additionalparam"]["tenant"] = ignorcase_get(request.data, "tenant")
297 ret = req_by_msb('api/nslcm/v1/ns/grantvnf', "POST", content=json.JSONEncoder().encode(data))
298 logger.info("ret = %s", ret)
300 return Response(data={'error': ret[1]}, status=ret[2])
301 resp = json.JSONDecoder().decode(ret[1])
303 'vimid': ignorcase_get(resp['vim'], 'vimid'),
304 'tenant': ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
306 logger.info("[%s]resp_data=%s", fun_name(), resp_data)
307 except Exception as e:
308 logger.error("Error occurred in Grant VNF.")
310 return Response(data=resp_data, status=ret[2])
313 @api_view(http_method_names=['POST'])
314 def notify(request, *args, **kwargs):
316 logger.info("[%s]req_data = %s", fun_name(), request.data)
321 "VNFInstanceID": "vnfInstanceId",
323 "EventType": "operation",
330 data = mapping_conv(notify_param_map, request.data)
331 logger.info("[%s]data = %s", fun_name(), data)
333 data["status"] = "result"
334 data["jobId"] = "notMust"
335 data["affectedVnfc"] = []
336 data["affectedVl"] = []
337 data["affectedVirtualStorage"] = []
338 data["affectedCp"] = []
340 extension = ignorcase_get(request.data, "extension")
341 openo_notification = ignorcase_get(extension, "openo_notification")
342 if openo_notification:
343 affectedvnfcs = ignorcase_get(openo_notification, "affectedVnfc")
344 affectedvls = ignorcase_get(openo_notification, "affectedvirtuallink")
345 affectedcps = ignorcase_get(openo_notification, "affectedCp")
346 vnfdmodule = ignorcase_get(openo_notification, "vnfdmodule")
348 affectedvnfcs = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvnfc")
349 affectedvls = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvl")
350 affectedcps = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedcp")
351 vnfdmodule = ignorcase_get(ignorcase_get(request.data, "extension"), "vnfdmodule")
353 data["vnfdmodule"] = vnfdmodule
355 for affectedvnfc in affectedvnfcs:
356 data["affectedVnfc"].append({
357 "vnfcInstanceId": ignorcase_get(affectedvnfc, "vnfcInstanceId"),
358 "vduId": ignorcase_get(affectedvnfc, "vduId"),
359 "changeType": ignorcase_get(affectedvnfc, "changeType"),
360 "vimId": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "vimId"),
361 "vmId": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "resourceId"),
362 "vmName": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "resourceName")
365 for affectedvl in affectedvls:
366 data["affectedVl"].append({
367 "vlInstanceId": ignorcase_get(affectedvl, "virtualLinkInstanceId"),
368 "changeType": ignorcase_get(affectedvl, "changeType"),
369 "vimId": ignorcase_get(ignorcase_get(affectedvl, "networkResource"), "vimId"),
370 "vldId": ignorcase_get(affectedvl, "virtuallinkdescid"),
372 "resourceType": "network",
373 "resourceId": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
374 "resourceName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
378 for affectedcp in affectedcps:
379 data["affectedCp"].append(affectedcp)
381 notify_url = 'api/nslcm/v1/ns/{vnfmid}/vnfs/{vnfInstanceId}/Notify'
382 ret = req_by_msb(notify_url.format(vnfmid=ignorcase_get(data, 'VNFMID'),
383 vnfInstanceId=ignorcase_get(data, 'vnfinstanceid')),
384 "POST", content=json.JSONEncoder().encode(data))
386 logger.info("[%s]data = %s", fun_name(), ret)
388 return Response(data={'error': ret[1]}, status=ret[2])
389 except Exception as e:
390 logger.error("Error occurred in LCM notification.")
391 logger.error(traceback.format_exc())
393 return Response(data=None, status=ret[2])
396 @api_view(http_method_names=['POST'])
397 def scale(request, *args, **kwargs):
398 logger.info("====scale_vnf===")
400 logger.info("request.data = %s", request.data)
401 logger.info("requested_url = %s", request.get_full_path())
402 vnfm_id = ignorcase_get(kwargs, "vnfmid")
403 nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
404 ret = get_vnfminfo_from_nslcm(vnfm_id)
406 return Response(data={'error': ret[1]}, status=ret[2])
407 vnfm_info = json.JSONDecoder().decode(ret[1])
408 scale_type = ignorcase_get(request.data, "type")
409 aspect_id = ignorcase_get(request.data, "aspectId")
410 number_of_steps = ignorcase_get(request.data, "numberOfSteps")
414 'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
415 'vmlist': [{'VMNumber': number_of_steps, 'VMFlavor': aspect_id}],
419 logger.info("data = %s", data)
420 ret = restcall.call_req(
421 base_url=ignorcase_get(vnfm_info, "url"),
422 user=ignorcase_get(vnfm_info, "userName"),
423 passwd=ignorcase_get(vnfm_info, "password"),
424 auth_type=restcall.rest_no_auth,
425 resource='/v1/vnfs/{vnfInstanceID}/scale'.format(vnfInstanceID=nf_instance_id),
427 content=json.JSONEncoder().encode(data))
428 logger.info("ret=%s", ret)
430 return Response(data={'error': 'scale error'}, status=ret[2])
431 resp_data = json.JSONDecoder().decode(ret[1])
432 logger.info("resp_data=%s", resp_data)
433 except Exception as e:
434 logger.error("Error occurred when scaling VNF,error:%s", e.message)
435 logger.error(traceback.format_exc())
436 return Response(data={'error': 'scale expection'}, status='500')
437 return Response(data=resp_data, status=ret[2])
441 @swagger_auto_schema(
442 request_body=HealReqSerializer(),
444 status.HTTP_202_ACCEPTED: InstScaleHealRespSerializer(),
445 status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error"
448 def post(self, request, vnfmid, vnfInstanceId):
449 logger.info("====heal_vnf===")
451 logger.info("request.data = %s", request.data)
452 logger.info("requested_url = %s", request.get_full_path())
453 healReqSerializer = HealReqSerializer(data=request.data)
454 if not healReqSerializer.is_valid():
455 raise Exception(healReqSerializer.errors)
457 ret = get_vnfminfo_from_nslcm(vnfmid)
459 return Response(data={'error': ret[1]}, status=ret[2])
460 vnfm_info = json.JSONDecoder().decode(ret[1])
462 data['action'] = ignorcase_get(healReqSerializer.data, 'action')
463 affectedvm = ignorcase_get(healReqSerializer.data, 'affectedvm')
464 data['affectedvm'] = []
465 if isinstance(affectedvm, list):
466 data['affectedvm'] = affectedvm
468 data['affectedvm'].append(affectedvm)
469 data['lifecycleoperation'] = 'operate'
470 data['isgrace'] = 'force'
472 logger.info("data = %s", data)
473 ret = restcall.call_req(
474 base_url=ignorcase_get(vnfm_info, "url"),
475 user=ignorcase_get(vnfm_info, "userName"),
476 passwd=ignorcase_get(vnfm_info, "password"),
477 auth_type=restcall.rest_no_auth,
478 resource='/api/v1/nf_m_i/nfs/{vnfInstanceID}/vms/operation'.format(vnfInstanceID=vnfInstanceId),
480 content=json.JSONEncoder().encode(data))
481 logger.info("ret=%s", ret)
483 raise Exception('heal error')
484 resp_data = json.JSONDecoder().decode(ret[1])
485 logger.info("resp_data=%s", resp_data)
486 healRespSerializer = InstScaleHealRespSerializer(data=resp_data)
487 if not healRespSerializer.is_valid():
488 raise Exception(healRespSerializer.errors)
490 return Response(data=healRespSerializer.data, status=status.HTTP_202_ACCEPTED)
491 except Exception as e:
492 logger.error("Error occurred when healing VNF,error:%s", e.message)
493 logger.error(traceback.format_exc())
494 return Response(data={'error': 'heal expection'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
497 def get_vdus(nf_model, aspect_id):
498 associated_group = ''
500 vnf_flavours = nf_model['vnf_flavours']
501 for vnf_flaour in vnf_flavours:
502 scaling_aspects = vnf_flaour['scaling_aspects']
503 for aspect in scaling_aspects:
504 if aspect_id == aspect['id']:
505 associated_group = aspect['associated_group']
507 if not associated_group:
508 logger.error('Cannot find the corresponding element group')
509 raise Exception('Cannot find the corresponding element group')
510 for element_group in nf_model['element_groups']:
511 if element_group['group_id'] == associated_group:
512 members = element_group['members']
514 logger.error('Cannot find the corresponding members')
515 raise Exception('Cannot find the corresponding members')
519 @api_view(http_method_names=['GET'])
520 def samples(request, *args, **kwargs):
521 return Response(data={"status": "ok"})