mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Fix template variable expand bug (#16405)
CloudWatch: Fix template variable issues
This commit is contained in:
parent
d7d20a5b10
commit
8f167c47e3
@ -2,10 +2,11 @@ import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import * as dateMath from 'app/core/utils/datemath';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import * as templatingVariable from 'app/features/templating/variable';
|
||||
import { CloudWatchQuery } from './types';
|
||||
import { DataSourceApi } from '@grafana/ui/src/types';
|
||||
// import * as moment from 'moment';
|
||||
|
||||
export default class CloudWatchDatasource {
|
||||
export default class CloudWatchDatasource implements DataSourceApi<CloudWatchQuery> {
|
||||
type: any;
|
||||
name: any;
|
||||
proxyUrl: any;
|
||||
@ -448,20 +449,19 @@ export default class CloudWatchDatasource {
|
||||
// Datasource and template srv logic uber-complected. This should be cleaned up.
|
||||
return _.chain(targets)
|
||||
.map(target => {
|
||||
if (target.id && target.id.length > 0 && target.expression && target.expression.length > 0) {
|
||||
return [target];
|
||||
}
|
||||
|
||||
const variableIndex = _.keyBy(templateSrv.variables, 'name');
|
||||
const dimensionKey = _.findKey(target.dimensions, v => {
|
||||
return templateSrv.variableExists(v) && !_.has(scopedVars, templateSrv.getVariableName(v));
|
||||
const variableName = templateSrv.getVariableName(v);
|
||||
return templateSrv.variableExists(v) && !_.has(scopedVars, variableName) && variableIndex[variableName].multi;
|
||||
});
|
||||
|
||||
if (dimensionKey) {
|
||||
const multiVariable = _.find(templateSrv.variables, variable => {
|
||||
return (
|
||||
templatingVariable.containsVariable(target.dimensions[dimensionKey], variable.name) && variable.multi
|
||||
);
|
||||
});
|
||||
const variable = _.find(templateSrv.variables, variable => {
|
||||
return templatingVariable.containsVariable(target.dimensions[dimensionKey], variable.name);
|
||||
});
|
||||
return this.getExpandedVariables(target, dimensionKey, multiVariable || variable, templateSrv);
|
||||
const multiVariable = variableIndex[templateSrv.getVariableName(target.dimensions[dimensionKey])];
|
||||
return this.getExpandedVariables(target, dimensionKey, multiVariable, templateSrv);
|
||||
} else {
|
||||
return [target];
|
||||
}
|
||||
|
@ -1,19 +1,17 @@
|
||||
import '../datasource';
|
||||
import CloudWatchDatasource from '../datasource';
|
||||
import * as dateMath from 'app/core/utils/datemath';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { CustomVariable } from 'app/features/templating/all';
|
||||
import _ from 'lodash';
|
||||
import { CloudWatchQuery } from '../types';
|
||||
|
||||
describe('CloudWatchDatasource', () => {
|
||||
const instanceSettings = {
|
||||
jsonData: { defaultRegion: 'us-east-1', access: 'proxy' },
|
||||
};
|
||||
|
||||
const templateSrv = {
|
||||
data: {},
|
||||
templateSettings: { interpolate: /\[\[([\s\S]+?)\]\]/g },
|
||||
replace: text => _.template(text, templateSrv.templateSettings)(templateSrv.data),
|
||||
variableExists: () => false,
|
||||
};
|
||||
const templateSrv = new TemplateSrv();
|
||||
|
||||
const timeSrv = {
|
||||
time: { from: 'now-1h', to: 'now' },
|
||||
@ -35,7 +33,7 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
|
||||
describe('When performing CloudWatch query', () => {
|
||||
let requestParams;
|
||||
let requestParams: { queries: CloudWatchQuery[] };
|
||||
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
@ -95,9 +93,18 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
|
||||
it('should generate the correct query with interval variable', done => {
|
||||
ctx.templateSrv.data = {
|
||||
period: '10m',
|
||||
};
|
||||
templateSrv.init([
|
||||
new CustomVariable(
|
||||
{
|
||||
name: 'period',
|
||||
current: {
|
||||
value: '10m',
|
||||
},
|
||||
multi: false,
|
||||
},
|
||||
{}
|
||||
),
|
||||
]);
|
||||
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
@ -167,7 +174,7 @@ describe('CloudWatchDatasource', () => {
|
||||
expect(ctx.ds.getActualRegion('some-fake-region-1')).toBe('some-fake-region-1');
|
||||
});
|
||||
|
||||
let requestParams;
|
||||
let requestParams: { queries: CloudWatchQuery[] };
|
||||
beforeEach(() => {
|
||||
ctx.ds.performTimeSeriesQuery = jest.fn(request => {
|
||||
requestParams = request;
|
||||
@ -257,6 +264,205 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing CloudWatch query with template variables', () => {
|
||||
let requestParams: { queries: CloudWatchQuery[] };
|
||||
beforeEach(() => {
|
||||
templateSrv.init([
|
||||
new CustomVariable(
|
||||
{
|
||||
name: 'var1',
|
||||
current: {
|
||||
value: 'var1-foo',
|
||||
},
|
||||
multi: false,
|
||||
},
|
||||
{}
|
||||
),
|
||||
new CustomVariable(
|
||||
{
|
||||
name: 'var2',
|
||||
current: {
|
||||
value: 'var2-foo',
|
||||
},
|
||||
multi: false,
|
||||
},
|
||||
{}
|
||||
),
|
||||
new CustomVariable(
|
||||
{
|
||||
name: 'var3',
|
||||
options: [
|
||||
{ selected: true, value: 'var3-foo' },
|
||||
{ selected: false, value: 'var3-bar' },
|
||||
{ selected: true, value: 'var3-baz' },
|
||||
],
|
||||
current: {
|
||||
value: ['var3-foo', 'var3-baz'],
|
||||
},
|
||||
multi: true,
|
||||
},
|
||||
{}
|
||||
),
|
||||
]);
|
||||
|
||||
ctx.backendSrv.datasourceRequest = jest.fn(params => {
|
||||
requestParams = params.data;
|
||||
return Promise.resolve({ data: {} });
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the correct query for single template variable', done => {
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
rangeRaw: { from: 1483228800, to: 1483232400 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
region: 'us-east-1',
|
||||
namespace: 'TestNamespace',
|
||||
metricName: 'TestMetricName',
|
||||
dimensions: {
|
||||
dim2: '[[var2]]',
|
||||
},
|
||||
statistics: ['Average'],
|
||||
period: 300,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
ctx.ds.query(query).then(() => {
|
||||
expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the correct query for multilple template variables', done => {
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
rangeRaw: { from: 1483228800, to: 1483232400 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
region: 'us-east-1',
|
||||
namespace: 'TestNamespace',
|
||||
metricName: 'TestMetricName',
|
||||
dimensions: {
|
||||
dim1: '[[var1]]',
|
||||
dim2: '[[var2]]',
|
||||
dim3: '[[var3]]',
|
||||
},
|
||||
statistics: ['Average'],
|
||||
period: 300,
|
||||
},
|
||||
],
|
||||
scopedVars: {
|
||||
var1: { selected: true, value: 'var1-foo' },
|
||||
var2: { selected: true, value: 'var2-foo' },
|
||||
},
|
||||
};
|
||||
|
||||
ctx.ds.query(query).then(() => {
|
||||
expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the correct query for multilple template variables, lack scopedVars', done => {
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
rangeRaw: { from: 1483228800, to: 1483232400 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
region: 'us-east-1',
|
||||
namespace: 'TestNamespace',
|
||||
metricName: 'TestMetricName',
|
||||
dimensions: {
|
||||
dim1: '[[var1]]',
|
||||
dim2: '[[var2]]',
|
||||
dim3: '[[var3]]',
|
||||
},
|
||||
statistics: ['Average'],
|
||||
period: 300,
|
||||
},
|
||||
],
|
||||
scopedVars: {
|
||||
var1: { selected: true, value: 'var1-foo' },
|
||||
},
|
||||
};
|
||||
|
||||
ctx.ds.query(query).then(() => {
|
||||
expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate the correct query for multilple template variables with expression', done => {
|
||||
const query = {
|
||||
range: { from: 'now-1h', to: 'now' },
|
||||
rangeRaw: { from: 1483228800, to: 1483232400 },
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
id: 'id1',
|
||||
region: 'us-east-1',
|
||||
namespace: 'TestNamespace',
|
||||
metricName: 'TestMetricName',
|
||||
dimensions: {
|
||||
dim1: '[[var1]]',
|
||||
dim2: '[[var2]]',
|
||||
dim3: '[[var3]]',
|
||||
},
|
||||
statistics: ['Average'],
|
||||
period: 300,
|
||||
expression: '',
|
||||
},
|
||||
{
|
||||
refId: 'B',
|
||||
id: 'id2',
|
||||
expression: 'METRICS("id1") * 2',
|
||||
dimensions: {
|
||||
// garbage data for fail test
|
||||
dim1: '[[var1]]',
|
||||
dim2: '[[var2]]',
|
||||
dim3: '[[var3]]',
|
||||
},
|
||||
statistics: [], // dummy
|
||||
},
|
||||
],
|
||||
scopedVars: {
|
||||
var1: { selected: true, value: 'var1-foo' },
|
||||
var2: { selected: true, value: 'var2-foo' },
|
||||
},
|
||||
};
|
||||
|
||||
ctx.ds.query(query).then(() => {
|
||||
expect(requestParams.queries.length).toBe(3);
|
||||
expect(requestParams.queries[0].id).toMatch(/^id1.*/);
|
||||
expect(requestParams.queries[0].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[0].dimensions['dim3']).toBe('var3-foo');
|
||||
expect(requestParams.queries[1].id).toMatch(/^id1.*/);
|
||||
expect(requestParams.queries[1].dimensions['dim1']).toBe('var1-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim2']).toBe('var2-foo');
|
||||
expect(requestParams.queries[1].dimensions['dim3']).toBe('var3-baz');
|
||||
expect(requestParams.queries[2].id).toMatch(/^id2.*/);
|
||||
expect(requestParams.queries[2].expression).toBe('METRICS("id1") * 2');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function describeMetricFindQuery(query, func) {
|
||||
describe('metricFindQuery ' + query, () => {
|
||||
const scenario: any = {};
|
||||
|
13
public/app/plugins/datasource/cloudwatch/types.ts
Normal file
13
public/app/plugins/datasource/cloudwatch/types.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { DataQuery } from '@grafana/ui/src/types';
|
||||
|
||||
export interface CloudWatchQuery extends DataQuery {
|
||||
id: string;
|
||||
region: string;
|
||||
namespace: string;
|
||||
metricName: string;
|
||||
dimensions: { [key: string]: string };
|
||||
statistics: string[];
|
||||
period: string;
|
||||
expression: string;
|
||||
returnData: boolean;
|
||||
}
|
Loading…
Reference in New Issue
Block a user