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