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