[Metrics UI] Require filterQuery to be ES JSON (#64937)
This commit is contained in:
parent
551bb077aa
commit
add56be7d6
|
@ -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>
|
||||
|
|
26
x-pack/plugins/infra/server/lib/alerting/common/utils.ts
Normal file
26
x-pack/plugins/infra/server/lib/alerting/common/utils.ts
Normal 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;
|
||||
}
|
||||
};
|
|
@ -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' }
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
);
|
||||
|
|
|
@ -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()),
|
||||
},
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue