CloudWatch: Use scopedVars in expressions (#49178) (#49769)

* CloudWatch: Use scopedVars in expressions

* fix spec test

(cherry picked from commit b80934617b)
This commit is contained in:
Isabella Siu
2022-05-30 09:38:15 +02:00
committed by GitHub
parent 1cee0bee9d
commit 9cb11a3c53
5 changed files with 63 additions and 25 deletions
@@ -43,7 +43,7 @@ export class ExpressionDatasourceApi extends DataSourceWithBackend<ExpressionQue
return query;
}
return ds?.interpolateVariablesInQueries([query], {})[0] as ExpressionQuery;
return ds?.interpolateVariablesInQueries([query], request.scopedVars)[0] as ExpressionQuery;
});
let sub = from(Promise.all(targets));
@@ -9,7 +9,11 @@ import { CustomVariableModel } from 'app/features/variables/types';
import { TemplateSrvMock } from '../../../../features/templating/template_srv.mock';
import { CloudWatchDatasource } from '../datasource';
export function setupMockedDataSource({ data = [], variables }: { data?: any; variables?: any } = {}) {
export function setupMockedDataSource({
data = [],
variables,
mockGetVariableName = true,
}: { data?: any; variables?: any; mockGetVariableName?: boolean } = {}) {
let templateService = new TemplateSrvMock({
region: 'templatedRegion',
fields: 'templatedField',
@@ -19,7 +23,9 @@ export function setupMockedDataSource({ data = [], variables }: { data?: any; va
templateService = new TemplateSrv();
templateService.init(variables);
templateService.getVariables = jest.fn().mockReturnValue(variables);
templateService.getVariableName = (name: string) => name;
if (mockGetVariableName) {
templateService.getVariableName = (name: string) => name;
}
}
const datasource = new CloudWatchDatasource(
@@ -5,6 +5,7 @@ import { ArrayVector, DataFrame, dataFrameToJSON, dateTime, Field, MutableDataFr
import { setDataSourceSrv } from '@grafana/runtime';
import {
dimensionVariable,
labelsVariable,
limitVariable,
metricVariable,
@@ -398,6 +399,30 @@ describe('datasource', () => {
});
});
describe('interpolateMetricsQueryVariables', () => {
it('interpolates dimensions correctly', () => {
const testQuery = {
id: 'a',
refId: 'a',
region: 'us-east-2',
namespace: '',
dimensions: { InstanceId: '$dimension' },
};
const ds = setupMockedDataSource({ variables: [dimensionVariable], mockGetVariableName: false });
const result = ds.datasource.interpolateMetricsQueryVariables(testQuery, {
dimension: { text: 'foo', value: 'foo' },
});
expect(result).toStrictEqual({
alias: '',
metricName: '',
namespace: '',
period: '',
sqlExpression: '',
dimensions: { InstanceId: ['foo'] },
});
});
});
describe('getLogGroupFields', () => {
it('passes region correctly', async () => {
const { datasource, fetchMock } = setupMockedDataSource();
@@ -842,20 +842,26 @@ export class CloudWatchDatasource
return { ...result, [key]: null };
}
const valueVar = this.templateSrv
.getVariables()
.find(({ name }) => name === this.templateSrv.getVariableName(value));
if (valueVar) {
if ((valueVar as unknown as VariableWithMultiSupport).multi) {
const values = this.templateSrv.replace(value, scopedVars, 'pipe').split('|');
return { ...result, [key]: values };
}
return { ...result, [key]: [this.templateSrv.replace(value, scopedVars)] };
}
return { ...result, [key]: [value] };
const newValues = this.getVariableValue(value, scopedVars);
return { ...result, [key]: newValues };
}, {});
}
// get the value for a given template variable
getVariableValue(value: string, scopedVars: ScopedVars): string[] {
const variableName = this.templateSrv.getVariableName(value);
const valueVar = this.templateSrv.getVariables().find(({ name }) => {
return name === variableName;
});
if (variableName && valueVar) {
if ((valueVar as unknown as VariableWithMultiSupport).multi) {
// rebuild the variable name to handle old migrated queries
const values = this.templateSrv.replace('$' + variableName, scopedVars, 'pipe').split('|');
return values;
}
return [this.templateSrv.replace(value, scopedVars)];
}
return [value];
}
replace(
target?: string,
@@ -929,13 +935,7 @@ export class CloudWatchDatasource
namespace: this.replace(query.namespace, scopedVars),
period: this.replace(query.period, scopedVars),
sqlExpression: this.replace(query.sqlExpression, scopedVars),
dimensions: Object.entries(query.dimensions ?? {}).reduce((prev, [key, value]) => {
if (Array.isArray(value)) {
return { ...prev, [key]: value };
}
return { ...prev, [this.replace(key, scopedVars)]: this.replace(value, scopedVars) };
}, {}),
dimensions: this.convertDimensionFormat(query.dimensions ?? {}, scopedVars),
};
}
}
@@ -585,7 +585,11 @@ describe('CloudWatchDatasource', () => {
});
it('should replace correct variables in CloudWatchMetricsQuery', () => {
const templateSrv: any = { replace: jest.fn(), getVariables: () => [] };
const templateSrv: any = {
replace: jest.fn(),
getVariables: () => [],
getVariableName: jest.fn((name: string) => name),
};
const { ds } = getTestContext({ templateSrv });
const variableName = 'someVar';
const logQuery: CloudWatchMetricsQuery = {
@@ -608,9 +612,12 @@ describe('CloudWatchDatasource', () => {
ds.interpolateVariablesInQueries([logQuery], {});
// We interpolate `expression`, `region`, `period`, `alias`, `metricName`, `nameSpace` and `dimensions` in CloudWatchMetricsQuery
// We interpolate `expression`, `region`, `period`, `alias`, `metricName`, and `nameSpace` in CloudWatchMetricsQuery
expect(templateSrv.replace).toHaveBeenCalledWith(`$${variableName}`, {});
expect(templateSrv.replace).toHaveBeenCalledTimes(9);
expect(templateSrv.replace).toHaveBeenCalledTimes(8);
expect(templateSrv.getVariableName).toHaveBeenCalledWith(`$${variableName}`);
expect(templateSrv.getVariableName).toHaveBeenCalledTimes(1);
});
});