mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Link prometheus and loki datasources to an alertmanager (#39887)
* add config option for alertmanager linking * Add button for silencing a rule * use uid for alertmanager * move alertmanager link to separate function
This commit is contained in:
@@ -530,6 +530,7 @@ export interface DataSourceJsonData {
|
||||
defaultRegion?: string;
|
||||
profile?: string;
|
||||
manageAlerts?: boolean;
|
||||
alertmanagerUid?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +1,34 @@
|
||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import React from 'react';
|
||||
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Switch } from '../Forms/Legacy/Switch/Switch';
|
||||
import { InlineField } from '../Forms/InlineField';
|
||||
import { InlineFieldRow } from '../Forms/InlineFieldRow';
|
||||
import { Select } from '../Select/Select';
|
||||
|
||||
type Props<T> = Pick<DataSourcePluginOptionsEditorProps<T>, 'options' | 'onOptionsChange'>;
|
||||
interface Props<T> extends Pick<DataSourcePluginOptionsEditorProps<T>, 'options' | 'onOptionsChange'> {
|
||||
alertmanagerDataSources: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
|
||||
}
|
||||
|
||||
export function AlertingSettings<T extends { manageAlerts?: boolean }>({
|
||||
interface AlertingConfig extends DataSourceJsonData {
|
||||
manageAlerts?: boolean;
|
||||
}
|
||||
|
||||
export function AlertingSettings<T extends AlertingConfig>({
|
||||
alertmanagerDataSources,
|
||||
options,
|
||||
onOptionsChange,
|
||||
}: Props<T>): JSX.Element {
|
||||
const alertmanagerOptions = useMemo(
|
||||
() =>
|
||||
alertmanagerDataSources.map((ds) => ({
|
||||
label: ds.name,
|
||||
value: ds.uid,
|
||||
imgUrl: ds.meta.info.logos.small,
|
||||
meta: ds.meta,
|
||||
})),
|
||||
[alertmanagerDataSources]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">Alerting</h3>
|
||||
@@ -27,6 +48,23 @@ export function AlertingSettings<T extends { manageAlerts?: boolean }>({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
tooltip="The alertmanager that manages alerts for this data source"
|
||||
label="Alertmanager data source"
|
||||
labelWidth={26}
|
||||
>
|
||||
<Select
|
||||
width={29}
|
||||
menuShouldPortal
|
||||
options={alertmanagerOptions}
|
||||
onChange={(value) =>
|
||||
onOptionsChange({ ...options, jsonData: { ...options.jsonData, alertmanagerUid: value?.value } })
|
||||
}
|
||||
value={options.jsonData.alertmanagerUid}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -9,11 +9,12 @@ import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { useIsRuleEditable } from '../../hooks/useIsRuleEditable';
|
||||
import { Annotation } from '../../utils/constants';
|
||||
import { getRulesSourceName, isCloudRulesSource } from '../../utils/datasource';
|
||||
import { createExploreLink, createViewLink } from '../../utils/misc';
|
||||
import { getRulesSourceName, isCloudRulesSource, isGrafanaRulesSource } from '../../utils/datasource';
|
||||
import { createExploreLink, createViewLink, makeSilenceLink } from '../../utils/misc';
|
||||
import * as ruleId from '../../utils/rule-id';
|
||||
import { deleteRuleAction } from '../../state/actions';
|
||||
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
|
||||
import { getAlertmanagerByUid } from '../../utils/alertmanager';
|
||||
|
||||
interface Props {
|
||||
rule: CombinedRule;
|
||||
@@ -27,6 +28,10 @@ export const RuleDetailsActionButtons: FC<Props> = ({ rule, rulesSource }) => {
|
||||
const { namespace, group, rulerRule } = rule;
|
||||
const [ruleToDelete, setRuleToDelete] = useState<CombinedRule>();
|
||||
|
||||
const alertmanagerSourceName = isGrafanaRulesSource(rulesSource)
|
||||
? rulesSource
|
||||
: getAlertmanagerByUid(rulesSource.jsonData.alertmanagerUid)?.name;
|
||||
|
||||
const leftButtons: JSX.Element[] = [];
|
||||
const rightButtons: JSX.Element[] = [];
|
||||
|
||||
@@ -123,6 +128,21 @@ export const RuleDetailsActionButtons: FC<Props> = ({ rule, rulesSource }) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (alertmanagerSourceName) {
|
||||
leftButtons.push(
|
||||
<LinkButton
|
||||
className={style.button}
|
||||
size="xs"
|
||||
key="silence"
|
||||
icon="bell-slash"
|
||||
target="__blank"
|
||||
href={makeSilenceLink(alertmanagerSourceName, rule)}
|
||||
>
|
||||
Silence
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isViewMode) {
|
||||
rightButtons.push(
|
||||
<LinkButton
|
||||
|
||||
@@ -2,6 +2,8 @@ import { AlertManagerCortexConfig, MatcherOperator, Route, Matcher } from 'app/p
|
||||
import { Labels } from 'app/types/unified-alerting-dto';
|
||||
import { MatcherFieldValue } from '../types/silence-form';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { getAllDataSources } from './config';
|
||||
import { DataSourceType } from './datasource';
|
||||
|
||||
export function addDefaultsToAlertmanagerConfig(config: AlertManagerCortexConfig): AlertManagerCortexConfig {
|
||||
// add default receiver if it does not exist
|
||||
@@ -174,3 +176,11 @@ export function labelsMatchMatchers(labels: Labels, matchers: Matcher[]): boolea
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getAllAlertmanagerDataSources() {
|
||||
return getAllDataSources().filter((ds) => ds.type === DataSourceType.Alertmanager);
|
||||
}
|
||||
|
||||
export function getAlertmanagerByUid(uid?: string) {
|
||||
return getAllAlertmanagerDataSources().find((ds) => uid === ds.uid);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,15 @@ export function makeAMLink(path: string, alertManagerName?: string): string {
|
||||
return `${path}${alertManagerName ? `?${ALERTMANAGER_NAME_QUERY_KEY}=${encodeURIComponent(alertManagerName)}` : ''}`;
|
||||
}
|
||||
|
||||
export function makeSilenceLink(alertmanagerSourceName: string, rule: CombinedRule) {
|
||||
return (
|
||||
`${config.appSubUrl}/alerting/silence/new?alertmanager=${alertmanagerSourceName}` +
|
||||
`&matchers=alertname=${rule.name},${Object.entries(rule.labels)
|
||||
.map(([key, value]) => encodeURIComponent(`${key}=${value}`))
|
||||
.join(',')}`
|
||||
);
|
||||
}
|
||||
|
||||
// keep retrying fn if it's error passes shouldRetry(error) and timeout has not elapsed yet
|
||||
export function retryWhile<T, E = Error>(
|
||||
fn: () => Promise<T>,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { AlertingSettings, DataSourceHttpSettings } from '@grafana/ui';
|
||||
import { LokiOptions } from '../types';
|
||||
import { MaxLinesField } from './MaxLinesField';
|
||||
import { DerivedFields } from './DerivedFields';
|
||||
import { getAllAlertmanagerDataSources } from 'app/features/alerting/unified/utils/alertmanager';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps<LokiOptions>;
|
||||
|
||||
@@ -25,6 +26,7 @@ const setDerivedFields = makeJsonUpdater('derivedFields');
|
||||
|
||||
export const ConfigEditor = (props: Props) => {
|
||||
const { options, onOptionsChange } = props;
|
||||
const alertmanagers = getAllAlertmanagerDataSources();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -35,7 +37,11 @@ export const ConfigEditor = (props: Props) => {
|
||||
onChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<AlertingSettings<LokiOptions> options={options} onOptionsChange={onOptionsChange} />
|
||||
<AlertingSettings<LokiOptions>
|
||||
alertmanagerDataSources={alertmanagers}
|
||||
options={options}
|
||||
onOptionsChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline">
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface LokiQuery extends DataQuery {
|
||||
export interface LokiOptions extends DataSourceJsonData {
|
||||
maxLines?: string;
|
||||
derivedFields?: DerivedFieldConfig[];
|
||||
alertmanager?: string;
|
||||
}
|
||||
|
||||
export interface LokiStats {
|
||||
|
||||
@@ -5,10 +5,12 @@ import { config } from 'app/core/config';
|
||||
import { PromOptions } from '../types';
|
||||
import { AzureAuthSettings } from './AzureAuthSettings';
|
||||
import { PromSettings } from './PromSettings';
|
||||
import { getAllAlertmanagerDataSources } from 'app/features/alerting/unified/utils/alertmanager';
|
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps<PromOptions>;
|
||||
export const ConfigEditor = (props: Props) => {
|
||||
const { options, onOptionsChange } = props;
|
||||
const alertmanagers = getAllAlertmanagerDataSources();
|
||||
|
||||
const azureAuthSettings = {
|
||||
azureAuthEnabled: config.featureToggles['prometheus_azure_auth'] ?? false,
|
||||
@@ -32,7 +34,11 @@ export const ConfigEditor = (props: Props) => {
|
||||
azureAuthSettings={azureAuthSettings}
|
||||
/>
|
||||
|
||||
<AlertingSettings<PromOptions> options={options} onOptionsChange={onOptionsChange} />
|
||||
<AlertingSettings<PromOptions>
|
||||
alertmanagerDataSources={alertmanagers}
|
||||
options={options}
|
||||
onOptionsChange={onOptionsChange}
|
||||
/>
|
||||
|
||||
<PromSettings options={options} onOptionsChange={onOptionsChange} />
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user