diff --git a/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts b/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts index 84b6cc59689..b3bff0f4753 100644 --- a/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts +++ b/public/app/plugins/datasource/cloud-monitoring/CloudMonitoringMetricFindQuery.ts @@ -100,7 +100,10 @@ export default class CloudMonitoringMetricFindQuery { return []; } const refId = 'handleLabelValuesQuery'; - const labels = await this.datasource.getLabels(selectedMetricType, refId, projectName, [labelKey]); + const labels = await this.datasource.getLabels(selectedMetricType, refId, projectName, { + groupBys: [labelKey], + crossSeriesReducer: 'REDUCE_MEAN', + }); const interpolatedKey = this.datasource.templateSrv.replace(labelKey); const values = labels.hasOwnProperty(interpolatedKey) ? labels[interpolatedKey] : []; return values.map(this.toFindQueryResult); diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx index 495b818ba43..40a129cbb04 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx @@ -61,15 +61,15 @@ function Editor({ variableOptionGroup, }: React.PropsWithChildren) { const [state, setState] = useState(defaultState); - const { projectName, metricType, groupBys, editorMode } = query; + const { projectName, metricType, groupBys, editorMode, crossSeriesReducer } = query; useEffect(() => { if (projectName && metricType) { datasource - .getLabels(metricType, refId, projectName, groupBys) + .getLabels(metricType, refId, projectName, { groupBys, crossSeriesReducer }) .then((labels) => setState((prevState) => ({ ...prevState, labels }))); } - }, [datasource, groupBys, metricType, projectName, refId]); + }, [datasource, groupBys, metricType, projectName, refId, crossSeriesReducer]); const onChange = useCallback( (metricQuery: MetricQuery | SLOQuery) => { diff --git a/public/app/plugins/datasource/cloud-monitoring/datasource.ts b/public/app/plugins/datasource/cloud-monitoring/datasource.ts index 94b78a815f8..cd3b314ecda 100644 --- a/public/app/plugins/datasource/cloud-monitoring/datasource.ts +++ b/public/app/plugins/datasource/cloud-monitoring/datasource.ts @@ -20,6 +20,7 @@ import { MetricDescriptor, QueryType, PostResponse, + Aggregation, } from './types'; import { CloudMonitoringVariableSupport } from './variables'; @@ -136,7 +137,7 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend< }; } - async getLabels(metricType: string, refId: string, projectName: string, groupBys?: string[]) { + async getLabels(metricType: string, refId: string, projectName: string, aggregation?: Aggregation) { const options = { targets: [ { @@ -146,8 +147,8 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend< metricQuery: { projectName: this.templateSrv.replace(projectName), metricType: this.templateSrv.replace(metricType), - groupBys: this.interpolateGroupBys(groupBys || [], {}), - crossSeriesReducer: 'REDUCE_NONE', + groupBys: this.interpolateGroupBys(aggregation?.groupBys || [], {}), + crossSeriesReducer: aggregation?.crossSeriesReducer ?? 'REDUCE_NONE', view: 'HEADERS', }, }, diff --git a/public/app/plugins/datasource/cloud-monitoring/specs/datasource.test.ts b/public/app/plugins/datasource/cloud-monitoring/specs/datasource.test.ts index 2058e476feb..2d679fe4ed4 100644 --- a/public/app/plugins/datasource/cloud-monitoring/specs/datasource.test.ts +++ b/public/app/plugins/datasource/cloud-monitoring/specs/datasource.test.ts @@ -17,6 +17,8 @@ jest.mock('@grafana/runtime', () => ({ type Args = { response?: any; throws?: boolean; templateSrv?: TemplateSrv }; +const fetchMock = jest.spyOn(backendSrv, 'fetch'); + function getTestcontext({ response = {}, throws = false, templateSrv = new TemplateSrv() }: Args = {}) { jest.clearAllMocks(); @@ -26,9 +28,12 @@ function getTestcontext({ response = {}, throws = false, templateSrv = new Templ }, } as unknown) as DataSourceInstanceSettings; - const timeSrv = {} as TimeSrv; - - const fetchMock = jest.spyOn(backendSrv, 'fetch'); + const timeSrv = { + timeRange: () => ({ + from: toUtc('2017-08-22T20:00:00Z'), + to: toUtc('2017-08-22T23:59:00Z'), + }), + } as TimeSrv; throws ? fetchMock.mockImplementation(() => throwError(response)) @@ -82,6 +87,41 @@ describe('CloudMonitoringDataSource', () => { }); }); + describe('When loading labels', () => { + describe('and no aggregation was specified', () => { + it('should use default values', async () => { + const { ds } = getTestcontext(); + await ds.getLabels('cpu', 'a', 'default-proj'); + + await expect(fetchMock.mock.calls[0][0].data.queries[0].metricQuery).toMatchObject({ + crossSeriesReducer: 'REDUCE_NONE', + groupBys: [], + metricType: 'cpu', + projectName: 'default-proj', + view: 'HEADERS', + }); + }); + }); + + describe('and an aggregation was specified', () => { + it('should use the provided aggregation', async () => { + const { ds } = getTestcontext(); + await ds.getLabels('sql', 'b', 'default-proj', { + crossSeriesReducer: 'REDUCE_MEAN', + groupBys: ['metadata.system_label.name'], + }); + + await expect(fetchMock.mock.calls[0][0].data.queries[0].metricQuery).toMatchObject({ + crossSeriesReducer: 'REDUCE_MEAN', + groupBys: ['metadata.system_label.name'], + metricType: 'sql', + projectName: 'default-proj', + view: 'HEADERS', + }); + }); + }); + }); + describe('when interpolating a template variable for the filter', () => { describe('and is single value variable', () => { it('should replace the variable with the value', () => { diff --git a/public/app/plugins/datasource/cloud-monitoring/types.ts b/public/app/plugins/datasource/cloud-monitoring/types.ts index 135147f4db2..347490a7844 100644 --- a/public/app/plugins/datasource/cloud-monitoring/types.ts +++ b/public/app/plugins/datasource/cloud-monitoring/types.ts @@ -53,6 +53,11 @@ export interface VariableQueryData { loading: boolean; } +export interface Aggregation { + crossSeriesReducer?: string; + groupBys?: string[]; +} + export enum QueryType { METRICS = 'metrics', SLO = 'slo',