Merge "Update README MarkDown files"
[nonrtric.git] / test / cr / app / cr.py
1
2 #  ============LICENSE_START===============================================
3 #  Copyright (C) 2020 Nordix Foundation. 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 from flask import Flask, request, Response
20 from time import sleep
21 import time
22 from datetime import datetime
23 import json
24 import traceback
25 import logging
26 import socket
27
28 # Disable all logging of GET on reading counters and db
29 class AjaxFilter(logging.Filter):
30     def filter(self, record):
31         return ("/counter/" not in record.getMessage()) and ("/db" not in record.getMessage())
32
33 log = logging.getLogger('werkzeug')
34 log.addFilter(AjaxFilter())
35
36 app = Flask(__name__)
37
38 # list of callback messages
39 msg_callbacks={}
40
41 # Server info
42 HOST_IP = "::"
43 HOST_PORT = 2222
44
45 # Metrics vars
46 cntr_msg_callbacks=0
47 cntr_msg_fetched=0
48 cntr_callbacks={}
49
50 # Request and response constants
51 CALLBACK_URL="/callbacks/<string:id>"
52 APP_READ_URL="/get-event/<string:id>"
53 APP_READ_ALL_URL="/get-all-events/<string:id>"
54 DUMP_ALL_URL="/db"
55
56 MIME_TEXT="text/plain"
57 MIME_JSON="application/json"
58 CAUGHT_EXCEPTION="Caught exception: "
59 SERVER_ERROR="Server error :"
60 TIME_STAMP="cr-timestamp"
61
62 # Remote host lookup and print host name
63 def remote_host_logging(request):
64
65     if request.environ.get('HTTP_X_FORWARDED_FOR') is None:
66         host_ip=str(request.environ['REMOTE_ADDR'])
67     else:
68         host_ip=str(request.environ['HTTP_X_FORWARDED_FOR'])
69     prefix='::ffff:'
70     if (host_ip.startswith('::ffff:')):
71         host_ip=host_ip[len(prefix):]
72     try:
73         name, alias, addresslist = socket.gethostbyaddr(host_ip)
74         print("Calling host: "+str(name))
75     except Exception:
76         print("Calling host not possible to retrieve IP: "+str(host_ip))
77
78
79 #I'm alive function
80 @app.route('/',
81     methods=['GET'])
82 def index():
83     return 'OK', 200
84
85 ### Callback interface, for control
86
87 # Fetch the oldest callback message for an id
88 # URI and parameter, (GET): /get-event/<id>
89 # response: message + 200 or just 204 or just 500(error)
90 @app.route(APP_READ_URL,
91     methods=['GET'])
92 def receiveresponse(id):
93     global msg_callbacks
94     global cntr_msg_fetched
95
96     try:
97         if ((id in msg_callbacks.keys()) and (len(msg_callbacks[id]) > 0)):
98             cntr_msg_fetched+=1
99             cntr_callbacks[id][1]+=1
100             msg=msg_callbacks[id][0]
101             print("Fetching msg for id: "+id+", msg="+str(msg))
102             del msg[TIME_STAMP]
103             del msg_callbacks[id][0]
104             return json.dumps(msg),200
105         print("No messages for id: "+id)
106     except Exception as e:
107         print(CAUGHT_EXCEPTION+str(e))
108         traceback.print_exc()
109         return "",500
110
111     return "",204
112
113 # Fetch all callback message for an id in an array
114 # URI and parameter, (GET): /get-all-events/<id>
115 # response: message + 200 or just 500(error)
116 @app.route(APP_READ_ALL_URL,
117     methods=['GET'])
118 def receiveresponse_all(id):
119     global msg_callbacks
120     global cntr_msg_fetched
121
122     try:
123         if ((id in msg_callbacks.keys()) and (len(msg_callbacks[id]) > 0)):
124             cntr_msg_fetched+=len(msg_callbacks[id])
125             cntr_callbacks[id][1]+=len(msg_callbacks[id])
126             msg=msg_callbacks[id]
127             print("Fetching all msgs for id: "+id+", msg="+str(msg))
128             for sub_msg in msg:
129                 del sub_msg[TIME_STAMP]
130             del msg_callbacks[id]
131             return json.dumps(msg),200
132         print("No messages for id: "+id)
133     except Exception as e:
134         print(CAUGHT_EXCEPTION+str(e))
135         traceback.print_exc()
136         return "",500
137
138     msg=[]
139     return json.dumps(msg),200
140
141 # Receive a callback message
142 # URI and payload, (PUT or POST): /callbacks/<id> <json messages>
143 # response: OK 200 or 500 for other errors
144 @app.route(CALLBACK_URL,
145     methods=['PUT','POST'])
146 def events_write(id):
147     global msg_callbacks
148     global cntr_msg_callbacks
149
150     try:
151         print("Received callback for id: "+id +", content-type="+request.content_type)
152         remote_host_logging(request)
153         try:
154             if (request.content_type == MIME_JSON):
155                 data = request.data
156                 msg = json.loads(data)
157                 print("Payload(json): "+str(msg))
158             else:
159                 msg={}
160                 print("Payload(content-type="+request.content_type+"). Setting empty json as payload")
161         except Exception as e:
162             msg={}
163             print("(Exception) Payload does not contain any json, setting empty json as payload")
164             traceback.print_exc()
165
166         cntr_msg_callbacks += 1
167         msg[TIME_STAMP]=str(datetime.now())
168         if (id in msg_callbacks.keys()):
169             msg_callbacks[id].append(msg)
170         else:
171             msg_callbacks[id]=[]
172             msg_callbacks[id].append(msg)
173
174         if (id in cntr_callbacks.keys()):
175             cntr_callbacks[id][0] += 1
176         else:
177             cntr_callbacks[id]=[]
178             cntr_callbacks[id].append(1)
179             cntr_callbacks[id].append(0)
180
181     except Exception as e:
182         print(CAUGHT_EXCEPTION+str(e))
183         traceback.print_exc()
184         return 'NOTOK',500
185
186     return 'OK',200
187
188 ### Functions for test ###
189
190 # Dump the whole db of current callbacks
191 # URI and parameter, (GET): /db
192 # response: message + 200
193 @app.route(DUMP_ALL_URL,
194     methods=['GET'])
195 def dump_db():
196     return json.dumps(msg_callbacks),200
197
198 ### Functions for metrics read out ###
199
200 @app.route('/counter/received_callbacks',
201     methods=['GET'])
202 def requests_submitted():
203     req_id = request.args.get('id')
204     if (req_id is None):
205         return Response(str(cntr_msg_callbacks), status=200, mimetype=MIME_TEXT)
206
207     if (req_id in cntr_callbacks.keys()):
208         return Response(str(cntr_callbacks[req_id][0]), status=200, mimetype=MIME_TEXT)
209     else:
210         return Response(str("0"), status=200, mimetype=MIME_TEXT)
211
212 @app.route('/counter/fetched_callbacks',
213     methods=['GET'])
214 def requests_fetched():
215     req_id = request.args.get('id')
216     if (req_id is None):
217         return Response(str(cntr_msg_fetched), status=200, mimetype=MIME_TEXT)
218
219     if (req_id in cntr_callbacks.keys()):
220         return Response(str(cntr_callbacks[req_id][1]), status=200, mimetype=MIME_TEXT)
221     else:
222         return Response(str("0"), status=200, mimetype=MIME_TEXT)
223
224 @app.route('/counter/current_messages',
225     methods=['GET'])
226 def current_messages():
227     req_id = request.args.get('id')
228     if (req_id is None):
229         return Response(str(cntr_msg_callbacks-cntr_msg_fetched), status=200, mimetype=MIME_TEXT)
230
231     if (req_id in cntr_callbacks.keys()):
232         return Response(str(cntr_callbacks[req_id][0]-cntr_callbacks[req_id][1]), status=200, mimetype=MIME_TEXT)
233     else:
234         return Response(str("0"), status=200, mimetype=MIME_TEXT)
235
236
237 ### Admin ###
238
239 # Reset all messsages and counters
240 @app.route('/reset',
241     methods=['GET', 'POST', 'PUT'])
242 def reset():
243     global msg_callbacks
244     global cntr_msg_fetched
245     global cntr_msg_callbacks
246     global cntr_callbacks
247
248     msg_callbacks={}
249     cntr_msg_fetched=0
250     cntr_msg_callbacks=0
251     cntr_callbacks={}
252
253     return Response('OK', status=200, mimetype=MIME_TEXT)
254
255 ### Main function ###
256
257 if __name__ == "__main__":
258     app.run(port=HOST_PORT, host=HOST_IP)