[Metrics UI] Require filterQuery to be ES JSON (#64937)

This commit is contained in:
Zacqary Adam Xeper 2020-05-05 10:33:41 -05:00 committed by GitHub
parent 551bb077aa
commit add56be7d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 46 deletions

View file

@ -251,7 +251,7 @@ export const Expressions: React.FC<Props> = props => {
context={alertsContext}
derivedIndexPattern={derivedIndexPattern}
source={source}
filterQuery={alertParams.filterQuery}
filterQuery={alertParams.filterQueryText}
groupBy={alertParams.groupBy}
/>
</ExpressionRow>

View file

@ -0,0 +1,26 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { isEmpty } from 'lodash';
import { schema } from '@kbn/config-schema';
export const oneOfLiterals = (arrayOfLiterals: Readonly<string[]>) =>
schema.string({
validate: value =>
arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`,
});
export const validateIsStringElasticsearchJSONFilter = (value: string) => {
const errorMessage = 'filterQuery must be a valid Elasticsearch filter expressed in JSON';
try {
const parsedValue = JSON.parse(value);
if (!isEmpty(parsedValue.bool)) {
return undefined;
}
return errorMessage;
} catch (e) {
return errorMessage;
}
};

View file

@ -11,19 +11,13 @@ import {
createInventoryMetricThresholdExecutor,
FIRED_ACTIONS,
} from './inventory_metric_threshold_executor';
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from './types';
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types';
import { InfraBackendLibs } from '../../infra_types';
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
const condition = schema.object({
threshold: schema.arrayOf(schema.number()),
comparator: schema.oneOf([
schema.literal('>'),
schema.literal('<'),
schema.literal('>='),
schema.literal('<='),
schema.literal('between'),
schema.literal('outside'),
]),
comparator: oneOfLiterals(Object.values(Comparator)),
timeUnit: schema.string(),
timeSize: schema.number(),
metric: schema.string(),
@ -37,7 +31,9 @@ export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs
{
criteria: schema.arrayOf(condition),
nodeType: schema.string(),
filterQuery: schema.maybe(schema.string()),
filterQuery: schema.maybe(
schema.string({ validate: validateIsStringElasticsearchJSONFilter })
),
sourceId: schema.string(),
},
{ unknowns: 'allow' }

View file

@ -58,18 +58,7 @@ const getParsedFilterQuery: (
filterQuery: string | undefined
) => Record<string, any> | Array<Record<string, any>> = filterQuery => {
if (!filterQuery) return {};
try {
return JSON.parse(filterQuery).bool;
} catch (e) {
return [
{
query_string: {
query: filterQuery,
analyze_wildcard: true,
},
},
];
}
return JSON.parse(filterQuery).bool;
};
export const getElasticsearchMetricQuery = (
@ -265,8 +254,8 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: s
const currentValues = await getMetric(
services,
criterion,
config.fields.timestamp,
config.metricAlias,
config.fields.timestamp,
groupBy,
filterQuery
);

View file

@ -11,12 +11,7 @@ import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metric
import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor';
import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types';
import { InfraBackendLibs } from '../../infra_types';
const oneOfLiterals = (arrayOfLiterals: Readonly<string[]>) =>
schema.string({
validate: value =>
arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`,
});
import { oneOfLiterals, validateIsStringElasticsearchJSONFilter } from '../common/utils';
export function registerMetricThresholdAlertType(libs: InfraBackendLibs) {
const baseCriterion = {
@ -68,7 +63,11 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs) {
{
criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])),
groupBy: schema.maybe(schema.string()),
filterQuery: schema.maybe(schema.string()),
filterQuery: schema.maybe(
schema.string({
validate: validateIsStringElasticsearchJSONFilter,
})
),
sourceId: schema.string(),
alertOnNoData: schema.maybe(schema.boolean()),
},

View file

@ -57,21 +57,6 @@ export default function({ getService }: FtrProviderContext) {
expect(result.hits).to.be.ok();
expect(result.aggregations).to.be.ok();
});
it('should work with a filterQuery in KQL format', async () => {
const searchBody = getElasticsearchMetricQuery(
getSearchParams('avg'),
'@timestamp',
undefined,
'"agent.hostname":"foo"'
);
const result = await client.search({
index,
body: searchBody,
});
expect(result.error).to.not.be.ok();
expect(result.hits).to.be.ok();
expect(result.aggregations).to.be.ok();
});
});
describe('querying with a groupBy parameter', () => {
for (const aggType of aggs) {