The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/alerting/unified/utils/datasource.ts

265 lines
9.4 KiB

import { DataSourceInstanceSettings, DataSourceJsonData, DataSourceSettings } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import {
AlertManagerDataSourceJsonData,
AlertManagerImplementation,
AlertmanagerChoice,
} from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import { RulesSource } from 'app/types/unified-alerting';
import { alertmanagerApi } from '../api/alertmanagerApi';
import { useAlertManagersByPermission } from '../hooks/useAlertManagerSources';
import { isAlertManagerWithConfigAPI } from '../state/AlertmanagerContext';
import { instancesPermissions, notificationsPermissions } from './access-control';
import { getAllDataSources } from './config';
export const GRAFANA_RULES_SOURCE_NAME = 'grafana';
export const GRAFANA_DATASOURCE_NAME = '-- Grafana --';
export enum DataSourceType {
Alertmanager = 'alertmanager',
Loki = 'loki',
Prometheus = 'prometheus',
}
export interface AlertManagerDataSource {
name: string;
imgUrl: string;
meta?: DataSourceInstanceSettings['meta'];
hasConfigurationAPI?: boolean;
handleGrafanaManagedAlerts?: boolean;
}
export const RulesDataSourceTypes: string[] = [DataSourceType.Loki, DataSourceType.Prometheus];
export function getRulesDataSources() {
if (!contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalRead)) {
return [];
}
return getAllDataSources()
.filter((ds) => RulesDataSourceTypes.includes(ds.type) && ds.jsonData.manageAlerts !== false)
.sort((a, b) => a.name.localeCompare(b.name));
}
export function getRulesDataSource(rulesSourceName: string) {
return getRulesDataSources().find((x) => x.name === rulesSourceName);
}
export function getAlertManagerDataSources() {
return getAllDataSources()
.filter(isAlertmanagerDataSourceInstance)
.sort((a, b) => a.name.localeCompare(b.name));
}
export function isAlertmanagerDataSourceInstance(
dataSource: DataSourceInstanceSettings
): dataSource is DataSourceInstanceSettings<AlertManagerDataSourceJsonData> {
return dataSource.type === DataSourceType.Alertmanager;
}
export function isAlertmanagerDataSource(
dataSource: DataSourceSettings
): dataSource is DataSourceSettings<AlertManagerDataSourceJsonData> {
return dataSource.type === DataSourceType.Alertmanager;
}
export function getExternalDsAlertManagers() {
return getAlertManagerDataSources().filter((ds) => ds.jsonData.handleGrafanaManagedAlerts);
}
const grafanaAlertManagerDataSource: AlertManagerDataSource = {
name: GRAFANA_RULES_SOURCE_NAME,
imgUrl: 'public/img/grafana_icon.svg',
hasConfigurationAPI: true,
};
// Used only as a fallback for Alert Group plugin
export function getAllAlertManagerDataSources(): AlertManagerDataSource[] {
return [
grafanaAlertManagerDataSource,
...getAlertManagerDataSources().map<AlertManagerDataSource>((ds) => ({
name: ds.name,
displayName: ds.name,
imgUrl: ds.meta.info.logos.small,
meta: ds.meta,
})),
];
}
/**
* This method gets all alert managers that the user has access, and then filter them first by being able to handle grafana managed alerts,
* and then depending on the current alerting configuration returns either only the internal alert managers, only the external alert managers, or both.
*
*/
export function useGetAlertManagerDataSourcesByPermissionAndConfig(
permission: 'instance' | 'notification'
): AlertManagerDataSource[] {
const allAlertManagersByPermission = useAlertManagersByPermission(permission); // this hook memoizes the result of getAlertManagerDataSourcesByPermission
const externalDsAlertManagers: AlertManagerDataSource[] =
allAlertManagersByPermission.availableExternalDataSources.filter((ds) => ds.handleGrafanaManagedAlerts);
const internalDSAlertManagers = allAlertManagersByPermission.availableInternalDataSources;
//get current alerting configuration
const { currentData: amConfigStatus } = alertmanagerApi.useGetAlertmanagerChoiceStatusQuery(undefined);
const alertmanagerChoice = amConfigStatus?.alertmanagersChoice;
switch (alertmanagerChoice) {
case AlertmanagerChoice.Internal:
return internalDSAlertManagers;
case AlertmanagerChoice.External:
return externalDsAlertManagers;
default:
return [...internalDSAlertManagers, ...externalDsAlertManagers];
}
}
/**
* This method gets all alert managers that the user has access to and then split them into two groups:
* 1. Internal alert managers
* 2. External alert managers
*/
export function getAlertManagerDataSourcesByPermission(permission: 'instance' | 'notification'): {
availableInternalDataSources: AlertManagerDataSource[];
availableExternalDataSources: AlertManagerDataSource[];
} {
const availableInternalDataSources: AlertManagerDataSource[] = [];
const availableExternalDataSources: AlertManagerDataSource[] = [];
const permissions = {
instance: instancesPermissions.read,
notification: notificationsPermissions.read,
};
if (contextSrv.hasPermission(permissions[permission].grafana)) {
availableInternalDataSources.push(grafanaAlertManagerDataSource);
}
if (contextSrv.hasPermission(permissions[permission].external)) {
const cloudSources = getAlertManagerDataSources().map<AlertManagerDataSource>((ds) => ({
name: ds.name,
displayName: ds.name,
imgUrl: ds.meta.info.logos.small,
meta: ds.meta,
hasConfigurationAPI: isAlertManagerWithConfigAPI(ds.jsonData),
handleGrafanaManagedAlerts: ds.jsonData.handleGrafanaManagedAlerts,
}));
availableExternalDataSources.push(...cloudSources);
}
return { availableInternalDataSources, availableExternalDataSources };
}
export function getLotexDataSourceByName(dataSourceName: string): DataSourceInstanceSettings {
const dataSource = getDataSourceByName(dataSourceName);
if (!dataSource) {
throw new Error(`Data source ${dataSourceName} not found`);
}
if (dataSource.type !== DataSourceType.Loki && dataSource.type !== DataSourceType.Prometheus) {
throw new Error(`Unexpected data source type ${dataSource.type}`);
}
return dataSource;
}
export function getAllRulesSourceNames(): string[] {
const availableRulesSources: string[] = getRulesDataSources().map((r) => r.name);
if (contextSrv.hasPermission(AccessControlAction.AlertingRuleRead)) {
availableRulesSources.push(GRAFANA_RULES_SOURCE_NAME);
}
return availableRulesSources;
}
export function getAllRulesSources(): RulesSource[] {
const availableRulesSources: RulesSource[] = getRulesDataSources();
if (contextSrv.hasPermission(AccessControlAction.AlertingRuleRead)) {
availableRulesSources.push(GRAFANA_RULES_SOURCE_NAME);
}
return availableRulesSources;
}
export function getRulesSourceName(rulesSource: RulesSource): string {
return isCloudRulesSource(rulesSource) ? rulesSource.name : rulesSource;
}
export function getRulesSourceUid(rulesSource: RulesSource): string {
return isCloudRulesSource(rulesSource) ? rulesSource.uid : GRAFANA_RULES_SOURCE_NAME;
}
export function isCloudRulesSource(rulesSource: RulesSource | string): rulesSource is DataSourceInstanceSettings {
return rulesSource !== GRAFANA_RULES_SOURCE_NAME;
}
export function isVanillaPrometheusAlertManagerDataSource(name: string): boolean {
return (
name !== GRAFANA_RULES_SOURCE_NAME &&
getAlertmanagerDataSourceByName(name)?.jsonData?.implementation === AlertManagerImplementation.prometheus
);
}
export function isGrafanaRulesSource(
rulesSource: RulesSource | string
): rulesSource is typeof GRAFANA_RULES_SOURCE_NAME {
return rulesSource === GRAFANA_RULES_SOURCE_NAME;
}
export function getDataSourceByName(name: string): DataSourceInstanceSettings<DataSourceJsonData> | undefined {
return getAllDataSources().find((source) => source.name === name);
}
export function getAlertmanagerDataSourceByName(name: string) {
return getAllDataSources()
.filter(isAlertmanagerDataSourceInstance)
.find((source) => source.name === name);
}
export function getRulesSourceByName(name: string): RulesSource | undefined {
if (name === GRAFANA_RULES_SOURCE_NAME) {
return GRAFANA_RULES_SOURCE_NAME;
}
return getDataSourceByName(name);
}
export function getDatasourceAPIId(dataSourceName: string) {
if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) {
return GRAFANA_RULES_SOURCE_NAME;
}
const ds = getDataSourceByName(dataSourceName);
if (!ds) {
throw new Error(`Datasource "${dataSourceName}" not found`);
}
return String(ds.id);
}
export function getDatasourceAPIUid(dataSourceName: string) {
if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) {
return GRAFANA_RULES_SOURCE_NAME;
}
const ds = getDataSourceByName(dataSourceName);
if (!ds) {
throw new Error(`Datasource "${dataSourceName}" not found`);
}
return ds.uid;
}
export function getFirstCompatibleDataSource(): DataSourceInstanceSettings<DataSourceJsonData> | undefined {
return getDataSourceSrv().getList({ alerting: true })[0];
}
export function getDefaultOrFirstCompatibleDataSource(): DataSourceInstanceSettings<DataSourceJsonData> | undefined {
const defaultDataSource = getDataSourceSrv().getInstanceSettings('default');
const defaultIsCompatible = defaultDataSource?.meta.alerting ?? false;
return defaultIsCompatible ? defaultDataSource : getFirstCompatibleDataSource();
}
export function isDataSourceManagingAlerts(ds: DataSourceInstanceSettings<DataSourceJsonData>) {
return ds.jsonData.manageAlerts !== false; //if this prop is undefined it defaults to true
}