A1-Simulator - Align with OSC Near-RT-RIC A1 Mediator
[sim/a1-interface.git] / near-rt-ric-simulator / src / STD_2.0.0 / main.py
1 #  ============LICENSE_START===============================================
2 #  Copyright (C) 2021 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 connexion
19 import json
20 import sys
21 import os
22 import requests
23
24
25 from pathlib import Path
26 from flask import Flask, escape, 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   data = resp.json()
203   return Response(data, 200, 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", threaded=False)