73 lines
2.3 KiB
Python
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)
|