mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Add support for keep_firing_for
field from external rulers (#75163)
* Add support for `keep_firing_for` in ruler proxy * Don't delete `keep_firing_for` when editing a rule with the field set Co-Authored-By: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> --------- Co-authored-by: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>
This commit is contained in:
parent
633605af4e
commit
925f12d0ea
@ -262,6 +262,7 @@ type ApiRuleNode struct {
|
|||||||
Alert string `yaml:"alert,omitempty" json:"alert,omitempty"`
|
Alert string `yaml:"alert,omitempty" json:"alert,omitempty"`
|
||||||
Expr string `yaml:"expr" json:"expr"`
|
Expr string `yaml:"expr" json:"expr"`
|
||||||
For *model.Duration `yaml:"for,omitempty" json:"for,omitempty"`
|
For *model.Duration `yaml:"for,omitempty" json:"for,omitempty"`
|
||||||
|
KeepFiringFor *model.Duration `yaml:"keep_firing_for,omitempty" json:"keep_firing_for,omitempty"`
|
||||||
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
|
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
|
||||||
Annotations map[string]string `yaml:"annotations,omitempty" json:"annotations,omitempty"`
|
Annotations map[string]string `yaml:"annotations,omitempty" json:"annotations,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,7 @@ export interface RuleFormValues {
|
|||||||
namespace: string;
|
namespace: string;
|
||||||
forTime: number;
|
forTime: number;
|
||||||
forTimeUnit: string;
|
forTimeUnit: string;
|
||||||
|
keepFiringForTime?: number;
|
||||||
|
keepFiringForTimeUnit?: string;
|
||||||
expression: string;
|
expression: string;
|
||||||
}
|
}
|
||||||
|
@ -59,3 +59,73 @@ exports[`formValuesToRulerGrafanaRuleDTO should not save both instant and range
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`formValuesToRulerGrafanaRuleDTO should not set keep_firing_for if values are undefined 1`] = `
|
||||||
|
{
|
||||||
|
"alert": "",
|
||||||
|
"annotations": {
|
||||||
|
"description": "",
|
||||||
|
"runbook_url": "",
|
||||||
|
"summary": "",
|
||||||
|
},
|
||||||
|
"expr": "",
|
||||||
|
"for": "1m",
|
||||||
|
"keep_firing_for": undefined,
|
||||||
|
"labels": {
|
||||||
|
"": "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`formValuesToRulerGrafanaRuleDTO should parse keep_firing_for 1`] = `
|
||||||
|
{
|
||||||
|
"annotations": [],
|
||||||
|
"expression": "B",
|
||||||
|
"forTime": 1,
|
||||||
|
"forTimeUnit": "m",
|
||||||
|
"keepFiringForTime": 1,
|
||||||
|
"keepFiringForTimeUnit": "m",
|
||||||
|
"labels": [
|
||||||
|
{
|
||||||
|
"key": "",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"name": "A",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`formValuesToRulerGrafanaRuleDTO should set keep_firing_for if values are populated 1`] = `
|
||||||
|
{
|
||||||
|
"alert": "",
|
||||||
|
"annotations": {
|
||||||
|
"description": "",
|
||||||
|
"runbook_url": "",
|
||||||
|
"summary": "",
|
||||||
|
},
|
||||||
|
"expr": "",
|
||||||
|
"for": "1m",
|
||||||
|
"keep_firing_for": "1m",
|
||||||
|
"labels": {
|
||||||
|
"": "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`formValuesToRulerGrafanaRuleDTO should set keepFiringForTime and keepFiringForTimeUnit to undefined if keep_firing_for not set 1`] = `
|
||||||
|
{
|
||||||
|
"annotations": [],
|
||||||
|
"expression": "B",
|
||||||
|
"forTime": 1,
|
||||||
|
"forTimeUnit": "m",
|
||||||
|
"keepFiringForTime": undefined,
|
||||||
|
"keepFiringForTimeUnit": undefined,
|
||||||
|
"labels": [
|
||||||
|
{
|
||||||
|
"key": "",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"name": "A",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import { PromQuery } from 'app/plugins/datasource/prometheus/types';
|
import { PromQuery } from 'app/plugins/datasource/prometheus/types';
|
||||||
|
import { RulerAlertingRuleDTO } from 'app/types/unified-alerting-dto';
|
||||||
|
|
||||||
import { RuleFormValues } from '../types/rule-form';
|
import { RuleFormType, RuleFormValues } from '../types/rule-form';
|
||||||
|
|
||||||
import { formValuesToRulerGrafanaRuleDTO, getDefaultFormValues } from './rule-form';
|
import {
|
||||||
|
alertingRulerRuleToRuleForm,
|
||||||
|
formValuesToRulerGrafanaRuleDTO,
|
||||||
|
formValuesToRulerRuleDTO,
|
||||||
|
getDefaultFormValues,
|
||||||
|
} from './rule-form';
|
||||||
|
|
||||||
describe('formValuesToRulerGrafanaRuleDTO', () => {
|
describe('formValuesToRulerGrafanaRuleDTO', () => {
|
||||||
it('should correctly convert rule form values', () => {
|
it('should correctly convert rule form values', () => {
|
||||||
@ -33,4 +39,49 @@ describe('formValuesToRulerGrafanaRuleDTO', () => {
|
|||||||
|
|
||||||
expect(formValuesToRulerGrafanaRuleDTO(values)).toMatchSnapshot();
|
expect(formValuesToRulerGrafanaRuleDTO(values)).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should set keep_firing_for if values are populated', () => {
|
||||||
|
const formValues: RuleFormValues = {
|
||||||
|
...getDefaultFormValues(),
|
||||||
|
type: RuleFormType.cloudAlerting,
|
||||||
|
condition: 'A',
|
||||||
|
keepFiringForTime: 1,
|
||||||
|
keepFiringForTimeUnit: 'm',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(formValuesToRulerRuleDTO(formValues)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set keep_firing_for if values are undefined', () => {
|
||||||
|
const formValues: RuleFormValues = {
|
||||||
|
...getDefaultFormValues(),
|
||||||
|
type: RuleFormType.cloudAlerting,
|
||||||
|
condition: 'A',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(formValuesToRulerRuleDTO(formValues)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse keep_firing_for', () => {
|
||||||
|
const rule: RulerAlertingRuleDTO = {
|
||||||
|
alert: 'A',
|
||||||
|
expr: 'B',
|
||||||
|
for: '1m',
|
||||||
|
keep_firing_for: '1m',
|
||||||
|
labels: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(alertingRulerRuleToRuleForm(rule)).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set keepFiringForTime and keepFiringForTimeUnit to undefined if keep_firing_for not set', () => {
|
||||||
|
const rule: RulerAlertingRuleDTO = {
|
||||||
|
alert: 'A',
|
||||||
|
expr: 'B',
|
||||||
|
for: '1m',
|
||||||
|
labels: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(alertingRulerRuleToRuleForm(rule)).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -75,11 +75,17 @@ export const getDefaultFormValues = (): RuleFormValues => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function formValuesToRulerRuleDTO(values: RuleFormValues): RulerRuleDTO {
|
export function formValuesToRulerRuleDTO(values: RuleFormValues): RulerRuleDTO {
|
||||||
const { name, expression, forTime, forTimeUnit, type } = values;
|
const { name, expression, forTime, forTimeUnit, keepFiringForTime, keepFiringForTimeUnit, type } = values;
|
||||||
if (type === RuleFormType.cloudAlerting) {
|
if (type === RuleFormType.cloudAlerting) {
|
||||||
|
let keepFiringFor: string | undefined;
|
||||||
|
if (keepFiringForTime && keepFiringForTimeUnit) {
|
||||||
|
keepFiringFor = `${keepFiringForTime}${keepFiringForTimeUnit}`;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
alert: name,
|
alert: name,
|
||||||
for: `${forTime}${forTimeUnit}`,
|
for: `${forTime}${forTimeUnit}`,
|
||||||
|
keep_firing_for: keepFiringFor,
|
||||||
annotations: arrayToRecord(values.annotations || []),
|
annotations: arrayToRecord(values.annotations || []),
|
||||||
labels: arrayToRecord(values.labels || []),
|
labels: arrayToRecord(values.labels || []),
|
||||||
expr: expression,
|
expr: expression,
|
||||||
@ -220,18 +226,34 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
|||||||
|
|
||||||
export function alertingRulerRuleToRuleForm(
|
export function alertingRulerRuleToRuleForm(
|
||||||
rule: RulerAlertingRuleDTO
|
rule: RulerAlertingRuleDTO
|
||||||
): Pick<RuleFormValues, 'name' | 'forTime' | 'forTimeUnit' | 'expression' | 'annotations' | 'labels'> {
|
): Pick<
|
||||||
|
RuleFormValues,
|
||||||
|
| 'name'
|
||||||
|
| 'forTime'
|
||||||
|
| 'forTimeUnit'
|
||||||
|
| 'keepFiringForTime'
|
||||||
|
| 'keepFiringForTimeUnit'
|
||||||
|
| 'expression'
|
||||||
|
| 'annotations'
|
||||||
|
| 'labels'
|
||||||
|
> {
|
||||||
const defaultFormValues = getDefaultFormValues();
|
const defaultFormValues = getDefaultFormValues();
|
||||||
|
|
||||||
const [forTime, forTimeUnit] = rule.for
|
const [forTime, forTimeUnit] = rule.for
|
||||||
? parseInterval(rule.for)
|
? parseInterval(rule.for)
|
||||||
: [defaultFormValues.forTime, defaultFormValues.forTimeUnit];
|
: [defaultFormValues.forTime, defaultFormValues.forTimeUnit];
|
||||||
|
|
||||||
|
const [keepFiringForTime, keepFiringForTimeUnit] = rule.keep_firing_for
|
||||||
|
? parseInterval(rule.keep_firing_for)
|
||||||
|
: [defaultFormValues.keepFiringForTime, defaultFormValues.keepFiringForTimeUnit];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: rule.alert,
|
name: rule.alert,
|
||||||
expression: rule.expr,
|
expression: rule.expr,
|
||||||
forTime,
|
forTime,
|
||||||
forTimeUnit,
|
forTimeUnit,
|
||||||
|
keepFiringForTime,
|
||||||
|
keepFiringForTimeUnit,
|
||||||
annotations: listifyLabelsOrAnnotations(rule.annotations, false),
|
annotations: listifyLabelsOrAnnotations(rule.annotations, false),
|
||||||
labels: listifyLabelsOrAnnotations(rule.labels, true),
|
labels: listifyLabelsOrAnnotations(rule.labels, true),
|
||||||
};
|
};
|
||||||
|
@ -174,6 +174,7 @@ export interface RulerRecordingRuleDTO extends RulerRuleBaseDTO {
|
|||||||
export interface RulerAlertingRuleDTO extends RulerRuleBaseDTO {
|
export interface RulerAlertingRuleDTO extends RulerRuleBaseDTO {
|
||||||
alert: string;
|
alert: string;
|
||||||
for?: string;
|
for?: string;
|
||||||
|
keep_firing_for?: string;
|
||||||
annotations?: Annotations;
|
annotations?: Annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user