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