A1 simulator for STD 2.0.0
[sim/a1-interface.git] / near-rt-ric-simulator / src / STD_2.0.0 / a1.py
1 #  ============LICENSE_START===============================================
2 #  Copyright (C) 2020 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 copy
19 import datetime
20 import json
21 import logging
22 import collections
23 import time
24
25 from connexion import NoContent
26 from flask import Flask, escape, request, Response, make_response
27 from jsonschema import validate
28 from var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set
29 from utils import calcFingerprint
30 from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
31
32 #Constsants
33 APPL_JSON='application/json'
34 APPL_PROB_JSON='application/problem+json'
35
36 # API Function: Get all policy type ids
37 def get_all_policy_types():
38
39   extract_host_name(hosts_set, request)
40
41   if ((r := check_modified_response()) is not None):
42     return r
43
44   res = list(policy_types.keys())
45   return (res, 200)
46
47 # API Function: Get a policy type
48 def get_policy_type(policyTypeId):
49
50   extract_host_name(hosts_set, request)
51
52   if ((r := check_modified_response()) is not None):
53     return r
54
55   policy_type_id=str(policyTypeId)
56
57   if (policy_type_id not in policy_types.keys()):
58     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_type_id)
59     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
60
61   return Response(json.dumps(policy_types[policy_type_id]), 200, mimetype=APPL_JSON)
62
63 # API Function: Get all policy ids
64 def get_all_policy_identities(policyTypeId):
65
66   extract_host_name(hosts_set, request)
67
68   if ((r := check_modified_response()) is not None):
69     return r
70
71   policy_type_id=str(policyTypeId)
72
73   if (policy_type_id not in policy_types.keys()):
74     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_type_id)
75     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
76
77   return (list(policy_instances[policy_type_id].keys()), 200)
78
79 # API Function: Create or update a policy
80 def put_policy(policyTypeId, policyId):
81
82   extract_host_name(hosts_set, request)
83
84   if ((r := check_modified_response()) is not None):
85     return r
86
87   policy_type_id=str(policyTypeId)
88   policy_id=str(policyId)
89
90   if (policy_type_id not in policy_types.keys()):
91     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id)
92     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
93
94   try:
95     data = request.data
96     data = json.loads(data)
97   except Exception:
98     pjson=create_problem_json(None, "The policy is corrupt or missing.", 400, None, policy_id)
99     return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
100
101   try:
102     validate(instance=data, schema=policy_types[policy_type_id]['policySchema'])
103   except Exception:
104     return (None, 400)
105
106   fp_previous=None
107   retcode=201
108   if policy_id in policy_instances[policy_type_id].keys():
109     retcode=200
110     fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id])
111   else:
112     if (policy_id in policy_fingerprint.values()):
113       return (None, 400)
114
115   fp=calcFingerprint(data)
116   if (fp in policy_fingerprint.keys()):
117     p_id=policy_fingerprint[fp]
118     if (p_id != policy_id):
119       pjson=create_problem_json(None, "Duplicate, the policy json already exists.", 400, None, policy_id)
120       return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
121
122   if (fp_previous is not None):
123     del policy_fingerprint[fp_previous]
124
125   policy_fingerprint[fp]=policy_id
126
127   noti=request.args.get('notificationDestination')
128   callbacks[policy_id]=noti
129
130   policy_instances[policy_type_id][policy_id]=data
131
132   if (policy_types[policy_type_id]['statusSchema'] is not None):
133     ps = {}
134     ps["enforceStatus"] = ""
135     ps["enforceReason"] = ""
136     policy_status[policy_id] = ps
137
138   if (retcode == 200):
139     return Response(json.dumps(data), 200, mimetype=APPL_JSON)
140   else:
141     headers={}
142     headers['Location']='/A1-P/v2/policytypes/' + policy_type_id + '/policies/' + policy_id
143     return Response(json.dumps(data), 201, headers=headers, mimetype=APPL_JSON)
144
145 # API Function: Get a policy
146 def get_policy(policyTypeId, policyId):
147
148   extract_host_name(hosts_set, request)
149
150   if ((r := check_modified_response()) is not None):
151     return r
152
153   policy_type_id=str(policyTypeId)
154   policy_id=str(policyId)
155
156   if (policy_type_id not in policy_types.keys()):
157     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id)
158     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
159
160   if (policy_id not in policy_instances[policy_type_id].keys()):
161     pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id)
162     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
163
164   return Response(json.dumps(policy_instances[policy_type_id][policy_id]), 200, mimetype=APPL_JSON)
165
166
167 # API Function: Delete a policy
168 def delete_policy(policyTypeId, policyId):
169
170   extract_host_name(hosts_set, request)
171
172   if ((r := check_modified_response()) is not None):
173     return r
174
175   policy_type_id=str(policyTypeId)
176   policy_id=str(policyId)
177
178   if (policy_type_id not in policy_types.keys()):
179     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id)
180     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
181
182   if (policy_id not in policy_instances[policy_type_id].keys()):
183     pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id)
184     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
185
186   fp_previous=calcFingerprint(policy_instances[policy_type_id][policy_id])
187   policy_fingerprint.pop(fp_previous)
188   policy_instances[policy_type_id].pop(policy_id)
189   policy_status.pop(policy_id)
190   callbacks.pop(policy_id)
191   return Response('', 204, mimetype=APPL_JSON)
192
193
194 # API Function: Get status for a policy
195 def get_policy_status(policyTypeId, policyId):
196
197   extract_host_name(hosts_set, request)
198
199   if ((r := check_modified_response()) is not None):
200     return r
201
202   policy_type_id=str(policyTypeId)
203   policy_id=str(policyId)
204
205   if (policy_type_id not in policy_types.keys()):
206     pjson=create_problem_json(None, "The policy type does not exist.", 404, None, policy_id)
207     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
208
209   if (policy_id not in policy_instances[policy_type_id].keys()):
210     pjson=create_problem_json(None, "The requested policy does not exist.", 404, None, policy_id)
211     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
212
213   return Response(json.dumps(policy_status[policy_id]), status=200, mimetype=APPL_JSON)
214
215 # Helper: Create a response object if forced http response code is set
216 def get_forced_response():
217   if (forced_settings['code'] is not None):
218     pjson=create_error_response(forced_settings['code'])
219     forced_settings['code']=None
220     return Response(json.dumps(pjson), pjson['status'], mimetype=APPL_PROB_JSON)
221   return None
222
223 # Helper: Delay if delayed response code is set
224 def do_delay():
225   if (forced_settings['delay'] is not None):
226     try:
227       val=int(forced_settings['delay'])
228       time.sleep(val)
229     except Exception:
230       return
231
232 # Helper: Check if response shall be delayed or a forced response shall be sent
233 def check_modified_response():
234   do_delay()
235   return get_forced_response()
236
237 # Helper: Create a problem json object
238 def create_problem_json(type_of, title, status, detail, instance):
239
240   error = {}
241   if type_of is not None:
242     error["type"] = type_of
243   if title is not None:
244     error["title"] = title
245   if status is not None:
246     error["status"] = status
247   if detail is not None:
248     error["detail"] = detail
249   if instance is not None:
250     error["instance"] = instance
251   return error
252
253 # Helper: Create a problem json based on a generic http response code
254 def create_error_response(code):
255
256     if code == '400':
257       return(create_problem_json(None, "Bad request", 400, "Object in payload not properly formulated or not related to the method", None))
258     elif code == '404':
259       return(create_problem_json(None, "Not found", 404, "No resource found at the URI", None))
260     elif code == '405':
261       return(create_problem_json(None, "Method not allowed", 405, "Method not allowed for the URI", None))
262     elif code == '409':
263       return(create_problem_json(None, "Conflict", 409, "Request could not be processed in the current state of the resource", None))
264     elif code == '429':
265       return(create_problem_json(None, "Too many requests", 429, "Too many requests have been sent in a given amount of time", None))
266     elif code == '507':
267       return(create_problem_json(None, "Insufficient storage", 507, "The method could not be performed on the resource because the provider is unable to store the representation needed to successfully complete the request", None))
268     elif code == '503':
269       return(create_problem_json(None, "Service unavailable", 503, "The provider is currently unable to handle the request due to a temporary overload", None))
270     else:
271       return(create_problem_json(None, "Unknown", code, "Not implemented response code", None))