mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudMonitoring: Fixes broken variable queries that use group bys (#43914)
This commit is contained in:
parent
9fb8339f87
commit
715166baf3
@ -100,7 +100,10 @@ export default class CloudMonitoringMetricFindQuery {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const refId = 'handleLabelValuesQuery';
|
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 interpolatedKey = this.datasource.templateSrv.replace(labelKey);
|
||||||
const values = labels.hasOwnProperty(interpolatedKey) ? labels[interpolatedKey] : [];
|
const values = labels.hasOwnProperty(interpolatedKey) ? labels[interpolatedKey] : [];
|
||||||
return values.map(this.toFindQueryResult);
|
return values.map(this.toFindQueryResult);
|
||||||
|
@ -61,15 +61,15 @@ function Editor({
|
|||||||
variableOptionGroup,
|
variableOptionGroup,
|
||||||
}: React.PropsWithChildren<Props>) {
|
}: React.PropsWithChildren<Props>) {
|
||||||
const [state, setState] = useState<State>(defaultState);
|
const [state, setState] = useState<State>(defaultState);
|
||||||
const { projectName, metricType, groupBys, editorMode } = query;
|
const { projectName, metricType, groupBys, editorMode, crossSeriesReducer } = query;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (projectName && metricType) {
|
if (projectName && metricType) {
|
||||||
datasource
|
datasource
|
||||||
.getLabels(metricType, refId, projectName, groupBys)
|
.getLabels(metricType, refId, projectName, { groupBys, crossSeriesReducer })
|
||||||
.then((labels) => setState((prevState) => ({ ...prevState, labels })));
|
.then((labels) => setState((prevState) => ({ ...prevState, labels })));
|
||||||
}
|
}
|
||||||
}, [datasource, groupBys, metricType, projectName, refId]);
|
}, [datasource, groupBys, metricType, projectName, refId, crossSeriesReducer]);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(metricQuery: MetricQuery | SLOQuery) => {
|
(metricQuery: MetricQuery | SLOQuery) => {
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
MetricDescriptor,
|
MetricDescriptor,
|
||||||
QueryType,
|
QueryType,
|
||||||
PostResponse,
|
PostResponse,
|
||||||
|
Aggregation,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { CloudMonitoringVariableSupport } from './variables';
|
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 = {
|
const options = {
|
||||||
targets: [
|
targets: [
|
||||||
{
|
{
|
||||||
@ -146,8 +147,8 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend<
|
|||||||
metricQuery: {
|
metricQuery: {
|
||||||
projectName: this.templateSrv.replace(projectName),
|
projectName: this.templateSrv.replace(projectName),
|
||||||
metricType: this.templateSrv.replace(metricType),
|
metricType: this.templateSrv.replace(metricType),
|
||||||
groupBys: this.interpolateGroupBys(groupBys || [], {}),
|
groupBys: this.interpolateGroupBys(aggregation?.groupBys || [], {}),
|
||||||
crossSeriesReducer: 'REDUCE_NONE',
|
crossSeriesReducer: aggregation?.crossSeriesReducer ?? 'REDUCE_NONE',
|
||||||
view: 'HEADERS',
|
view: 'HEADERS',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,6 +17,8 @@ jest.mock('@grafana/runtime', () => ({
|
|||||||
|
|
||||||
type Args = { response?: any; throws?: boolean; templateSrv?: TemplateSrv };
|
type Args = { response?: any; throws?: boolean; templateSrv?: TemplateSrv };
|
||||||
|
|
||||||
|
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||||
|
|
||||||
function getTestcontext({ response = {}, throws = false, templateSrv = new TemplateSrv() }: Args = {}) {
|
function getTestcontext({ response = {}, throws = false, templateSrv = new TemplateSrv() }: Args = {}) {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
||||||
@ -26,9 +28,12 @@ function getTestcontext({ response = {}, throws = false, templateSrv = new Templ
|
|||||||
},
|
},
|
||||||
} as unknown) as DataSourceInstanceSettings<CloudMonitoringOptions>;
|
} as unknown) as DataSourceInstanceSettings<CloudMonitoringOptions>;
|
||||||
|
|
||||||
const timeSrv = {} as TimeSrv;
|
const timeSrv = {
|
||||||
|
timeRange: () => ({
|
||||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
from: toUtc('2017-08-22T20:00:00Z'),
|
||||||
|
to: toUtc('2017-08-22T23:59:00Z'),
|
||||||
|
}),
|
||||||
|
} as TimeSrv;
|
||||||
|
|
||||||
throws
|
throws
|
||||||
? fetchMock.mockImplementation(() => throwError(response))
|
? 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('when interpolating a template variable for the filter', () => {
|
||||||
describe('and is single value variable', () => {
|
describe('and is single value variable', () => {
|
||||||
it('should replace the variable with the value', () => {
|
it('should replace the variable with the value', () => {
|
||||||
|
@ -53,6 +53,11 @@ export interface VariableQueryData {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Aggregation {
|
||||||
|
crossSeriesReducer?: string;
|
||||||
|
groupBys?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export enum QueryType {
|
export enum QueryType {
|
||||||
METRICS = 'metrics',
|
METRICS = 'metrics',
|
||||||
SLO = 'slo',
|
SLO = 'slo',
|
||||||
|
Loading…
Reference in New Issue
Block a user