blob: 29d66f568faa28cdbb00c62cc09e911285f3e246 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2020-present Open Networking Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import time
import datetime
import pytz
import threading
from icalevents.icalevents import events
from flask import Flask, jsonify, abort, request, Response
import prometheus_client as prom
SECRET_ICAL_URL = os.environ.get("SECRET_ICAL_URL")
NO_RESULT_THRESHOLD = 720
app = Flask(__name__)
edges = [
{
'name': 'production-edge-example',
'status': {
'control_plane': 'connected',
'user_plane': 'connected'
},
'last_update': time.time(),
}
]
status_codes = {
"no result": -2,
"error": -1,
"disconnected": 0,
"connecting": 1,
"connected": 2
}
room_mapping = {
"production-edge-onf-menlo": "(Compute)-MP-1-Aether Production",
"production-edge-example": "(Compute)-MP-1-Aether Production" # for testing
}
cp_status = prom.Gauge("aetheredge_status_control_plane", "Control plane status code", ["name"])
up_status = prom.Gauge("aetheredge_status_user_plane", "User plane status code", ["name"])
last_update = prom.Gauge("aetheredge_last_update", "Last reported test result", ["name"])
maint_window = prom.Gauge("aetheredge_in_maintenance_window", "Currently in a maintenance window", ["name"])
def is_my_event(event, name):
for field in ["summary", "location", "description"]:
if name in getattr(event, field, ""):
return True
return False
def in_maintenance_window(events, name, now):
for event in events:
if event.start < now and event.end > now:
if is_my_event(event, name):
return True
if name in room_mapping and is_my_event(event, room_mapping[name]):
return True
return False
def pull_maintenance_events():
while(True):
now = datetime.datetime.now(pytz.utc)
try:
es = events(SECRET_ICAL_URL, start = now)
except Exception as e:
print(e)
else:
for edge in edges:
if 'maintenance' not in edge:
edge['maintenance'] = {}
edge['maintenance']['in_window'] = in_maintenance_window(es, edge['name'], now)
edge['maintenance']['last_update'] = time.time()
time.sleep(60)
def time_out_stale_results():
for edge in edges:
time_elapsed = time.time() - edge["last_update"]
if time_elapsed > NO_RESULT_THRESHOLD:
edge['status']['control_plane'] = "no result"
edge['status']['user_plane'] = "no result"
@app.route('/edges/metrics', methods=['GET'])
def get_prometheus_metrics():
res = []
time_out_stale_results()
for edge in edges:
if edge['name'] == "production-edge-example":
continue
cp_status.labels(edge['name']).set(status_codes[edge['status']['control_plane']])
up_status.labels(edge['name']).set(status_codes[edge['status']['user_plane']])
last_update.labels(edge['name']).set(edge['last_update'])
if 'maintenance' in edge:
maint_window.labels(edge['name']).set(int(edge['maintenance']['in_window']))
res.append(prom.generate_latest(cp_status))
res.append(prom.generate_latest(up_status))
res.append(prom.generate_latest(last_update))
res.append(prom.generate_latest(maint_window))
return Response(res, mimetype="text/plain")
@app.route('/edges/healthz', methods=['GET'])
def get_health():
return {'message': 'healthy'}
@app.route('/edges', methods=['GET'])
def get_edges():
time_out_stale_results()
return jsonify({'edges': edges})
@app.route('/edges/<string:name>', methods=['GET'])
def get_edge(name):
time_out_stale_results()
edge = [edge for edge in edges if edge['name'] == name]
if len(edge) == 0:
abort(404)
return jsonify({'edge': edge[0]})
@app.route('/edges', methods=['POST'])
def create_or_update_edge():
if not request.json:
abort(400)
if 'name' not in request.json:
abort(400)
if 'status' not in request.json:
abort(400)
req_edge = {
'name': request.json['name'],
'status': {
'control_plane': request.json['status']['control_plane'],
'user_plane': request.json['status']['user_plane']
},
'last_update': time.time()
}
edge = [edge for edge in edges if edge['name'] == req_edge['name']]
if len(edge) == 0:
print("new edge request " + req_edge['name'])
edges.append(req_edge)
else:
edge[0]['status']['control_plane'] = req_edge['status']['control_plane']
edge[0]['status']['user_plane'] = req_edge['status']['user_plane']
edge[0]['last_update'] = req_edge['last_update']
return jsonify({'edge': req_edge}), 201
if __name__ == '__main__':
if SECRET_ICAL_URL:
print(" * Starting maintenance calendar polling thread")
t = threading.Thread(target=pull_maintenance_events)
t.start()
app.run(debug=True, host='0.0.0.0', port=80)