Alerting: Fix expression queries when coming from a panel (#114095)
* Add getDefaultExpressions tests * Fix expression queries when building form values from a panel * make query params empty and add some better types * update snapshots * fix tests * Revert devenv changes * update shapshot --------- Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
This commit is contained in:
co-authored by
Gilles De Mey
parent
b0f3e531b1
commit
4e24b2977c
+2
-6
@@ -52,9 +52,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -90,9 +88,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
|
||||
+2
-6
@@ -78,9 +78,7 @@ exports[`RuleEditor grafana recording rules can create new grafana recording rul
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -208,9 +206,7 @@ exports[`RuleEditor grafana recording rules can create new grafana recording rul
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
|
||||
+10
-30
@@ -79,9 +79,7 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -117,9 +115,7 @@ exports[`Can create a new grafana managed alert using simplified routing can cre
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -249,9 +245,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -287,9 +281,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -422,9 +414,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -460,9 +450,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -598,9 +586,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -636,9 +622,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -771,9 +755,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -809,9 +791,7 @@ exports[`Can create a new grafana managed alert using simplified routing switch
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
|
||||
+2
-6
@@ -81,9 +81,7 @@ exports[`RuleEditor grafana managed rules can create new grafana managed alert 1
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -119,9 +117,7 @@ exports[`RuleEditor grafana managed rules can create new grafana managed alert 1
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PromQuery } from '@grafana/prometheus';
|
||||
import { ExpressionDatasourceUID, ExpressionQueryType } from 'app/features/expressions/types';
|
||||
import { RuleWithLocation } from 'app/types/unified-alerting';
|
||||
import {
|
||||
AlertDataQuery,
|
||||
@@ -8,6 +9,7 @@ import {
|
||||
RulerAlertingRuleDTO,
|
||||
} from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { EvalFunction } from '../../state/alertDef';
|
||||
import { mockDataSource, mockRuleWithLocation, mockRulerGrafanaRecordingRule } from '../mocks';
|
||||
import { getDefaultFormValues } from '../rule-editor/formDefaults';
|
||||
import { setupDataSources } from '../testSetup/datasources';
|
||||
@@ -21,6 +23,7 @@ import {
|
||||
formValuesToRulerGrafanaRuleDTO,
|
||||
formValuesToRulerRuleDTO,
|
||||
getContactPointsFromDTO,
|
||||
getDefaultExpressions,
|
||||
getInstantFromDataQuery,
|
||||
getNotificationSettingsForDTO,
|
||||
rulerRuleToFormValues,
|
||||
@@ -417,3 +420,103 @@ describe('getInstantFromDataQuery', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefaultExpressions', () => {
|
||||
it('should create a reduce expression as the first query', () => {
|
||||
const result = getDefaultExpressions('B', 'C');
|
||||
const reduceQuery = result[0];
|
||||
const model = reduceQuery.model;
|
||||
|
||||
expect(reduceQuery.refId).toBe('B');
|
||||
expect(reduceQuery.datasourceUid).toBe(ExpressionDatasourceUID);
|
||||
expect(reduceQuery.queryType).toBe('');
|
||||
expect(model.type).toBe(ExpressionQueryType.reduce);
|
||||
expect(model.datasource?.uid).toBe(ExpressionDatasourceUID);
|
||||
expect(model.reducer).toBe('last');
|
||||
});
|
||||
|
||||
it('should create reduce expression with proper conditions structure', () => {
|
||||
const result = getDefaultExpressions('B', 'C');
|
||||
const reduceQuery = result[0];
|
||||
const model = reduceQuery.model;
|
||||
|
||||
expect(model.conditions).toHaveLength(1);
|
||||
expect(model.expression).toBe('A');
|
||||
expect(model.conditions?.[0]).toEqual({
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a threshold expression as the second query', () => {
|
||||
const result = getDefaultExpressions('B', 'C');
|
||||
const thresholdQuery = result[1];
|
||||
const model = thresholdQuery.model;
|
||||
|
||||
expect(thresholdQuery.refId).toBe('C');
|
||||
expect(thresholdQuery.datasourceUid).toBe(ExpressionDatasourceUID);
|
||||
expect(thresholdQuery.queryType).toBe('');
|
||||
expect(model.type).toBe(ExpressionQueryType.threshold);
|
||||
expect(model.datasource?.uid).toBe(ExpressionDatasourceUID);
|
||||
});
|
||||
|
||||
it('should create threshold expression with proper conditions structure', () => {
|
||||
const result = getDefaultExpressions('B', 'C');
|
||||
const thresholdQuery = result[1];
|
||||
const model = thresholdQuery.model;
|
||||
|
||||
expect(model.conditions).toHaveLength(1);
|
||||
expect(model.conditions?.[0]).toEqual({
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [0],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should reference the reduce expression in the threshold expression', () => {
|
||||
const result = getDefaultExpressions('B', 'C');
|
||||
const thresholdQuery = result[1];
|
||||
const model = thresholdQuery.model;
|
||||
|
||||
expect(model.expression).toBe('B');
|
||||
});
|
||||
|
||||
it('should properly use different refIds throughout the structure', () => {
|
||||
const result = getDefaultExpressions('X', 'Y');
|
||||
const reduceModel = result[0].model;
|
||||
const thresholdModel = result[1].model;
|
||||
|
||||
expect(result[0].refId).toBe('X');
|
||||
expect(reduceModel.refId).toBe('X');
|
||||
expect(reduceModel.conditions?.[0].query.params).toEqual([]);
|
||||
|
||||
expect(result[1].refId).toBe('Y');
|
||||
expect(thresholdModel.refId).toBe('Y');
|
||||
expect(thresholdModel.expression).toBe('X');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -536,85 +536,18 @@ export const getDefaultRecordingRulesQueries = (
|
||||
},
|
||||
];
|
||||
};
|
||||
const getDefaultExpressions = (...refIds: [string, string]): AlertQuery[] => {
|
||||
|
||||
export const getDefaultExpressions = (...refIds: [string, string]) => {
|
||||
const refOne = refIds[0];
|
||||
const refTwo = refIds[1];
|
||||
|
||||
const reduceExpression: ExpressionQuery = {
|
||||
refId: refIds[0],
|
||||
type: ExpressionQueryType.reduce,
|
||||
datasource: {
|
||||
uid: ExpressionDatasourceUID,
|
||||
type: ExpressionDatasourceRef.type,
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [refOne],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
},
|
||||
],
|
||||
reducer: 'last',
|
||||
expression: 'A',
|
||||
};
|
||||
const reduceQuery = getDefaultReduceExpression({ inputRefId: 'A', reduceRefId: refOne });
|
||||
const thresholdQuery = getDefaultThresholdExpression({ inputRefId: refOne, thresholdRefId: refTwo });
|
||||
|
||||
const thresholdExpression: ExpressionQuery = {
|
||||
refId: refTwo,
|
||||
type: ExpressionQueryType.threshold,
|
||||
datasource: {
|
||||
uid: ExpressionDatasourceUID,
|
||||
type: ExpressionDatasourceRef.type,
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [0],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [refTwo],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
},
|
||||
],
|
||||
expression: refOne,
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
refId: refOne,
|
||||
datasourceUid: ExpressionDatasourceUID,
|
||||
queryType: '',
|
||||
model: reduceExpression,
|
||||
},
|
||||
{
|
||||
refId: refTwo,
|
||||
datasourceUid: ExpressionDatasourceUID,
|
||||
queryType: '',
|
||||
model: thresholdExpression,
|
||||
},
|
||||
];
|
||||
return [reduceQuery, thresholdQuery] as const;
|
||||
};
|
||||
const getDefaultExpressionsForRecording = (refOne: string): AlertQuery[] => {
|
||||
|
||||
const getDefaultExpressionsForRecording = (refOne: string): Array<AlertQuery<ExpressionQuery>> => {
|
||||
const reduceExpression: ExpressionQuery = {
|
||||
refId: refOne,
|
||||
type: ExpressionQueryType.reduce,
|
||||
@@ -633,7 +566,7 @@ const getDefaultExpressionsForRecording = (refOne: string): AlertQuery[] => {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [refOne],
|
||||
params: [],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
@@ -655,6 +588,95 @@ const getDefaultExpressionsForRecording = (refOne: string): AlertQuery[] => {
|
||||
];
|
||||
};
|
||||
|
||||
function getDefaultReduceExpression({
|
||||
inputRefId,
|
||||
reduceRefId,
|
||||
}: {
|
||||
inputRefId: string;
|
||||
reduceRefId: string;
|
||||
}): AlertQuery<ExpressionQuery> {
|
||||
const reduceExpression: ExpressionQuery = {
|
||||
refId: reduceRefId,
|
||||
type: ExpressionQueryType.reduce,
|
||||
datasource: {
|
||||
uid: ExpressionDatasourceUID,
|
||||
type: ExpressionDatasourceRef.type,
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
},
|
||||
],
|
||||
reducer: 'last',
|
||||
expression: inputRefId,
|
||||
};
|
||||
|
||||
return {
|
||||
refId: reduceRefId,
|
||||
datasourceUid: ExpressionDatasourceUID,
|
||||
queryType: '',
|
||||
model: reduceExpression,
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultThresholdExpression({
|
||||
inputRefId,
|
||||
thresholdRefId,
|
||||
}: {
|
||||
inputRefId: string;
|
||||
thresholdRefId: string;
|
||||
}): AlertQuery<ExpressionQuery> {
|
||||
const thresholdExpression: ExpressionQuery = {
|
||||
refId: thresholdRefId,
|
||||
type: ExpressionQueryType.threshold,
|
||||
datasource: {
|
||||
uid: ExpressionDatasourceUID,
|
||||
type: ExpressionDatasourceRef.type,
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
type: 'query',
|
||||
evaluator: {
|
||||
params: [0],
|
||||
type: EvalFunction.IsAbove,
|
||||
},
|
||||
operator: {
|
||||
type: 'and',
|
||||
},
|
||||
query: {
|
||||
params: [],
|
||||
},
|
||||
reducer: {
|
||||
params: [],
|
||||
type: 'last',
|
||||
},
|
||||
},
|
||||
],
|
||||
expression: inputRefId,
|
||||
};
|
||||
|
||||
return {
|
||||
refId: thresholdRefId,
|
||||
datasourceUid: ExpressionDatasourceUID,
|
||||
queryType: '',
|
||||
model: thresholdExpression,
|
||||
};
|
||||
}
|
||||
|
||||
const dataQueriesToGrafanaQueries = async (
|
||||
queries: DataQuery[],
|
||||
relativeTimeRange: RelativeTimeRange,
|
||||
@@ -736,14 +758,23 @@ export const panelToRuleFormValues = async (
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lastQuery = queries.at(-1);
|
||||
if (!lastQuery) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!queries.find((query) => query.datasourceUid === ExpressionDatasourceUID)) {
|
||||
const [reduceExpression, _thresholdExpression] = getDefaultExpressions(getNextRefId(queries), '-');
|
||||
const reduceExpression = getDefaultReduceExpression({
|
||||
inputRefId: lastQuery.refId,
|
||||
reduceRefId: getNextRefId(queries),
|
||||
});
|
||||
queries.push(reduceExpression);
|
||||
|
||||
const [_reduceExpression, thresholdExpression] = getDefaultExpressions(
|
||||
reduceExpression.refId,
|
||||
getNextRefId(queries)
|
||||
);
|
||||
const thresholdExpression = getDefaultThresholdExpression({
|
||||
inputRefId: reduceExpression.refId,
|
||||
thresholdRefId: getNextRefId(queries),
|
||||
});
|
||||
|
||||
queries.push(thresholdExpression);
|
||||
}
|
||||
|
||||
@@ -808,14 +839,23 @@ export const scenesPanelToRuleFormValues = async (vizPanel: VizPanel): Promise<P
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lastQuery = grafanaQueries.at(-1);
|
||||
if (!lastQuery) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!grafanaQueries.find((query) => query.datasourceUid === ExpressionDatasourceUID)) {
|
||||
const [reduceExpression, _thresholdExpression] = getDefaultExpressions(getNextRefId(grafanaQueries), '-');
|
||||
const reduceExpression = getDefaultReduceExpression({
|
||||
inputRefId: lastQuery.refId,
|
||||
reduceRefId: getNextRefId(grafanaQueries),
|
||||
});
|
||||
grafanaQueries.push(reduceExpression);
|
||||
|
||||
const [_reduceExpression, thresholdExpression] = getDefaultExpressions(
|
||||
reduceExpression.refId,
|
||||
getNextRefId(grafanaQueries)
|
||||
);
|
||||
const thresholdExpression = getDefaultThresholdExpression({
|
||||
inputRefId: reduceExpression.refId,
|
||||
thresholdRefId: getNextRefId(grafanaQueries),
|
||||
});
|
||||
|
||||
grafanaQueries.push(thresholdExpression);
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -47,9 +47,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"B",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
@@ -85,9 +83,7 @@ exports[`PanelAlertTabContent Will render alerts belonging to panel and a button
|
||||
"type": "and",
|
||||
},
|
||||
"query": {
|
||||
"params": [
|
||||
"C",
|
||||
],
|
||||
"params": [],
|
||||
},
|
||||
"reducer": {
|
||||
"params": [],
|
||||
|
||||
Reference in New Issue
Block a user