fix: error-pages graded healthy, unwired sensors listed apart, Maintenance failed reads 0 (#5780, #5781, #5782)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m23s
CI / unit (push) Successful in 1m29s
CI / publish (push) Successful in 18s

- #5780 "The error-pages service is graded on other routers' errors". The
  Traefik scrape reads which services an errors middleware sends to, and
  grades them healthy: their 4xx and 5xx are the codes of the errors they
  cover for, already graded on the routers that failed.
- #5781 "The Maintenance failed rules sit at no data until a host has had
  a maintenance job". Every host with an agent reads 0 until a job fails.
- #5782 "VDNT-Util01's host page lists SYSTIN at 115 °C in red". The host
  page lists sensors that counts_as_hottest leaves out (unwired board
  inputs, 0 °C or below) on one muted line, not as heat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 21:15:44 -04:00
co-authored by Claude Opus 5.5
parent 0f604ecb4a
commit 72e754b580
9 changed files with 120 additions and 13 deletions
+16 -1
View File
@@ -26,6 +26,16 @@ def router_domains() -> dict[str, list[str]] | None:
return _router_domains
# The services Traefik's errors middlewares send error pages to (#5780), as
# last read from its API. Kept through an API blip: that config rarely moves,
# and dropping it would grade the error pages as failing for that while.
_error_page_services: frozenset[str] = frozenset()
def error_page_services() -> frozenset[str]:
return _error_page_services
# Access log state
_geoip_db = None
_access_log_last_tick: "datetime | None" = None
@@ -48,7 +58,7 @@ def make_scrape_task(app: "Quart") -> ScheduledTask:
async def _do_scrape(app: "Quart") -> None:
"""Fetch Traefik metrics, write to DB, and emit plugin_metrics."""
global _prev_metrics, _prev_time, _router_domains
global _prev_metrics, _prev_time, _router_domains, _error_page_services
from datetime import datetime, timezone
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric, TraefikStatusCode
@@ -59,6 +69,7 @@ async def _do_scrape(app: "Quart") -> None:
compute_status_codes,
extract_certs,
fetch_metrics,
fetch_error_page_services,
fetch_router_domains,
)
from steward.core.alerts import MetricBatch
@@ -77,6 +88,10 @@ async def _do_scrape(app: "Quart") -> None:
if _router_domains is not None:
logger.warning("Traefik API stopped answering (%s); certificates shown without routers", exc)
_router_domains = None
try:
_error_page_services = await fetch_error_page_services(api_base(metrics_url, cfg.get("api_url") or ""))
except Exception as exc:
logger.debug("Traefik middlewares not read (%s); keeping the last error-page services", exc)
now = time.monotonic()
elapsed = now - _prev_time if _prev_time else 60.0