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