Includes atomic migrations, per-rule reminder semantics, first-run helper script and the note on the undecided UI chat idea. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
83 lines
4.1 KiB
Python
83 lines
4.1 KiB
Python
import re
|
|
|
|
from ..constants import (ALERTS_AI_PER_MINUTE, ALERTS_BUNDLE_SECONDS, ALERTS_DEFAULT_DELAY_MINUTES,
|
|
ALERTS_HOST_DELAY_MINUTES, ALERTS_RECOVERY_ENABLED, ALERTS_REMINDER_HOURS,
|
|
ALERTS_SEND_LIMIT, DEFAULT_AI_PER_MINUTE, DEFAULT_BUNDLE_SECONDS,
|
|
DEFAULT_DELAY_MINUTES, DEFAULT_HOST_DELAY_MINUTES, DEFAULT_POLL_INTERVAL,
|
|
DEFAULT_REMINDER_HOURS, DEFAULT_SEND_LIMIT, MAX_DELAY_MINUTES, MAX_REMINDER_HOURS,
|
|
MAX_SEND_LIMIT, MIN_POLL_INTERVAL, MIN_SEND_LIMIT, POLL_INTERVAL, UI_BASE_URL)
|
|
from .sections import Action, Field, Section
|
|
|
|
SLUG = "alerting"
|
|
BASELINE_PATH = f"/settings/{SLUG}/baseline"
|
|
BASE_URL_MAX = 200
|
|
BASE_URL_RE = re.compile(r"^https?://[^\s/?#]+(/[^\s?#]*)?$")
|
|
|
|
MAX_POLL_INTERVAL = 3600
|
|
MAX_BUNDLE_SECONDS = 3600
|
|
MAX_AI_PER_MINUTE = 600
|
|
|
|
LIMITS = (
|
|
(POLL_INTERVAL, "Abfrageintervall", MIN_POLL_INTERVAL, MAX_POLL_INTERVAL),
|
|
(ALERTS_DEFAULT_DELAY_MINUTES, "Standard-Verzögerung", 0, MAX_DELAY_MINUTES),
|
|
(ALERTS_REMINDER_HOURS, "Erinnerung", 0, MAX_REMINDER_HOURS),
|
|
(ALERTS_BUNDLE_SECONDS, "Bündelungsfenster", 0, MAX_BUNDLE_SECONDS),
|
|
(ALERTS_AI_PER_MINUTE, "KI-Analysen pro Minute", 0, MAX_AI_PER_MINUTE),
|
|
(ALERTS_HOST_DELAY_MINUTES, "Host-Verzögerung", 0, MAX_DELAY_MINUTES),
|
|
(ALERTS_SEND_LIMIT, "Sendelimit", MIN_SEND_LIMIT, MAX_SEND_LIMIT),
|
|
)
|
|
|
|
|
|
def strip_trailing_slash(value: str) -> str:
|
|
return value.rstrip("/")
|
|
|
|
|
|
def validate(values: dict) -> list[str]:
|
|
errors = []
|
|
for key, label, low, high in LIMITS:
|
|
raw = values.get(key, "").strip()
|
|
if not raw:
|
|
continue
|
|
if not raw.isdecimal() or not low <= int(raw) <= high:
|
|
errors.append(f"{label} muss eine ganze Zahl zwischen {low} und {high} sein.")
|
|
base_url = values.get(UI_BASE_URL, "").strip()
|
|
if base_url and (len(base_url) > BASE_URL_MAX or not BASE_URL_RE.match(base_url.rstrip("/"))):
|
|
errors.append("Basis-URL der Oberfläche muss mit http:// oder https:// beginnen und darf keine "
|
|
"Leerzeichen, Parameter oder Anker enthalten.")
|
|
return errors
|
|
|
|
|
|
SECTION = Section(
|
|
slug=SLUG,
|
|
title="Alarmierung",
|
|
fields=(
|
|
Field(POLL_INTERVAL, "Abfrageintervall in Sekunden", default=str(DEFAULT_POLL_INTERVAL)),
|
|
Field(ALERTS_DEFAULT_DELAY_MINUTES,
|
|
"Standard-Verzögerung in Minuten (Problem wird erst nach dieser Zeit gemeldet, 0 = sofort; "
|
|
"Regeln können das überschreiben)", default=str(DEFAULT_DELAY_MINUTES)),
|
|
Field(ALERTS_RECOVERY_ENABLED, "Recovery-Meldungen senden (wieder OK)", kind="checkbox"),
|
|
Field(ALERTS_REMINDER_HOURS,
|
|
"Standard-Erinnerung für offene CRIT-Probleme in Stunden (0 = aus; Regeln überschreiben)",
|
|
default=str(DEFAULT_REMINDER_HOURS)),
|
|
Field(ALERTS_BUNDLE_SECONDS, "Bündelungsfenster pro Host in Sekunden",
|
|
default=str(DEFAULT_BUNDLE_SECONDS)),
|
|
Field(ALERTS_AI_PER_MINUTE, "Max. KI-Analysen pro Minute (0 = keine)",
|
|
default=str(DEFAULT_AI_PER_MINUTE)),
|
|
Field(ALERTS_HOST_DELAY_MINUTES,
|
|
"Host-Verzögerung in Minuten (Host DOWN/UNREACH wird erst nach dieser Zeit gemeldet, 0 = sofort)",
|
|
default=str(DEFAULT_HOST_DELAY_MINUTES),
|
|
hint="Regel-Verzögerungen gelten nicht für Host-Alarme. Solange ein Host nicht UP ist, werden "
|
|
"Service-Alarme dieses Hosts unterdrückt."),
|
|
Field(ALERTS_SEND_LIMIT, "Sendelimit: Nachrichten pro Minute und Ziel (1 bis 60)",
|
|
default=str(DEFAULT_SEND_LIMIT),
|
|
hint="Überschuss wird nicht einzeln gesendet, sondern als eine Sammelmeldung pro Minute und Ziel; "
|
|
"alle Alarme bleiben im Verlauf."),
|
|
Field(UI_BASE_URL, "Basis-URL dieser Oberfläche (optional)", placeholder="https://checkbot.example.de",
|
|
transform=strip_trailing_slash,
|
|
hint="Wenn gesetzt, enthält jede Alarmnachricht einen Link \"Details\" auf den Verlauf."),
|
|
),
|
|
validate=validate,
|
|
optional=True,
|
|
actions=(Action("Baseline neu setzen", BASELINE_PATH),),
|
|
)
|