fix(prometheus, syslog): a target or pattern pauses with a Pause/Resume button, not an "on" tick box in its form (#6419)
CI / lint (push) Successful in 2s
CI / unit (push) Failing after 1m42s
CI / integration (push) Successful in 1m45s
CI / publish (push) Skipped

Monitors, schedules and maintenance plans already pause with a
Pause/Resume button and say "Paused" where they're listed. Prometheus
targets and syslog patterns only had a tick box inside the edit form,
so a target refused by its endpoint couldn't be stopped from its page.

- Both get a Pause/Resume button (target page and list; patterns list)
  posting to /toggle, recorded in the audit log, and a Paused badge.
- The forms lose the tick box. A new one starts running; an edit keeps
  whether it is paused.
- A target's "off" state is now "paused", in its pages and MCP tools.
  A resumed target reads "not scraped yet" until its next scrape, and its
  counter rates start over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 17:48:31 -04:00
co-authored by Claude Opus 5.5
parent 0b787a0676
commit d20d78498e
15 changed files with 104 additions and 51 deletions
+3 -3
View File
@@ -19,7 +19,7 @@ from .models import PrometheusTarget
from .routes import group_series
from .service import OWN_METRICS, SOURCE, target_state
REACHES = ("down", "stale", "pending", "up", "off")
REACHES = ("down", "stale", "pending", "up", "paused")
_ORDER = {r: i for i, r in enumerate(REACHES)}
@@ -37,7 +37,7 @@ async def list_prometheus_targets() -> dict:
"""The /metrics endpoints Steward scrapes, not answering first.
`reach`: "down" (the last scrape failed; `says` is why), "stale" (not
scraped recently), "pending", "up" or "off". `series_kept` /
scraped recently), "pending", "up" or "paused". `series_kept` /
`series_dropped` count the newest scrape's series the keep/drop patterns
let through or left out; `series_capped` those past `series_cap`, which
were not stored. get_prometheus_target lists a target's series;
@@ -94,7 +94,7 @@ async def get_prometheus_target(target: str, search: str = "", limit: int = 100)
def target_findings(views: list[dict]) -> list[dict]:
"""A target whose last scrape failed. Stale and off are the plugin or
"""A target whose last scrape failed. Stale and paused are the plugin or
the admin's choice, not the endpoint, so they are left out."""
return [finding("warning", "prometheus_target_down", v["name"],
f"Prometheus target {v['name']} isn't answering: {v['says']}",