CloudMonitoring: Correctly interpolate multi-valued template variables in PromQL queries (#86391)

* Interpolate promql queries appropriately

- Use pipes for multi-valued variables in PromQL queries
- Update tests

* Don't break betterer

* Another any

* Update public/app/plugins/datasource/cloud-monitoring/datasource.ts

Co-authored-by: Andrew Hackmann <5140848+bossinc@users.noreply.github.com>

---------

Co-authored-by: Andrew Hackmann <5140848+bossinc@users.noreply.github.com>
This commit is contained in:
Andreas Christou
2024-04-19 21:07:15 +01:00
committed by GitHub
parent 57bea68453
commit ec8dfc4dda
2 changed files with 52 additions and 4 deletions

View File

@ -1,7 +1,7 @@
import { get } from 'lodash';
import { lastValueFrom, of } from 'rxjs';
import { CustomVariableModel } from '@grafana/data';
import { CustomVariableModel, ScopedVars } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
import { createMockInstanceSetttings } from './__mocks__/cloudMonitoringInstanceSettings';
@ -72,6 +72,33 @@ describe('Cloud Monitoring Datasource', () => {
expect(templatedQuery[0]).toHaveProperty('datasource');
expect(templatedQuery[0].timeSeriesList?.projectName).toEqual('project-variable');
});
it('should correctly apply template variables for PromQLQuery (single-value)', () => {
const templateSrv = getTemplateSrv();
templateSrv.replace = jest.fn().mockReturnValue('filter-variable');
const mockInstanceSettings = createMockInstanceSetttings();
const ds = new Datasource(mockInstanceSettings, templateSrv);
const query = createMockQuery({ promQLQuery: { expr: '$testVar', projectName: 'test-project', step: '1' } });
const templatedQuery = ds.interpolateVariablesInQueries([query], {});
expect(templatedQuery[0]).toHaveProperty('datasource');
expect(templatedQuery[0].promQLQuery?.expr).toContain('filter-variable');
});
it('should correctly apply template variables for PromQLQuery (multi-value)', () => {
const templateSrv = getTemplateSrv();
templateSrv.replace = jest
.fn()
.mockImplementation((_target: string, _v2: ScopedVars, formatFunction: Function) => {
if (formatFunction) {
return formatFunction(['filter-variable', 'filter-variable2']);
}
return undefined;
});
const mockInstanceSettings = createMockInstanceSetttings();
const ds = new Datasource(mockInstanceSettings, templateSrv);
const query = createMockQuery({ promQLQuery: { expr: '$testVar', projectName: 'test-project', step: '1' } });
const templatedQuery = ds.interpolateVariablesInQueries([query], {});
expect(templatedQuery[0]).toHaveProperty('datasource');
expect(templatedQuery[0].promQLQuery?.expr).toContain('filter-variable|filter-variable2');
});
});
describe('migrateQuery', () => {

View File

@ -6,6 +6,7 @@ import {
DataQueryRequest,
DataQueryResponse,
DataSourceInstanceSettings,
QueryVariableModel,
ScopedVars,
SelectableValue,
TimeRange,
@ -84,7 +85,7 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend<
),
},
sloQuery: sloQuery && this.interpolateProps(sloQuery, scopedVars),
promQLQuery: promQLQuery && this.interpolateProps(promQLQuery, scopedVars),
promQLQuery: promQLQuery && this.interpolateProps(promQLQuery, scopedVars, { expr: this.interpolatePromQLQuery }),
};
}
@ -294,11 +295,31 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend<
return query;
}
interpolateProps<T extends Record<string, any>>(object: T, scopedVars: ScopedVars = {}): T {
interpolatePromQLQuery(value: string | string[], _variable: QueryVariableModel) {
if (isArray(value)) {
return value.join('|');
}
return value;
}
interpolateProps<T extends Record<string, any>>(
object: T,
scopedVars: ScopedVars = {},
formattingFunctions?: { [key: string]: Function | undefined }
): T {
return Object.entries(object).reduce((acc, [key, value]) => {
let interpolatedValue = value;
if (value && isString(value)) {
// Pass a function to the template service for formatting
interpolatedValue = this.templateSrv.replace(
value,
scopedVars,
formattingFunctions && formattingFunctions[key]
);
}
return {
...acc,
[key]: value && isString(value) ? this.templateSrv.replace(value, scopedVars) : value,
[key]: interpolatedValue,
};
}, {} as T);
}