1 # Copyright 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.response import Response
24 from rest_framework.views import APIView
26 from driver.interfaces.serializers.serializers import VnfInstReqParamsSerializer, ResponseSerializer
27 from driver.interfaces.serializers.serializers import VnfNotifyReqSerializer, VNFLCMOpOccSerializer
28 from driver.interfaces.serializers.serializers import VnfOperRespSerializer, VnfGrantReqSerializer, VnfGrantRespSerializer
29 from driver.interfaces.serializers.serializers import VnfTermReqSerializer, VnfQueryRespSerializer
30 from driver.pub.exceptions import GvnfmDriverException
31 from driver.pub.utils import restcall
32 from driver.pub.utils.restcall import req_by_msb
34 logger = logging.getLogger(__name__)
37 class VnfInstInfo(APIView):
39 request_body=VnfInstReqParamsSerializer(),
41 status.HTTP_201_CREATED: ResponseSerializer(),
42 status.HTTP_404_NOT_FOUND: "The vnfm instance id is wrong",
43 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
46 def post(self, request, vnfmtype, vnfmid):
47 logger.debug("instantiate_vnf--post::> %s" % request.data)
48 logger.debug("Create vnf begin!")
50 requestSerializer = VnfInstReqParamsSerializer(data=request.data)
51 request_isValid = requestSerializer.is_valid()
52 if not request_isValid:
53 raise Exception(requestSerializer.errors)
55 # requestData = requestSerializer.data
56 requestData = request.data
58 "vnfdId": ignorcase_get(requestData, "vnfDescriptorId"),
59 "vnfInstanceName": ignorcase_get(requestData, "vnfInstanceName"),
60 "vnfInstanceDescription": ignorcase_get(requestData, "vnfInstanceDescription")
63 logger.debug("do_createvnf: request data=[%s],input_data=[%s],vnfm_id=[%s]",
64 request.data, input_data, vnfm_id)
65 resp = do_createvnf(vnfm_id, input_data)
66 logger.debug("do_createvnf: response data=[%s]", resp)
67 logger.debug("Create vnf end!")
69 logger.debug("Instantiate vnf start!")
70 vnfInstanceId = resp["id"]
72 "flavourId": ignorcase_get(requestData, "flavourId"),
73 "extVirtualLinks": ignorcase_get(requestData, "extVirtualLink"),
74 "additionalParams": ignorcase_get(requestData, "additionalParam"),
76 logger.debug("do_instvnf: vnfInstanceId=[%s],request data=[%s],input_data=[%s],vnfm_id=[%s]",
77 vnfInstanceId, request.data, input_data, vnfm_id)
78 resp = do_instvnf(vnfInstanceId, vnfm_id, input_data)
79 logger.debug("do_instvnf: response data=[%s]", resp)
81 "vnfInstanceId": vnfInstanceId,
82 "jobId": ignorcase_get(resp, "jobId")
84 logger.debug("Instantiate vnf end!")
85 return Response(data=resp_data, status=status.HTTP_201_CREATED)
86 except GvnfmDriverException as e:
87 logger.error('instantiate vnf failed, detail message: %s' % e.message)
88 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
90 logger.error(traceback.format_exc())
91 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
94 class VnfTermInfo(APIView):
96 request_body=VnfTermReqSerializer(),
98 status.HTTP_201_CREATED: ResponseSerializer(),
99 status.HTTP_404_NOT_FOUND: "The vnfmid and vnfInstanceId are wrong",
100 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
103 def post(self, request, vnfmtype, vnfmid, vnfInstanceId):
104 logger.debug("terminate_vnf--post::> %s" % request.data)
105 logger.debug("Terminate vnf begin!")
109 "terminationType": ignorcase_get(request.data, "terminationType"),
110 "gracefulTerminationTimeout": ignorcase_get(request.data, "gracefulTerminationTimeout")
112 logger.debug("do_terminatevnf: vnfm_id=[%s],vnfInstanceId=[%s],input_data=[%s]",
113 vnfm_id, vnfInstanceId, input_data)
114 resp = do_terminatevnf(vnfm_id, vnfInstanceId, input_data)
115 logger.debug("terminate_vnf: response data=[%s]", resp)
117 jobId = ignorcase_get(resp, "jobId")
118 gracefulTerminationTimeout = ignorcase_get(request.data, "gracefulTerminationTimeout")
119 logger.debug("wait4job: vnfm_id=[%s],jobId=[%s],gracefulTerminationTimeout=[%s]",
120 vnfm_id, jobId, gracefulTerminationTimeout)
121 resp = wait4job(vnfm_id, jobId, gracefulTerminationTimeout)
122 logger.debug("[wait4job] response=[%s]", resp)
124 logger.debug("Delete vnf start!")
125 logger.debug("do_deletevnf: vnfm_id=[%s],vnfInstanceId=[%s],request data=[%s]",
126 vnfm_id, vnfInstanceId, request.data)
127 resp = do_deletevnf(vnfm_id, vnfInstanceId, request.data)
128 logger.debug("do_deletevnf: response data=[%s]", resp)
129 logger.debug("Delete vnf end!")
131 return Response(data=resp, status=status.HTTP_204_NO_CONTENT)
132 except GvnfmDriverException as e:
133 logger.error('Terminate vnf failed, detail message: %s' % e.message)
134 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
136 logger.error(traceback.format_exc())
137 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
140 class VnfQueryInfo(APIView):
141 @swagger_auto_schema(
143 status.HTTP_201_CREATED: VnfQueryRespSerializer(),
144 status.HTTP_404_NOT_FOUND: "The vnfmid and vnfInstanceId are wrong",
145 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
148 def get(self, request, vnfmtype, vnfmid, vnfInstanceId):
149 logger.debug("query_vnf--post::> %s" % request.data)
152 logger.debug("[%s] request.data=%s", fun_name(), request.data)
153 resp = do_queryvnf(request, vnfm_id, vnfInstanceId)
154 query_vnf_resp_mapping = {
156 "vnfInstanceName": "",
157 "vnfInstanceDescription": "",
165 ResponseInfo = ignorcase_get(resp, "ResponseInfo")
166 resp_response_data = mapping_conv(query_vnf_resp_mapping, ResponseInfo)
168 "vnfInfo": resp_response_data
170 id = ignorcase_get(ResponseInfo, "id")
172 resp_data["vnfInfo"]["vnfInstanceId"] = id
173 vnfPkgId = ignorcase_get(ResponseInfo, "vnfPkgId")
175 resp_data["vnfInfo"]["vnfPackageId"] = vnfPkgId
176 vnfSoftwareVersion = ignorcase_get(ResponseInfo, "vnfSoftwareVersion")
177 if vnfSoftwareVersion:
178 resp_data["vnfInfo"]["version"] = vnfSoftwareVersion
179 if ignorcase_get(ResponseInfo, "instantiationState") == "INSTANTIATED":
180 resp_data["vnfInfo"]["vnfStatus"] = "ACTIVE"
181 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
182 return Response(data=resp_data, status=status.HTTP_200_OK)
183 except GvnfmDriverException as e:
184 logger.error('Query vnf failed, detail message: %s' % e.message)
185 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
187 logger.error(traceback.format_exc())
188 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
191 class VnfOperInfo(APIView):
192 @swagger_auto_schema(
194 status.HTTP_201_CREATED: VnfOperRespSerializer(),
195 status.HTTP_404_NOT_FOUND: "The vnfmid, jobid and responseId are wrong",
196 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
199 def get(self, request, vnfmtype, vnfmid, jobid):
200 logger.debug("operation_status--post::> %s" % request.data)
202 logger.debug("[%s] request.data=%s", fun_name(), request.data)
205 responseId = ignorcase_get(request.META, 'responseId')
206 logger.debug("[operation_status] vnfm_id=%s", vnfm_id)
207 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
208 logger.debug("[operation_status] vnfm_info=[%s]", vnfm_info)
210 ret = call_vnfm("api/vnflcm/v1/vnf_lc_ops/%s?responseId=%s" % (jobId, responseId), "GET", vnfm_info)
212 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
213 raise GvnfmDriverException('Failed to query vnf operation status.')
214 resp_data = json.JSONDecoder().decode(ret[1])
215 logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
216 ResponseInfo = ignorcase_get(resp_data, "ResponseInfo")
217 responseDescriptor = ignorcase_get(ResponseInfo, "responseDescriptor")
218 status_tmp = ignorcase_get(responseDescriptor, "lcmOperationStatus")
219 del responseDescriptor["lcmOperationStatus"]
220 responseDescriptor["status"] = status_tmp
222 "jobId": ignorcase_get(ResponseInfo, "vnfLcOpId"),
223 "responseDescriptor": responseDescriptor
225 return Response(data=operation_data, status=status.HTTP_200_OK)
226 except GvnfmDriverException as e:
227 logger.error('Query vnf failed, detail message: %s' % e.message)
228 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
230 logger.error(traceback.format_exc())
231 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
234 class VnfGrantInfo(APIView):
235 @swagger_auto_schema(
236 request_body=VnfGrantReqSerializer(), # TODO: not used
238 status.HTTP_201_CREATED: VnfGrantRespSerializer(),
239 status.HTTP_404_NOT_FOUND: "The request body is wrong",
240 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
243 def put(self, request, vnfmtype):
245 logger.debug("[grantvnf] req_data = %s", request.data)
246 ret = req_by_msb('api/nslcm/v2/grants', "POST", content=json.JSONEncoder().encode(request.data))
247 logger.debug("ret = %s", ret)
249 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
250 raise GvnfmDriverException('Failed to grant vnf.')
251 resp = json.JSONDecoder().decode(ret[1])
252 logger.debug("[%s]resp_data=%s", fun_name(), resp)
253 return Response(data=resp, status=status.HTTP_201_CREATED)
254 except GvnfmDriverException as e:
255 logger.error('Grant vnf failed, detail message: %s' % e.message)
256 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
258 logger.error(traceback.format_exc())
259 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
262 class VnfNotifyInfo(APIView):
263 @swagger_auto_schema(
264 request_body=VnfNotifyReqSerializer(),
266 status.HTTP_201_CREATED: "Successful Notify",
267 status.HTTP_404_NOT_FOUND: "The request body is wrong",
268 status.HTTP_500_INTERNAL_SERVER_ERROR: "The url is invalid"
271 def post(self, request, vnfmtype): # TODO: not compatable with VnfIdentifierCreationNotification and VnfIdentifierDeletionNotification
273 logger.debug("[%s]req_data = %s", fun_name(), request.data)
274 vnfminstid = ignorcase_get(request.data, 'vnfmInstId')
275 vnfinstanceid = ignorcase_get(request.data, 'vnfInstanceId')
276 request.data.pop("vnfmInstId")
277 ret = req_by_msb("api/nslcm/v2/ns/%s/vnfs/%s/Notify" % (vnfminstid, vnfinstanceid), "POST",
278 json.JSONEncoder().encode(request.data))
279 logger.debug("[%s]data = %s", fun_name(), ret)
281 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
282 raise GvnfmDriverException('Failed to notify vnf.')
283 return Response(data=None, status=status.HTTP_200_OK)
284 except GvnfmDriverException as e:
285 logger.error('Grant vnf failed, detail message: %s' % e.message)
286 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
288 logger.error(traceback.format_exc())
289 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
292 class VnfPkgsInfo(APIView):
293 def get(request, *args, **kwargs):
295 logger.debug("Enter %s", fun_name())
296 ret = req_by_msb("api/nslcm/v1/vnfpackage", "GET")
298 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
299 raise GvnfmDriverException('Failed to get vnfpkgs.')
300 resp = json.JSONDecoder().decode(ret[1])
301 return Response(data=resp, status=status.HTTP_200_OK)
302 except GvnfmDriverException as e:
303 logger.error('Get vnfpkgs failed, detail message: %s' % e.message)
304 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
306 logger.error(traceback.format_exc())
307 return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
309 class QuerySingleVnfLcmOpOcc(APIView):
310 @swagger_auto_schema(
312 status.HTTP_200_OK: VNFLCMOpOccSerializer(),
313 status.HTTP_500_INTERNAL_SERVER_ERROR: ""
316 def get(self, request, vnfmtype, vnfmid, lcmopoccid):
317 logger.debug("[%s]LCMOpOccId = %s", fun_name(), lcmopoccid)
319 vnfm_info = get_vnfminfo_from_nslcm(vnfmid)
320 logger.debug("[get lcm op occ] vnfm_info=[%s]", vnfm_info)
321 ret = call_vnfm("api/vnflcm/v1/vnf_lcm_op_occs/%s" % lcmopoccid, "GET", vnfm_info)
323 logger.error("Status code is %s. detail is %s.", ret[2], ret[1])
324 raise GvnfmDriverException("Failed to query vnf lcm op occ %s" % lcmopoccid)
325 resp_data = json.JSONDecoder().decode(ret[1])
326 vnf_lcm_op_occ_serializer = VNFLCMOpOccSerializer(data=resp_data)
327 if vnf_lcm_op_occ_serializer.is_valid():
328 logger.debug("[%s]resp_data=%s" % (fun_name(), resp_data))
329 return Response(data=vnf_lcm_op_occ_serializer.data, status=status.HTTP_200_OK)
331 raise GvnfmDriverException(vnf_lcm_op_occ_serializer.errors)
332 except GvnfmDriverException as e:
333 logger.error("Query vnflcmopocc failed, detail message: %s" % e.message)
334 return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
336 logger.error(traceback.format_exc())
337 return Response(data={'error': traceback.format_exc()}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
340 def call_vnfm(resource, method, vnfm_info, data=""):
341 ret = restcall.call_req(
342 base_url=ignorcase_get(vnfm_info, "url"),
343 user=ignorcase_get(vnfm_info, "userName"),
344 passwd=ignorcase_get(vnfm_info, "password"),
345 auth_type=restcall.rest_no_auth,
348 content=json.JSONEncoder().encode(data))
352 def mapping_conv(keyword_map, rest_return):
354 for param in keyword_map:
355 # if keyword_map[param]:
356 if isinstance(keyword_map[param], dict):
357 resp_data[param] = mapping_conv(keyword_map[param], ignorcase_get(rest_return, param))
359 value = ignorcase_get(rest_return, param)
361 resp_data[param] = value
366 return "=========%s=========" % inspect.stack()[1][3]
369 def ignorcase_get(args, key):
377 if old_key.upper() == key.upper():
382 def get_vnfminfo_from_nslcm(vnfm_id):
383 logger.debug("[get_vnfminfo_from_nslcm] vnfm_id=[%s]", vnfm_id)
384 # ret = req_by_msb("api/aai-esr-server/v1/vnfms/%s" % vnfm_id, "GET")
385 ret = req_by_msb("api/nslcm/v1/vnfms/%s" % vnfm_id, "GET")
386 logger.debug("[get_vnfminfo_from_nslcm] response=%s", ret)
388 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
389 raise GvnfmDriverException("Failed to query vnfm(%s) from nslcm." % vnfm_id)
390 return json.JSONDecoder().decode(ret[1])
393 def wait4job(vnfm_id, job_id, gracefulTerminationTimeout=1200, retry_count=60, interval_second=3):
394 logger.debug("[wait4job] vnfm_id=[%s],jobId=[%s],gracefulTerminationTimeout=[%s]",
395 vnfm_id, job_id, gracefulTerminationTimeout)
397 response_id, new_response_id = 0, 0
398 job_end_normal, job_timeout = False, True
399 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
400 logger.debug("[do_terminatevnf] vnfm_info=[%s]", vnfm_info)
401 while count < retry_count:
403 time.sleep(interval_second)
404 ret = call_vnfm("api/vnflcm/v1/vnf_lc_ops/%s?responseId=%s" % (job_id, response_id), "GET", vnfm_info)
406 logger.error("Failed to query job: %s:%s", ret[2], ret[1])
408 job_result = json.JSONDecoder().decode(ret[1])
409 if "responseDescriptor" not in job_result:
410 logger.error("Job(%s) does not exist.", job_id)
412 progress = job_result["responseDescriptor"]["progress"]
413 new_response_id = job_result["responseDescriptor"]["responseId"]
414 job_desc = job_result["responseDescriptor"]["statusDescription"]
415 if new_response_id != response_id:
416 logger.debug("%s:%s:%s", progress, new_response_id, job_desc)
417 response_id = new_response_id
421 logger.error("Job(%s) failed: %s", job_id, job_desc)
423 elif progress == 100:
424 job_end_normal, job_timeout = True, False
425 logger.debug("Job(%s) ended normally,job_end_normal=[%s],job_timeout=[%s]",
426 job_id, job_end_normal, job_timeout)
427 return {"success": "success"}
429 logger.error("Job(%s) timeout", job_id)
430 raise GvnfmDriverException("Fail to get job status!")
433 def do_createvnf(vnfm_id, data):
434 logger.debug("[%s] request.data=%s", fun_name(), data)
435 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
436 logger.debug("[do_createvnf] vnfm_info=[%s]", vnfm_info)
437 ret = call_vnfm("api/vnflcm/v1/vnf_instances", "POST", vnfm_info, data)
438 logger.debug("[%s] call_req ret=%s", fun_name(), ret)
440 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
441 raise GvnfmDriverException('Failed to create vnf.')
442 return json.JSONDecoder().decode(ret[1])
445 def do_instvnf(vnfInstanceId, vnfm_id, data):
446 logger.debug("[%s] request.data=%s", fun_name(), data)
447 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
448 logger.debug("[do_instvnf] vnfm_info=[%s]", vnfm_info)
449 ret = call_vnfm("api/vnflcm/v1/vnf_instances/%s/instantiate" % vnfInstanceId, "POST", vnfm_info, data)
450 logger.debug("[%s] call_req ret=%s", fun_name(), ret)
452 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
453 raise GvnfmDriverException('Failed to inst vnf.')
454 return json.JSONDecoder().decode(ret[1])
457 def do_terminatevnf(vnfm_id, vnfInstanceId, data):
458 logger.debug("[%s] request.data=%s", fun_name(), data)
459 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
460 logger.debug("[do_terminatevnf] vnfm_info=[%s]", vnfm_info)
461 ret = call_vnfm("api/vnflcm/v1/vnf_instances/%s/terminate" % vnfInstanceId, "POST", vnfm_info, data)
463 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
464 raise GvnfmDriverException('Failed to terminate vnf.')
465 return json.JSONDecoder().decode(ret[1])
468 def do_deletevnf(vnfm_id, vnfInstanceId, data):
469 logger.debug("[%s] request.data=%s", fun_name(), data)
470 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
471 logger.debug("[do_deletevnf] vnfm_info=[%s]", vnfm_info)
472 ret = call_vnfm("api/vnflcm/v1/vnf_instances/%s" % vnfInstanceId, "DELETE", vnfm_info)
474 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
475 raise GvnfmDriverException('Failed to delete vnf.')
476 return json.JSONDecoder().decode(ret[1])
479 def do_queryvnf(data, vnfm_id, vnfInstanceId):
480 logger.debug("[%s] request.data=%s", fun_name(), data)
481 vnfm_info = get_vnfminfo_from_nslcm(vnfm_id)
482 logger.debug("[do_deletevnf] vnfm_info=[%s]", vnfm_info)
483 ret = call_vnfm("api/vnflcm/v1/vnf_instances/%s" % vnfInstanceId, "GET", vnfm_info)
485 logger.error("Status code is %s, detail is %s.", ret[2], ret[1])
486 raise GvnfmDriverException('Failed to query vnf.')
487 return json.JSONDecoder().decode(ret[1])