3057169b613d1021c04ff85de464956f790d9bc2
[sim/a1-interface.git] / near-rt-ric-simulator / src / STD_2.0.0 / main.py
1 #  ============LICENSE_START===============================================
2 #  Copyright (C) 2023 Nordix Foundation. All rights reserved.
3 #  Copyright (C) 2023 OpenInfra Foundation Europe. All rights reserved.
4 #  ========================================================================
5 #  Licensed under the Apache License, Version 2.0 (the "License");
6 #  you may not use this file except in compliance with the License.
7 #  You may obtain a copy of the License at
8 #
9 #       http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #  Unless required by applicable law or agreed to in writing, software
12 #  distributed under the License is distributed on an "AS IS" BASIS,
13 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #  See the License for the specific language governing permissions and
15 #  limitations under the License.
16 #  ============LICENSE_END=================================================
17 #
18
19 import connexion
20 import uvicorn
21 import json
22 import sys
23 import os
24 import requests
25
26
27 from pathlib import Path
28 from flask import Flask, request, Response
29 from jsonschema import validate
30 from var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set, data_delivery_counter, app
31 from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
32
33 # Constants
34 TEXT_PLAIN='text/plain'
35 APPL_JSON='application/json'
36
37
38 check_apipath()
39
40 # app is created in var_declarations
41
42 import payload_logging   # app var need to be initialized
43
44 #Check alive function
45 @app.route('/', methods=['GET'])
46 def test():
47
48   return Response("OK", 200, mimetype=TEXT_PLAIN)
49
50 #Return the current and all supported yamls for the this container
51 @app.route('/container_interfaces', methods=['GET'])
52 def container_interfaces():
53
54     return get_supported_interfaces_response()
55
56 #Delete all created instances and status
57 @app.route('/deleteinstances', methods=['POST'])
58 def delete_instances():
59
60   for i in policy_instances.keys():
61     policy_instances[i]={}
62   policy_status.clear()
63   callbacks.clear()
64   forced_settings['code']=None
65   forced_settings['delay']=None
66   policy_fingerprint.clear()
67   return Response("All policy instances deleted", 200, mimetype=TEXT_PLAIN)
68
69 #Delete all - all reset
70 @app.route('/deleteall', methods=['POST'])
71 def delete_all():
72   global data_delivery_counter
73
74   policy_instances.clear()
75   policy_types.clear()
76   policy_status.clear()
77   callbacks.clear()
78   forced_settings['code']=None
79   forced_settings['delay']=None
80   policy_fingerprint.clear()
81   data_delivery_counter=0
82   return Response("All policy instances and types deleted", 200, mimetype=TEXT_PLAIN)
83
84 #Load a policy type
85 @app.route('/policytype', methods=['PUT'])
86 def policytype():
87
88   policy_type_id=request.args.get('id')
89   if (policy_type_id is None):
90     return Response('Parameter <id> missing in request', status=400, mimetype=TEXT_PLAIN)
91
92   try:
93     data = request.data
94     data = json.loads(data)
95   except Exception:
96     return Response("The policy type is corrupt or missing", 400, mimetype=TEXT_PLAIN)
97
98   if ('policySchema' not in data.keys()):
99     return Response("The policy type atribute policySchema is missing", 400, mimetype=TEXT_PLAIN)
100
101   retcode=201
102   if (policy_type_id in policy_types.keys()):
103     retcode=200
104     if (len(policy_instances[policy_type_id]) > 0):
105       return Response("The policy type already exists and instances exists", 400, mimetype=TEXT_PLAIN)
106
107   policy_types[policy_type_id]=data
108   policy_instances[policy_type_id]={}
109   return Response("Policy type " + policy_type_id + " is OK.", retcode, mimetype=TEXT_PLAIN)
110
111 #Delete a policy type
112 @app.route('/policytype', methods=['DELETE'])
113 def del_policytype():
114
115   policy_type_id=request.args.get('id')
116   if (policy_type_id is None):
117     return Response('Parameter <id> missing in request', status=400, mimetype=TEXT_PLAIN)
118
119   if (policy_type_id in policy_types.keys()):
120     if (len(policy_instances[policy_type_id]) > 0):
121       return Response("The policy type already exists and instances exists", 400, mimetype=TEXT_PLAIN)
122
123     del policy_types[policy_type_id]
124     del policy_instances[policy_type_id]
125     return Response("Policy type " + policy_type_id + " is OK.", 204, mimetype=TEXT_PLAIN)
126
127   return Response("Policy type " + policy_type_id + " not found.", 204, mimetype=TEXT_PLAIN)
128
129
130 # Get all policy type ids
131 @app.route('/policytypes', methods=['GET'])
132 def get_policytype_ids():
133
134   return (json.dumps(list(policy_instances.keys())), 200)
135
136
137 #Set force response for one A1 response
138 #/forceresponse?code=<responsecode>
139 @app.route('/forceresponse', methods=['POST'])
140 def forceresponse():
141
142   try:
143     forced_settings['code']=request.args.get('code')
144   except Exception:
145     forced_settings['code']=None
146   return Response("Force response code: " + str(forced_settings['code']) + " set for one single A1 response", 200, mimetype=TEXT_PLAIN)
147
148 #Set force delay response, in seconds, for all A1 responses
149 #/froceesponse?delay=<seconds>
150 @app.route('/forcedelay', methods=['POST'])
151 def forcedelay():
152
153   try:
154     forced_settings['delay']=request.args.get('delay')
155   except Exception:
156     forced_settings['delay']=None
157   return Response("Force delay: " + str(forced_settings['delay']) + " sec set for all A1 responses", 200, mimetype=TEXT_PLAIN)
158
159
160 #Set status and reason
161 #/status?policyid=<policyid>&status=<status>[&reason=<reason>]
162 @app.route('/status', methods=['PUT'])
163 def setstatus():
164
165   policy_id=request.args.get('policyid')
166   if (policy_id is None):
167     return Response('Parameter <policyid> missing in request', status=400, mimetype=TEXT_PLAIN)
168   if policy_id not in policy_status.keys():
169     return Response('Policyid: '+policy_id+' not found.', status=404, mimetype=TEXT_PLAIN)
170   status=request.args.get('status')
171   if (status is None):
172     return Response('Parameter <status> missing in request', status=400, mimetype=TEXT_PLAIN)
173   reason=request.args.get('reason')
174   ps = {}
175   ps["enforceStatus"] = status
176   msg="Status set to "+status
177   if (reason is not None):
178     ps["enforceReason"] = reason
179     msg=msg+" and "+reason
180   policy_status[policy_id] = ps
181   msg=msg+" for policy: " + policy_id
182   return Response(msg, 200, mimetype=TEXT_PLAIN)
183
184 #Send status
185 #/status?policyid=<policyid>
186 @app.route('/sendstatus', methods=['POST'])
187 def sendstatus():
188   policyid=request.args.get('policyid')
189   if (policyid is None):
190     return Response('Parameter <policyid> missing in request', status=400, mimetype=TEXT_PLAIN)
191
192   if (policyid not in policy_status.keys()):
193     return Response('Policyid: '+policyid+' not found.', status=404, mimetype=TEXT_PLAIN)
194
195   ps=policy_status[policyid]
196   cb=callbacks[policyid]
197   try:
198     resp=requests.post(cb,json=json.dumps(ps), verify=False) # NOSONAR
199   except Exception:
200     return Response('Post status failed, could not send to: '+str(cb), status=500, mimetype=TEXT_PLAIN)
201   if (resp.status_code<199 & resp.status_code > 299):
202     return Response('Post status failed with code: '+resp.status_code, status=500, mimetype=TEXT_PLAIN)
203
204   return Response(None, 204, mimetype=APPL_JSON)
205
206 #Receive status (only for testing callbacks)
207 #/statustest
208 @app.route('/statustest', methods=['POST', 'PUT'])
209 def statustest():
210   try:
211     data = request.data
212     data = json.loads(data)
213   except Exception:
214     return Response("The status data is corrupt or missing.", 400, mimetype=TEXT_PLAIN)
215
216   return Response(json.dumps(data), 200, mimetype=APPL_JSON)
217
218 #Receive a data delivery package
219 #/datadelivery
220 @app.route('/datadelivery', methods=['POST'])
221 def datadelivery():
222   global data_delivery_counter
223   try:
224     data = request.data
225     data = json.loads(data)
226   except Exception:
227     return Response("The data is corrupt or missing.", 400, mimetype=TEXT_PLAIN)
228   data_delivery_counter += 1
229   return Response("", 200, mimetype=TEXT_PLAIN)
230
231 #Metrics function
232 #Get a named counter
233 @app.route('/counter/<string:countername>', methods=['GET'])
234 def getcounter(countername):
235
236   if (countername == "num_instances"):
237     return Response(str(len(policy_fingerprint)), 200, mimetype=TEXT_PLAIN)
238   elif (countername == "num_types"):
239     return Response(str(len(policy_instances)),200, mimetype=TEXT_PLAIN)
240   elif (countername == "interface"):
241     p=Path(os.getcwd())
242     pp=p.parts
243     return Response(str(pp[len(pp)-1]),200, mimetype=TEXT_PLAIN)
244   elif (countername == "remote_hosts"):
245     hosts=",".join(hosts_set)
246     return str(hosts),200
247   elif (countername == "datadelivery"):
248     return Response(str(data_delivery_counter),200, mimetype=TEXT_PLAIN)
249   else:
250     return Response("Counter name: "+countername+" not found.",404, mimetype=TEXT_PLAIN)
251
252 port_number = 2222
253 if len(sys.argv) >= 2:
254   if isinstance(sys.argv[1], int):
255     port_number = sys.argv[1]
256
257 if __name__ == '__main__':
258   # Use Uvicorn to run the combined app
259   uvicorn.run(app, host="127.0.0.1", port=port_number, log_level="info")