Files
ntp/reporter/main.py
2025-10-22 16:37:20 -04:00

73 lines
2.3 KiB
Python

import os
import subprocess
import csv
import io
from flask import Flask, jsonify
app = Flask(__name__)
# Config
NODE_ID = os.environ.get("NODE_ID", "unknown-node")
PUBLIC_IP = os.environ.get("PUBLIC_IP", "unknown-ip")
BIND_IP = os.environ.get("BIND_IP", "127.0.0.1")
CHRONY_HOST = "127.0.0.1"
def run_chronyc(command):
try:
result = subprocess.run(
["chronyc", "-h", CHRONY_HOST, "-c"] + command,
capture_output=True, text=True, timeout=2, check=True
)
return result.stdout.strip()
except Exception as e:
print(f"Error running 'chronyc {command}': {e}")
return None
def parse_tracking():
raw_csv = run_chronyc(["tracking"])
if not raw_csv: return {"Error": "Could not run tracking command"}
try:
reader = csv.reader(io.StringIO(raw_csv))
headers = [
"Reference ID", "Ref Source IP", "Stratum", "Ref time (UTC)", "System time",
"Last offset", "RMS offset", "Frequency", "Residual freq",
"Skew", "Root delay", "Root dispersion", "Update interval", "Leap status"
]
values = next(reader)
return dict(zip(headers, values))
except Exception as e:
return {"Error": f"Failed to parse tracking CSV: {e}", "RawData": raw_csv}
def parse_sources():
raw_csv = run_chronyc(["sources"])
if not raw_csv: return []
try:
reader = csv.reader(io.StringIO(raw_csv))
# --- FIX: Add 10th header 'Std Dev' ---
headers = [
"Mode", "State", "Name/IP address", "Stratum", "Poll", "Reach",
"LastRx", "Last sample", "Last sample original", "Std Dev" # Was: Last sample error
]
sources_list = []
for row in reader:
if row: sources_list.append(dict(zip(headers, row)))
return sources_list
except Exception as e:
print(f"Error parsing sources: {e}")
return []
@app.route('/fragment.json')
def get_fragment():
tracking_data = parse_tracking()
sources_data = parse_sources()
return jsonify({
"node_id": NODE_ID,
"public_ip": PUBLIC_IP,
"report_generated_time": subprocess.run(["date", "-u", "+%Y-%m-%dT%H:%M:%SZ"], capture_output=True, text=True).stdout.strip(),
"tracking": tracking_data,
"sources": sources_data
})
if __name__ == '__main__':
app.run(host=BIND_IP, port=9898)