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