Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RAC] Update alert documents in lifecycle rule type helper #101598

Merged
merged 8 commits into from
Jun 16, 2021
6 changes: 2 additions & 4 deletions x-pack/plugins/apm/server/lib/services/get_service_alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { ALERT_UUID } from '@kbn/rule-data-utils/target/technical_field_names';
import { EVENT_KIND } from '@kbn/rule-data-utils/target/technical_field_names';
import { RuleDataClient } from '../../../../rule_registry/server';
import {
SERVICE_NAME,
Expand Down Expand Up @@ -36,6 +36,7 @@ export async function getServiceAlerts({
...rangeQuery(start, end),
...environmentQuery(environment),
{ term: { [SERVICE_NAME]: serviceName } },
{ term: { [EVENT_KIND]: 'signal' } },
],
should: [
{
Expand Down Expand Up @@ -64,9 +65,6 @@ export async function getServiceAlerts({
},
size: 100,
fields: ['*'],
collapse: {
field: ALERT_UUID,
},
sort: {
'@timestamp': 'desc',
},
Expand Down
12 changes: 7 additions & 5 deletions x-pack/plugins/observability/server/lib/rules/get_top_alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { ALERT_UUID, TIMESTAMP } from '@kbn/rule-data-utils/target/technical_field_names';
import { EVENT_KIND, TIMESTAMP } from '@kbn/rule-data-utils/target/technical_field_names';
import { RuleDataClient } from '../../../../rule_registry/server';
import type { AlertStatus } from '../../../common/typings';
import { kqlQuery, rangeQuery, alertStatusQuery } from '../../utils/queries';
Expand All @@ -28,13 +28,15 @@ export async function getTopAlerts({
body: {
query: {
bool: {
filter: [...rangeQuery(start, end), ...kqlQuery(kuery), ...alertStatusQuery(status)],
filter: [
...rangeQuery(start, end),
...kqlQuery(kuery),
...alertStatusQuery(status),
{ term: { [EVENT_KIND]: 'signal' } },
],
},
},
fields: ['*'],
collapse: {
field: ALERT_UUID,
},
size,
sort: {
[TIMESTAMP]: 'desc',
Expand Down
3 changes: 0 additions & 3 deletions x-pack/plugins/rule_registry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ const response = await ruleDataClient.getReader().search({
},
size: 100,
fields: ['*'],
collapse: {
field: ALERT_UUID,
},
sort: {
'@timestamp': 'desc',
},
Expand Down
37 changes: 28 additions & 9 deletions x-pack/plugins/rule_registry/server/rule_data_client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { isEmpty } from 'lodash';
import type { estypes } from '@elastic/elasticsearch';
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
import { IndexPatternsFetcher } from '../../../../../src/plugins/data/server';
Expand Down Expand Up @@ -44,15 +46,26 @@ export class RuleDataClient implements IRuleDataClient {
const clusterClient = await this.getClusterClient();
const indexPatternsFetcher = new IndexPatternsFetcher(clusterClient);

const fields = await indexPatternsFetcher.getFieldsForWildcard({
pattern: index,
});

return {
fields,
timeFieldName: '@timestamp',
title: index,
};
try {
const fields = await indexPatternsFetcher.getFieldsForWildcard({
pattern: index,
});

return {
fields,
timeFieldName: '@timestamp',
title: index,
};
} catch (err) {
if (err.output?.payload?.code === 'no_matching_indices') {
return {
fields: [],
timeFieldName: '@timestamp',
title: index,
};
}
throw err;
}
},
};
}
Expand Down Expand Up @@ -127,6 +140,12 @@ export class RuleDataClient implements IRuleDataClient {

const mappings: estypes.MappingTypeMapping = simulateResponse.template.mappings;

if (isEmpty(mappings)) {
throw new Error(
'No mappings would be generated for this index, possibly due to failed/misconfigured bootstrapping'
);
}

await clusterClient.indices.putMapping({ index: `${alias}*`, body: mappings });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const createLifecycleRuleTypeFactory: CreateLifecycleRuleTypeFactory = ({
...alertData,
...ruleExecutorData,
[TIMESTAMP]: timestamp,
[EVENT_KIND]: 'state',
[EVENT_KIND]: 'event',
[ALERT_ID]: alertId,
};

Expand Down Expand Up @@ -221,8 +221,29 @@ export const createLifecycleRuleTypeFactory: CreateLifecycleRuleTypeFactory = ({
});

if (eventsToIndex.length) {
const alertEvents: Map<string, ParsedTechnicalFields> = new Map();

for (const event of eventsToIndex) {
const uuid = event[ALERT_UUID]!;
let storedEvent = alertEvents.get(uuid);
if (!storedEvent) {
storedEvent = event;
}
alertEvents.set(uuid, {
...storedEvent,
[EVENT_KIND]: 'signal',
});
}

await ruleDataClient.getWriter().bulk({
body: eventsToIndex.flatMap((event) => [{ index: {} }, event]),
body: eventsToIndex
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clever, but it would be cleverer with an explanation of what's going on and a unit test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OKAY OKAY I GET IT.

.flatMap((event) => [{ index: {} }, event])
.concat(
Array.from(alertEvents.values()).flatMap((event) => [
{ index: { _id: event[ALERT_UUID]! } },
event,
])
),
});
}

Expand Down
23 changes: 16 additions & 7 deletions x-pack/test/apm_api_integration/tests/alerts/rule_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import expect from '@kbn/expect';
import { merge, omit } from 'lodash';
import { format } from 'url';
import { EVENT_KIND } from '../../../../../packages/kbn-rule-data-utils/src/technical_field_names';
import { FtrProviderContext } from '../../common/ftr_provider_context';
import { registry } from '../../common/registry';

Expand Down Expand Up @@ -259,7 +260,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
index: ALERTS_INDEX_TARGET,
body: {
query: {
match_all: {},
term: {
[EVENT_KIND]: 'signal',
},
},
size: 1,
sort: {
Expand All @@ -286,7 +289,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
index: ALERTS_INDEX_TARGET,
body: {
query: {
match_all: {},
term: {
[EVENT_KIND]: 'signal',
},
},
size: 1,
sort: {
Expand All @@ -313,7 +318,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
index: ALERTS_INDEX_TARGET,
body: {
query: {
match_all: {},
term: {
[EVENT_KIND]: 'signal',
},
},
size: 1,
sort: {
Expand Down Expand Up @@ -346,7 +353,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
"open",
],
"event.kind": Array [
"state",
"signal",
],
"kibana.rac.alert.duration.us": Array [
0,
Expand Down Expand Up @@ -416,7 +423,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
"open",
],
"event.kind": Array [
"state",
"signal",
],
"kibana.rac.alert.duration.us": Array [
0,
Expand Down Expand Up @@ -486,7 +493,9 @@ export default function ApiTest({ getService }: FtrProviderContext) {
index: ALERTS_INDEX_TARGET,
body: {
query: {
match_all: {},
term: {
[EVENT_KIND]: 'signal',
},
},
size: 1,
sort: {
Expand Down Expand Up @@ -521,7 +530,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
"close",
],
"event.kind": Array [
"state",
"signal",
],
"kibana.rac.alert.evaluation.threshold": Array [
30,
Expand Down