diff --git a/public/app/features/expressions/ExpressionDatasource.ts b/public/app/features/expressions/ExpressionDatasource.ts index cb9d4f16be6..096224682b6 100644 --- a/public/app/features/expressions/ExpressionDatasource.ts +++ b/public/app/features/expressions/ExpressionDatasource.ts @@ -43,7 +43,7 @@ export class ExpressionDatasourceApi extends DataSourceWithBackend name; + if (mockGetVariableName) { + templateService.getVariableName = (name: string) => name; + } } const datasource = new CloudWatchDatasource( diff --git a/public/app/plugins/datasource/cloudwatch/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/datasource.test.ts index c4baf75a911..4eed42a1a2d 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.test.ts @@ -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(); diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index c4161b4e912..8dbf54c7e0a 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -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), }; } } diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts index 72dfae2fe70..02869426c78 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts @@ -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); }); });