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;
|
defaultRegion?: string;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
manageAlerts?: boolean;
|
manageAlerts?: boolean;
|
||||||
|
alertmanagerUid?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Switch } from '../Forms/Legacy/Switch/Switch';
|
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,
|
options,
|
||||||
onOptionsChange,
|
onOptionsChange,
|
||||||
}: Props<T>): JSX.Element {
|
}: 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3 className="page-heading">Alerting</h3>
|
<h3 className="page-heading">Alerting</h3>
|
||||||
@@ -27,6 +48,23 @@ export function AlertingSettings<T extends { manageAlerts?: boolean }>({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import { contextSrv } from 'app/core/services/context_srv';
|
|||||||
import { appEvents } from 'app/core/core';
|
import { appEvents } from 'app/core/core';
|
||||||
import { useIsRuleEditable } from '../../hooks/useIsRuleEditable';
|
import { useIsRuleEditable } from '../../hooks/useIsRuleEditable';
|
||||||
import { Annotation } from '../../utils/constants';
|
import { Annotation } from '../../utils/constants';
|
||||||
import { getRulesSourceName, isCloudRulesSource } from '../../utils/datasource';
|
import { getRulesSourceName, isCloudRulesSource, isGrafanaRulesSource } from '../../utils/datasource';
|
||||||
import { createExploreLink, createViewLink } from '../../utils/misc';
|
import { createExploreLink, createViewLink, makeSilenceLink } from '../../utils/misc';
|
||||||
import * as ruleId from '../../utils/rule-id';
|
import * as ruleId from '../../utils/rule-id';
|
||||||
import { deleteRuleAction } from '../../state/actions';
|
import { deleteRuleAction } from '../../state/actions';
|
||||||
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
|
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
|
||||||
|
import { getAlertmanagerByUid } from '../../utils/alertmanager';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
rule: CombinedRule;
|
rule: CombinedRule;
|
||||||
@@ -27,6 +28,10 @@ export const RuleDetailsActionButtons: FC<Props> = ({ rule, rulesSource }) => {
|
|||||||
const { namespace, group, rulerRule } = rule;
|
const { namespace, group, rulerRule } = rule;
|
||||||
const [ruleToDelete, setRuleToDelete] = useState<CombinedRule>();
|
const [ruleToDelete, setRuleToDelete] = useState<CombinedRule>();
|
||||||
|
|
||||||
|
const alertmanagerSourceName = isGrafanaRulesSource(rulesSource)
|
||||||
|
? rulesSource
|
||||||
|
: getAlertmanagerByUid(rulesSource.jsonData.alertmanagerUid)?.name;
|
||||||
|
|
||||||
const leftButtons: JSX.Element[] = [];
|
const leftButtons: JSX.Element[] = [];
|
||||||
const rightButtons: 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) {
|
if (!isViewMode) {
|
||||||
rightButtons.push(
|
rightButtons.push(
|
||||||
<LinkButton
|
<LinkButton
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { AlertManagerCortexConfig, MatcherOperator, Route, Matcher } from 'app/p
|
|||||||
import { Labels } from 'app/types/unified-alerting-dto';
|
import { Labels } from 'app/types/unified-alerting-dto';
|
||||||
import { MatcherFieldValue } from '../types/silence-form';
|
import { MatcherFieldValue } from '../types/silence-form';
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
|
import { getAllDataSources } from './config';
|
||||||
|
import { DataSourceType } from './datasource';
|
||||||
|
|
||||||
export function addDefaultsToAlertmanagerConfig(config: AlertManagerCortexConfig): AlertManagerCortexConfig {
|
export function addDefaultsToAlertmanagerConfig(config: AlertManagerCortexConfig): AlertManagerCortexConfig {
|
||||||
// add default receiver if it does not exist
|
// 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)}` : ''}`;
|
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
|
// keep retrying fn if it's error passes shouldRetry(error) and timeout has not elapsed yet
|
||||||
export function retryWhile<T, E = Error>(
|
export function retryWhile<T, E = Error>(
|
||||||
fn: () => Promise<T>,
|
fn: () => Promise<T>,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { AlertingSettings, DataSourceHttpSettings } from '@grafana/ui';
|
|||||||
import { LokiOptions } from '../types';
|
import { LokiOptions } from '../types';
|
||||||
import { MaxLinesField } from './MaxLinesField';
|
import { MaxLinesField } from './MaxLinesField';
|
||||||
import { DerivedFields } from './DerivedFields';
|
import { DerivedFields } from './DerivedFields';
|
||||||
|
import { getAllAlertmanagerDataSources } from 'app/features/alerting/unified/utils/alertmanager';
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<LokiOptions>;
|
export type Props = DataSourcePluginOptionsEditorProps<LokiOptions>;
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ const setDerivedFields = makeJsonUpdater('derivedFields');
|
|||||||
|
|
||||||
export const ConfigEditor = (props: Props) => {
|
export const ConfigEditor = (props: Props) => {
|
||||||
const { options, onOptionsChange } = props;
|
const { options, onOptionsChange } = props;
|
||||||
|
const alertmanagers = getAllAlertmanagerDataSources();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -35,7 +37,11 @@ export const ConfigEditor = (props: Props) => {
|
|||||||
onChange={onOptionsChange}
|
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-group">
|
||||||
<div className="gf-form-inline">
|
<div className="gf-form-inline">
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export interface LokiQuery extends DataQuery {
|
|||||||
export interface LokiOptions extends DataSourceJsonData {
|
export interface LokiOptions extends DataSourceJsonData {
|
||||||
maxLines?: string;
|
maxLines?: string;
|
||||||
derivedFields?: DerivedFieldConfig[];
|
derivedFields?: DerivedFieldConfig[];
|
||||||
|
alertmanager?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LokiStats {
|
export interface LokiStats {
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import { config } from 'app/core/config';
|
|||||||
import { PromOptions } from '../types';
|
import { PromOptions } from '../types';
|
||||||
import { AzureAuthSettings } from './AzureAuthSettings';
|
import { AzureAuthSettings } from './AzureAuthSettings';
|
||||||
import { PromSettings } from './PromSettings';
|
import { PromSettings } from './PromSettings';
|
||||||
|
import { getAllAlertmanagerDataSources } from 'app/features/alerting/unified/utils/alertmanager';
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<PromOptions>;
|
export type Props = DataSourcePluginOptionsEditorProps<PromOptions>;
|
||||||
export const ConfigEditor = (props: Props) => {
|
export const ConfigEditor = (props: Props) => {
|
||||||
const { options, onOptionsChange } = props;
|
const { options, onOptionsChange } = props;
|
||||||
|
const alertmanagers = getAllAlertmanagerDataSources();
|
||||||
|
|
||||||
const azureAuthSettings = {
|
const azureAuthSettings = {
|
||||||
azureAuthEnabled: config.featureToggles['prometheus_azure_auth'] ?? false,
|
azureAuthEnabled: config.featureToggles['prometheus_azure_auth'] ?? false,
|
||||||
@@ -32,7 +34,11 @@ export const ConfigEditor = (props: Props) => {
|
|||||||
azureAuthSettings={azureAuthSettings}
|
azureAuthSettings={azureAuthSettings}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AlertingSettings<PromOptions> options={options} onOptionsChange={onOptionsChange} />
|
<AlertingSettings<PromOptions>
|
||||||
|
alertmanagerDataSources={alertmanagers}
|
||||||
|
options={options}
|
||||||
|
onOptionsChange={onOptionsChange}
|
||||||
|
/>
|
||||||
|
|
||||||
<PromSettings options={options} onOptionsChange={onOptionsChange} />
|
<PromSettings options={options} onOptionsChange={onOptionsChange} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user