From 4838793677fa2f30a273800570a3117604c7a859 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 15 Oct 2025 22:25:04 +0000 Subject: [PATCH] feat: enhance alerts system with tests and improved thresholds - Add comprehensive test coverage for alerts package with 285+ new tests - Implement ThresholdsTable component with metric thresholds display - Enhance Alerts page UI with improved layout and metric filtering - Add frontend component tests for Alerts page and ThresholdsTable - Set up Vitest testing infrastructure for SolidJS components - Improve config persistence with better validation - Expand discovery tests with 333+ test cases - Update API, configuration, and Docker monitoring documentation --- docs/API.md | 1 + docs/CONFIGURATION.md | 5 + docs/DOCKER_MONITORING.md | 4 + frontend-modern/package-lock.json | Bin 159852 -> 236624 bytes frontend-modern/package.json | 7 +- .../src/components/Alerts/ThresholdsTable.tsx | 63 ++++ .../Alerts/__tests__/ThresholdsTable.test.tsx | 216 ++++++++++++ frontend-modern/src/pages/Alerts.tsx | 173 +++++---- .../pages/__tests__/Alerts.helpers.test.ts | 162 +++++++++ frontend-modern/src/test/setup.ts | 1 + frontend-modern/src/types/alerts.ts | 1 + internal/alerts/alerts.go | 96 ++++- internal/alerts/alerts_test.go | 285 +++++++++++++++ internal/config/persistence.go | 2 + internal/config/persistence_test.go | 89 +++++ pkg/discovery/discovery_test.go | 333 +++++++++++++++++- 16 files changed, 1353 insertions(+), 85 deletions(-) create mode 100644 frontend-modern/src/components/Alerts/__tests__/ThresholdsTable.test.tsx create mode 100644 frontend-modern/src/pages/__tests__/Alerts.helpers.test.ts create mode 100644 frontend-modern/src/test/setup.ts diff --git a/docs/API.md b/docs/API.md index b8645ea..ee902c5 100644 --- a/docs/API.md +++ b/docs/API.md @@ -657,6 +657,7 @@ Alert configuration responses model Pulse's hysteresis thresholds and advanced b - `guestDefaults`, `nodeDefaults`, `storageDefault`, `dockerDefaults`, `pmgThresholds` expose the baseline trigger/clear values applied globally. Each metric uses `{ "trigger": 90, "clear": 85 }`, so fractional thresholds (e.g. `12.5`) are supported. - `overrides` is keyed by resource ID for bespoke thresholds. Setting a threshold to `-1` disables that signal for that resource. - `timeThresholds` and `metricTimeThresholds` provide per-resource/per-metric grace periods, reducing alert noise on bursty workloads. +- `dockerIgnoredContainerPrefixes` suppresses alerts for ephemeral containers whose name or ID begins with a listed prefix. Matching is case-insensitive and controlled through the Alerts UI. - `aggregation`, `flapping`, `schedule` configure deduplication, cooldown, and quiet hours. These values are shared with the notification pipeline. - Active and historical alerts include `metadata.clearThreshold`, `resourceType`, and other context so UIs can render the trigger/clear pair and supply timeline explanations. diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 566cf69..af15401 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -200,6 +200,10 @@ PROXY_AUTH_LOGOUT_URL=/logout # URL for SSO logout "restartCount": 3, "restartWindow": 300 }, + "dockerIgnoredContainerPrefixes": [ + "runner-", + "ci-temp-" + ], "pmgThresholds": { "queueTotalWarning": 500, "oldestMessageWarnMins": 30 @@ -249,6 +253,7 @@ PROXY_AUTH_LOGOUT_URL=/logout # URL for SSO logout - Set a metric to `-1` to disable it globally or per-resource (the UI shows “Off” and adds a **Custom** badge). - `timeThresholds` apply a grace period before an alert fires; `metricTimeThresholds` allow per-metric overrides (e.g., delay network alerts longer than CPU). - `overrides` are indexed by the stable resource ID returned from `/api/state` (VMs: `instance/qemu/vmid`, containers: `instance/lxc/ctid`, nodes: `instance/node`). +- `dockerIgnoredContainerPrefixes` lets you silence state/metric/restart alerts for ephemeral containers whose names or IDs share a common, case-insensitive prefix. The Docker tab in the UI keeps this list in sync. - Quiet hours, escalation, deduplication, and restart loop detection are all managed here, and the UI keeps the JSON in sync automatically. > Tip: Back up `alerts.json` alongside `.env` during exports. Restoring it preserves all overrides, quiet-hour schedules, and webhook routing. diff --git a/docs/DOCKER_MONITORING.md b/docs/DOCKER_MONITORING.md index 00fccd2..18399ec 100644 --- a/docs/DOCKER_MONITORING.md +++ b/docs/DOCKER_MONITORING.md @@ -137,6 +137,10 @@ docker run -d \ The agent automatically discovers the Docker socket via the usual environment variables. To use SSH tunnels or TCP sockets, export `DOCKER_HOST` as you would for the Docker CLI. +### Suppressing ephemeral containers + +CI runners and short-lived build containers can generate noisy state alerts when they exit on schedule. In Pulse v4.24.0 and later you can provide a list of prefixes to ignore under **Alerts → Thresholds → Docker → Ignored container prefixes**. Any container whose name *or* ID begins with a configured prefix is skipped for state, health, metric, restart-loop, and OOM alerts. Matching is case-insensitive and the list is saved as `dockerIgnoredContainerPrefixes` inside `alerts.json`. Use one entry per family of ephemeral containers (for example, `runner-` or `gitlab-job-`). + ## Testing and troubleshooting - Run with `--interval 15s --insecure` in a terminal to see log output while testing. diff --git a/frontend-modern/package-lock.json b/frontend-modern/package-lock.json index 100f1d466be2033bbe11c54dfcc799cf5b28c3e3..2f62f0a843b368677a831169240e4b7cb1d73c3a 100644 GIT binary patch delta 30127 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 delta 522 zcmWN}-Ahw(7yw}2_w4M$+{~HH3Oj~g#FpuXO4lNiC0cYLzLc$;CW-z$V{K6w0Y&k*rFYnC&H2 z9+3{)Ec>jIJ67Wu7_F_h2V6t`K(M=~y(Q+b+D6@xa4_N@96o08wuu(^iS}myfkrv}d8wn0Wg}cEHH2YxJ5dJufc=~Vo-Sq~SwfzhFs7l`x522Uv-d$p`tlf( zKuyo!6*AX2lr!gZP|<}2c%h; [column.key, column.normalized]), ); +export const normalizeDockerIgnoredInput = (value: string): string[] => + value + .split('\n') + .map((entry) => entry.trim()) + .filter((entry) => entry.length > 0); + // Simple threshold object for the UI interface SimpleThresholds { cpu?: number; @@ -143,11 +149,14 @@ interface ThresholdsTableProps { setDockerDefaults: ( value: { cpu: number; memory: number; restartCount: number; restartWindow: number; memoryWarnPct: number; memoryCriticalPct: number } | ((prev: { cpu: number; memory: number; restartCount: number; restartWindow: number; memoryWarnPct: number; memoryCriticalPct: number }) => { cpu: number; memory: number; restartCount: number; restartWindow: number; memoryWarnPct: number; memoryCriticalPct: number }), ) => void; + dockerIgnoredPrefixes: () => string[]; + setDockerIgnoredPrefixes: (value: string[] | ((prev: string[]) => string[])) => void; storageDefault: () => number; setStorageDefault: (value: number) => void; resetGuestDefaults?: () => void; resetNodeDefaults?: () => void; resetDockerDefaults?: () => void; + resetDockerIgnoredPrefixes?: () => void; resetStorageDefault?: () => void; factoryGuestDefaults?: Record; factoryNodeDefaults?: Record; @@ -202,6 +211,13 @@ export function ThresholdsTable(props: ThresholdsTableProps) { >({}); const [activeTab, setActiveTab] = createSignal<'proxmox' | 'pmg' | 'docker'>('proxmox'); let searchInputRef: HTMLInputElement | undefined; + const [dockerIgnoredInput, setDockerIgnoredInput] = createSignal( + props.dockerIgnoredPrefixes().join('\n'), + ); + + createEffect(() => { + setDockerIgnoredInput(props.dockerIgnoredPrefixes().join('\n')); + }); // Determine active tab from URL const getActiveTabFromRoute = (): 'proxmox' | 'pmg' | 'docker' => { @@ -235,6 +251,23 @@ export function ThresholdsTable(props: ThresholdsTableProps) { navigate(tabRoutes[tab]); }; + const handleDockerIgnoredChange = (value: string) => { + setDockerIgnoredInput(value); + const normalized = normalizeDockerIgnoredInput(value); + props.setDockerIgnoredPrefixes(normalized); + props.setHasUnsavedChanges(true); + }; + + const handleResetDockerIgnored = () => { + if (props.resetDockerIgnoredPrefixes) { + props.resetDockerIgnoredPrefixes(); + } else { + props.setDockerIgnoredPrefixes([]); + } + setDockerIgnoredInput(''); + props.setHasUnsavedChanges(true); + }; + // Set up keyboard shortcuts onMount(() => { const isEditableElement = (el: HTMLElement | null | undefined): boolean => { @@ -1952,6 +1985,36 @@ const dockerContainersGroupedByHost = createMemo>((pr +
+
+
+

+ Ignored container prefixes +

+

+ Containers whose name or ID starts with any prefix below are skipped for Docker + alerts. Enter one prefix per line; matching is case-insensitive. +

+
+ 0}> + + +
+