diff --git a/web/src/api/alert.ts b/web/src/api/alert.ts index 064341061..d0176fd42 100644 --- a/web/src/api/alert.ts +++ b/web/src/api/alert.ts @@ -16,3 +16,18 @@ export interface AlertsGroups { limit?: number; rules: Rule[]; } + +export interface SilencedAlert { + id: string; + status: SilencedAlertStatus; + matchers: SilenceMatcher[]; +} + +export interface SilencedAlertStatus { + state: string; +} + +export interface SilenceMatcher { + name: string; + value: string; +} diff --git a/web/src/api/routes.ts b/web/src/api/routes.ts index a2efc4c28..cf42436f4 100644 --- a/web/src/api/routes.ts +++ b/web/src/api/routes.ts @@ -13,7 +13,7 @@ import { Config, defaultConfig } from '../model/config'; import { TimeRange } from '../utils/datetime'; import { ContextSingleton } from '../utils/context'; import { parseMetrics } from '../utils/metrics'; -import { AlertsResult } from './alert'; +import { AlertsResult, SilencedAlert } from './alert'; export const getFlows = (params: FlowQuery): Promise => { return axios.get(ContextSingleton.getHost() + '/api/loki/flows', { params }).then(r => { @@ -37,6 +37,15 @@ export const getAlerts = (): Promise => { }); }; +export const getSilencedAlerts = (): Promise => { + return axios.get('/api/alertmanager/api/v2/silences').then(r => { + if (r.status >= 400) { + throw new Error(`${r.statusText} [code=${r.status}]`); + } + return r.data; + }); +}; + export const getExportFlowsURL = (params: FlowQuery, columns?: string[]): string => { const exportQuery = buildExportQuery(params, columns); return `${ContextSingleton.getHost()}/api/loki/export?${exportQuery}`; diff --git a/web/src/components/__tests__/netflow-traffic.spec.tsx b/web/src/components/__tests__/netflow-traffic.spec.tsx index 7a2257e02..8e7b6f601 100644 --- a/web/src/components/__tests__/netflow-traffic.spec.tsx +++ b/web/src/components/__tests__/netflow-traffic.spec.tsx @@ -9,7 +9,7 @@ import { extensionsMock } from '../__tests-data__/extensions'; import { FlowsResultSample } from '../__tests-data__/flows'; import NetflowTrafficParent from '../netflow-traffic-parent'; import { TopologyResult } from '../../api/loki'; -import { AlertsResult } from '../../api/alert'; +import { AlertsResult, SilencedAlert } from '../../api/alert'; import { ConfigResultSample } from '../__tests-data__/config'; const useResolvedExtensionsMock = useResolvedExtensions as jest.Mock; @@ -20,7 +20,8 @@ jest.mock('../../api/routes', () => ({ getTopology: jest.fn(() => Promise.resolve({ metrics: [], stats: { numQueries: 0, limitReached: false } } as TopologyResult) ), - getAlerts: jest.fn(() => Promise.resolve({ data: { groups: [] }, status: 'success' } as AlertsResult)) + getAlerts: jest.fn(() => Promise.resolve({ data: { groups: [] }, status: 'success' } as AlertsResult)), + getSilencedAlerts: jest.fn(() => Promise.resolve([] as SilencedAlert[])) })); const getConfigMock = getConfig as jest.Mock; const getFlowsMock = getFlows as jest.Mock; diff --git a/web/src/components/alerts/fetcher.tsx b/web/src/components/alerts/fetcher.tsx index d5211ee3d..7c3b8eec3 100644 --- a/web/src/components/alerts/fetcher.tsx +++ b/web/src/components/alerts/fetcher.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import AlertBanner from './banner'; -import { getAlerts } from '../../api/routes'; +import { getAlerts, getSilencedAlerts } from '../../api/routes'; import { Rule } from '@openshift-console/dynamic-plugin-sdk'; import { murmur3 } from 'murmurhash-js'; @@ -9,6 +9,7 @@ type AlertFetcherProps = {}; export const AlertFetcher: React.FC = ({ children }) => { const [alerts, setAlerts] = React.useState([]); + const [silencedAlerts, setSilencedAlerts] = React.useState(null); React.useEffect(() => { getAlerts() .then(result => { @@ -38,10 +39,35 @@ export const AlertFetcher: React.FC = ({ children }) => { }); return; }, []); + + React.useEffect(() => { + getSilencedAlerts() + .then(result => { + setSilencedAlerts( + result + .filter(rule => rule.status.state == 'active') + .map(rule => { + const matcher = rule.matchers.find(m => m.name == 'alertname'); + return typeof matcher !== 'undefined' ? matcher.value : ''; + }) + ); + }) + .catch(() => { + console.log('Could not get silenced alerts'); + // Showing all alerts since we could not get silenced alerts list + setSilencedAlerts([]); + }); + return; + }, []); + + let firingAlerts: Rule[] = []; + if (silencedAlerts != null) { + firingAlerts = alerts.filter(rule => !silencedAlerts.includes(rule.name)); + } return ( <>
- {alerts.map(a => ( + {firingAlerts.map(a => ( setAlerts(alerts.filter(alert => alert.name != a.name))} /> ))}