Add vfc-ztevnfmdriver heal auto-swagger
[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 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
26
27 from driver.interfaces.serializers import HealReqSerializer, HealRespSerializer
28 from driver.pub.utils import restcall
29 from driver.pub.utils.restcall import req_by_msb
30 from driver.pub.config.config import VNF_FTP
31
32 logger = logging.getLogger(__name__)
33
34
35 def load_json_file(file_name):
36     json_file = os.path.join(os.path.dirname(__file__), "data/" + file_name)
37     f = open(json_file)
38     json_data = json.JSONDecoder().decode(f.read())
39     f.close()
40     return json_data
41
42
43 def fun_name():
44     return "=================%s==================" % inspect.stack()[1][3]
45
46
47 def ignorcase_get(args, key):
48     if not key:
49         return ""
50     if not args:
51         return ""
52     if key in args:
53         return args[key]
54     for old_key in args:
55         if old_key.upper() == key.upper():
56             return args[old_key]
57     return ""
58
59
60 def mapping_conv(keyword_map, rest_return):
61     resp_data = {}
62     for param in keyword_map:
63         if keyword_map[param]:
64             resp_data[keyword_map[param]] = ignorcase_get(rest_return, param)
65     return resp_data
66
67
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")
71     return ret
72
73
74 # Query vnfd_info from nslcm
75 def vnfd_get(vnfpackageid):
76     ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % vnfpackageid, "GET")
77     return ret
78
79
80 # Query vnfpackage_info from nslcm
81 def vnfpackage_get(csarid):
82     ret = req_by_msb("api/nslcm/v1/vnfpackage/%s" % csarid, "GET")
83     return ret
84
85
86 @api_view(http_method_names=['POST'])
87 def instantiate_vnf(request, *args, **kwargs):
88     try:
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)
92         if ret[0] != 0:
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)
98         if ret[0] != 0:
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)
104         if ret[0] != 0:
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)
109         data = {}
110         data["NFVOID"] = 1
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
116         inputs = []
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")
123         else:
124             data["VNFD"] = ignorcase_get(packageInfo, "downloadUri")
125
126         data["VNFURL"] = data["VNFD"]
127
128         data["extension"] = {}
129         for name, value in ignorcase_get(ignorcase_get(request.data, "additionalParam"), "inputs").items():
130             inputs.append({"name": name, "value": value})
131
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)
139
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,
145             resource="v1/vnfs",
146             method='post',
147             content=json.JSONEncoder().encode(data))
148
149         logger.debug("[%s] call_req ret=%s", fun_name(), ret)
150         if ret[0] != 0:
151             return Response(data={'error': ret[1]}, status=ret[2])
152         resp = json.JSONDecoder().decode(ret[1])
153         resp_data = {
154             "vnfInstanceId": ignorcase_get(resp, "VNFInstanceID"),
155             "jobId": ignorcase_get(resp, "JobId")
156         }
157         logger.info("[%s]resp_data=%s", fun_name(), resp_data)
158     except Exception as e:
159         logger.error("Error occurred when instantiating VNF")
160         raise e
161     return Response(data=resp_data, status=ret[2])
162
163
164 @api_view(http_method_names=['POST'])
165 def terminate_vnf(request, *args, **kwargs):
166     try:
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)
170         if ret[0] != 0:
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")),
180             method='delete',
181             content=json.JSONEncoder().encode(request.data))
182         if ret[0] != 0:
183             return Response(data={'error': ret[1]}, status=ret[2])
184         resp = json.JSONDecoder().decode(ret[1])
185         resp_data = {
186             "vnfInstanceId": ignorcase_get(resp, "VNFInstanceID"),
187             "jobId": ignorcase_get(resp, "JobId")
188         }
189         logger.debug("[%s]resp_data=%s", fun_name(), resp_data)
190     except Exception as e:
191         logger.error("Error occurred when terminating VNF")
192         raise e
193     return Response(data=resp_data, status=ret[2])
194
195
196 @api_view(http_method_names=['GET'])
197 def query_vnf(request, *args, **kwargs):
198     try:
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)
202         if ret[0] != 0:
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")),
212             method='get',
213             content=json.JSONEncoder().encode({}))
214         if ret[0] != 0:
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.")
222         raise e
223     return Response(data=resp_data, status=ret[2])
224
225
226 @api_view(http_method_names=['GET'])
227 def operation_status(request, *args, **kwargs):
228     data = {}
229     try:
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)
233         if ret[0] != 0:
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')),
246             method='get',
247             content=json.JSONEncoder().encode(data))
248
249         if ret[0] != 0:
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.")
255         raise e
256     return Response(data=resp_data, status=ret[2])
257
258
259 @api_view(http_method_names=['PUT'])
260 def grantvnf(request, *args, **kwargs):
261     logger.info("=====grantvnf=====")
262     try:
263         logger.info("req_data = %s", request.data)
264         grant_vnf_param_map = {
265             "VNFMID": "",
266             "NFVOID": "",
267             "VIMID": "",
268             "ExVIMIDList": "",
269             "ExVIMID": "",
270             "Tenant": "",
271             "VNFInstanceID": "vnfInstanceId",
272             "OperationRight": "",
273             "VMList": "",
274             "VMFlavor": "",
275             "VMNumber": ""
276         }
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(
285                         {
286                             "type": "vdu",
287                             "resourceDefinitionId": i,
288                             "vdu": ignorcase_get(vm, "vmflavor"),
289                             "vimid": ignorcase_get(vm, "vimid"),
290                             "tenant": ignorcase_get(vm, "tenant")})
291
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")
296
297         ret = req_by_msb('api/nslcm/v1/ns/grantvnf', "POST", content=json.JSONEncoder().encode(data))
298         logger.info("ret = %s", ret)
299         if ret[0] != 0:
300             return Response(data={'error': ret[1]}, status=ret[2])
301         resp = json.JSONDecoder().decode(ret[1])
302         resp_data = {
303             'vimid': ignorcase_get(resp['vim'], 'vimid'),
304             'tenant': ignorcase_get(ignorcase_get(resp['vim'], 'accessinfo'), 'tenant')
305         }
306         logger.info("[%s]resp_data=%s", fun_name(), resp_data)
307     except Exception as e:
308         logger.error("Error occurred in Grant VNF.")
309         raise e
310     return Response(data=resp_data, status=ret[2])
311
312
313 @api_view(http_method_names=['POST'])
314 def notify(request, *args, **kwargs):
315     try:
316         logger.info("[%s]req_data = %s", fun_name(), request.data)
317         notify_param_map = {
318             "NFVOID": "",
319             "VNFMID": "VNFMID",
320             "VIMID": "vimid",
321             "VNFInstanceID": "vnfInstanceId",
322             "TimeStamp": "",
323             "EventType": "operation",
324             "VMList": "",
325             "VMFlavor": "",
326             "VMNumber": "",
327             "VMIDlist": "",
328             "VMUUID": ""
329         }
330         data = mapping_conv(notify_param_map, request.data)
331         logger.info("[%s]data = %s", fun_name(), data)
332
333         data["status"] = "result"
334         data["jobId"] = "notMust"
335         data["affectedVnfc"] = []
336         data["affectedVl"] = []
337         data["affectedVirtualStorage"] = []
338         data["affectedCp"] = []
339
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")
347         else:
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")
352
353         data["vnfdmodule"] = vnfdmodule
354
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")
363             })
364
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"),
371                 "networkResource": {
372                     "resourceType": "network",
373                     "resourceId": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourceid"),
374                     "resourceName": ignorcase_get(ignorcase_get(affectedvl, "networkresource"), "resourcename")
375                 }
376             })
377
378         for affectedcp in affectedcps:
379             data["affectedCp"].append(affectedcp)
380
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))
385
386         logger.info("[%s]data = %s", fun_name(), ret)
387         if ret[0] != 0:
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())
392         raise e
393     return Response(data=None, status=ret[2])
394
395
396 @api_view(http_method_names=['POST'])
397 def scale(request, *args, **kwargs):
398     logger.info("====scale_vnf===")
399     try:
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)
405         if ret[0] != 0:
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")
411         data = {
412             'vnfmid': vnfm_id,
413             'nfvoid': 1,
414             'scaletype': '0' if scale_type == 'SCALE_OUT' else '1',
415             'vmlist': [{'VMNumber': number_of_steps, 'VMFlavor': aspect_id}],
416             'extension': ''
417         }
418
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),
426             method='put',  # POST
427             content=json.JSONEncoder().encode(data))
428         logger.info("ret=%s", ret)
429         if ret[0] != 0:
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])
438
439
440 class Heal(APIView):
441     @swagger_auto_schema(
442         request_body=HealReqSerializer(),
443         responses={
444             status.HTTP_202_ACCEPTED: HealRespSerializer(),
445             status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error"
446         }
447     )
448     def post(self, request, vnfmid, vnfInstanceId):
449         logger.info("====heal_vnf===")
450         try:
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)
456
457             ret = get_vnfminfo_from_nslcm(vnfmid)
458             if ret[0] != 0:
459                 return Response(data={'error': ret[1]}, status=ret[2])
460             vnfm_info = json.JSONDecoder().decode(ret[1])
461             data = {}
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
467             else:
468                 data['affectedvm'].append(affectedvm)
469             data['lifecycleoperation'] = 'operate'
470             data['isgrace'] = 'force'
471
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),
479                 method='post',
480                 content=json.JSONEncoder().encode(data))
481             logger.info("ret=%s", ret)
482             if ret[0] != 0:
483                 raise Exception('heal error')
484             resp_data = json.JSONDecoder().decode(ret[1])
485             logger.info("resp_data=%s", resp_data)
486             healRespSerializer = HealRespSerializer(data=resp_data)
487             if not healRespSerializer.is_valid():
488                 raise Exception(healRespSerializer.errors)
489
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)
495
496
497 def get_vdus(nf_model, aspect_id):
498     associated_group = ''
499     members = []
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']
506                 break
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']
513     if not members:
514         logger.error('Cannot find the corresponding members')
515         raise Exception('Cannot find the corresponding members')
516     return members
517
518
519 @api_view(http_method_names=['GET'])
520 def samples(request, *args, **kwargs):
521     return Response(data={"status": "ok"})