aec84c512e3f5076a93cd461212715d2c971f2df
[sim/a1-interface.git] / near-rt-ric-simulator / src / OSC_2.1.0 / controllers / a1_mediator_controller.py
1 #  ============LICENSE_START===============================================
2 #  Copyright (C) 2021-2023 Nordix Foundation. All rights reserved.
3 #  ========================================================================
4 #  Licensed under the Apache License, Version 2.0 (the "License");
5 #  you may not use this file except in compliance with the License.
6 #  You may obtain a copy of the License at
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #  Unless required by applicable law or agreed to in writing, software
11 #  distributed under the License is distributed on an "AS IS" BASIS,
12 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #  See the License for the specific language governing permissions and
14 #  limitations under the License.
15 #  ============LICENSE_END=================================================
16 #
17
18 import json
19 # import datetime
20 import time
21
22 from datetime import datetime
23 from flask import request, Response
24 from jsonschema import validate
25 from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, callbacks, forced_settings, hosts_set, jobs, data_delivery
26 from models.enforceStatus import EnforceStatus
27 from utils import calcFingerprint
28 from maincommon import extract_host_name, is_duplicate_check
29 from payload_logging import is_payload_logging
30
31 # Constants
32 APPL_JSON = 'application/json'
33
34 #Helper funtion to log http reponse
35 def log_resp_text(msg):
36   global payload_log
37   if (is_payload_logging()):
38     print("-----Error description-----")
39     print(str(msg))
40
41 # API Function: Health check
42 def a1_controller_get_healthcheck():
43
44   extract_host_name(hosts_set, request)
45
46   if ((r := check_modified_response()) is not None):
47     return r
48
49   return (None, 200)
50
51 # API Function: Get all policy type ids
52 def a1_controller_get_all_policy_types():
53   extract_host_name(hosts_set, request)
54
55   if ((r := check_modified_response()) is not None):
56     return r
57
58   res = list(policy_instances.keys())
59   res = list(map(int, res))
60   return (res, 200)
61
62 # API Function: Get a policy type
63 def a1_controller_get_policy_type(policy_type_id):
64   extract_host_name(hosts_set, request)
65
66   if ((r := check_modified_response()) is not None):
67     return r
68
69   policy_type_id=str(policy_type_id)
70
71   if (policy_type_id not in policy_types.keys()):
72     log_resp_text("Policy type id not found")
73     return (None, 404)
74
75   return Response(json.dumps(policy_types[policy_type_id]), 200, mimetype=APPL_JSON)
76
77 # API Function: Delete a policy type
78 def a1_controller_delete_policy_type(policy_type_id):
79
80   extract_host_name(hosts_set, request)
81
82   if ((r := check_modified_response()) is not None):
83     return r
84
85   policy_type_id=str(policy_type_id)
86
87   if (policy_type_id not in policy_instances.keys()):
88     log_resp_text("Policy type not found")
89     return (None, 404)
90
91   if (len(policy_instances[policy_type_id]) > 0):
92     log_resp_text("Policy type cannot be removed, instances exists")
93     return (None, 400)
94
95   del policy_instances[policy_type_id]
96   del policy_types[policy_type_id]
97
98   return (None, 204)
99
100
101 # API Function: Create a policy type
102 def a1_controller_create_policy_type(policy_type_id):
103
104   extract_host_name(hosts_set, request)
105
106   if ((r := check_modified_response()) is not None):
107     return r
108
109   try:
110     int(policy_type_id)
111   except Exception:
112     return Response("The policy type id is not an int", 400, mimetype='text/plain')
113
114   policy_type_id=str(policy_type_id)
115
116   if (policy_type_id in policy_instances.keys()):
117     if (len(policy_instances[policy_type_id]) > 0):
118       log_resp_text("Policy type id already exists")
119       return (None, 400)
120
121   try:
122     data = request.data
123     data = json.loads(data)
124   except Exception:
125     log_resp_text("Policy type validation failure")
126     return (None, 400)
127
128   if (('name' not in data.keys()) or ('description' not in data.keys()) or ('policy_type_id' not in data.keys()) or ('create_schema' not in data.keys())):
129     log_resp_text("Parameters missing in policy type")
130     return (None, 400)
131
132   if (policy_type_id not in policy_instances.keys()):
133     policy_instances[policy_type_id]={}
134
135   policy_types[policy_type_id]=data
136
137   return (None, 201)
138
139
140 # API Function: Get all policy ids for a type
141 def  a1_controller_get_all_instances_for_type(policy_type_id):
142
143   extract_host_name(hosts_set, request)
144
145   if ((r := check_modified_response()) is not None):
146     return r
147
148   policy_type_id=str(policy_type_id)
149
150   if (policy_type_id not in policy_instances.keys()):
151     log_resp_text("Policy type id not found")
152     return (None, 404)
153   return (list(policy_instances[policy_type_id].keys()), 200)
154
155 # API Function: Get a policy instance
156 def a1_controller_get_policy_instance(policy_type_id, policy_instance_id):
157
158   extract_host_name(hosts_set, request)
159
160   if ((r := check_modified_response()) is not None):
161     return r
162
163   policy_type_id=str(policy_type_id)
164
165   if (policy_type_id not in policy_instances.keys()):
166     log_resp_text("Policy type id not found")
167     return (None, 404)
168
169   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
170     log_resp_text("Policy instance id not found")
171     return (None, 404)
172
173   return Response(json.dumps(policy_instances[policy_type_id][policy_instance_id]), 200, mimetype=APPL_JSON)
174
175 # API function: Delete a policy
176 def a1_controller_delete_policy_instance(policy_type_id, policy_instance_id):
177
178   extract_host_name(hosts_set, request)
179
180   if ((r := check_modified_response()) is not None):
181     return r
182
183   policy_type_id=str(policy_type_id)
184
185   if (policy_type_id not in policy_instances.keys()):
186     log_resp_text("Policy type id not found")
187     return (None, 404)
188
189   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
190     log_resp_text("Policy instance id not found")
191     return (None, 404)
192
193   if (is_duplicate_check()):
194     fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id], policy_type_id)
195   else:
196     fp_previous=policy_instance_id
197
198   del policy_fingerprint[fp_previous]
199   del policy_instances[policy_type_id][policy_instance_id]
200   del policy_status[policy_instance_id]
201   callbacks.pop(policy_instance_id)
202
203   return (None, 202)
204
205
206 # API function: Create/update a policy
207 def a1_controller_create_or_replace_policy_instance(policy_type_id, policy_instance_id):
208
209   extract_host_name(hosts_set, request)
210
211   if ((r := check_modified_response()) is not None):
212     return r
213
214   policy_type_id=str(policy_type_id)
215
216   if (policy_type_id not in policy_instances.keys()):
217     log_resp_text("Policy type id not found")
218     return (None, 404)
219
220   try:
221     data = request.data
222     data = json.loads(data)
223   except Exception:
224     log_resp_text("Policy json error")
225     return (None, 400)
226
227   try:
228     validate(instance=data, schema=policy_types[policy_type_id]['create_schema'])
229   except Exception:
230     log_resp_text("Policy validation error")
231     return (None, 400)
232
233   fp_previous=None
234   if policy_instance_id in policy_instances[policy_type_id].keys():
235     if (is_duplicate_check()):
236       fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_instance_id], policy_type_id)
237     else:
238       fp_previous=policy_instance_id
239
240   else:
241     if (policy_instance_id in policy_fingerprint.values()):
242       log_resp_text("Policy id already exist for other type")
243       return (None, 400)
244
245   if is_duplicate_check():
246     fp = calcFingerprint(data, policy_type_id)
247   else:
248     fp = policy_instance_id
249
250   if (fp in policy_fingerprint.keys()) and is_duplicate_check():
251     p_id = policy_fingerprint[fp]
252     if (p_id != policy_instance_id):
253       log_resp_text("Policy json duplicate of other instance")
254       return (None, 400)
255
256   if fp_previous is not None:
257     del policy_fingerprint[fp_previous]
258
259   policy_fingerprint[fp]=policy_instance_id
260
261   noti = request.args.get('notificationDestination')
262   callbacks[policy_instance_id] = noti
263
264   policy_instances[policy_type_id][policy_instance_id]=data
265
266   enforceStatus = EnforceStatus("NOT_ENFORCED", "OTHER_REASON")
267   policy_status[policy_instance_id] = enforceStatus.to_dict()
268
269   # return Response(json.dumps(data), 200, mimetype=APPL_JSON)
270   return (None, 202)
271
272 # API function: Get policy status
273 def a1_controller_get_policy_instance_status(policy_type_id, policy_instance_id):
274
275   extract_host_name(hosts_set, request)
276
277   if ((r := check_modified_response()) is not None):
278     return r
279
280   policy_type_id=str(policy_type_id)
281   if (policy_type_id not in policy_instances.keys()):
282     log_resp_text("Policy type id not found")
283     return (None, 404)
284
285   if (policy_instance_id not in policy_instances[policy_type_id].keys()):
286     log_resp_text("Policy instance id not found")
287     return (None, 404)
288
289   return Response(json.dumps(policy_status[policy_instance_id]), 200, mimetype=APPL_JSON)
290
291 # API function: Receive a data delivery package
292 def a1_controller_data_delivery():
293  
294   extract_host_name(hosts_set, request)
295   if ((r := check_modified_response()) is not None):
296     return r
297
298   try:
299     data = request.data
300     data = json.loads(data)
301     job = data['job']
302     jobs.index(job)
303   except ValueError:
304     log_resp_text("no job id defined for this data delivery")
305     return (None, 404)
306   except Exception:
307     log_resp_text("The data is corrupt or missing.")
308     return (None, 400)
309   data_delivery.append(data)
310   return (None, 200) # Should A1 and the A1 Simulator return 201 for creating a new resource?
311
312 # Helper: Create a response object if forced http response code is set
313 def get_forced_response():
314
315   response_code=forced_settings['code']
316   if (response_code is not None):
317     forced_settings['code'] = None
318     return (None, response_code)
319   return None
320
321 # Helper: Delay if delayed response code is set
322 def do_delay():
323
324   if (forced_settings['delay'] is not None):
325     try:
326       val=int(forced_settings['delay'])
327       time.sleep(val)
328     except Exception:
329       return
330
331 # Helper: Check if response shall be delayed or a forced response shall be sent
332 def check_modified_response():
333   do_delay()
334   return get_forced_response()