mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Response Ops][Alerting] Removing top level rule fields passed into executors (#144270)
* Removing top level fields passed into executors * Updating stack rules * Updating other rules * Fixing types * Fixing functional test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
cb2f4ba9d9
commit
3b59a90671
32 changed files with 123 additions and 158 deletions
|
@ -120,13 +120,9 @@ This is the primary function for a rule type. Whenever the rule needs to execute
|
|||
|previousStartedAt|The previous date and time the rule type started a successful execution.|
|
||||
|params|Parameters for the execution. This is where the parameters you require will be passed in. (e.g. threshold). Use rule type validation to ensure values are set before execution.|
|
||||
|state|State returned from the previous execution. This is the rule level state. What the executor returns will be serialized and provided here at the next execution.|
|
||||
|alertId|The id of this rule.|
|
||||
|spaceId|The id of the space of this rule.|
|
||||
|namespace|The namespace of the space of this rule. This is the same as `spaceId`, unless `spaceId === "default"`, in which case the namespace = `undefined`.|
|
||||
|name|The name of this rule. This will eventually be removed in favor of `rule.name`.|
|
||||
|tags|The tags associated with this rule. This will eventually be removed in favor of `rule.tags`.|
|
||||
|createdBy|The user ID of the user that created this rule. This will eventually be removed in favor of `rule.createdBy`.|
|
||||
|updatedBy|The user ID of the user that last updated this rule. This will eventually be removed in favor of `rule.updatedBy`.|
|
||||
|rule.id|The id of this rule.|
|
||||
|rule.name|The name of this rule.|
|
||||
|rule.tags|The tags associated with this rule.|
|
||||
|rule.consumer|The consumer of this rule type.|
|
||||
|
|
|
@ -124,6 +124,7 @@ export type ResolvedSanitizedRule<Params extends RuleTypeParams = never> = Sanit
|
|||
|
||||
export type SanitizedRuleConfig = Pick<
|
||||
SanitizedRule,
|
||||
| 'id'
|
||||
| 'name'
|
||||
| 'tags'
|
||||
| 'consumer'
|
||||
|
|
|
@ -231,11 +231,8 @@ describe('Task Runner', () => {
|
|||
expect(call.startedAt).toStrictEqual(new Date(DATE_1970));
|
||||
expect(call.previousStartedAt).toStrictEqual(new Date(DATE_1970_5_MIN));
|
||||
expect(call.state).toEqual({});
|
||||
expect(call.name).toBe(RULE_NAME);
|
||||
expect(call.tags).toEqual(['rule-', '-tags']);
|
||||
expect(call.createdBy).toBe('rule-creator');
|
||||
expect(call.updatedBy).toBe('rule-updater');
|
||||
expect(call.rule).not.toBe(null);
|
||||
expect(call.rule.id).toBe('1');
|
||||
expect(call.rule.name).toBe(RULE_NAME);
|
||||
expect(call.rule.tags).toEqual(['rule-', '-tags']);
|
||||
expect(call.rule.consumer).toBe('bar');
|
||||
|
@ -2059,11 +2056,8 @@ describe('Task Runner', () => {
|
|||
expect(call.startedAt).toEqual(new Date(DATE_1970));
|
||||
expect(call.previousStartedAt).toEqual(new Date(DATE_1970_5_MIN));
|
||||
expect(call.state).toEqual({});
|
||||
expect(call.name).toBe(RULE_NAME);
|
||||
expect(call.tags).toEqual(['rule-', '-tags']);
|
||||
expect(call.createdBy).toBe('rule-creator');
|
||||
expect(call.updatedBy).toBe('rule-updater');
|
||||
expect(call.rule).not.toBe(null);
|
||||
expect(call.rule.id).toBe('1');
|
||||
expect(call.rule.name).toBe(RULE_NAME);
|
||||
expect(call.rule.tags).toEqual(['rule-', '-tags']);
|
||||
expect(call.rule.consumer).toBe('bar');
|
||||
|
|
|
@ -355,7 +355,6 @@ export class TaskRunner<
|
|||
|
||||
updatedState = await this.context.executionContext.withContext(ctx, () =>
|
||||
this.ruleType.executor({
|
||||
alertId: ruleId,
|
||||
executionId: this.executionId,
|
||||
services: {
|
||||
savedObjectsClient,
|
||||
|
@ -372,11 +371,8 @@ export class TaskRunner<
|
|||
previousStartedAt: previousStartedAt ? new Date(previousStartedAt) : null,
|
||||
spaceId,
|
||||
namespace,
|
||||
name,
|
||||
tags,
|
||||
createdBy,
|
||||
updatedBy,
|
||||
rule: {
|
||||
id: ruleId,
|
||||
name,
|
||||
tags,
|
||||
consumer,
|
||||
|
|
|
@ -90,11 +90,8 @@ export interface RuleExecutorOptions<
|
|||
InstanceContext extends AlertInstanceContext = never,
|
||||
ActionGroupIds extends string = never
|
||||
> {
|
||||
alertId: string; // Is actually the Rule ID. Will be updated as part of https://github.com/elastic/kibana/issues/100115
|
||||
createdBy: string | null;
|
||||
executionId: string;
|
||||
logger: Logger;
|
||||
name: string;
|
||||
params: Params;
|
||||
previousStartedAt: Date | null;
|
||||
rule: SanitizedRuleConfig;
|
||||
|
@ -102,8 +99,6 @@ export interface RuleExecutorOptions<
|
|||
spaceId: string;
|
||||
startedAt: Date;
|
||||
state: State;
|
||||
tags: string[];
|
||||
updatedBy: string | null;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,14 +66,17 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) =
|
|||
InventoryMetricThresholdAlertState,
|
||||
InventoryMetricThresholdAlertContext,
|
||||
InventoryMetricThresholdAllowedActionGroups
|
||||
>(async ({ services, params, alertId, executionId, spaceId, startedAt }) => {
|
||||
>(async ({ services, params, executionId, spaceId, startedAt, rule: { id: ruleId } }) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
const { criteria, filterQuery, sourceId = 'default', nodeType, alertOnNoData } = params;
|
||||
|
||||
if (criteria.length === 0) throw new Error('Cannot execute an alert with 0 conditions');
|
||||
|
||||
const logger = createScopedLogger(libs.logger, 'inventoryRule', { alertId, executionId });
|
||||
const logger = createScopedLogger(libs.logger, 'inventoryRule', {
|
||||
alertId: ruleId,
|
||||
executionId,
|
||||
});
|
||||
|
||||
const esClient = services.scopedClusterClient.asCurrentUser;
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ const logger = {
|
|||
} as unknown as Logger;
|
||||
|
||||
const mockOptions = {
|
||||
alertId: '',
|
||||
executionId: '',
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: null,
|
||||
|
@ -89,11 +88,8 @@ const mockOptions = {
|
|||
},
|
||||
},
|
||||
spaceId: '',
|
||||
name: '',
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: '',
|
||||
name: '',
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
|
|
@ -74,12 +74,23 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs) =>
|
|||
>(async function (options) {
|
||||
const startTime = Date.now();
|
||||
|
||||
const { services, params, state, startedAt, alertId, executionId, spaceId } = options;
|
||||
const {
|
||||
services,
|
||||
params,
|
||||
state,
|
||||
startedAt,
|
||||
executionId,
|
||||
spaceId,
|
||||
rule: { id: ruleId },
|
||||
} = options;
|
||||
|
||||
const { criteria } = params;
|
||||
if (criteria.length === 0) throw new Error('Cannot execute an alert with 0 conditions');
|
||||
|
||||
const logger = createScopedLogger(libs.logger, 'metricThresholdRule', { alertId, executionId });
|
||||
const logger = createScopedLogger(libs.logger, 'metricThresholdRule', {
|
||||
alertId: ruleId,
|
||||
executionId,
|
||||
});
|
||||
|
||||
const { alertWithLifecycle, savedObjectsClient, getAlertUuid } = services;
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ export function registerAnomalyDetectionAlertType({
|
|||
minimumLicenseRequired: MINIMUM_FULL_LICENSE,
|
||||
isExportable: true,
|
||||
doesSetRecoveryContext: true,
|
||||
async executor({ services, params, alertId, state, previousStartedAt, startedAt, name }) {
|
||||
async executor({ services, params }) {
|
||||
const fakeRequest = {} as KibanaRequest;
|
||||
const { execute } = mlSharedServices.alertingServiceProvider(
|
||||
services.savedObjectsClient,
|
||||
|
|
|
@ -142,7 +142,10 @@ export function registerJobsMonitoringRuleType({
|
|||
isExportable: true,
|
||||
doesSetRecoveryContext: true,
|
||||
async executor(options) {
|
||||
const { services, name } = options;
|
||||
const {
|
||||
services,
|
||||
rule: { name },
|
||||
} = options;
|
||||
|
||||
const fakeRequest = {} as KibanaRequest;
|
||||
const { getTestsResults } = mlServicesProviders.jobsHealthServiceProvider(
|
||||
|
|
|
@ -89,12 +89,6 @@ export type LifecycleRuleExecutor<
|
|||
>
|
||||
) => Promise<State | void>;
|
||||
|
||||
/*
|
||||
`alertId` will at some point be renamed to `ruleId` as that more
|
||||
accurately describes the meaning of the variable.
|
||||
See https://github.com/elastic/kibana/issues/100115
|
||||
*/
|
||||
|
||||
const trackedAlertStateRt = rt.type({
|
||||
alertId: rt.string,
|
||||
alertUuid: rt.string,
|
||||
|
@ -269,7 +263,7 @@ export const createLifecycleExecutor =
|
|||
[ALERT_WORKFLOW_STATUS]: alertData?.fields[ALERT_WORKFLOW_STATUS] ?? 'open',
|
||||
[EVENT_KIND]: 'signal',
|
||||
[EVENT_ACTION]: isNew ? 'open' : isActive ? 'active' : 'close',
|
||||
[TAGS]: options.tags,
|
||||
[TAGS]: options.rule.tags,
|
||||
[VERSION]: ruleDataClient.kibanaVersion,
|
||||
...(isRecovered ? { [ALERT_END]: commonRuleFields[TIMESTAMP] } : {}),
|
||||
};
|
||||
|
|
|
@ -95,15 +95,13 @@ function createRule(shouldWriteAlerts: boolean = true) {
|
|||
scheduleActions.mockClear();
|
||||
|
||||
state = ((await type.executor({
|
||||
alertId: 'alertId',
|
||||
createdBy: 'createdBy',
|
||||
executionId: 'b33f65d7-6e8b-4aae-8d20-c93613dec9f9',
|
||||
logger: loggerMock.create(),
|
||||
name: 'name',
|
||||
namespace: 'namespace',
|
||||
params: {},
|
||||
previousStartedAt,
|
||||
rule: {
|
||||
id: 'alertId',
|
||||
actions: [],
|
||||
consumer: 'consumer',
|
||||
createdAt,
|
||||
|
@ -135,8 +133,6 @@ function createRule(shouldWriteAlerts: boolean = true) {
|
|||
spaceId: 'spaceId',
|
||||
startedAt,
|
||||
state,
|
||||
tags: ['tags'],
|
||||
updatedBy: 'updatedBy',
|
||||
})) ?? {}) as Record<string, any>;
|
||||
|
||||
previousStartedAt = startedAt;
|
||||
|
|
|
@ -31,9 +31,9 @@ export const getCommonAlertFields = (
|
|||
[ALERT_RULE_NAME]: options.rule.name,
|
||||
[ALERT_RULE_PRODUCER]: options.rule.producer,
|
||||
[ALERT_RULE_TYPE_ID]: options.rule.ruleTypeId,
|
||||
[ALERT_RULE_UUID]: options.alertId,
|
||||
[ALERT_RULE_UUID]: options.rule.id,
|
||||
[SPACE_IDS]: [options.spaceId],
|
||||
[ALERT_RULE_TAGS]: options.tags,
|
||||
[ALERT_RULE_TAGS]: options.rule.tags,
|
||||
[TIMESTAMP]: options.startedAt.toISOString(),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -47,15 +47,13 @@ export const createDefaultAlertExecutorOptions = <
|
|||
updatedAt?: Date;
|
||||
shouldWriteAlerts?: boolean;
|
||||
}): RuleExecutorOptions<Params, State, InstanceState, InstanceContext, ActionGroupIds> => ({
|
||||
alertId,
|
||||
createdBy: 'CREATED_BY',
|
||||
startedAt,
|
||||
name: ruleName,
|
||||
rule: {
|
||||
id: alertId,
|
||||
updatedBy: null,
|
||||
tags: [],
|
||||
name: ruleName,
|
||||
createdBy: null,
|
||||
createdBy: 'CREATED_BY',
|
||||
actions: [],
|
||||
enabled: true,
|
||||
consumer: 'CONSUMER',
|
||||
|
@ -68,7 +66,6 @@ export const createDefaultAlertExecutorOptions = <
|
|||
ruleTypeId: 'RULE_TYPE_ID',
|
||||
ruleTypeName: 'RULE_TYPE_NAME',
|
||||
},
|
||||
tags: [],
|
||||
params,
|
||||
spaceId: 'SPACE_ID',
|
||||
services: {
|
||||
|
@ -82,7 +79,6 @@ export const createDefaultAlertExecutorOptions = <
|
|||
searchSourceClient: searchSourceCommonMock,
|
||||
},
|
||||
state,
|
||||
updatedBy: null,
|
||||
previousStartedAt: null,
|
||||
namespace: undefined,
|
||||
executionId: 'b33f65d7-6e8b-4aae-8d20-c93613deb33f',
|
||||
|
|
|
@ -39,19 +39,15 @@ describe('legacyRules_notification_alert_type', () => {
|
|||
logger = loggingSystemMock.createLogger();
|
||||
|
||||
payload = {
|
||||
alertId: '1111',
|
||||
executionId: 'b33f65d7-b33f-4aae-8d20-c93613dec9f9',
|
||||
services: alertServices,
|
||||
params: { ruleAlertId: '2222' },
|
||||
state: {},
|
||||
spaceId: '',
|
||||
name: 'name',
|
||||
tags: [],
|
||||
startedAt: new Date('2019-12-14T16:40:33.400Z'),
|
||||
previousStartedAt: new Date('2019-12-13T16:40:33.400Z'),
|
||||
createdBy: 'elastic',
|
||||
updatedBy: 'elastic',
|
||||
rule: {
|
||||
id: '1111',
|
||||
name: 'name',
|
||||
tags: [],
|
||||
consumer: 'foo',
|
||||
|
|
|
@ -50,7 +50,14 @@ export const legacyRulesNotificationAlertType = ({
|
|||
},
|
||||
minimumLicenseRequired: 'basic',
|
||||
isExportable: false,
|
||||
async executor({ startedAt, previousStartedAt, alertId, services, params, spaceId }) {
|
||||
async executor({
|
||||
startedAt,
|
||||
previousStartedAt,
|
||||
rule: { id: ruleId },
|
||||
services,
|
||||
params,
|
||||
spaceId,
|
||||
}) {
|
||||
const ruleAlertSavedObject = await services.savedObjectsClient.get<AlertAttributes>(
|
||||
'alert',
|
||||
params.ruleAlertId
|
||||
|
@ -60,7 +67,7 @@ export const legacyRulesNotificationAlertType = ({
|
|||
logger.error(
|
||||
[
|
||||
`Security Solution notification (Legacy) saved object for alert ${params.ruleAlertId} was not found with`,
|
||||
`id: "${alertId}".`,
|
||||
`id: "${ruleId}".`,
|
||||
`space id: "${spaceId}"`,
|
||||
'This indicates a dangling (Legacy) notification alert.',
|
||||
'You should delete this rule through "Kibana UI -> Stack Management -> Rules and Connectors" to remove this error message.',
|
||||
|
@ -118,7 +125,7 @@ export const legacyRulesNotificationAlertType = ({
|
|||
);
|
||||
|
||||
if (signalsCount !== 0) {
|
||||
const alertInstance = services.alertFactory.create(alertId);
|
||||
const alertInstance = services.alertFactory.create(ruleId);
|
||||
scheduleNotificationActions({
|
||||
alertInstance,
|
||||
signalsCount,
|
||||
|
|
|
@ -217,6 +217,7 @@ export const previewRulesRoute = async (
|
|||
|
||||
const rule = {
|
||||
...internalRule,
|
||||
id: previewId,
|
||||
createdAt: new Date(),
|
||||
createdBy: username ?? 'preview-created-by',
|
||||
producer: 'preview-producer',
|
||||
|
@ -232,10 +233,7 @@ export const previewRulesRoute = async (
|
|||
invocationStartTime = moment();
|
||||
|
||||
statePreview = (await executor({
|
||||
alertId: previewId,
|
||||
createdBy: rule.createdBy,
|
||||
executionId: uuid.v4(),
|
||||
name: rule.name,
|
||||
params,
|
||||
previousStartedAt,
|
||||
rule,
|
||||
|
@ -257,8 +255,6 @@ export const previewRulesRoute = async (
|
|||
spaceId,
|
||||
startedAt: startedAt.toDate(),
|
||||
state: statePreview,
|
||||
tags: [],
|
||||
updatedBy: rule.updatedBy,
|
||||
logger,
|
||||
})) as TState;
|
||||
|
||||
|
|
|
@ -195,6 +195,7 @@ export const getThreatRuleParams = (): ThreatRuleParams => {
|
|||
};
|
||||
|
||||
export const getRuleConfigMock = (type: string = 'rule-type'): SanitizedRuleConfig => ({
|
||||
id: sampleRuleGuid,
|
||||
actions: [],
|
||||
enabled: true,
|
||||
name: 'rule-name',
|
||||
|
|
|
@ -62,7 +62,6 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
agent.setTransactionName(`${options.rule.ruleTypeId} execution`);
|
||||
return withSecuritySpan('securityRuleTypeExecutor', async () => {
|
||||
const {
|
||||
alertId,
|
||||
executionId,
|
||||
params,
|
||||
previousStartedAt,
|
||||
|
@ -70,7 +69,6 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
services,
|
||||
spaceId,
|
||||
state,
|
||||
updatedBy: updatedByUser,
|
||||
rule,
|
||||
} = options;
|
||||
let runState = state;
|
||||
|
@ -99,7 +97,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
savedObjectsClient,
|
||||
context: {
|
||||
executionId,
|
||||
ruleId: alertId,
|
||||
ruleId: rule.id,
|
||||
ruleUuid: params.ruleId,
|
||||
ruleName: rule.name,
|
||||
ruleType: rule.ruleTypeId,
|
||||
|
@ -110,7 +108,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
const completeRule = {
|
||||
ruleConfig: rule,
|
||||
ruleParams: params,
|
||||
alertId,
|
||||
alertId: rule.id,
|
||||
};
|
||||
|
||||
const {
|
||||
|
@ -135,7 +133,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
const notificationRuleParams: NotificationRuleTypeParams = {
|
||||
...params,
|
||||
name,
|
||||
id: alertId,
|
||||
id: rule.id,
|
||||
};
|
||||
|
||||
const primaryTimestamp = timestampOverride ?? TIMESTAMP;
|
||||
|
@ -270,7 +268,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
try {
|
||||
const { listClient, exceptionsClient } = getListClient({
|
||||
esClient: services.scopedClusterClient.asCurrentUser,
|
||||
updatedByUser,
|
||||
updatedByUser: rule.updatedBy,
|
||||
spaceId,
|
||||
lists,
|
||||
savedObjectClient: options.services.savedObjectsClient,
|
||||
|
@ -393,7 +391,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
const resultsLink = getNotificationResultsLink({
|
||||
from: fromInMs,
|
||||
to: toInMs,
|
||||
id: alertId,
|
||||
id: rule.id,
|
||||
kibanaSiemAppUrl: (meta as { kibana_siem_app_url?: string } | undefined)
|
||||
?.kibana_siem_app_url,
|
||||
});
|
||||
|
@ -403,10 +401,10 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
if (completeRule.ruleConfig.throttle != null) {
|
||||
// NOTE: Since this is throttled we have to call it even on an error condition, otherwise it will "reset" the throttle and fire early
|
||||
await scheduleThrottledNotificationActions({
|
||||
alertInstance: services.alertFactory.create(alertId),
|
||||
alertInstance: services.alertFactory.create(rule.id),
|
||||
throttle: completeRule.ruleConfig.throttle ?? '',
|
||||
startedAt,
|
||||
id: alertId,
|
||||
id: rule.id,
|
||||
kibanaSiemAppUrl: (meta as { kibana_siem_app_url?: string } | undefined)
|
||||
?.kibana_siem_app_url,
|
||||
outputIndex: ruleDataClient.indexNameWithNamespace(spaceId),
|
||||
|
@ -417,7 +415,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
logger,
|
||||
});
|
||||
} else if (createdSignalsCount) {
|
||||
const alertInstance = services.alertFactory.create(alertId);
|
||||
const alertInstance = services.alertFactory.create(rule.id);
|
||||
scheduleNotificationActions({
|
||||
alertInstance,
|
||||
signalsCount: createdSignalsCount,
|
||||
|
@ -482,7 +480,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
|||
// NOTE: Since this is throttled we have to call it even on an error condition, otherwise it will "reset" the throttle and fire early
|
||||
if (actions.length && completeRule.ruleConfig.throttle != null) {
|
||||
await scheduleThrottledNotificationActions({
|
||||
alertInstance: services.alertFactory.create(alertId),
|
||||
alertInstance: services.alertFactory.create(rule.id),
|
||||
throttle: completeRule.ruleConfig.throttle ?? '',
|
||||
startedAt,
|
||||
id: completeRule.alertId,
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('ActionContext', () => {
|
|||
hits: [],
|
||||
link: 'link-mock',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"rule '[rule-name]' matched query"`);
|
||||
expect(context.message).toEqual(
|
||||
`rule '[rule-name]' is active:
|
||||
|
@ -60,7 +60,7 @@ describe('ActionContext', () => {
|
|||
hits: [],
|
||||
link: 'link-mock',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params, true);
|
||||
const context = addMessages('[rule-name]', base, params, true);
|
||||
expect(context.title).toMatchInlineSnapshot(`"rule '[rule-name]' recovered"`);
|
||||
expect(context.message).toEqual(
|
||||
`rule '[rule-name]' is recovered:
|
||||
|
@ -91,7 +91,7 @@ describe('ActionContext', () => {
|
|||
hits: [],
|
||||
link: 'link-mock',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"rule '[rule-name]' matched query"`);
|
||||
expect(context.message).toEqual(
|
||||
`rule '[rule-name]' is active:
|
||||
|
|
|
@ -7,13 +7,10 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import { RuleExecutorOptions, AlertInstanceContext } from '@kbn/alerting-plugin/server';
|
||||
import { AlertInstanceContext } from '@kbn/alerting-plugin/server';
|
||||
import { OnlyEsQueryRuleParams, OnlySearchSourceRuleParams } from './types';
|
||||
|
||||
// rule type context provided to actions
|
||||
|
||||
type RuleInfo = Pick<RuleExecutorOptions, 'name'>;
|
||||
|
||||
export interface ActionContext extends EsQueryRuleActionContext {
|
||||
// a short pre-constructed message which may be used in an action field
|
||||
title: string;
|
||||
|
@ -36,7 +33,7 @@ export interface EsQueryRuleActionContext extends AlertInstanceContext {
|
|||
}
|
||||
|
||||
export function addMessages(
|
||||
ruleInfo: RuleInfo,
|
||||
ruleName: string,
|
||||
baseContext: EsQueryRuleActionContext,
|
||||
params: OnlyEsQueryRuleParams | OnlySearchSourceRuleParams,
|
||||
isRecovered: boolean = false
|
||||
|
@ -44,7 +41,7 @@ export function addMessages(
|
|||
const title = i18n.translate('xpack.stackAlerts.esQuery.alertTypeContextSubjectTitle', {
|
||||
defaultMessage: `rule '{name}' {verb}`,
|
||||
values: {
|
||||
name: ruleInfo.name,
|
||||
name: ruleName,
|
||||
verb: isRecovered ? 'recovered' : 'matched query',
|
||||
},
|
||||
});
|
||||
|
@ -58,7 +55,7 @@ export function addMessages(
|
|||
- Timestamp: {date}
|
||||
- Link: {link}`,
|
||||
values: {
|
||||
name: ruleInfo.name,
|
||||
name: ruleName,
|
||||
value: baseContext.value,
|
||||
conditions: baseContext.conditions,
|
||||
window,
|
||||
|
|
|
@ -20,7 +20,14 @@ import { isEsQueryRule } from './util';
|
|||
|
||||
export async function executor(core: CoreSetup, options: ExecutorOptions<EsQueryRuleParams>) {
|
||||
const esQueryRule = isEsQueryRule(options.params.searchType);
|
||||
const { alertId: ruleId, name, services, params, state, spaceId, logger } = options;
|
||||
const {
|
||||
rule: { id: ruleId, name },
|
||||
services,
|
||||
params,
|
||||
state,
|
||||
spaceId,
|
||||
logger,
|
||||
} = options;
|
||||
const { alertFactory, scopedClusterClient, searchSourceClient } = services;
|
||||
const currentTimestamp = new Date().toISOString();
|
||||
const publicBaseUrl = core.http.basePath.publicBaseUrl ?? '';
|
||||
|
@ -75,7 +82,7 @@ export async function executor(core: CoreSetup, options: ExecutorOptions<EsQuery
|
|||
conditions: getContextConditionsDescription(params.thresholdComparator, params.threshold),
|
||||
} as EsQueryRuleActionContext;
|
||||
|
||||
const actionContext = addMessages(options, baseActiveContext, params);
|
||||
const actionContext = addMessages(name, baseActiveContext, params);
|
||||
const alertInstance = alertFactory.create(ConditionMetAlertInstanceId);
|
||||
alertInstance
|
||||
// store the params we would need to recreate the query that led to this alert instance
|
||||
|
@ -107,7 +114,7 @@ export async function executor(core: CoreSetup, options: ExecutorOptions<EsQuery
|
|||
true
|
||||
),
|
||||
} as EsQueryRuleActionContext;
|
||||
const recoveryContext = addMessages(options, baseRecoveryContext, params, true);
|
||||
const recoveryContext = addMessages(name, baseRecoveryContext, params, true);
|
||||
alert.setContext(recoveryContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -640,7 +640,6 @@ async function invokeExecutor({
|
|||
state?: EsQueryRuleState;
|
||||
}) {
|
||||
return await ruleType.executor({
|
||||
alertId: uuid.v4(),
|
||||
executionId: uuid.v4(),
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: new Date(),
|
||||
|
@ -655,11 +654,8 @@ async function invokeExecutor({
|
|||
...state,
|
||||
},
|
||||
spaceId: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
|
|
@ -143,7 +143,7 @@ export const getGeoContainmentExecutor = (): GeoContainmentAlertType['executor']
|
|||
startedAt: windowEnd,
|
||||
services,
|
||||
params,
|
||||
alertId,
|
||||
rule: { id: ruleId },
|
||||
state,
|
||||
logger,
|
||||
}): Promise<GeoContainmentState> {
|
||||
|
@ -155,7 +155,7 @@ export const getGeoContainmentExecutor = (): GeoContainmentAlertType['executor']
|
|||
params.geoField,
|
||||
services.scopedClusterClient.asCurrentUser,
|
||||
logger,
|
||||
alertId,
|
||||
ruleId,
|
||||
params.boundaryNameField,
|
||||
params.boundaryIndexQuery
|
||||
);
|
||||
|
@ -170,7 +170,7 @@ export const getGeoContainmentExecutor = (): GeoContainmentAlertType['executor']
|
|||
// Start collecting data only on the first cycle
|
||||
let currentIntervalResults: estypes.SearchResponse<unknown> | undefined;
|
||||
if (!windowStart) {
|
||||
logger.debug(`alert ${GEO_CONTAINMENT_ID}:${alertId} alert initialized. Collecting data`);
|
||||
logger.debug(`alert ${GEO_CONTAINMENT_ID}:${ruleId} alert initialized. Collecting data`);
|
||||
// Consider making first time window configurable?
|
||||
const START_TIME_WINDOW = 1;
|
||||
const tempPreviousEndTime = new Date(windowEnd);
|
||||
|
|
|
@ -518,7 +518,7 @@ describe('geo_containment', () => {
|
|||
boundaryIndexId: 'testBoundaryIndexId',
|
||||
boundaryGeoField: 'testBoundaryGeoField',
|
||||
};
|
||||
const alertId = 'testAlertId';
|
||||
const ruleId = 'testAlertId';
|
||||
const geoContainmentState = {
|
||||
shapesFilters: {
|
||||
testShape: 'thisIsAShape',
|
||||
|
@ -567,7 +567,10 @@ describe('geo_containment', () => {
|
|||
// @ts-ignore
|
||||
services: alertServicesWithSearchMock,
|
||||
params: geoContainmentParams,
|
||||
alertId,
|
||||
// @ts-ignore
|
||||
rule: {
|
||||
id: ruleId,
|
||||
},
|
||||
// @ts-ignore
|
||||
state: {},
|
||||
});
|
||||
|
@ -587,7 +590,10 @@ describe('geo_containment', () => {
|
|||
// @ts-ignore
|
||||
services: alertServicesWithSearchMock,
|
||||
params: geoContainmentParams,
|
||||
alertId,
|
||||
// @ts-ignore
|
||||
rule: {
|
||||
id: ruleId,
|
||||
},
|
||||
state: geoContainmentState,
|
||||
});
|
||||
if (executionResult && executionResult.shapesFilters) {
|
||||
|
@ -606,7 +612,10 @@ describe('geo_containment', () => {
|
|||
// @ts-ignore
|
||||
services: alertServicesWithSearchMock,
|
||||
params: geoContainmentParams,
|
||||
alertId,
|
||||
// @ts-ignore
|
||||
rule: {
|
||||
id: ruleId,
|
||||
},
|
||||
state: geoContainmentState,
|
||||
});
|
||||
if (executionResult && executionResult.shapesFilters) {
|
||||
|
@ -642,7 +651,10 @@ describe('geo_containment', () => {
|
|||
// @ts-ignore
|
||||
services: alertServicesWithSearchMock,
|
||||
params: geoContainmentParams,
|
||||
alertId,
|
||||
// @ts-ignore
|
||||
rule: {
|
||||
id: ruleId,
|
||||
},
|
||||
state: geoContainmentState,
|
||||
});
|
||||
if (executionResult && executionResult.prevLocationMap) {
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('ActionContext', () => {
|
|||
value: 42,
|
||||
conditions: 'count greater than 4',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"alert [rule-name] group [group] met threshold"`);
|
||||
expect(context.message).toEqual(
|
||||
`alert '[rule-name]' is active for group '[group]':
|
||||
|
@ -59,7 +59,7 @@ describe('ActionContext', () => {
|
|||
value: 42,
|
||||
conditions: 'avg([aggField]) greater than 4.2',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"alert [rule-name] group [group] met threshold"`);
|
||||
expect(context.message).toEqual(
|
||||
`alert '[rule-name]' is active for group '[group]':
|
||||
|
@ -89,7 +89,7 @@ describe('ActionContext', () => {
|
|||
value: 4,
|
||||
conditions: 'count between 4 and 5',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"alert [rule-name] group [group] met threshold"`);
|
||||
expect(context.message).toEqual(
|
||||
`alert '[rule-name]' is active for group '[group]':
|
||||
|
@ -119,7 +119,7 @@ describe('ActionContext', () => {
|
|||
value: 'unknown',
|
||||
conditions: 'count between 4 and 5',
|
||||
};
|
||||
const context = addMessages({ name: '[rule-name]' }, base, params);
|
||||
const context = addMessages('[rule-name]', base, params);
|
||||
expect(context.title).toMatchInlineSnapshot(`"alert [rule-name] group [group] met threshold"`);
|
||||
expect(context.message).toEqual(
|
||||
`alert '[rule-name]' is active for group '[group]':
|
||||
|
|
|
@ -6,13 +6,10 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { RuleExecutorOptions, AlertInstanceContext } from '@kbn/alerting-plugin/server';
|
||||
import { AlertInstanceContext } from '@kbn/alerting-plugin/server';
|
||||
import { Params } from './rule_type_params';
|
||||
|
||||
// rule type context provided to actions
|
||||
|
||||
type RuleInfo = Pick<RuleExecutorOptions, 'name'>;
|
||||
|
||||
export interface ActionContext extends BaseActionContext {
|
||||
// a short pre-constructed message which may be used in an action field
|
||||
title: string;
|
||||
|
@ -79,20 +76,20 @@ const RECOVERY_MESSAGE = (name: string, context: BaseActionContext, window: stri
|
|||
});
|
||||
|
||||
export function addMessages(
|
||||
ruleInfo: RuleInfo,
|
||||
ruleName: string,
|
||||
baseContext: BaseActionContext,
|
||||
params: Params,
|
||||
isRecoveryMessage?: boolean
|
||||
): ActionContext {
|
||||
const title = isRecoveryMessage
|
||||
? RECOVERY_TITLE(ruleInfo.name, baseContext.group)
|
||||
: DEFAULT_TITLE(ruleInfo.name, baseContext.group);
|
||||
? RECOVERY_TITLE(ruleName, baseContext.group)
|
||||
: DEFAULT_TITLE(ruleName, baseContext.group);
|
||||
|
||||
const window = `${params.timeWindowSize}${params.timeWindowUnit}`;
|
||||
|
||||
const message = isRecoveryMessage
|
||||
? RECOVERY_MESSAGE(ruleInfo.name, baseContext, window)
|
||||
: DEFAULT_MESSAGE(ruleInfo.name, baseContext, window);
|
||||
? RECOVERY_MESSAGE(ruleName, baseContext, window)
|
||||
: DEFAULT_MESSAGE(ruleName, baseContext, window);
|
||||
|
||||
return { ...baseContext, title, message };
|
||||
}
|
||||
|
|
|
@ -183,7 +183,6 @@ describe('ruleType', () => {
|
|||
};
|
||||
|
||||
await ruleType.executor({
|
||||
alertId: uuid.v4(),
|
||||
executionId: uuid.v4(),
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: new Date(),
|
||||
|
@ -197,11 +196,8 @@ describe('ruleType', () => {
|
|||
latestTimestamp: undefined,
|
||||
},
|
||||
spaceId: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
@ -250,7 +246,6 @@ describe('ruleType', () => {
|
|||
};
|
||||
|
||||
await ruleType.executor({
|
||||
alertId: uuid.v4(),
|
||||
executionId: uuid.v4(),
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: new Date(),
|
||||
|
@ -264,11 +259,8 @@ describe('ruleType', () => {
|
|||
latestTimestamp: undefined,
|
||||
},
|
||||
spaceId: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
@ -317,7 +309,6 @@ describe('ruleType', () => {
|
|||
};
|
||||
|
||||
await ruleType.executor({
|
||||
alertId: uuid.v4(),
|
||||
executionId: uuid.v4(),
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: new Date(),
|
||||
|
@ -331,11 +322,8 @@ describe('ruleType', () => {
|
|||
latestTimestamp: undefined,
|
||||
},
|
||||
spaceId: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
@ -383,7 +371,6 @@ describe('ruleType', () => {
|
|||
};
|
||||
|
||||
await ruleType.executor({
|
||||
alertId: uuid.v4(),
|
||||
executionId: uuid.v4(),
|
||||
startedAt: new Date(),
|
||||
previousStartedAt: new Date(),
|
||||
|
@ -397,11 +384,8 @@ describe('ruleType', () => {
|
|||
latestTimestamp: undefined,
|
||||
},
|
||||
spaceId: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
createdBy: null,
|
||||
updatedBy: null,
|
||||
rule: {
|
||||
id: uuid.v4(),
|
||||
name: uuid.v4(),
|
||||
tags: [],
|
||||
consumer: '',
|
||||
|
|
|
@ -134,7 +134,12 @@ export function getRuleType(
|
|||
async function executor(
|
||||
options: RuleExecutorOptions<Params, {}, {}, ActionContext, typeof ActionGroupId>
|
||||
) {
|
||||
const { alertId: ruleId, name, services, params, logger } = options;
|
||||
const {
|
||||
rule: { id: ruleId, name },
|
||||
services,
|
||||
params,
|
||||
logger,
|
||||
} = options;
|
||||
const { alertFactory, scopedClusterClient } = services;
|
||||
|
||||
const alertLimit = alertFactory.alertLimit.getValue();
|
||||
|
@ -229,7 +234,7 @@ export function getRuleType(
|
|||
value,
|
||||
conditions: humanFn,
|
||||
};
|
||||
const actionContext = addMessages(options, baseContext, params);
|
||||
const actionContext = addMessages(name, baseContext, params);
|
||||
const alert = alertFactory.create(alertId);
|
||||
alert.scheduleActions(ActionGroupId, actionContext);
|
||||
logger.debug(`scheduled actionGroup: ${JSON.stringify(actionContext)}`);
|
||||
|
@ -249,7 +254,7 @@ export function getRuleType(
|
|||
params.thresholdComparator
|
||||
)} ${params.threshold.join(' and ')}`,
|
||||
};
|
||||
const recoveryContext = addMessages(options, baseContext, params, true);
|
||||
const recoveryContext = addMessages(name, baseContext, params, true);
|
||||
recoveredAlert.setContext(recoveryContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,21 +95,9 @@ function getAlwaysFiringAlertType() {
|
|||
}
|
||||
|
||||
async function alwaysFiringExecutor(alertExecutorOptions: any) {
|
||||
const {
|
||||
services,
|
||||
params,
|
||||
state,
|
||||
alertId,
|
||||
spaceId,
|
||||
namespace,
|
||||
name,
|
||||
tags,
|
||||
createdBy,
|
||||
updatedBy,
|
||||
rule,
|
||||
} = alertExecutorOptions;
|
||||
const { services, params, state, spaceId, namespace, rule } = alertExecutorOptions;
|
||||
let group: string | null = 'default';
|
||||
const alertInfo = { alertId, spaceId, namespace, name, tags, createdBy, updatedBy, ...rule };
|
||||
const alertInfo = { spaceId, namespace, ...rule };
|
||||
|
||||
if (params.groupsToScheduleActionsInSeries) {
|
||||
const index = state.groupInSeriesIndex || 0;
|
||||
|
|
|
@ -144,7 +144,7 @@ export default function alertTests({ getService }: FtrProviderContext) {
|
|||
reference,
|
||||
},
|
||||
alertInfo: {
|
||||
alertId,
|
||||
id: alertId,
|
||||
consumer: 'alertsFixture',
|
||||
spaceId: space.id,
|
||||
namespace: space.id,
|
||||
|
@ -296,7 +296,7 @@ instanceStateValue: true
|
|||
reference,
|
||||
},
|
||||
alertInfo: {
|
||||
alertId,
|
||||
id: alertId,
|
||||
consumer: 'alertsFixture',
|
||||
spaceId: space.id,
|
||||
namespace: space.id,
|
||||
|
@ -428,7 +428,7 @@ instanceStateValue: true
|
|||
['createdAt', 'updatedAt']
|
||||
);
|
||||
expect(alertSearchResultInfoWithoutDates).to.eql({
|
||||
alertId,
|
||||
id: alertId,
|
||||
consumer: 'alertsFixture',
|
||||
spaceId: space.id,
|
||||
namespace: space.id,
|
||||
|
|
|
@ -98,7 +98,7 @@ export function alertTests({ getService }: FtrProviderContext, space: Space) {
|
|||
reference,
|
||||
},
|
||||
alertInfo: {
|
||||
alertId,
|
||||
id: alertId,
|
||||
consumer: 'alertsFixture',
|
||||
spaceId: space.id,
|
||||
namespace: space.namespace,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue