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