# plugins/snmp/scheduler.py from __future__ import annotations import asyncio import logging from typing import TYPE_CHECKING if TYPE_CHECKING: from quart import Quart from fabledscryer.core.scheduler import ScheduledTask logger = logging.getLogger(__name__) def make_poll_task(app: "Quart") -> ScheduledTask: interval = app.config["PLUGINS"]["snmp"].get("poll_interval_seconds", 60) async def poll() -> None: await _do_poll(app) return ScheduledTask( name="snmp_poll", coro_factory=poll, interval_seconds=int(interval), run_on_startup=True, ) async def _do_poll(app: "Quart") -> None: from datetime import datetime, timezone from .poller import poll_device_sync from fabledscryer.core.alerts import record_metric devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", []) if not devices: return loop = asyncio.get_event_loop() now = datetime.now(timezone.utc) async with app.db_sessionmaker() as session: async with session.begin(): for device in devices: if not isinstance(device, dict): continue name = device.get("name") or device.get("host", "unknown") host = device.get("host", "") port = int(device.get("port", 161)) community = device.get("community", "public") version = str(device.get("version", "2c")) oids = device.get("oids", []) if not host or not oids: continue try: readings = await loop.run_in_executor( None, poll_device_sync, host, port, community, version, oids, ) except Exception: logger.exception("SNMP poll failed for device %s (%s)", name, host) continue for label, value in readings.items(): await record_metric( session=session, source_module="snmp", resource_name=name, metric_name=label, value=value, ) if readings: logger.debug("SNMP polled %s (%s): %d OID(s)", name, host, len(readings)) else: logger.debug("SNMP polled %s (%s): no readings", name, host)