mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Allow hidden queries to be executed in case an ID is provided (#50987)
* allow hidden queries in case an id is provided * cleanup test * name tests properly
This commit is contained in:
parent
1f0c951bce
commit
fcbe0059c2
@ -0,0 +1,28 @@
|
|||||||
|
import { CloudWatchMetricsQuery, MetricQueryType, MetricEditorMode, CloudWatchLogsQuery } from '../types';
|
||||||
|
|
||||||
|
export const validMetricsQuery: CloudWatchMetricsQuery = {
|
||||||
|
id: '',
|
||||||
|
queryMode: 'Metrics',
|
||||||
|
region: 'us-east-2',
|
||||||
|
namespace: 'AWS/EC2',
|
||||||
|
period: '3000',
|
||||||
|
alias: '',
|
||||||
|
metricName: 'CPUUtilization',
|
||||||
|
dimensions: { InstanceId: 'i-123' },
|
||||||
|
matchExact: true,
|
||||||
|
statistic: 'Average',
|
||||||
|
expression: '',
|
||||||
|
refId: 'A',
|
||||||
|
metricQueryType: MetricQueryType.Search,
|
||||||
|
metricEditorMode: MetricEditorMode.Code,
|
||||||
|
hide: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validLogsQuery: CloudWatchLogsQuery = {
|
||||||
|
queryMode: 'Logs',
|
||||||
|
logGroupNames: ['group-A', 'group-B'],
|
||||||
|
hide: false,
|
||||||
|
id: '',
|
||||||
|
region: 'us-east-2',
|
||||||
|
refId: 'A',
|
||||||
|
};
|
@ -15,10 +15,11 @@ import {
|
|||||||
setupMockedDataSource,
|
setupMockedDataSource,
|
||||||
regionVariable,
|
regionVariable,
|
||||||
} from './__mocks__/CloudWatchDataSource';
|
} from './__mocks__/CloudWatchDataSource';
|
||||||
|
import { validLogsQuery, validMetricsQuery } from './__mocks__/queries';
|
||||||
import {
|
import {
|
||||||
CloudWatchLogsQuery,
|
|
||||||
CloudWatchLogsQueryStatus,
|
CloudWatchLogsQueryStatus,
|
||||||
CloudWatchMetricsQuery,
|
CloudWatchMetricsQuery,
|
||||||
|
CloudWatchQuery,
|
||||||
MetricEditorMode,
|
MetricEditorMode,
|
||||||
MetricQueryType,
|
MetricQueryType,
|
||||||
} from './types';
|
} from './types';
|
||||||
@ -45,6 +46,19 @@ describe('datasource', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const testTable: Array<{ query: CloudWatchQuery; valid: boolean }> = [
|
||||||
|
{ query: { ...validLogsQuery, hide: true }, valid: false },
|
||||||
|
{ query: { ...validLogsQuery, hide: false }, valid: true },
|
||||||
|
{ query: { ...validMetricsQuery, hide: true }, valid: false },
|
||||||
|
{ query: { ...validMetricsQuery, hide: true, id: 'queryA' }, valid: true },
|
||||||
|
{ query: { ...validMetricsQuery, hide: false }, valid: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
test.each(testTable)('should filter out hidden queries unless id is provided', ({ query, valid }) => {
|
||||||
|
const { datasource } = setupMockedDataSource();
|
||||||
|
expect(datasource.filterQuery(query)).toEqual(valid);
|
||||||
|
});
|
||||||
|
|
||||||
it('should interpolate variables in the query', async () => {
|
it('should interpolate variables in the query', async () => {
|
||||||
const { datasource, fetchMock } = setupMockedDataSource();
|
const { datasource, fetchMock } = setupMockedDataSource();
|
||||||
await lastValueFrom(
|
await lastValueFrom(
|
||||||
@ -180,120 +194,107 @@ describe('datasource', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('filterQuery', () => {
|
describe('filterMetricsQuery', () => {
|
||||||
const datasource = setupMockedDataSource().datasource;
|
const datasource = setupMockedDataSource().datasource;
|
||||||
describe('CloudWatchLogsQuery', () => {
|
let baseQuery: CloudWatchMetricsQuery;
|
||||||
const baseQuery: CloudWatchLogsQuery = {
|
beforeEach(() => {
|
||||||
queryMode: 'Logs',
|
baseQuery = {
|
||||||
id: '',
|
id: '',
|
||||||
region: '',
|
region: 'us-east-2',
|
||||||
|
namespace: '',
|
||||||
|
period: '',
|
||||||
|
alias: '',
|
||||||
|
metricName: '',
|
||||||
|
dimensions: {},
|
||||||
|
matchExact: true,
|
||||||
|
statistic: '',
|
||||||
|
expression: '',
|
||||||
refId: '',
|
refId: '',
|
||||||
logGroupNames: ['foo', 'bar'],
|
|
||||||
};
|
};
|
||||||
it('should return false if empty logGroupNames', () => {
|
|
||||||
expect(datasource.filterQuery({ ...baseQuery, logGroupNames: undefined })).toBeFalsy();
|
|
||||||
});
|
|
||||||
it('should return true if has logGroupNames', () => {
|
|
||||||
expect(datasource.filterQuery(baseQuery)).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('CloudWatchMetricsQuery', () => {
|
|
||||||
let baseQuery: CloudWatchMetricsQuery;
|
it('should error if invalid mode', async () => {
|
||||||
|
expect(() => datasource.filterMetricQuery(baseQuery)).toThrowError('invalid metric editor mode');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('metric search queries', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
baseQuery = {
|
baseQuery = {
|
||||||
id: '',
|
...baseQuery,
|
||||||
region: 'us-east-2',
|
namespace: 'AWS/EC2',
|
||||||
namespace: '',
|
metricName: 'CPUUtilization',
|
||||||
period: '',
|
statistic: 'Average',
|
||||||
alias: '',
|
metricQueryType: MetricQueryType.Search,
|
||||||
metricName: '',
|
metricEditorMode: MetricEditorMode.Builder,
|
||||||
dimensions: {},
|
|
||||||
matchExact: true,
|
|
||||||
statistic: '',
|
|
||||||
expression: '',
|
|
||||||
refId: '',
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error if invalid mode', async () => {
|
it('should not allow builder queries that dont have namespace, metric or statistic', async () => {
|
||||||
expect(() => datasource.filterQuery(baseQuery)).toThrowError('invalid metric editor mode');
|
expect(datasource.filterMetricQuery({ ...baseQuery, statistic: undefined })).toBeFalsy();
|
||||||
|
expect(datasource.filterMetricQuery({ ...baseQuery, metricName: undefined })).toBeFalsy();
|
||||||
|
expect(datasource.filterMetricQuery({ ...baseQuery, namespace: '' })).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('metric search queries', () => {
|
it('should allow builder queries that have namespace, metric or statistic', async () => {
|
||||||
beforeEach(() => {
|
expect(datasource.filterMetricQuery(baseQuery)).toBeTruthy();
|
||||||
baseQuery = {
|
|
||||||
...baseQuery,
|
|
||||||
namespace: 'AWS/EC2',
|
|
||||||
metricName: 'CPUUtilization',
|
|
||||||
statistic: 'Average',
|
|
||||||
metricQueryType: MetricQueryType.Search,
|
|
||||||
metricEditorMode: MetricEditorMode.Builder,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not allow builder queries that dont have namespace, metric or statistic', async () => {
|
|
||||||
expect(datasource.filterQuery({ ...baseQuery, statistic: undefined })).toBeFalsy();
|
|
||||||
expect(datasource.filterQuery({ ...baseQuery, metricName: undefined })).toBeFalsy();
|
|
||||||
expect(datasource.filterQuery({ ...baseQuery, namespace: '' })).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow builder queries that have namespace, metric or statistic', async () => {
|
|
||||||
expect(datasource.filterQuery(baseQuery)).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not allow code queries that dont have an expression', async () => {
|
|
||||||
expect(
|
|
||||||
datasource.filterQuery({ ...baseQuery, expression: undefined, metricEditorMode: MetricEditorMode.Code })
|
|
||||||
).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow code queries that have an expression', async () => {
|
|
||||||
expect(
|
|
||||||
datasource.filterQuery({ ...baseQuery, expression: 'x * 2', metricEditorMode: MetricEditorMode.Code })
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('metric search expression queries', () => {
|
it('should not allow code queries that dont have an expression', async () => {
|
||||||
beforeEach(() => {
|
expect(
|
||||||
baseQuery = {
|
datasource.filterMetricQuery({
|
||||||
...baseQuery,
|
...baseQuery,
|
||||||
metricQueryType: MetricQueryType.Search,
|
expression: undefined,
|
||||||
metricEditorMode: MetricEditorMode.Code,
|
metricEditorMode: MetricEditorMode.Code,
|
||||||
};
|
})
|
||||||
});
|
).toBeFalsy();
|
||||||
|
|
||||||
it('should not allow queries that dont have an expression', async () => {
|
|
||||||
const valid = datasource.filterQuery(baseQuery);
|
|
||||||
expect(valid).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow queries that have an expression', async () => {
|
|
||||||
baseQuery.expression = 'SUM([a,x])';
|
|
||||||
const valid = datasource.filterQuery(baseQuery);
|
|
||||||
expect(valid).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('metric query queries', () => {
|
it('should allow code queries that have an expression', async () => {
|
||||||
beforeEach(() => {
|
expect(
|
||||||
baseQuery = {
|
datasource.filterMetricQuery({ ...baseQuery, expression: 'x * 2', metricEditorMode: MetricEditorMode.Code })
|
||||||
...baseQuery,
|
).toBeTruthy();
|
||||||
metricQueryType: MetricQueryType.Query,
|
});
|
||||||
metricEditorMode: MetricEditorMode.Code,
|
});
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not allow queries that dont have a sql expresssion', async () => {
|
describe('metric search expression queries', () => {
|
||||||
const valid = datasource.filterQuery(baseQuery);
|
beforeEach(() => {
|
||||||
expect(valid).toBeFalsy();
|
baseQuery = {
|
||||||
});
|
...baseQuery,
|
||||||
|
metricQueryType: MetricQueryType.Search,
|
||||||
|
metricEditorMode: MetricEditorMode.Code,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow queries that have a sql expresssion', async () => {
|
it('should not allow queries that dont have an expression', async () => {
|
||||||
baseQuery.sqlExpression = 'select SUM(CPUUtilization) from "AWS/EC2"';
|
const valid = datasource.filterMetricQuery(baseQuery);
|
||||||
const valid = datasource.filterQuery(baseQuery);
|
expect(valid).toBeFalsy();
|
||||||
expect(valid).toBeTruthy();
|
});
|
||||||
});
|
|
||||||
|
it('should allow queries that have an expression', async () => {
|
||||||
|
baseQuery.expression = 'SUM([a,x])';
|
||||||
|
const valid = datasource.filterMetricQuery(baseQuery);
|
||||||
|
expect(valid).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('metric query queries', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
baseQuery = {
|
||||||
|
...baseQuery,
|
||||||
|
metricQueryType: MetricQueryType.Query,
|
||||||
|
metricEditorMode: MetricEditorMode.Code,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow queries that dont have a sql expresssion', async () => {
|
||||||
|
const valid = datasource.filterMetricQuery(baseQuery);
|
||||||
|
expect(valid).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow queries that have a sql expresssion', async () => {
|
||||||
|
baseQuery.sqlExpression = 'select SUM(CPUUtilization) from "AWS/EC2"';
|
||||||
|
const valid = datasource.filterMetricQuery(baseQuery);
|
||||||
|
expect(valid).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -133,10 +133,14 @@ export class CloudWatchDatasource
|
|||||||
this.annotations = CloudWatchAnnotationSupport;
|
this.annotations = CloudWatchAnnotationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterQuery(query: CloudWatchQuery) {
|
||||||
|
return query.hide !== true || (isCloudWatchMetricsQuery(query) && query.id !== '');
|
||||||
|
}
|
||||||
|
|
||||||
query(options: DataQueryRequest<CloudWatchQuery>): Observable<DataQueryResponse> {
|
query(options: DataQueryRequest<CloudWatchQuery>): Observable<DataQueryResponse> {
|
||||||
options = cloneDeep(options);
|
options = cloneDeep(options);
|
||||||
|
|
||||||
let queries = options.targets.filter((item) => item.hide !== true);
|
let queries = options.targets.filter(this.filterQuery);
|
||||||
const { logQueries, metricsQueries, annotationQueries } = this.getTargetsByQueryMode(queries);
|
const { logQueries, metricsQueries, annotationQueries } = this.getTargetsByQueryMode(queries);
|
||||||
|
|
||||||
const dataQueryResponses: Array<Observable<DataQueryResponse>> = [];
|
const dataQueryResponses: Array<Observable<DataQueryResponse>> = [];
|
||||||
@ -245,14 +249,7 @@ export class CloudWatchDatasource
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
filterQuery(query: CloudWatchQuery): boolean {
|
filterMetricQuery(query: CloudWatchMetricsQuery): boolean {
|
||||||
if (isCloudWatchLogsQuery(query)) {
|
|
||||||
return !!query.logGroupNames?.length;
|
|
||||||
} else if (isCloudWatchAnnotationQuery(query)) {
|
|
||||||
// annotation query validity already checked in annotationSupport
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { region, metricQueryType, metricEditorMode, expression, metricName, namespace, sqlExpression, statistic } =
|
const { region, metricQueryType, metricEditorMode, expression, metricName, namespace, sqlExpression, statistic } =
|
||||||
query;
|
query;
|
||||||
if (!region) {
|
if (!region) {
|
||||||
@ -296,19 +293,21 @@ export class CloudWatchDatasource
|
|||||||
format: 'Z',
|
format: 'Z',
|
||||||
}).replace(':', '');
|
}).replace(':', '');
|
||||||
|
|
||||||
const validMetricsQueries = metricQueries.filter(this.filterQuery).map((q: CloudWatchMetricsQuery): MetricQuery => {
|
const validMetricsQueries = metricQueries
|
||||||
const migratedQuery = migrateMetricQuery(q);
|
.filter(this.filterMetricQuery)
|
||||||
const migratedAndIterpolatedQuery = this.replaceMetricQueryVars(migratedQuery, options);
|
.map((q: CloudWatchMetricsQuery): MetricQuery => {
|
||||||
|
const migratedQuery = migrateMetricQuery(q);
|
||||||
|
const migratedAndIterpolatedQuery = this.replaceMetricQueryVars(migratedQuery, options);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timezoneUTCOffset,
|
timezoneUTCOffset,
|
||||||
intervalMs: options.intervalMs,
|
intervalMs: options.intervalMs,
|
||||||
maxDataPoints: options.maxDataPoints,
|
maxDataPoints: options.maxDataPoints,
|
||||||
...migratedAndIterpolatedQuery,
|
...migratedAndIterpolatedQuery,
|
||||||
type: 'timeSeriesQuery',
|
type: 'timeSeriesQuery',
|
||||||
datasource: this.getRef(),
|
datasource: this.getRef(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// No valid targets, return the empty result to save a round trip.
|
// No valid targets, return the empty result to save a round trip.
|
||||||
if (isEmpty(validMetricsQueries)) {
|
if (isEmpty(validMetricsQueries)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user