[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:
Ying Mao 2022-11-04 09:20:54 -04:00 committed by GitHub
parent cb2f4ba9d9
commit 3b59a90671
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 123 additions and 158 deletions

View file

@ -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.|

View file

@ -124,6 +124,7 @@ export type ResolvedSanitizedRule<Params extends RuleTypeParams = never> = Sanit
export type SanitizedRuleConfig = Pick<
SanitizedRule,
| 'id'
| 'name'
| 'tags'
| 'consumer'

View file

@ -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');

View file

@ -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,

View file

@ -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;
}

View file

@ -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;

View file

@ -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: '',

View file

@ -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;

View file

@ -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,

View file

@ -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(

View file

@ -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] } : {}),
};

View file

@ -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;

View file

@ -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(),
};
};

View file

@ -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',

View file

@ -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',

View file

@ -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,

View file

@ -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;

View file

@ -195,6 +195,7 @@ export const getThreatRuleParams = (): ThreatRuleParams => {
};
export const getRuleConfigMock = (type: string = 'rule-type'): SanitizedRuleConfig => ({
id: sampleRuleGuid,
actions: [],
enabled: true,
name: 'rule-name',

View file

@ -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,

View file

@ -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:

View file

@ -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,

View file

@ -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);
}

View file

@ -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: '',

View file

@ -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);

View file

@ -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) {

View file

@ -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]':

View file

@ -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 };
}

View file

@ -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: '',

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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,

View file

@ -98,7 +98,7 @@ export function alertTests({ getService }: FtrProviderContext, space: Space) {
reference,
},
alertInfo: {
alertId,
id: alertId,
consumer: 'alertsFixture',
spaceId: space.id,
namespace: space.namespace,