mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
graphite: fix nested alerting queries (#10633)
This commit is contained in:
committed by
Torkel Ödegaard
parent
d85b9c28c1
commit
e6c19eb8e9
@@ -181,6 +181,22 @@ export default class GraphiteQuery {
|
||||
var nestedSeriesRefRegex = /\#([A-Z])/g;
|
||||
var targetWithNestedQueries = target.target;
|
||||
|
||||
// Use ref count to track circular references
|
||||
function countTargetRefs(targetsByRefId, refId) {
|
||||
let refCount = 0;
|
||||
_.each(targetsByRefId, (t, id) => {
|
||||
if (id !== refId) {
|
||||
let match = nestedSeriesRefRegex.exec(t.target);
|
||||
let count = match && match.length ? match.length - 1 : 0;
|
||||
refCount += count;
|
||||
}
|
||||
});
|
||||
targetsByRefId[refId].refCount = refCount;
|
||||
}
|
||||
_.each(targetsByRefId, (t, id) => {
|
||||
countTargetRefs(targetsByRefId, id);
|
||||
});
|
||||
|
||||
// Keep interpolating until there are no query references
|
||||
// The reason for the loop is that the referenced query might contain another reference to another query
|
||||
while (targetWithNestedQueries.match(nestedSeriesRefRegex)) {
|
||||
@@ -191,7 +207,11 @@ export default class GraphiteQuery {
|
||||
}
|
||||
|
||||
// no circular references
|
||||
delete targetsByRefId[g1];
|
||||
if (t.refCount === 0) {
|
||||
delete targetsByRefId[g1];
|
||||
}
|
||||
t.refCount--;
|
||||
|
||||
return t.target;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import gfunc from '../gfunc';
|
||||
import GraphiteQuery from '../graphite_query';
|
||||
|
||||
describe('Graphite query model', () => {
|
||||
let ctx: any = {
|
||||
datasource: {
|
||||
getFuncDef: gfunc.getFuncDef,
|
||||
getFuncDefs: jest.fn().mockReturnValue(Promise.resolve(gfunc.getFuncDefs('1.0'))),
|
||||
waitForFuncDefsLoaded: jest.fn().mockReturnValue(Promise.resolve(null)),
|
||||
createFuncInstance: gfunc.createFuncInstance,
|
||||
},
|
||||
templateSrv: {},
|
||||
targets: [],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
ctx.target = { refId: 'A', target: 'scaleToSeconds(#A, 60)' };
|
||||
ctx.queryModel = new GraphiteQuery(ctx.datasource, ctx.target, ctx.templateSrv);
|
||||
});
|
||||
|
||||
describe('when updating targets with nested queries', () => {
|
||||
beforeEach(() => {
|
||||
ctx.target = { refId: 'D', target: 'asPercent(#A, #C)' };
|
||||
ctx.targets = [
|
||||
{ refId: 'A', target: 'first.query.count' },
|
||||
{ refId: 'B', target: 'second.query.count' },
|
||||
{ refId: 'C', target: 'diffSeries(#A, #B)' },
|
||||
{ refId: 'D', target: 'asPercent(#A, #C)' },
|
||||
];
|
||||
ctx.queryModel = new GraphiteQuery(ctx.datasource, ctx.target, ctx.templateSrv);
|
||||
});
|
||||
|
||||
it('targetFull should include nested queries', () => {
|
||||
ctx.queryModel.updateRenderedTarget(ctx.target, ctx.targets);
|
||||
const targetFullExpected = 'asPercent(first.query.count, diffSeries(first.query.count, second.query.count))';
|
||||
expect(ctx.queryModel.target.targetFull).toBe(targetFullExpected);
|
||||
});
|
||||
|
||||
it('should not hang on circular references', () => {
|
||||
ctx.target.target = 'asPercent(#A, #B)';
|
||||
ctx.targets = [{ refId: 'A', target: 'asPercent(#B, #C)' }, { refId: 'B', target: 'asPercent(#A, #C)' }];
|
||||
ctx.queryModel.updateRenderedTarget(ctx.target, ctx.targets);
|
||||
// Just ensure updateRenderedTarget() is completed and doesn't hang
|
||||
expect(ctx.queryModel.target.targetFull).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user