Optimize vfc-ztevnfmdriver instantiation Code
[vfc/nfvo/driver/vnfm/svnfm.git] / zte / vmanager / driver / interfaces / views.py
1 # Copyright 2016-2017 ZTE Corporation.
2 #
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
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 import inspect
16 import json
17 import logging
18 import traceback
19 import os
20
21 from rest_framework.decorators import api_view
22 from rest_framework.response import Response
23
24 from driver.pub.utils import restcall
25 from driver.pub.utils.restcall import req_by_msb
26 from driver.pub.config.config import VNF_FTP
27
28 logger = logging.getLogger(__name__)
29
30
31 def load_json_file(file_name):
32     json_file = os.path.join(os.path.dirname(__file__), "data/" + file_name)
33     f = open(json_file)
34     json_data = json.JSONDecoder().decode(f.read())
35     f.close()
36     return json_data
37
38
39 def fun_name():
40     return "=================%s==================" % inspect.stack()[1][3]
41
42
43 def ignorcase_get(args, key):
44     if not key:
45         return ""
46     if not args:
47         return ""
48     if key in args:
49         return args[key]
50     for old_key in args:
51         if old_key.upper() == key.upper():
52             return args[old_key]
53     return ""
54
55
56 def mapping_conv(keyword_map, rest_return):
57     resp_data = {}
58     for param in keyword_map:
59         if keyword_map[param]:
60             resp_data[keyword_map[param]] = ignorcase_get(rest_return, param)
61     return resp_data
62
63
64 # Query vnfm_info from nslcm
65 def get_vnfminfo_from_nslcm(vnfmid):
66     ret = req_by_msb("api/nslcm/v1/vnfms/%s" % vnfmid, "GET")
67     return ret
68
69
70 # Query vnfd_info from nslcm
71 def vnfd_get(vnfpackageid):
72     ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
73     return ret
74
75
76 # Query vnfpackage_info from nslcm
77 def vnfpackage_get(csarid):
78     ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % csarid, "GET")
79     return ret
80
81
82 @api_view(http_method_names=['POST'])
83 def instantiate_vnf(request, *args, **kwargs):
84     try:
85         logger.debug("[%s] request.data=%s", fun_name(), request.data)
86         vnfm_id = ignorcase_get(kwargs, "vnfmid")
87         ret = get_vnfminfo_from_nslcm(vnfm_id)
88         if ret[0] != 0:
89             return Response(data={'error': ret[1]}, status=ret[2])
90         vnfm_info = json.JSONDecoder().decode(ret[1])
91         logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
92         vnf_package_id = ignorcase_get(request.data, "vnfPackageId")
93         ret = vnfd_get(vnf_package_id)
94         if ret[0] != 0:
95             return Response(data={'error': ret[1]}, status=ret[2])
96         vnfd_info = json.JSONDecoder().decode(ret[1])
97         logger.debug("[%s] vnfd_info=%s", fun_name(), vnfd_info)
98         csar_id = ignorcase_get(vnfd_info, "csarId")
99         ret = vnfpackage_get(csar_id)
100         if ret[0] != 0:
101             return Response(data={'error': ret[1]}, status=ret[2])
102         vnf_package_info = json.JSONDecoder().decode(ret[1])
103         packageInfo = ignorcase_get(vnf_package_info, "packageInfo")
104         logger.debug("[%s] packageInfo=%s", fun_name(), packageInfo)
105         data = {}
106         data["NFVOID"] = 1
107         data["VNFMID"] = vnfm_id
108         vnfdModel = json.loads(ignorcase_get(packageInfo, "vnfdModel"))
109         metadata = ignorcase_get(vnfdModel, "metadata")
110         vnfd_name = ignorcase_get(metadata, "name")
111         # TODO  convert sdc vnf package to vnf vender package
112         inputs = []
113         if "SPGW" in vnfd_name.upper():
114             data["VNFD"] = VNF_FTP + "SPGW"
115             inputs = load_json_file("SPGW" + "_inputs.json")
116         elif "MME" in vnfd_name.upper():
117             data["VNFD"] = VNF_FTP + "MME"
118             inputs = load_json_file("MME" + "_inputs.json")
119         else:
120             data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
121
122         data["VNFURL"] = data["VNFD"]
123
124         data["extension"] = {}
125         for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
126             inputs.append({"name": name, "value": value})
127
128         data["extension"]["inputs"] = json.dumps(inputs)
129         additionalParam = ignorcase_get(request.data, "additionalParam")
130         data["extension"]["extVirtualLinks"] = ignorcase_get(additionalParam, "extVirtualLinks")
131         data["extension"]["vnfinstancename"] = ignorcase_get(request.data, "vnfInstanceName")
132         data["extension"]["vnfid"] = data["VNFD"]
133         data["extension"]["multivim"] = 0
134         logger.debug("[%s] call_req data=%s", fun_name(), data)
135
136         ret = restcall.call_req(
137             base_url=ignorcase_get(vnfm_info, "url"),
138             user=ignorcase_get(vnfm_info, "userName"),
139             passwd=ignorcase_get(vnfm_info, "password"),
140             auth_type=restcall.rest_no_auth,
141             resource="v1/vnfs",
142             method='post',
143             content=json.JSONEncoder().encode(data))
144
145         logger.debug("[%s] call_req ret=%s", fun_name(), ret)
146         if ret[0] != 0:
147             return Response(data={'error': ret[1]}, status=ret[2])
148         resp = json.JSONDecoder().decode(ret[1])
149         create_vnf_resp_mapping = {
150             "VNFInstanceID": "vnfInstanceId",
151             "JobId": "jobid"
152         }
153         resp_data = mapping_conv(create_vnf_resp_mapping, resp)
154         logger.info("[%s]resp_data=%s", fun_name(), resp_data)
155     except Exception as e:
156         logger.error("Error occurred when instantiating VNF")
157         raise e
158     return Response(data=resp_data, status=ret[2])
159
160
161 vnf_delete_url = "v1/vnfs/%s"
162 vnf_delete_param_mapping = {
163     "terminationType": "terminationType",
164     "gracefulTerminationTimeout": "gracefulTerminationTimeout"}
165 vnf_delete_resp_mapping = {
166     "vnfInstanceId": "vnfInstanceId",
167     "JobId": "jobid"}
168
169
170 @api_view(http_method_names=['POST'])
171 def terminate_vnf(request, *args, **kwargs):
172     try:
173         logger.debug("[%s] request.data=%s", fun_name(), request.data)
174         vnfm_id = ignorcase_get(kwargs, "vnfmid")
175         ret = get_vnfminfo_from_nslcm(vnfm_id)
176         if ret[0] != 0:
177             return Response(data={'error': ret[1]}, status=ret[2])
178         vnfm_info = json.JSONDecoder().decode(ret[1])
179         logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
180         data = {}
181         logger.debug("[%s]req_data=%s", fun_name(), data)
182         ret = restcall.call_req(
183             base_url=ignorcase_get(vnfm_info, "url"),
184             user=ignorcase_get(vnfm_info, "userName"),
185             passwd=ignorcase_get(vnfm_info, "password"),
186             auth_type=restcall.rest_no_auth,
187             resource=vnf_delete_url % (ignorcase_get(kwargs, "vnfInstanceID")),
188             method='delete',
189             content=json.JSONEncoder().encode(data))
190         if ret[0] != 0:
191             return Response(data={'error': ret[1]}, status=ret[2])
192         resp = json.JSONDecoder().decode(ret[1])
193         resp_data = mapping_conv(vnf_delete_resp_mapping, resp)
194         logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
195     except Exception as e:
196         logger.error("Error occurred when terminating VNF")
197         raise e
198     return Response(data=resp_data, status=ret[2])
199
200
201 vnf_detail_url = "v1/vnfs/%s"
202 vnf_detail_resp_mapping = {
203     "VNFInstanseStatus": "status"
204 }
205
206
207 @api_view(http_method_names=['GET'])
208 def query_vnf(request, *args, **kwargs):
209     try:
210         logger.debug("[%s] request.data=%s", fun_name(), request.data)
211         vnfm_id = ignorcase_get(kwargs, "vnfmid")
212         ret = get_vnfminfo_from_nslcm(vnfm_id)
213         if ret[0] != 0:
214             return Response(data={'error': ret[1]}, status=ret[2])
215         vnfm_info = json.JSONDecoder().decode(ret[1])
216         logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
217         data = {}
218         ret = restcall.call_req(
219             base_url=ignorcase_get(vnfm_info, "url"),
220             user=ignorcase_get(vnfm_info, "userName"),
221             passwd=ignorcase_get(vnfm_info, "password"),
222             auth_type=restcall.rest_no_auth,
223             resource=vnf_detail_url % (ignorcase_get(kwargs, "vnfInstanceID")),
224             method='get',
225             content=json.JSONEncoder().encode(data))
226         if ret[0] != 0:
227             return Response(data={'error': ret[1]}, status=ret[2])
228         resp = json.JSONDecoder().decode(ret[1])
229         vnf_status = ignorcase_get(resp, "vnfinstancestatus")
230         resp_data = {"vnfInfo": {"vnfStatus": vnf_status}}
231         logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
232     except Exception as e:
233         logger.error("Error occurred when querying VNF information.")
234         raise e
235     return Response(data=resp_data, status=ret[2])
236
237
238 # Get Operation Status
239 operation_status_url = '/v1/jobs/{jobId}?NFVOID={nfvoId}&VNFMID={vnfmId}&ResponseID={responseId}'
240 operation_status_resp_map = {
241     "JobId": "jobId",
242     "Status": "status",
243     "Progress": "progress",
244     "StatusDescription": "currentStep",
245     "ErrorCode": "errorCode",
246     "ResponseId": "responseId",
247     "ResponseHistoryList": "responseHistoryList",
248     "ResponseDescriptor": "responseDescriptor"
249 }
250
251
252 @api_view(http_method_names=['GET'])
253 def operation_status(request, *args, **kwargs):
254     data = {}
255     try:
256         logger.debug("[%s] request.data=%s", fun_name(), request.data)
257         vnfm_id = ignorcase_get(kwargs, "vnfmid")
258         ret = get_vnfminfo_from_nslcm(vnfm_id)
259         if ret[0] != 0:
260             return Response(data={'error': ret[1]}, status=ret[2])
261         vnfm_info = json.JSONDecoder().decode(ret[1])
262         logger.debug("[%s] vnfm_info=%s", fun_name(), vnfm_info)
263         ret = restcall.call_req(
264             base_url=ignorcase_get(vnfm_info, 'url'),
265             user=ignorcase_get(vnfm_info, 'userName'),
266             passwd=ignorcase_get(vnfm_info, 'password'),
267             auth_type=restcall.rest_no_auth,
268             resource=operation_status_url.format(jobId=ignorcase_get(kwargs, 'jobid'), nfvoId=1,
269                                                  vnfmId=ignorcase_get(kwargs, 'vnfmid'),
270                                                  responseId=ignorcase_get(request.GET, 'responseId')),
271             method='get',
272             content=json.JSONEncoder().encode(data))
273
274         if ret[0] != 0:
275             return Response(data={'error': ret[1]}, status=ret[2])
276         resp_data = json.JSONDecoder().decode(ret[1])
277         logger.info("[%s]resp_data=%s", fun_name(), resp_data)
278     except Exception as e:
279         logger.error("Error occurred when getting operation status information.")
280         raise e
281     return Response(data=resp_data, status=ret[2])
282
283
284 # Grant VNF Lifecycle Operation
285 grant_vnf_url = 'api/nslcm/v1/ns/grantvnf'
286 grant_vnf_param_map = {
287     "VNFMID": "",
288     "NFVOID": "",
289     "VIMID": "",
290     "ExVIMIDList": "",
291     "ExVIMID": "",
292     "Tenant": "",
293     "VNFInstanceID": "vnfInstanceId",
294     "OperationRight": "",
295     "VMList": "",
296     "VMFlavor": "",
297     "VMNumber": ""}
298
299
300 @api_view(http_method_names=['PUT'])
301 def grantvnf(request, *args, **kwargs):
302     logger.info("=====grantvnf=====")
303     try:
304         resp_data = {}
305         logger.info("req_data = %s", request.data)
306         data = mapping_conv(grant_vnf_param_map, request.data)
307         logger.info("grant_vnf_url = %s", grant_vnf_url)
308         data["vnfDescriptorId"] = ""
309         if ignorcase_get(request.data, "operationright") == 0:
310             data["lifecycleOperation"] = "Instantiate"
311             data["addresource"] = []
312             for vm in ignorcase_get(request.data, "vmlist"):
313                 for i in range(int(ignorcase_get(vm, "vmnumber"))):
314                     data["addresource"].append(
315                         {"type": "vdu",
316                          "resourceDefinitionId": i,
317                          "vdu": ignorcase_get(vm, "vmflavor"),
318                          "vimid": ignorcase_get(vm, "vimid"),
319                          "tenant": ignorcase_get(vm, "tenant")
320                          })
321
322         data["additionalparam"] = {}
323         data["additionalparam"]["vnfmid"] = ignorcase_get(request.data, "vnfmid")
324         data["additionalparam"]["vimid"] = ignorcase_get(request.data, "vimid")
325         data["additionalparam"]["tenant"] = ignorcase_get(request.data, "tenant")
326
327         logger.info("data = %s", data)
328         ret = req_by_msb(grant_vnf_url, "POST", content=json.JSONEncoder().encode(data))
329         logger.info("ret = %s", ret)
330         if ret[0] != 0:
331             return Response(data={'error': ret[1]}, status=ret[2])
332         resp = json.JSONDecoder().decode(ret[1])
333
334         resp_data['vimid'] = ignorcase_get(resp['vim'], 'vimid')
335         resp_data['tenant'] = ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
336
337         logger.info("[%s]resp_data=%s", fun_name(), resp_data)
338     except Exception as e:
339         logger.error("Error occurred in Grant VNF.")
340         raise e
341     return Response(data=resp_data, status=ret[2])
342
343
344 # Notify LCM Events
345 notify_url = 'api/nslcm/v1/ns/{vnfmid}/vnfs/{vnfInstanceId}/Notify'
346 notify_param_map = {
347     "NFVOID": "",
348     "VNFMID": "VNFMID",
349     "VIMID": "vimid",
350     "VNFInstanceID": "vnfInstanceId",
351     "TimeStamp": "",
352     "EventType": "operation",
353     "VMList": "",
354     "VMFlavor": "",
355     "VMNumber": "",
356     "VMIDlist": "",
357     "VMUUID": ""
358 }
359
360
361 @api_view(http_method_names=['POST'])
362 def notify(request, *args, **kwargs):
363     try:
364         logger.info("[%s]req_data = %s", fun_name(), request.data)
365         data = mapping_conv(notify_param_map, request.data)
366         logger.info("[%s]data = %s", fun_name(), data)
367
368         data["status"] = "result"
369         data["jobId"] = "notMust"
370         data["affectedVnfc"] = []
371         data["affectedVl"] = []
372         data["affectedVirtualStorage"] = []
373         data["affectedCp"] = []
374
375         extension = ignorcase_get(request.data, "extension")
376         openo_notification = ignorcase_get(extension, "openo_notification")
377         if openo_notification:
378             affectedvnfcs = ignorcase_get(openo_notification, "affectedVnfc")
379             affectedvls = ignorcase_get(openo_notification, "affectedvirtuallink")
380             affectedcps = ignorcase_get(openo_notification, "affectedCp")
381             vnfdmodule = ignorcase_get(openo_notification, "vnfdmodule")
382         else:
383             affectedvnfcs = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvnfc")
384             affectedvls = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedvl")
385             affectedcps = ignorcase_get(ignorcase_get(request.data, "extension"), "affectedcp")
386             vnfdmodule = ignorcase_get(ignorcase_get(request.data, "extension"), "vnfdmodule")
387
388         data["vnfdmodule"] = vnfdmodule
389
390         for affectedvnfc in affectedvnfcs:
391             data["affectedVnfc"].append({
392                 "vnfcInstanceId": ignorcase_get(affectedvnfc, "vnfcInstanceId"),
393                 "vduId": ignorcase_get(affectedvnfc, "vduId"),
394                 "changeType": ignorcase_get(affectedvnfc, "changeType"),
395                 "vimid": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "vimId"),
396                 "vmId": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "resourceId"),
397                 "vmName": ignorcase_get(ignorcase_get(affectedvnfc, "computeResource"), "resourceName")
398             })
399
400         for affectedvl in affectedvls:
401             data["affectedVl"].append({
402                 "vlInstanceId": ignorcase_get(affectedvl, "virtuallinkinstanceid"),
403                 "vimid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "vimid"),
404                 "vldid": ignorcase_get(affectedvl, "virtuallinkdescid"),
405                 "vllid": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
406                 "vlName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
407             })
408
409         for affectedcp in affectedcps:
410             data["affectedCp"].append(affectedcp)
411
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))
415
416         logger.info("[%s]data = %s", fun_name(), ret)
417         if ret[0] != 0:
418             return Response(data={'error': ret[1]}, status=ret[2])
419     except Exception as e:
420         logger.error("Error occurred in LCM notification.")
421         logger.error(traceback.format_exc())
422         raise e
423     return Response(data=None, status=ret[2])
424
425
426 nf_scaling_url = '/v1/vnfs/{vnfInstanceID}/scale'
427
428
429 @api_view(http_method_names=['POST'])
430 def scale(request, *args, **kwargs):
431     logger.info("====scale_vnf===")
432     try:
433         logger.info("request.data = %s", request.data)
434         logger.info("requested_url = %s", request.get_full_path())
435         vnfm_id = ignorcase_get(kwargs, "vnfmid")
436         nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
437         ret = get_vnfminfo_from_nslcm(vnfm_id)
438         if ret[0] != 0:
439             return Response(data={'error': ret[1]}, status=ret[2])
440         vnfm_info = json.JSONDecoder().decode(ret[1])
441         scale_type = ignorcase_get(request.data, "type")
442         aspect_id = ignorcase_get(request.data, "aspectId")
443         number_of_steps = ignorcase_get(request.data, "numberOfSteps")
444         # extension = ignorcase_get(request.data, "additionalParam")
445         # vnfd_model = ignorcase_get(extension, "vnfdModel")
446         data = {
447             'vnfmid': vnfm_id,
448             'nfvoid': 1,
449             'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
450             'vmlist': [{'VMNumber': number_of_steps, 'VMFlavor': aspect_id}],
451             'extension': ''
452         }
453         '''
454         for vdu_id in get_vdus(vnfd_model, aspect_id):
455             data['vmlist'].append({
456                 "VMFlavor": vdu_id,
457                 "VMNumber": number_of_steps
458             })
459         '''
460         logger.info("data = %s", data)
461         ret = restcall.call_req(
462             base_url=ignorcase_get(vnfm_info, "url"),
463             user=ignorcase_get(vnfm_info, "userName"),
464             passwd=ignorcase_get(vnfm_info, "password"),
465             auth_type=restcall.rest_no_auth,
466             resource=nf_scaling_url.format(vnfInstanceID=nf_instance_id),
467             method='put',  # POST
468             content=json.JSONEncoder().encode(data))
469         logger.info("ret=%s", ret)
470         if ret[0] != 0:
471             return Response(data={'error': 'scale error'}, status=ret[2])
472         resp_data = json.JSONDecoder().decode(ret[1])
473         logger.info("resp_data=%s", resp_data)
474     except Exception as e:
475         logger.error("Error occurred when scaling VNF,error:%s", e.message)
476         logger.error(traceback.format_exc())
477         return Response(data={'error': 'scale expection'}, status='500')
478     return Response(data=resp_data, status=ret[2])
479
480
481 nf_healing_url = '/api/v1/nf_m_i/nfs/{vnfInstanceID}/vms/operation'
482
483
484 @api_view(http_method_names=['POST'])
485 def heal(request, *args, **kwargs):
486     logger.info("====heal_vnf===")
487     try:
488         logger.info("request.data = %s", request.data)
489         logger.info("requested_url = %s", request.get_full_path())
490         vnfm_id = ignorcase_get(kwargs, "vnfmid")
491         nf_instance_id = ignorcase_get(kwargs, "vnfInstanceId")
492         ret = get_vnfminfo_from_nslcm(vnfm_id)
493         if ret[0] != 0:
494             return Response(data={'error': ret[1]}, status=ret[2])
495         vnfm_info = json.JSONDecoder().decode(ret[1])
496         data = {}
497         data['action'] = ignorcase_get(request.data, 'action')
498         affectedvm = ignorcase_get(request.data, 'affectedvm')
499         data['affectedvm'] = []
500         if isinstance(affectedvm, list):
501             data['affectedvm'] = affectedvm
502         else:
503             data['affectedvm'].append(affectedvm)
504         data['lifecycleoperation'] = 'operate'
505         data['isgrace'] = 'force'
506
507         logger.info("data = %s", data)
508         ret = restcall.call_req(
509             base_url=ignorcase_get(vnfm_info, "url"),
510             user=ignorcase_get(vnfm_info, "userName"),
511             passwd=ignorcase_get(vnfm_info, "password"),
512             auth_type=restcall.rest_no_auth,
513             resource=nf_healing_url.format(vnfInstanceID=nf_instance_id),
514             method='post',
515             content=json.JSONEncoder().encode(data))
516         logger.info("ret=%s", ret)
517         if ret[0] != 0:
518             return Response(data={'error': 'heal error'}, status=ret[2])
519         resp_data = json.JSONDecoder().decode(ret[1])
520         logger.info("resp_data=%s", resp_data)
521     except Exception as e:
522         logger.error("Error occurred when healing VNF,error:%s", e.message)
523         logger.error(traceback.format_exc())
524         return Response(data={'error': 'heal expection'}, status='500')
525     return Response(data=resp_data, status=ret[2])
526
527
528 def get_vdus(nf_model, aspect_id):
529     associated_group = ''
530     members = []
531     vnf_flavours = nf_model['vnf_flavours']
532     for vnf_flaour in vnf_flavours:
533         scaling_aspects = vnf_flaour['scaling_aspects']
534         for aspect in scaling_aspects:
535             if aspect_id == aspect['id']:
536                 associated_group = aspect['associated_group']
537                 break
538     if not associated_group:
539         logger.error('Cannot find the corresponding element group')
540         raise Exception('Cannot find the corresponding element group')
541     for element_group in nf_model['element_groups']:
542         if element_group['group_id'] == associated_group:
543             members = element_group['members']
544     if not members:
545         logger.error('Cannot find the corresponding members')
546         raise Exception('Cannot find the corresponding members')
547     return members
548
549
550 @api_view(http_method_names=['GET'])
551 def samples(request, *args, **kwargs):
552     return Response(data={"status": "ok"})