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
pull/40462/head^2
Nathan Rodman 4 years ago committed by GitHub
parent 0c5491d6fd
commit 4fc86594c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/grafana-data/src/types/datasource.ts
  2. 46
      packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx
  3. 24
      public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx
  4. 10
      public/app/features/alerting/unified/utils/alertmanager.ts
  5. 9
      public/app/features/alerting/unified/utils/misc.ts
  6. 8
      public/app/plugins/datasource/loki/configuration/ConfigEditor.tsx
  7. 1
      public/app/plugins/datasource/loki/types.ts
  8. 8
      public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx

@ -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>>;
}
interface AlertingConfig extends DataSourceJsonData {
manageAlerts?: boolean;
}
export function AlertingSettings<T extends { 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} />
</>

Loading…
Cancel
Save