Skip to content

Commit 312d24b

Browse files
[Metrics UI] Require filterQuery to be ES JSON (#64937) (#65757)
Co-authored-by: Elastic Machine <[email protected]>
1 parent c3890b6 commit 312d24b

File tree

6 files changed

+41
-46
lines changed

6 files changed

+41
-46
lines changed

x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ export const Expressions: React.FC<Props> = props => {
251251
context={alertsContext}
252252
derivedIndexPattern={derivedIndexPattern}
253253
source={source}
254-
filterQuery={alertParams.filterQuery}
254+
filterQuery={alertParams.filterQueryText}
255255
groupBy={alertParams.groupBy}
256256
/>
257257
</ExpressionRow>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
import { isEmpty } from 'lodash';
7+
import { schema } from '@kbn/config-schema';
8+
9+
export const oneOfLiterals = (arrayOfLiterals: Readonly<string[]>) =>
10+
schema.string({
11+
validate: value =>
12+
arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`,
13+
});
14+
15+
export const validateIsStringElasticsearchJSONFilter = (value: string) => {
16+
const errorMessage = 'filterQuery must be a valid Elasticsearch filter expressed in JSON';
17+
try {
18+
const parsedValue = JSON.parse(value);
19+
if (!isEmpty(parsedValue.bool)) {
20+
return undefined;
21+
}
22+
return errorMessage;
23+
} catch (e) {
24+
return errorMessage;
25+
}
26+
};

x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,13 @@ import {
1111
createInventoryMetricThresholdExecutor,
1212
FIRED_ACTIONS,
1313
} from './inventory_metric_threshold_executor';
14-
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from './types';
14+
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types';
1515
import { InfraBackendLibs } from '../../infra_types';
16+
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
1617

1718
const condition = schema.object({
1819
threshold: schema.arrayOf(schema.number()),
19-
comparator: schema.oneOf([
20-
schema.literal('>'),
21-
schema.literal('<'),
22-
schema.literal('>='),
23-
schema.literal('<='),
24-
schema.literal('between'),
25-
schema.literal('outside'),
26-
]),
20+
comparator: oneOfLiterals(Object.values(Comparator)),
2721
timeUnit: schema.string(),
2822
timeSize: schema.number(),
2923
metric: schema.string(),
@@ -37,7 +31,9 @@ export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs
3731
{
3832
criteria: schema.arrayOf(condition),
3933
nodeType: schema.string(),
40-
filterQuery: schema.maybe(schema.string()),
34+
filterQuery: schema.maybe(
35+
schema.string({ validate: validateIsStringElasticsearchJSONFilter })
36+
),
4137
sourceId: schema.string(),
4238
},
4339
{ unknowns: 'allow' }

x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,7 @@ const getParsedFilterQuery: (
5858
filterQuery: string | undefined
5959
) => Record<string, any> | Array<Record<string, any>> = filterQuery => {
6060
if (!filterQuery) return {};
61-
try {
62-
return JSON.parse(filterQuery).bool;
63-
} catch (e) {
64-
return [
65-
{
66-
query_string: {
67-
query: filterQuery,
68-
analyze_wildcard: true,
69-
},
70-
},
71-
];
72-
}
61+
return JSON.parse(filterQuery).bool;
7362
};
7463

7564
export const getElasticsearchMetricQuery = (
@@ -265,8 +254,8 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: s
265254
const currentValues = await getMetric(
266255
services,
267256
criterion,
268-
config.fields.timestamp,
269257
config.metricAlias,
258+
config.fields.timestamp,
270259
groupBy,
271260
filterQuery
272261
);

x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@ import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metric
1111
import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor';
1212
import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types';
1313
import { InfraBackendLibs } from '../../infra_types';
14-
15-
const oneOfLiterals = (arrayOfLiterals: Readonly<string[]>) =>
16-
schema.string({
17-
validate: value =>
18-
arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`,
19-
});
14+
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
2015

2116
export function registerMetricThresholdAlertType(libs: InfraBackendLibs) {
2217
const baseCriterion = {
@@ -68,7 +63,11 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs) {
6863
{
6964
criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])),
7065
groupBy: schema.maybe(schema.string()),
71-
filterQuery: schema.maybe(schema.string()),
66+
filterQuery: schema.maybe(
67+
schema.string({
68+
validate: validateIsStringElasticsearchJSONFilter,
69+
})
70+
),
7271
sourceId: schema.string(),
7372
alertOnNoData: schema.maybe(schema.boolean()),
7473
},

x-pack/test/api_integration/apis/infra/metrics_alerting.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,6 @@ export default function({ getService }: FtrProviderContext) {
5757
expect(result.hits).to.be.ok();
5858
expect(result.aggregations).to.be.ok();
5959
});
60-
it('should work with a filterQuery in KQL format', async () => {
61-
const searchBody = getElasticsearchMetricQuery(
62-
getSearchParams('avg'),
63-
'@timestamp',
64-
undefined,
65-
'"agent.hostname":"foo"'
66-
);
67-
const result = await client.search({
68-
index,
69-
body: searchBody,
70-
});
71-
expect(result.error).to.not.be.ok();
72-
expect(result.hits).to.be.ok();
73-
expect(result.aggregations).to.be.ok();
74-
});
7560
});
7661
describe('querying with a groupBy parameter', () => {
7762
for (const aggType of aggs) {

0 commit comments

Comments
 (0)