Add local SQLite database and sync with Uptime Kuma
All checks were successful
Build and Push Container / build (push) Successful in 1m4s
All checks were successful
Build and Push Container / build (push) Successful in 1m4s
Features: - SQLite database to track monitors and hosts locally - Uses Uptime Kuma tags to mark monitors as managed by Kuma Strapper - Sync on startup, before each scan, and on-demand via API - Shows existing monitors when re-scanning a host New files: - backend/services/database.py - SQLite database service - backend/services/sync.py - Sync service for Uptime Kuma reconciliation API endpoints: - POST /api/sync - Full sync with Uptime Kuma - POST /api/sync/host/<hostname> - Sync specific host - GET /api/hosts - List tracked hosts - GET /api/hosts/<hostname>/monitors - Get monitors for host - GET /api/monitors/tracked - Get all tracked monitors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
104
backend/app.py
104
backend/app.py
@@ -17,6 +17,8 @@ from services.monitors import (
|
||||
parse_docker_containers_from_scan,
|
||||
)
|
||||
from services.kuma_client import get_kuma_client
|
||||
from services.database import get_database
|
||||
from services.sync import get_sync_service
|
||||
from utils.approval import get_approval_queue, ApprovalStatus
|
||||
|
||||
|
||||
@@ -90,6 +92,20 @@ def start_scan():
|
||||
|
||||
# Start scan in background thread
|
||||
def run_scan():
|
||||
# Sync this host's monitors before scanning
|
||||
try:
|
||||
sync = get_sync_service()
|
||||
sync_result = sync.sync_host(hostname)
|
||||
db = get_database()
|
||||
existing_monitors = db.get_monitors_for_hostname(hostname)
|
||||
socketio.emit("host_sync_complete", {
|
||||
"hostname": hostname,
|
||||
"sync_result": sync_result,
|
||||
"existing_monitors": [m.to_dict() for m in existing_monitors],
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"Pre-scan sync failed (non-fatal): {e}")
|
||||
|
||||
discovery = get_discovery_service()
|
||||
|
||||
def on_progress(cmd_name, status):
|
||||
@@ -576,6 +592,72 @@ def test_kuma_connection():
|
||||
return jsonify({"connected": False, "error": str(e)})
|
||||
|
||||
|
||||
# Sync endpoints
|
||||
@app.route("/api/sync", methods=["POST"])
|
||||
def trigger_sync():
|
||||
"""Trigger a full sync with Uptime Kuma."""
|
||||
try:
|
||||
sync = get_sync_service()
|
||||
result = sync.full_sync()
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/sync/host/<hostname>", methods=["POST"])
|
||||
def sync_host(hostname):
|
||||
"""Sync monitors for a specific host."""
|
||||
try:
|
||||
sync = get_sync_service()
|
||||
result = sync.sync_host(hostname)
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/hosts", methods=["GET"])
|
||||
def get_hosts():
|
||||
"""Get all tracked hosts."""
|
||||
try:
|
||||
db = get_database()
|
||||
hosts = db.get_all_hosts()
|
||||
return jsonify({
|
||||
"hosts": [h.to_dict() for h in hosts],
|
||||
"count": len(hosts)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/hosts/<hostname>/monitors", methods=["GET"])
|
||||
def get_host_monitors(hostname):
|
||||
"""Get all tracked monitors for a host."""
|
||||
try:
|
||||
db = get_database()
|
||||
monitors = db.get_monitors_for_hostname(hostname)
|
||||
return jsonify({
|
||||
"hostname": hostname,
|
||||
"monitors": [m.to_dict() for m in monitors],
|
||||
"count": len(monitors)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/monitors/tracked", methods=["GET"])
|
||||
def get_tracked_monitors():
|
||||
"""Get all tracked monitors across all hosts."""
|
||||
try:
|
||||
db = get_database()
|
||||
monitors = db.get_all_monitors()
|
||||
return jsonify({
|
||||
"monitors": [m.to_dict() for m in monitors],
|
||||
"count": len(monitors)
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
# WebSocket events
|
||||
@socketio.on("connect")
|
||||
def handle_connect():
|
||||
@@ -587,6 +669,19 @@ def handle_disconnect():
|
||||
pass
|
||||
|
||||
|
||||
def startup_sync():
|
||||
"""Run initial sync with Uptime Kuma on startup."""
|
||||
try:
|
||||
print("Running startup sync with Uptime Kuma...")
|
||||
sync = get_sync_service()
|
||||
result = sync.full_sync()
|
||||
print(f"Startup sync complete: added={result['added']}, updated={result['updated']}, removed={result['removed']}")
|
||||
if result['errors']:
|
||||
print(f"Sync errors: {result['errors']}")
|
||||
except Exception as e:
|
||||
print(f"Startup sync failed (non-fatal): {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Validate config on startup
|
||||
config = get_config()
|
||||
@@ -600,4 +695,13 @@ if __name__ == "__main__":
|
||||
print("Configuration OK")
|
||||
print(f"Dev mode: {'enabled' if config.dev_mode else 'disabled'}")
|
||||
|
||||
# Run startup sync in background after short delay
|
||||
def delayed_sync():
|
||||
import time
|
||||
time.sleep(2) # Wait for app to fully start
|
||||
startup_sync()
|
||||
|
||||
sync_thread = threading.Thread(target=delayed_sync, daemon=True)
|
||||
sync_thread.start()
|
||||
|
||||
socketio.run(app, host="0.0.0.0", port=5000, debug=os.environ.get("DEBUG", "false").lower() == "true")
|
||||
|
||||
Reference in New Issue
Block a user