136 lines
4.2 KiB
Python
136 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: UTF-8 -*-
|
|
#-------------------------------------------------------------------------------
|
|
# Name: check_providers_api.py
|
|
# Purpose: Flask API to expose check_providers state and history
|
|
#
|
|
# Routes:
|
|
# GET /status -> current state of all providers (from JSON state file)
|
|
# GET /history -> event history from SQLite
|
|
# ?provider=NAME -> filter by provider name
|
|
# ?limit=N -> number of rows (default: 200)
|
|
# ?transitions=true -> only show up<->down transitions
|
|
# ?days=N -> limit to last N days (default: 7)
|
|
#-------------------------------------------------------------------------------
|
|
|
|
import os
|
|
import json
|
|
import sqlite3
|
|
|
|
from flask import Flask, jsonify, request, Response
|
|
|
|
app = Flask(__name__)
|
|
|
|
BASE_DIR = '/opt/check_providers'
|
|
STATE_FILE = os.path.join(BASE_DIR, 'check-providers-state.json')
|
|
DB_PATH = os.path.join(BASE_DIR, 'check-providers.db')
|
|
|
|
|
|
def get_db():
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Routes
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@app.route('/status')
|
|
def status():
|
|
"""Return the current state of all providers from the JSON state file."""
|
|
try:
|
|
with open(STATE_FILE) as f:
|
|
content = f.read()
|
|
return Response(content, mimetype='application/json')
|
|
except FileNotFoundError:
|
|
return jsonify({'error': 'No state file found — is the monitor running?'}), 503
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@app.route('/history')
|
|
def history():
|
|
"""
|
|
Return event history from SQLite.
|
|
|
|
Query params:
|
|
provider : filter by provider name
|
|
limit : max rows returned (default 200, max 5000)
|
|
transitions : if 'true', only return up<->down transitions
|
|
days : only return events from the last N days (default 7)
|
|
"""
|
|
provider = request.args.get('provider')
|
|
limit = min(int(request.args.get('limit', 200)), 5000)
|
|
only_transitions = request.args.get('transitions', 'false').lower() == 'true'
|
|
days = int(request.args.get('days', 7))
|
|
|
|
query = '''
|
|
SELECT id, ts, provider, available, rtt, loss, status, transition
|
|
FROM events
|
|
'''
|
|
where, params = [], []
|
|
|
|
where.append("ts >= datetime('now', '-{} days')".format(days))
|
|
|
|
if provider:
|
|
where.append('provider = ?')
|
|
params.append(provider)
|
|
|
|
if only_transitions:
|
|
where.append('transition = 1')
|
|
|
|
if where:
|
|
query += ' WHERE ' + ' AND '.join(where)
|
|
|
|
query += ' ORDER BY id DESC LIMIT ?'
|
|
params.append(limit)
|
|
|
|
try:
|
|
with get_db() as conn:
|
|
rows = conn.execute(query, params).fetchall()
|
|
return jsonify([dict(r) for r in rows])
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
@app.route('/history/summary')
|
|
def history_summary():
|
|
"""
|
|
Return per-provider stats: total events, transitions, last seen, avg rtt.
|
|
|
|
Query params:
|
|
days : window in days (default 7)
|
|
"""
|
|
days = int(request.args.get('days', 7))
|
|
query = '''
|
|
SELECT
|
|
provider,
|
|
COUNT(*) AS total_events,
|
|
SUM(transition) AS total_transitions,
|
|
SUM(CASE WHEN available=1 THEN 1 ELSE 0 END) AS up_count,
|
|
SUM(CASE WHEN available=0 THEN 1 ELSE 0 END) AS down_count,
|
|
ROUND(AVG(rtt), 2) AS avg_rtt,
|
|
MAX(ts) AS last_seen
|
|
FROM events
|
|
WHERE ts >= datetime('now', '-{} days')
|
|
GROUP BY provider
|
|
ORDER BY provider
|
|
'''.format(days)
|
|
|
|
try:
|
|
with get_db() as conn:
|
|
rows = conn.execute(query).fetchall()
|
|
return jsonify([dict(r) for r in rows])
|
|
except Exception as e:
|
|
return jsonify({'error': str(e)}), 500
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Entry point
|
|
# ---------------------------------------------------------------------------
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=5050, debug=False)
|
|
|