From 280d8f66bf811bf6ca05da4703c4fdadcd89504a Mon Sep 17 00:00:00 2001 From: Abhishek Desai Date: Wed, 10 Sep 2025 00:23:05 +0530 Subject: [PATCH] mgr/dashboard : Hide suppressed alert on landing page fixes : https://tracker.ceph.com/issues/72944 Signed-off-by: Abhishek Desai --- .../active-alert-list.component.html | 1 + .../active-alert-list.component.ts | 16 ++++++++++ .../silence-form.component.spec.ts | 4 +-- .../silence-form/silence-form.component.ts | 6 ++-- .../dashboard/dashboard-v3.component.html | 5 ++-- .../app/shared/models/prometheus-alerts.ts | 13 ++++++-- .../services/prometheus-alert.service.ts | 30 ++++++++++++------- 7 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html index b3ba03caed840..b20efd6509a5c 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/active-alert-list/active-alert-list.component.html @@ -11,6 +11,7 @@ { + if (value === 'Active') return row.status?.state === AlertState.ACTIVE; + else if (value === 'Suppressed') return row.status?.state === AlertState.SUPPRESSED; + if (value === 'All') return true; + return false; + } + } + ]; + constructor( // NotificationsComponent will refresh all alerts every 5s (No need to do it here as well) private authStorageService: AuthStorageService, diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.spec.ts index 1613c9650b877..acff1a473d28a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.spec.ts @@ -102,7 +102,7 @@ describe('SilenceFormComponent', () => { prometheus = new PrometheusHelper(); prometheusService = TestBed.inject(PrometheusService); - spyOn(prometheusService, 'getGroupedAlerts').and.callFake(() => { + spyOn(prometheusService, 'getAlerts').and.callFake(() => { const name = _.split(router.url, '/').pop(); return of([prometheus.createAlert(name)]); }); @@ -285,7 +285,7 @@ describe('SilenceFormComponent', () => { params = { id: 'alert0' }; expectMode('alertAdd', false, false, 'Create'); expect(prometheusService.getSilences).not.toHaveBeenCalled(); - expect(prometheusService.getGroupedAlerts).toHaveBeenCalled(); + expect(prometheusService.getAlerts).toHaveBeenCalled(); expect(component.matchers).toEqual([createMatcher('alertname', 'alert0', false)]); expect(component.matcherMatch).toEqual({ cssClass: 'has-success', diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.ts index a9002040f07db..958039a31dc71 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/prometheus/silence-form/silence-form.component.ts @@ -19,7 +19,7 @@ import { AlertmanagerSilenceMatcherMatch } from '~/app/shared/models/alertmanager-silence'; import { Permission } from '~/app/shared/models/permissions'; -import { GroupAlertmanagerAlert, PrometheusRule } from '~/app/shared/models/prometheus-alerts'; +import { AlertmanagerAlert, PrometheusRule } from '~/app/shared/models/prometheus-alerts'; import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; import { ModalService } from '~/app/shared/services/modal.service'; import { NotificationService } from '~/app/shared/services/notification.service'; @@ -225,7 +225,7 @@ export class SilenceFormComponent { } }); } else { - this.prometheusService.getGroupedAlerts().subscribe((alerts) => { + this.prometheusService.getAlerts().subscribe((alerts) => { const alert = _.find(alerts, ['fingerprint', params.id]); if (!_.isUndefined(alert)) { this.fillFormByAlert(alert); @@ -258,7 +258,7 @@ export class SilenceFormComponent { this.form.updateValueAndValidity(); } - private fillFormByAlert(alert: GroupAlertmanagerAlert) { + private fillFormByAlert(alert: AlertmanagerAlert) { const labels = alert.labels; this.setMatcher({ name: 'alertname', diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html index f3e583db274f6..b2b3d10f1603b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html @@ -288,8 +288,8 @@
+ (alert.labels.severity === alertType || + !alertType)">
@@ -309,6 +309,7 @@ [title]="alert.startsAt | cdDate" i18n>Active since: {{ alert.startsAt | relativeDate }} Total occurrences: {{ alert.alert_count }}

diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/prometheus-alerts.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/prometheus-alerts.ts index a7b24235aa788..a27f4c741781a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/prometheus-alerts.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/prometheus-alerts.ts @@ -1,3 +1,5 @@ +type AlertState = 'active' | 'suppressed' | 'resolved' | 'unprocessed'; + export class PrometheusAlertLabels { alertname: string; instance: string; @@ -48,7 +50,7 @@ export class PrometheusRule { export class AlertmanagerAlert extends CommonAlertmanagerAlert { status: { - state: 'unprocessed' | 'active' | 'suppressed'; + state: AlertState; silencedBy: null | string[]; inhibitedBy: null | string[]; }; @@ -84,10 +86,17 @@ export class AlertmanagerNotification { } export class PrometheusCustomAlert { - status: 'resolved' | 'unprocessed' | 'active' | 'suppressed'; + status: AlertState; name: string; url: string; description: string; fingerprint?: string | boolean; severity?: string; } + +export const AlertState = { + ACTIVE: 'active' as AlertState, + SUPPRESSED: 'suppressed' as AlertState, + RESOLVED: 'resolved' as AlertState, + UNPROCCESSED: 'unprocessed' as AlertState +}; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts index cba2aeedeb39c..048ecc572e91d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/prometheus-alert.service.ts @@ -7,7 +7,8 @@ import { AlertmanagerAlert, PrometheusCustomAlert, PrometheusRule, - GroupAlertmanagerAlert + GroupAlertmanagerAlert, + AlertState } from '../models/prometheus-alerts'; import { PrometheusAlertFormatter } from './prometheus-alert-formatter'; import { BehaviorSubject } from 'rxjs'; @@ -64,10 +65,15 @@ export class PrometheusAlertService { private handleAlerts(alertGroups: GroupAlertmanagerAlert[]) { const alerts: AlertmanagerAlert[] = alertGroups - .map((g) => { - if (!g.alerts.length) return null; - if (g.alerts.length === 1) return { ...g.alerts[0], alert_count: 1 }; - return { ...g.alerts[0], alert_count: g.alerts.length, subalerts: g.alerts }; + .map((group) => { + if (!group.alerts.length) return null; + if (group.alerts.length === 1) return { ...group.alerts[0], alert_count: 1 }; + const hasActive = group.alerts.some( + (alert: AlertmanagerAlert) => alert.status.state === AlertState.ACTIVE + ); + const parent = { ...group.alerts[0] }; + if (hasActive) parent.status.state = AlertState.ACTIVE; + return { ...parent, alert_count: group.alerts.length, subalerts: group.alerts }; }) .filter(Boolean) as AlertmanagerAlert[]; @@ -78,19 +84,23 @@ export class PrometheusAlertService { } this.activeAlerts = _.reduce( alerts, - (result, alert) => (alert.status.state === 'active' ? ++result : result), + (result, alert) => (alert.status.state === AlertState.ACTIVE ? ++result : result), 0 ); this.activeCriticalAlerts = _.reduce( alerts, (result, alert) => - alert.status.state === 'active' && alert.labels.severity === 'critical' ? ++result : result, + alert.status.state === AlertState.ACTIVE && alert.labels.severity === 'critical' + ? ++result + : result, 0 ); this.activeWarningAlerts = _.reduce( alerts, (result, alert) => - alert.status.state === 'active' && alert.labels.severity === 'warning' ? ++result : result, + alert.status.state === AlertState.ACTIVE && alert.labels.severity === 'warning' + ? ++result + : result, 0 ); this.alerts = alerts @@ -105,7 +115,7 @@ export class PrometheusAlertService { this.alertFormatter.convertToCustomAlerts(oldAlerts) ); const suppressedFiltered = _.filter(changedAlerts, (alert) => { - return alert.status !== 'suppressed'; + return alert.status !== AlertState.SUPPRESSED; }); const notifications = suppressedFiltered.map((alert) => this.alertFormatter.convertAlertToNotification(alert) @@ -121,7 +131,7 @@ export class PrometheusAlertService { private getVanishedAlerts(alerts: PrometheusCustomAlert[], oldAlerts: PrometheusCustomAlert[]) { return _.differenceWith(oldAlerts, alerts, (a, b) => a.fingerprint === b.fingerprint).map( (alert) => { - alert.status = 'resolved'; + alert.status = AlertState.RESOLVED; return alert; } ); -- 2.39.5