Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
alerting
/
unified
/
hooks
/
File Content:
useExternalAmSelector.ts
import { DataSourceSettings } from '@grafana/data'; import { AlertManagerDataSourceJsonData, ExternalAlertmanagers } from 'app/plugins/datasource/alertmanager/types'; import { alertmanagerApi } from '../api/alertmanagerApi'; import { dataSourcesApi } from '../api/dataSourcesApi'; import { isAlertmanagerDataSource } from '../utils/datasource'; type ConnectionStatus = 'active' | 'pending' | 'dropped' | 'inconclusive' | 'uninterested' | 'unknown'; export interface ExternalAlertmanagerDataSourceWithStatus { dataSourceSettings: DataSourceSettings<AlertManagerDataSourceJsonData>; status: ConnectionStatus; } /** * Returns all configured Alertmanager data sources and their connection status with the internal ruler */ export function useExternalDataSourceAlertmanagers(): ExternalAlertmanagerDataSourceWithStatus[] { // firstly we'll fetch the settings for all datasources and filter for "alertmanager" type const { alertmanagerDataSources } = dataSourcesApi.endpoints.getAllDataSourceSettings.useQuery(undefined, { refetchOnReconnect: true, selectFromResult: (result) => { const alertmanagerDataSources = result.currentData?.filter(isAlertmanagerDataSource) ?? []; return { ...result, alertmanagerDataSources }; }, }); // we'll also fetch the configuration for which Alertmanagers we are forwarding Grafana-managed alerts too // @TODO use polling when we have one or more alertmanagers in pending state const { currentData: externalAlertmanagers } = alertmanagerApi.endpoints.getExternalAlertmanagers.useQuery( undefined, { refetchOnReconnect: true } ); if (!alertmanagerDataSources) { return []; } return alertmanagerDataSources.map<ExternalAlertmanagerDataSourceWithStatus>((dataSourceSettings) => { const status = externalAlertmanagers ? determineAlertmanagerConnectionStatus(externalAlertmanagers, dataSourceSettings) : 'unknown'; return { dataSourceSettings, status, }; }); } // using the information from /api/v1/ngalert/alertmanagers we should derive the connection status of a single data source function determineAlertmanagerConnectionStatus( externalAlertmanagers: ExternalAlertmanagers, dataSourceSettings: DataSourceSettings<AlertManagerDataSourceJsonData> ): ConnectionStatus { const isInterestedInAlerts = dataSourceSettings.jsonData.handleGrafanaManagedAlerts; if (!isInterestedInAlerts) { return 'uninterested'; } const isActive = externalAlertmanagers?.activeAlertManagers.some((am) => { return isAlertmanagerMatchByURL(dataSourceSettings.url, am.url); }) ?? []; const isDropped = externalAlertmanagers?.droppedAlertManagers.some((am) => { return isAlertmanagerMatchByURL(dataSourceSettings.url, am.url); }) ?? []; // the Alertmanager is being adopted (pending) if it is interested in handling alerts but not in either "active" or "dropped" const isPending = !isActive && !isDropped; if (isPending) { return 'pending'; } // Multiple Alertmanagers of the same URL may exist (e.g. with different credentials) // Alertmanager response only contains URLs, so when the URL exists in both active and dropped, we are not able // to distinguish which is which, resulting in an inconclusive status. const isInconclusive = isActive && isDropped; if (isInconclusive) { return 'inconclusive'; } // if we get here, it's neither "uninterested", nor "inconclusive" nor "pending" if (isActive) { return 'active'; } else if (isDropped) { return 'dropped'; } return 'unknown'; } // the vanilla Alertmanager and Mimir Alertmanager mount their API endpoints on different sub-paths // Cortex also uses the same paths as Mimir const MIMIR_ALERTMANAGER_PATH = '/alertmanager/api/v2/alerts'; const VANILLA_ALERTMANAGER_PATH = '/api/v2/alerts'; // when using the Mimir Alertmanager, those paths are mounted under "/alertmanager" function isAlertmanagerMatchByURL(dataSourceUrl: string, alertmanagerUrl: string) { const normalizedUrl = normalizeDataSourceURL(dataSourceUrl); const prometheusAlertmanagerMatch = alertmanagerUrl === `${normalizedUrl}${VANILLA_ALERTMANAGER_PATH}`; const mimirAlertmanagerMatch = alertmanagerUrl === `${normalizedUrl}${MIMIR_ALERTMANAGER_PATH}`; return prometheusAlertmanagerMatch || mimirAlertmanagerMatch; } // Grafana prepends the http protocol if there isn't one, but it doesn't store that in the datasource settings function normalizeDataSourceURL(url: string) { const hasProtocol = new RegExp('^[^:]*://').test(url); return hasProtocol ? url : `http://${url}`; }
Edit
Rename
Chmod
Delete
FILE
FOLDER
INFO
Name
Size
Permission
Action
__snapshots__
---
0755
alert-details
---
0755
useAbilities.test.tsx
6404 bytes
0644
useAbilities.ts
13933 bytes
0644
useAlertManagerSources.ts
293 bytes
0644
useAlertQueriesStatus.ts
681 bytes
0644
useAlertmanagerConfig.ts
732 bytes
0644
useCombinedRule.ts
10042 bytes
0644
useCombinedRuleNamespaces.test.ts
1785 bytes
0644
useCombinedRuleNamespaces.ts
15283 bytes
0644
useControlledFieldArray.ts
1841 bytes
0644
useExternalAMSelector.test.tsx
6805 bytes
0644
useExternalAmSelector.ts
4616 bytes
0644
useFilteredAmGroups.ts
1291 bytes
0644
useFilteredRules.test.ts
8782 bytes
0644
useFilteredRules.ts
12938 bytes
0644
useFolder.ts
847 bytes
0644
useGroupedAlerts.ts
3338 bytes
0644
useHasRuler.ts
1062 bytes
0644
useIsRuleEditable.test.tsx
5996 bytes
0644
useIsRuleEditable.ts
2778 bytes
0644
useManagedAlertStateHistory.ts
692 bytes
0644
useMuteTimingOptions.ts
897 bytes
0644
usePagination.test.tsx
2055 bytes
0644
usePagination.ts
1058 bytes
0644
usePanelCombinedRules.ts
2733 bytes
0644
usePluginBridge.ts
847 bytes
0644
useReturnTo.test.tsx
1946 bytes
0644
useReturnTo.ts
1546 bytes
0644
useRuleSourcesWithRuler.ts
812 bytes
0644
useSilenceNavData.test.tsx
1249 bytes
0644
useSilenceNavData.ts
797 bytes
0644
useStateHistoryModal.tsx
2855 bytes
0644
useURLSearchParams.ts
628 bytes
0644
useUnifiedAlertingSelector.ts
531 bytes
0644
useVizHeight.ts
877 bytes
0644
N4ST4R_ID | Naxtarrr