diff --git a/fablednetmon/app.py b/fablednetmon/app.py index dc1acc4..fbbfe87 100644 --- a/fablednetmon/app.py +++ b/fablednetmon/app.py @@ -1,4 +1,5 @@ from __future__ import annotations +import asyncio from pathlib import Path from quart import Quart from .config import load_config @@ -33,16 +34,103 @@ def create_app( from unittest.mock import MagicMock app.db_sessionmaker = MagicMock() + # Alert pipeline + from .core.alerts import init_alerts + init_alerts(app) + # Register blueprints from .auth.routes import auth_bp - app.register_blueprint(auth_bp) - from .dashboard.routes import dashboard_bp + from .hosts.routes import hosts_bp + from .alerts.routes import alerts_bp + + app.register_blueprint(auth_bp) app.register_blueprint(dashboard_bp) + app.register_blueprint(hosts_bp) + app.register_blueprint(alerts_bp) + + # Build task registry + app._task_registry = [] + + if not testing: + _register_core_tasks(app, cfg) # Health check @app.get("/health") async def health(): return {"status": "ok"} + # Start scheduler on first request + @app.before_serving + async def startup(): + if not testing: + asyncio.create_task(_run_scheduler(app)) + return app + + +def _register_core_tasks(app: Quart, cfg: dict) -> None: + from .core.scheduler import ScheduledTask + + poll_interval = cfg.get("monitors", {}).get("poll_interval_seconds", 60) + cleanup_interval = 3600 # hourly + + async def run_ping_monitors(): + from sqlalchemy import select + from .models.hosts import Host + from .monitors.ping import ping_check + async with app.db_sessionmaker() as session: + async with session.begin(): + result = await session.execute( + select(Host).where(Host.ping_enabled.is_(True)) + ) + for host in result.scalars().all(): + try: + await ping_check(host, session) + except Exception: + app.logger.exception(f"Ping check failed for host {host.name!r}") + + async def run_dns_monitors(): + from sqlalchemy import select + from .models.hosts import Host + from .monitors.dns import dns_check + async with app.db_sessionmaker() as session: + async with session.begin(): + result = await session.execute( + select(Host).where(Host.dns_enabled.is_(True)) + ) + for host in result.scalars().all(): + try: + await dns_check(host, session) + except Exception: + app.logger.exception(f"DNS check failed for host {host.name!r}") + + async def run_cleanup(): + from .core.cleanup import run_cleanup as _cleanup + await _cleanup(app) + + app._task_registry.extend([ + ScheduledTask( + name="ping_monitor", + coro_factory=run_ping_monitors, + interval_seconds=poll_interval, + run_on_startup=True, + ), + ScheduledTask( + name="dns_monitor", + coro_factory=run_dns_monitors, + interval_seconds=poll_interval, + run_on_startup=True, + ), + ScheduledTask( + name="data_cleanup", + coro_factory=run_cleanup, + interval_seconds=cleanup_interval, + run_on_startup=False, + ), + ]) + + +async def _run_scheduler(app: Quart) -> None: + from .core.scheduler import start_scheduler + await start_scheduler(app._task_registry) diff --git a/fablednetmon/templates/base.html b/fablednetmon/templates/base.html index 876b107..f314ae7 100644 --- a/fablednetmon/templates/base.html +++ b/fablednetmon/templates/base.html @@ -34,6 +34,8 @@ {% endif %} diff --git a/fablednetmon/templates/dashboard/index.html b/fablednetmon/templates/dashboard/index.html index 94717a7..a60ce9a 100644 --- a/fablednetmon/templates/dashboard/index.html +++ b/fablednetmon/templates/dashboard/index.html @@ -4,16 +4,26 @@

Dashboard

-

Ping Monitor

-

No hosts configured yet.

+

Ping Monitor

+

+ Manage hosts to begin monitoring. +

-

DNS Monitor

-

No hosts configured yet.

+

DNS Monitor

+

+ Enable DNS monitoring on a host. +

-

Ansible

-

No playbook sources configured yet.

+

Alerts

+

+ Configure alert rules against any metric. +

+
+
+

Ansible

+

Coming in Plan 3.

{% endblock %}