[Alerting] Rename alert instance to alert and changing signature of alert (instance) factory alert creation (#124390)

* Rename alert instance to alert and add create fn to alert factory

* Rename alert instance to alert and add create fn to alert factory

* Fixing types

* Fixing types

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ying Mao 2022-02-07 16:38:24 -05:00 committed by GitHub
parent aedbc9f4c9
commit 270adf4958
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
82 changed files with 997 additions and 1065 deletions

View file

@ -65,8 +65,8 @@ export const alertType: RuleType<
range(instances)
.map(() => uuid.v4())
.forEach((id: string) => {
services
.alertInstanceFactory(id)
services.alertFactory
.create(id)
.replaceState({ triggerdOnCycle: count })
.scheduleActions(getTShirtSizeByIdAndThreshold(id, thresholds));
});

View file

@ -70,7 +70,7 @@ export const alertType: RuleType<
if (getOperator(op)(peopleInCraft.length, outerSpaceCapacity)) {
peopleInCraft.forEach(({ craft, name }) => {
services.alertInstanceFactory(name).replaceState({ craft }).scheduleActions('default');
services.alertFactory.create(name).replaceState({ craft }).scheduleActions('default');
});
}

View file

@ -40,8 +40,6 @@ Table of Contents
> References to `rule` and `rule type` entities are still named `AlertType` within the codebase.
> References to `alert` and `alert factory` entities are still named `AlertInstance` and `alertInstanceFactory` within the codebase.
**Rule Type**: A function that takes parameters and executes actions on alerts.
**Rule**: A configuration that defines a schedule, a rule type w/ parameters, state information and actions.
@ -113,7 +111,7 @@ This is the primary function for a rule type. Whenever the rule needs to execute
|---|---|
|services.scopedClusterClient|This is an instance of the Elasticsearch client. Use this to do Elasticsearch queries in the context of the user who created the alert when security is enabled.|
|services.savedObjectsClient|This is an instance of the saved objects client. This provides the ability to perform CRUD operations on any saved object that lives in the same space as the rule.<br><br>The scope of the saved objects client is tied to the user who created the rule (only when security is enabled).|
|services.alertInstanceFactory(id)|This [alert factory](#alert-factory) creates alerts and must be used in order to execute actions. The id you give to the alert factory is a unique identifier for the alert.|
|services.alertFactory|This [alert factory](#alert-factory) creates alerts and must be used in order to schedule action execution. The id you give to the alert factory create function() is a unique identifier for the alert.|
|services.log(tags, [data], [timestamp])|Use this to create server logs. (This is the same function as server.log)|
|services.shouldWriteAlerts()|This returns a boolean indicating whether the executor should write out alerts as data. This is determined by whether rule execution has been cancelled due to timeout AND whether both the Kibana `cancelAlertsOnRuleTimeout` flag and the rule type `cancelAlertsOnRuleTimeout` are set to `true`.|
|services.shouldStopExecution()|This returns a boolean indicating whether rule execution has been cancelled due to timeout.|
@ -310,7 +308,7 @@ const myRuleType: RuleType<
// scenario the provided server will be used. Also, this ID will be
// used to make `getState()` return previous state, if any, on
// matching identifiers.
const alert = services.alertInstanceFactory(server);
const alert = services.alertFactory.create(server);
// State from the last execution. This will exist if an alert was
// created and executed in the previous execution
@ -731,13 +729,13 @@ Query:
## Alert Factory
**alertInstanceFactory(id)**
**alertFactory.create(id)**
One service passed in to each rule type is the alert factory. This factory creates alerts and must be used in order to execute actions. The `id` you give to the alert factory is the unique identifier for the alert (e.g. the server identifier if the alert is about servers). The alert factory will use this identifier to retrieve the state of previous alerts with the same `id`. These alerts support persisting state between rule executions, but will clear out once the alert stops firing.
One service passed in to each rule type is the alert factory. This factory creates alerts and must be used in order to schedule action execution. The `id` you give to the alert factory create fn() is the unique identifier for the alert (e.g. the server identifier if the alert is about servers). The alert factory will use this identifier to retrieve the state of previous alerts with the same `id`. These alerts support persisting state between rule executions, but will clear out once the alert stops firing.
Note that the `id` only needs to be unique **within the scope of a specific rule**, not unique across all rules or rule types. For example, Rule 1 and Rule 2 can both create an alert with an `id` of `"a"` without conflicting with one another. But if Rule 1 creates 2 alerts, then they must be differentiated with `id`s of `"a"` and `"b"`.
This factory returns an instance of `AlertInstance`. The `AlertInstance` class has the following methods. Note that we have removed the methods that you shouldn't touch.
This factory returns an instance of `Alert`. The `Alert` class has the following methods. Note that we have removed the methods that you shouldn't touch.
|Method|Description|
|---|---|
@ -781,7 +779,8 @@ The templating engine is [mustache]. General definition for the [mustache variab
The following code would be within a rule type. As you can see `cpuUsage` will replace the state of the alert and `server` is the context for the alert to execute. The difference between the two is that `cpuUsage` will be accessible at the next execution.
```
alertInstanceFactory('server_1')
alertFactory
.create('server_1')
.replaceState({
cpuUsage: 80,
})

View file

@ -0,0 +1,488 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import sinon from 'sinon';
import { Alert } from './alert';
import { AlertInstanceState, AlertInstanceContext, DefaultActionGroupId } from '../../common';
let clock: sinon.SinonFakeTimers;
beforeAll(() => {
clock = sinon.useFakeTimers();
});
beforeEach(() => clock.reset());
afterAll(() => clock.restore());
describe('hasScheduledActions()', () => {
test('defaults to false', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
expect(alert.hasScheduledActions()).toEqual(false);
});
test('returns true when scheduleActions is called', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default');
expect(alert.hasScheduledActions()).toEqual(true);
});
});
describe('isThrottled', () => {
test(`should throttle when group didn't change and throttle period is still active`, () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(30000);
alert.scheduleActions('default');
expect(alert.isThrottled('1m')).toEqual(true);
});
test(`shouldn't throttle when group didn't change and throttle period expired`, () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(30000);
alert.scheduleActions('default');
expect(alert.isThrottled('15s')).toEqual(false);
});
test(`shouldn't throttle when group changes`, () => {
const alert = new Alert<never, never, 'default' | 'other-group'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(5000);
alert.scheduleActions('other-group');
expect(alert.isThrottled('1m')).toEqual(false);
});
});
describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
test('should be false if no last scheduled and nothing scheduled', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert.scheduleActions('default');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group and subgroup does not change', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alert.scheduleActionsWithSubGroup('default', 'subgroup');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change and subgroup goes from undefined to defined', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert.scheduleActionsWithSubGroup('default', 'subgroup');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change and subgroup goes from defined to undefined', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alert.scheduleActions('default');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be true if no last scheduled and has scheduled action', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does change', () => {
const alert = new Alert<never, never, 'default' | 'penguin'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert.scheduleActions('penguin');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does change and subgroup does change', () => {
const alert = new Alert<never, never, 'default' | 'penguin'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alert.scheduleActionsWithSubGroup('penguin', 'fish');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does not change and subgroup does change', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alert.scheduleActionsWithSubGroup('default', 'fish');
expect(alert.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
});
describe('getScheduledActionOptions()', () => {
test('defaults to undefined', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
expect(alert.getScheduledActionOptions()).toBeUndefined();
});
});
describe('unscheduleActions()', () => {
test('makes hasScheduledActions() return false', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default');
expect(alert.hasScheduledActions()).toEqual(true);
alert.unscheduleActions();
expect(alert.hasScheduledActions()).toEqual(false);
});
test('makes getScheduledActionOptions() return undefined', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default');
expect(alert.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
context: {},
state: {},
});
alert.unscheduleActions();
expect(alert.getScheduledActionOptions()).toBeUndefined();
});
});
describe('getState()', () => {
test('returns state passed to constructor', () => {
const state = { foo: true };
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state,
});
expect(alert.getState()).toEqual(state);
});
});
describe('scheduleActions()', () => {
test('makes hasScheduledActions() return true', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alert.hasScheduledActions()).toEqual(true);
});
test('makes isThrottled() return true when throttled', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alert.isThrottled('1m')).toEqual(true);
});
test('make isThrottled() return false when throttled expired', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(120000);
alert.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alert.isThrottled('1m')).toEqual(false);
});
test('makes getScheduledActionOptions() return given options', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {},
});
alert.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alert.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
context: { field: true },
state: { otherField: true },
});
});
test('cannot schdule for execution twice', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default', { field: true });
expect(() =>
alert.scheduleActions('default', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
});
describe('scheduleActionsWithSubGroup()', () => {
test('makes hasScheduledActions() return true', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.hasScheduledActions()).toEqual(true);
});
test('makes isThrottled() return true when throttled and subgroup is the same', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.isThrottled('1m')).toEqual(true);
});
test('makes isThrottled() return true when throttled and last schedule had no subgroup', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.isThrottled('1m')).toEqual(true);
});
test('makes isThrottled() return false when throttled and subgroup is the different', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'prev-subgroup',
},
},
});
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.isThrottled('1m')).toEqual(false);
});
test('make isThrottled() return false when throttled expired', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(120000);
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.isThrottled('1m')).toEqual(false);
});
test('makes getScheduledActionOptions() return given options', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
meta: {},
});
alert
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alert.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
subgroup: 'subgroup',
context: { field: true },
state: { otherField: true },
});
});
test('cannot schdule for execution twice', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
test('cannot schdule for execution twice with different subgroups', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
test('cannot schdule for execution twice whether there are subgroups', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>();
alert.scheduleActions('default', { field: true });
expect(() =>
alert.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
});
describe('replaceState()', () => {
test('replaces previous state', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
state: { foo: true },
});
alert.replaceState({ bar: true });
expect(alert.getState()).toEqual({ bar: true });
alert.replaceState({ baz: true });
expect(alert.getState()).toEqual({ baz: true });
});
});
describe('updateLastScheduledActions()', () => {
test('replaces previous lastScheduledActions', () => {
const alert = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>({
meta: {},
});
alert.updateLastScheduledActions('default');
expect(alert.toJSON()).toEqual({
state: {},
meta: {
lastScheduledActions: {
date: new Date().toISOString(),
group: 'default',
},
},
});
});
});
describe('toJSON', () => {
test('only serializes state and meta', () => {
const alertInstance = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>(
{
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
}
);
expect(JSON.stringify(alertInstance)).toEqual(
'{"state":{"foo":true},"meta":{"lastScheduledActions":{"date":"1970-01-01T00:00:00.000Z","group":"default"}}}'
);
});
});
describe('toRaw', () => {
test('returns unserialised underlying state and meta', () => {
const raw = {
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
};
const alertInstance = new Alert<AlertInstanceState, AlertInstanceContext, DefaultActionGroupId>(
raw
);
expect(alertInstance.toRaw()).toEqual(raw);
});
});

View file

@ -27,16 +27,16 @@ interface ScheduledExecutionOptions<
state: State;
}
export type PublicAlertInstance<
export type PublicAlert<
State extends AlertInstanceState = AlertInstanceState,
Context extends AlertInstanceContext = AlertInstanceContext,
ActionGroupIds extends string = DefaultActionGroupId
> = Pick<
AlertInstance<State, Context, ActionGroupIds>,
Alert<State, Context, ActionGroupIds>,
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
>;
export class AlertInstance<
export class Alert<
State extends AlertInstanceState = AlertInstanceState,
Context extends AlertInstanceContext = AlertInstanceContext,
ActionGroupIds extends string = never

View file

@ -6,8 +6,8 @@
*/
import sinon from 'sinon';
import { AlertInstance } from './alert_instance';
import { createAlertInstanceFactory } from './create_alert_instance_factory';
import { Alert } from './alert';
import { createAlertFactory } from './create_alert_factory';
let clock: sinon.SinonFakeTimers;
@ -17,9 +17,9 @@ beforeAll(() => {
beforeEach(() => clock.reset());
afterAll(() => clock.restore());
test('creates new instances for ones not passed in', () => {
const alertInstanceFactory = createAlertInstanceFactory({});
const result = alertInstanceFactory('1');
test('creates new alerts for ones not passed in', () => {
const alertFactory = createAlertFactory({ alerts: {} });
const result = alertFactory.create('1');
expect(result).toMatchInlineSnapshot(`
Object {
"meta": Object {},
@ -28,15 +28,17 @@ test('creates new instances for ones not passed in', () => {
`);
});
test('reuses existing instances', () => {
const alertInstance = new AlertInstance({
test('reuses existing alerts', () => {
const alert = new Alert({
state: { foo: true },
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
});
const alertInstanceFactory = createAlertInstanceFactory({
'1': alertInstance,
const alertFactory = createAlertFactory({
alerts: {
'1': alert,
},
});
const result = alertInstanceFactory('1');
const result = alertFactory.create('1');
expect(result).toMatchInlineSnapshot(`
Object {
"meta": Object {
@ -52,11 +54,11 @@ test('reuses existing instances', () => {
`);
});
test('mutates given instances', () => {
const alertInstances = {};
const alertInstanceFactory = createAlertInstanceFactory(alertInstances);
alertInstanceFactory('1');
expect(alertInstances).toMatchInlineSnapshot(`
test('mutates given alerts', () => {
const alerts = {};
const alertFactory = createAlertFactory({ alerts });
alertFactory.create('1');
expect(alerts).toMatchInlineSnapshot(`
Object {
"1": Object {
"meta": Object {},

View file

@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { AlertInstanceContext, AlertInstanceState } from '../types';
import { Alert } from './alert';
export interface CreateAlertFactoryOpts<
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
ActionGroupIds extends string
> {
alerts: Record<string, Alert<InstanceState, InstanceContext, ActionGroupIds>>;
}
export function createAlertFactory<
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
ActionGroupIds extends string
>({ alerts }: CreateAlertFactoryOpts<InstanceState, InstanceContext, ActionGroupIds>) {
return {
create: (id: string): Alert<InstanceState, InstanceContext, ActionGroupIds> => {
if (!alerts[id]) {
alerts[id] = new Alert<InstanceState, InstanceContext, ActionGroupIds>();
}
return alerts[id];
},
};
}

View file

@ -5,6 +5,6 @@
* 2.0.
*/
export type { PublicAlertInstance } from './alert_instance';
export { AlertInstance } from './alert_instance';
export { createAlertInstanceFactory } from './create_alert_instance_factory';
export type { PublicAlert } from './alert';
export { Alert } from './alert';
export { createAlertFactory } from './create_alert_factory';

View file

@ -1,604 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import sinon from 'sinon';
import { AlertInstance } from './alert_instance';
import { AlertInstanceState, AlertInstanceContext, DefaultActionGroupId } from '../../common';
let clock: sinon.SinonFakeTimers;
beforeAll(() => {
clock = sinon.useFakeTimers();
});
beforeEach(() => clock.reset());
afterAll(() => clock.restore());
describe('hasScheduledActions()', () => {
test('defaults to false', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
expect(alertInstance.hasScheduledActions()).toEqual(false);
});
test('returns true when scheduleActions is called', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default');
expect(alertInstance.hasScheduledActions()).toEqual(true);
});
});
describe('isThrottled', () => {
test(`should throttle when group didn't change and throttle period is still active`, () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(30000);
alertInstance.scheduleActions('default');
expect(alertInstance.isThrottled('1m')).toEqual(true);
});
test(`shouldn't throttle when group didn't change and throttle period expired`, () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(30000);
alertInstance.scheduleActions('default');
expect(alertInstance.isThrottled('15s')).toEqual(false);
});
test(`shouldn't throttle when group changes`, () => {
const alertInstance = new AlertInstance<never, never, 'default' | 'other-group'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(5000);
alertInstance.scheduleActions('other-group');
expect(alertInstance.isThrottled('1m')).toEqual(false);
});
});
describe('scheduledActionGroupOrSubgroupHasChanged()', () => {
test('should be false if no last scheduled and nothing scheduled', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance.scheduleActions('default');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group and subgroup does not change', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change and subgroup goes from undefined to defined', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be false if group does not change and subgroup goes from defined to undefined', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alertInstance.scheduleActions('default');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(false);
});
test('should be true if no last scheduled and has scheduled action', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does change', () => {
const alertInstance = new AlertInstance<never, never, 'default' | 'penguin'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance.scheduleActions('penguin');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does change and subgroup does change', () => {
const alertInstance = new AlertInstance<never, never, 'default' | 'penguin'>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alertInstance.scheduleActionsWithSubGroup('penguin', 'fish');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
test('should be true if group does not change and subgroup does change', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alertInstance.scheduleActionsWithSubGroup('default', 'fish');
expect(alertInstance.scheduledActionGroupOrSubgroupHasChanged()).toEqual(true);
});
});
describe('getScheduledActionOptions()', () => {
test('defaults to undefined', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
expect(alertInstance.getScheduledActionOptions()).toBeUndefined();
});
});
describe('unscheduleActions()', () => {
test('makes hasScheduledActions() return false', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default');
expect(alertInstance.hasScheduledActions()).toEqual(true);
alertInstance.unscheduleActions();
expect(alertInstance.hasScheduledActions()).toEqual(false);
});
test('makes getScheduledActionOptions() return undefined', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default');
expect(alertInstance.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
context: {},
state: {},
});
alertInstance.unscheduleActions();
expect(alertInstance.getScheduledActionOptions()).toBeUndefined();
});
});
describe('getState()', () => {
test('returns state passed to constructor', () => {
const state = { foo: true };
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({ state });
expect(alertInstance.getState()).toEqual(state);
});
});
describe('scheduleActions()', () => {
test('makes hasScheduledActions() return true', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alertInstance.hasScheduledActions()).toEqual(true);
});
test('makes isThrottled() return true when throttled', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(true);
});
test('make isThrottled() return false when throttled expired', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(120000);
alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(false);
});
test('makes getScheduledActionOptions() return given options', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({ state: { foo: true }, meta: {} });
alertInstance.replaceState({ otherField: true }).scheduleActions('default', { field: true });
expect(alertInstance.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
context: { field: true },
state: { otherField: true },
});
});
test('cannot schdule for execution twice', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default', { field: true });
expect(() =>
alertInstance.scheduleActions('default', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
});
describe('scheduleActionsWithSubGroup()', () => {
test('makes hasScheduledActions() return true', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.hasScheduledActions()).toEqual(true);
});
test('makes isThrottled() return true when throttled and subgroup is the same', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'subgroup',
},
},
});
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(true);
});
test('makes isThrottled() return true when throttled and last schedule had no subgroup', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(true);
});
test('makes isThrottled() return false when throttled and subgroup is the different', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
subgroup: 'prev-subgroup',
},
},
});
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(false);
});
test('make isThrottled() return false when throttled expired', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
clock.tick(120000);
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.isThrottled('1m')).toEqual(false);
});
test('makes getScheduledActionOptions() return given options', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({ state: { foo: true }, meta: {} });
alertInstance
.replaceState({ otherField: true })
.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(alertInstance.getScheduledActionOptions()).toEqual({
actionGroup: 'default',
subgroup: 'subgroup',
context: { field: true },
state: { otherField: true },
});
});
test('cannot schdule for execution twice', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
test('cannot schdule for execution twice with different subgroups', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup', { field: true });
expect(() =>
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
test('cannot schdule for execution twice whether there are subgroups', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>();
alertInstance.scheduleActions('default', { field: true });
expect(() =>
alertInstance.scheduleActionsWithSubGroup('default', 'subgroup', { field: false })
).toThrowErrorMatchingInlineSnapshot(
`"Alert instance execution has already been scheduled, cannot schedule twice"`
);
});
});
describe('replaceState()', () => {
test('replaces previous state', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({ state: { foo: true } });
alertInstance.replaceState({ bar: true });
expect(alertInstance.getState()).toEqual({ bar: true });
alertInstance.replaceState({ baz: true });
expect(alertInstance.getState()).toEqual({ baz: true });
});
});
describe('updateLastScheduledActions()', () => {
test('replaces previous lastScheduledActions', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({ meta: {} });
alertInstance.updateLastScheduledActions('default');
expect(alertInstance.toJSON()).toEqual({
state: {},
meta: {
lastScheduledActions: {
date: new Date().toISOString(),
group: 'default',
},
},
});
});
});
describe('toJSON', () => {
test('only serializes state and meta', () => {
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>({
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
});
expect(JSON.stringify(alertInstance)).toEqual(
'{"state":{"foo":true},"meta":{"lastScheduledActions":{"date":"1970-01-01T00:00:00.000Z","group":"default"}}}'
);
});
});
describe('toRaw', () => {
test('returns unserialised underlying state and meta', () => {
const raw = {
state: { foo: true },
meta: {
lastScheduledActions: {
date: new Date(),
group: 'default',
},
},
};
const alertInstance = new AlertInstance<
AlertInstanceState,
AlertInstanceContext,
DefaultActionGroupId
>(raw);
expect(alertInstance.toRaw()).toEqual(raw);
});
});

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { AlertInstanceContext, AlertInstanceState } from '../types';
import { AlertInstance } from './alert_instance';
export function createAlertInstanceFactory<
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext,
ActionGroupIds extends string
>(alertInstances: Record<string, AlertInstance<InstanceState, InstanceContext, ActionGroupIds>>) {
return (id: string): AlertInstance<InstanceState, InstanceContext, ActionGroupIds> => {
if (!alertInstances[id]) {
alertInstances[id] = new AlertInstance<InstanceState, InstanceContext, ActionGroupIds>();
}
return alertInstances[id];
};
}

View file

@ -32,7 +32,7 @@ export type {
export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config';
export type { PluginSetupContract, PluginStartContract } from './plugin';
export type { FindResult } from './rules_client';
export type { PublicAlertInstance as AlertInstance } from './alert_instance';
export type { PublicAlert as Alert } from './alert';
export { parseDuration } from './lib';
export { getEsErrorMessage } from './lib/errors';
export type {

View file

@ -7,7 +7,7 @@
import { rulesClientMock } from './rules_client.mock';
import { PluginSetupContract, PluginStartContract } from './plugin';
import { AlertInstance } from './alert_instance';
import { Alert } from './alert';
import {
elasticsearchServiceMock,
savedObjectsClientMock,
@ -37,30 +37,33 @@ const createStartMock = () => {
export type AlertInstanceMock<
State extends AlertInstanceState = AlertInstanceState,
Context extends AlertInstanceContext = AlertInstanceContext
> = jest.Mocked<AlertInstance<State, Context>>;
const createAlertInstanceFactoryMock = <
InstanceState extends AlertInstanceState = AlertInstanceState,
InstanceContext extends AlertInstanceContext = AlertInstanceContext
>() => {
const mock = {
hasScheduledActions: jest.fn(),
isThrottled: jest.fn(),
getScheduledActionOptions: jest.fn(),
unscheduleActions: jest.fn(),
getState: jest.fn(),
scheduleActions: jest.fn(),
replaceState: jest.fn(),
updateLastScheduledActions: jest.fn(),
toJSON: jest.fn(),
toRaw: jest.fn(),
};
> = jest.Mocked<Alert<State, Context>>;
// support chaining
mock.replaceState.mockReturnValue(mock);
mock.unscheduleActions.mockReturnValue(mock);
mock.scheduleActions.mockReturnValue(mock);
const createAlertFactoryMock = {
create: <
InstanceState extends AlertInstanceState = AlertInstanceState,
InstanceContext extends AlertInstanceContext = AlertInstanceContext
>() => {
const mock = {
hasScheduledActions: jest.fn(),
isThrottled: jest.fn(),
getScheduledActionOptions: jest.fn(),
unscheduleActions: jest.fn(),
getState: jest.fn(),
scheduleActions: jest.fn(),
replaceState: jest.fn(),
updateLastScheduledActions: jest.fn(),
toJSON: jest.fn(),
toRaw: jest.fn(),
};
return mock as unknown as AlertInstanceMock<InstanceState, InstanceContext>;
// support chaining
mock.replaceState.mockReturnValue(mock);
mock.unscheduleActions.mockReturnValue(mock);
mock.scheduleActions.mockReturnValue(mock);
return mock as unknown as AlertInstanceMock<InstanceState, InstanceContext>;
},
};
const createAbortableSearchClientMock = () => {
@ -82,11 +85,11 @@ const createAlertServicesMock = <
InstanceState extends AlertInstanceState = AlertInstanceState,
InstanceContext extends AlertInstanceContext = AlertInstanceContext
>() => {
const alertInstanceFactoryMock = createAlertInstanceFactoryMock<InstanceState, InstanceContext>();
const alertFactoryMockCreate = createAlertFactoryMock.create<InstanceState, InstanceContext>();
return {
alertInstanceFactory: jest
.fn<jest.Mocked<AlertInstance<InstanceState, InstanceContext>>, [string]>()
.mockReturnValue(alertInstanceFactoryMock),
alertFactory: {
create: jest.fn().mockReturnValue(alertFactoryMockCreate),
},
savedObjectsClient: savedObjectsClientMock.create(),
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
shouldWriteAlerts: () => true,
@ -97,7 +100,7 @@ const createAlertServicesMock = <
export type AlertServicesMock = ReturnType<typeof createAlertServicesMock>;
export const alertsMock = {
createAlertInstanceFactory: createAlertInstanceFactoryMock,
createAlertFactory: createAlertFactoryMock,
createSetup: createSetupMock,
createStart: createStartMock,
createAlertServices: createAlertServicesMock,

View file

@ -22,23 +22,23 @@ import {
import { esKuery } from '../../../../../src/plugins/data/server';
import { ActionsClient, ActionsAuthorization } from '../../../actions/server';
import {
Alert,
PartialAlert,
Alert as Rule,
PartialAlert as PartialRule,
RawRule,
RuleTypeRegistry,
AlertAction,
AlertAction as RuleAction,
IntervalSchedule,
SanitizedAlert,
SanitizedAlert as SanitizedRule,
RuleTaskState,
AlertSummary,
AlertExecutionStatusValues,
AlertNotifyWhenType,
AlertTypeParams,
AlertExecutionStatusValues as RuleExecutionStatusValues,
AlertNotifyWhenType as RuleNotifyWhenType,
AlertTypeParams as RuleTypeParams,
ResolvedSanitizedRule,
AlertWithLegacyId,
AlertWithLegacyId as RuleWithLegacyId,
SanitizedRuleWithLegacyId,
PartialAlertWithLegacyId,
RawAlertInstance,
PartialAlertWithLegacyId as PartialRuleWithLegacyId,
RawAlertInstance as RawAlert,
} from '../types';
import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getAlertNotifyWhenType } from '../lib';
import {
@ -74,7 +74,7 @@ import { ruleAuditEvent, RuleAuditAction } from './audit_events';
import { KueryNode, nodeBuilder } from '../../../../../src/plugins/data/common';
import { mapSortField, validateOperationOnAttributes } from './lib';
import { getRuleExecutionStatusPending } from '../lib/rule_execution_status';
import { AlertInstance } from '../alert_instance';
import { Alert } from '../alert';
import { EVENT_LOG_ACTIONS } from '../plugin';
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
import { getDefaultRuleMonitoring } from '../task_runner/task_runner';
@ -82,7 +82,7 @@ import { getDefaultRuleMonitoring } from '../task_runner/task_runner';
export interface RegistryAlertTypeWithAuth extends RegistryRuleType {
authorizedConsumers: string[];
}
type NormalizedAlertAction = Omit<AlertAction, 'actionTypeId'>;
type NormalizedAlertAction = Omit<RuleAction, 'actionTypeId'>;
export type CreateAPIKeyResult =
| { apiKeysEnabled: false }
| { apiKeysEnabled: true; result: SecurityPluginGrantAPIKeyResult };
@ -174,16 +174,16 @@ export interface AggregateResult {
ruleMutedStatus?: { muted: number; unmuted: number };
}
export interface FindResult<Params extends AlertTypeParams> {
export interface FindResult<Params extends RuleTypeParams> {
page: number;
perPage: number;
total: number;
data: Array<SanitizedAlert<Params>>;
data: Array<SanitizedRule<Params>>;
}
export interface CreateOptions<Params extends AlertTypeParams> {
export interface CreateOptions<Params extends RuleTypeParams> {
data: Omit<
Alert<Params>,
Rule<Params>,
| 'id'
| 'createdBy'
| 'updatedBy'
@ -202,7 +202,7 @@ export interface CreateOptions<Params extends AlertTypeParams> {
};
}
export interface UpdateOptions<Params extends AlertTypeParams> {
export interface UpdateOptions<Params extends RuleTypeParams> {
id: string;
data: {
name: string;
@ -211,7 +211,7 @@ export interface UpdateOptions<Params extends AlertTypeParams> {
actions: NormalizedAlertAction[];
params: Params;
throttle: string | null;
notifyWhen: AlertNotifyWhenType | null;
notifyWhen: RuleNotifyWhenType | null;
};
}
@ -248,7 +248,7 @@ export class RulesClient {
private readonly kibanaVersion!: PluginInitializerContext['env']['packageInfo']['version'];
private readonly auditLogger?: AuditLogger;
private readonly eventLogger?: IEventLogger;
private readonly fieldsToExcludeFromPublicApi: Array<keyof SanitizedAlert> = ['monitoring'];
private readonly fieldsToExcludeFromPublicApi: Array<keyof SanitizedRule> = ['monitoring'];
constructor({
ruleTypeRegistry,
@ -286,10 +286,10 @@ export class RulesClient {
this.eventLogger = eventLogger;
}
public async create<Params extends AlertTypeParams = never>({
public async create<Params extends RuleTypeParams = never>({
data,
options,
}: CreateOptions<Params>): Promise<SanitizedAlert<Params>> {
}: CreateOptions<Params>): Promise<SanitizedRule<Params>> {
const id = options?.id || SavedObjectsUtils.generateId();
try {
@ -432,7 +432,7 @@ export class RulesClient {
);
}
public async get<Params extends AlertTypeParams = never>({
public async get<Params extends RuleTypeParams = never>({
id,
includeLegacyId = false,
excludeFromPublicApi = false,
@ -440,7 +440,7 @@ export class RulesClient {
id: string;
includeLegacyId?: boolean;
excludeFromPublicApi?: boolean;
}): Promise<SanitizedAlert<Params> | SanitizedRuleWithLegacyId<Params>> {
}): Promise<SanitizedRule<Params> | SanitizedRuleWithLegacyId<Params>> {
const result = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
try {
await this.authorization.ensureAuthorized({
@ -475,7 +475,7 @@ export class RulesClient {
);
}
public async resolve<Params extends AlertTypeParams = never>({
public async resolve<Params extends RuleTypeParams = never>({
id,
includeLegacyId,
}: {
@ -612,7 +612,7 @@ export class RulesClient {
});
}
public async find<Params extends AlertTypeParams = never>({
public async find<Params extends RuleTypeParams = never>({
options: { fields, ...options } = {},
excludeFromPublicApi = false,
}: { options?: FindOptions; excludeFromPublicApi?: boolean } = {}): Promise<FindResult<Params>> {
@ -762,7 +762,7 @@ export class RulesClient {
},
};
for (const key of AlertExecutionStatusValues) {
for (const key of RuleExecutionStatusValues) {
placeholder.alertExecutionStatus[key] = 0;
}
@ -783,7 +783,7 @@ export class RulesClient {
};
// Fill missing keys with zeroes
for (const key of AlertExecutionStatusValues) {
for (const key of RuleExecutionStatusValues) {
if (!ret.alertExecutionStatus.hasOwnProperty(key)) {
ret.alertExecutionStatus[key] = 0;
}
@ -878,10 +878,10 @@ export class RulesClient {
return removeResult;
}
public async update<Params extends AlertTypeParams = never>({
public async update<Params extends RuleTypeParams = never>({
id,
data,
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
}: UpdateOptions<Params>): Promise<PartialRule<Params>> {
return await retryIfConflicts(
this.logger,
`rulesClient.update('${id}')`,
@ -889,10 +889,10 @@ export class RulesClient {
);
}
private async updateWithOCC<Params extends AlertTypeParams>({
private async updateWithOCC<Params extends RuleTypeParams>({
id,
data,
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
}: UpdateOptions<Params>): Promise<PartialRule<Params>> {
let alertSavedObject: SavedObject<RawRule>;
try {
@ -974,10 +974,10 @@ export class RulesClient {
return updateResult;
}
private async updateAlert<Params extends AlertTypeParams>(
private async updateAlert<Params extends RuleTypeParams>(
{ id, data }: UpdateOptions<Params>,
{ attributes, version }: SavedObject<RawRule>
): Promise<PartialAlert<Params>> {
): Promise<PartialRule<Params>> {
const ruleType = this.ruleTypeRegistry.get(attributes.alertTypeId);
// Validate
@ -1048,7 +1048,7 @@ export class RulesClient {
throw e;
}
return this.getPartialAlertFromRaw(
return this.getPartialRuleFromRaw(
id,
ruleType,
updatedObject.attributes,
@ -1332,12 +1332,12 @@ export class RulesClient {
try {
const { state } = taskInstanceToAlertTaskInstance(
await this.taskManager.get(attributes.scheduledTaskId),
attributes as unknown as SanitizedAlert
attributes as unknown as SanitizedRule
);
const recoveredAlertInstances = mapValues<Record<string, RawAlertInstance>, AlertInstance>(
const recoveredAlertInstances = mapValues<Record<string, RawAlert>, Alert>(
state.alertInstances ?? {},
(rawAlertInstance) => new AlertInstance(rawAlertInstance)
(rawAlertInstance) => new Alert(rawAlertInstance)
);
const recoveredAlertInstanceIds = Object.keys(recoveredAlertInstances);
@ -1568,7 +1568,7 @@ export class RulesClient {
}
private async muteInstanceWithOCC({ alertId, alertInstanceId }: MuteOptions) {
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Alert>(
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Rule>(
'alert',
alertId
);
@ -1636,7 +1636,7 @@ export class RulesClient {
alertId: string;
alertInstanceId: string;
}) {
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Alert>(
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Rule>(
'alert',
alertId
);
@ -1751,22 +1751,22 @@ export class RulesClient {
...omit(action, 'actionRef'),
id: reference.id,
};
}) as Alert['actions'];
}) as Rule['actions'];
}
private getAlertFromRaw<Params extends AlertTypeParams>(
private getAlertFromRaw<Params extends RuleTypeParams>(
id: string,
ruleTypeId: string,
rawRule: RawRule,
references: SavedObjectReference[] | undefined,
includeLegacyId: boolean = false,
excludeFromPublicApi: boolean = false
): Alert | AlertWithLegacyId {
): Rule | RuleWithLegacyId {
const ruleType = this.ruleTypeRegistry.get(ruleTypeId);
// In order to support the partial update API of Saved Objects we have to support
// partial updates of an Alert, but when we receive an actual RawRule, it is safe
// to cast the result to an Alert
const res = this.getPartialAlertFromRaw<Params>(
const res = this.getPartialRuleFromRaw<Params>(
id,
ruleType,
rawRule,
@ -1776,13 +1776,13 @@ export class RulesClient {
);
// include to result because it is for internal rules client usage
if (includeLegacyId) {
return res as AlertWithLegacyId;
return res as RuleWithLegacyId;
}
// exclude from result because it is an internal variable
return omit(res, ['legacyId']) as Alert;
return omit(res, ['legacyId']) as Rule;
}
private getPartialAlertFromRaw<Params extends AlertTypeParams>(
private getPartialRuleFromRaw<Params extends RuleTypeParams>(
id: string,
ruleType: UntypedNormalizedRuleType,
{
@ -1801,7 +1801,7 @@ export class RulesClient {
references: SavedObjectReference[] | undefined,
includeLegacyId: boolean = false,
excludeFromPublicApi: boolean = false
): PartialAlert<Params> | PartialAlertWithLegacyId<Params> {
): PartialRule<Params> | PartialRuleWithLegacyId<Params> {
const rule = {
id,
notifyWhen,
@ -1820,8 +1820,8 @@ export class RulesClient {
};
return includeLegacyId
? ({ ...rule, legacyId } as PartialAlertWithLegacyId<Params>)
: (rule as PartialAlert<Params>);
? ({ ...rule, legacyId } as PartialRuleWithLegacyId<Params>)
: (rule as PartialRule<Params>);
}
private async validateActions(
@ -1873,8 +1873,8 @@ export class RulesClient {
}
private async extractReferences<
Params extends AlertTypeParams,
ExtractedParams extends AlertTypeParams
Params extends RuleTypeParams,
ExtractedParams extends RuleTypeParams
>(
ruleType: UntypedNormalizedRuleType,
ruleActions: NormalizedAlertAction[],
@ -1909,8 +1909,8 @@ export class RulesClient {
}
private injectReferencesIntoParams<
Params extends AlertTypeParams,
ExtractedParams extends AlertTypeParams
Params extends RuleTypeParams,
ExtractedParams extends RuleTypeParams
>(
ruleId: string,
ruleType: UntypedNormalizedRuleType,

View file

@ -309,7 +309,7 @@ describe('Task Runner', () => {
},
]
`);
expect(call.services.alertInstanceFactory).toBeTruthy();
expect(call.services.alertFactory.create).toBeTruthy();
expect(call.services.scopedClusterClient).toBeTruthy();
expect(call.services).toBeTruthy();
@ -427,8 +427,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices
.alertInstanceFactory('1')
executorServices.alertFactory
.create('1')
.scheduleActionsWithSubGroup('default', 'subDefault');
}
);
@ -708,7 +708,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -934,8 +934,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertInstanceFactory('2').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
executorServices.alertFactory.create('2').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -991,7 +991,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -1192,7 +1192,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -1268,8 +1268,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices
.alertInstanceFactory('1')
executorServices.alertFactory
.create('1')
.scheduleActionsWithSubGroup('default', 'subgroup1');
}
);
@ -1350,7 +1350,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -1672,7 +1672,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -2080,10 +2080,10 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
// create an instance, but don't schedule any actions, so it doesn't go active
executorServices.alertInstanceFactory('3');
executorServices.alertFactory.create('3');
}
);
const taskRunner = new TaskRunner(
@ -2186,7 +2186,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -2297,7 +2297,7 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const date = new Date().toISOString();
@ -3692,8 +3692,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertInstanceFactory('2').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
executorServices.alertFactory.create('2').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -4006,8 +4006,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertInstanceFactory('2').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
executorServices.alertFactory.create('2').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -4251,8 +4251,8 @@ describe('Task Runner', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertInstanceFactory('2').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
executorServices.alertFactory.create('2').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(
@ -5035,7 +5035,7 @@ describe('Task Runner', () => {
},
]
`);
expect(call.services.alertInstanceFactory).toBeTruthy();
expect(call.services.alertFactory.create).toBeTruthy();
expect(call.services.scopedClusterClient).toBeTruthy();
expect(call.services).toBeTruthy();

View file

@ -15,7 +15,7 @@ import { Logger, KibanaRequest } from '../../../../../src/core/server';
import { TaskRunnerContext } from './task_runner_factory';
import { ConcreteTaskInstance, throwUnrecoverableError } from '../../../task_manager/server';
import { createExecutionHandler, ExecutionHandler } from './create_execution_handler';
import { AlertInstance, createAlertInstanceFactory } from '../alert_instance';
import { Alert as CreatedAlert, createAlertFactory } from '../alert';
import {
validateRuleTypeParams,
executionStatusFromState,
@ -285,7 +285,7 @@ export class TaskRunner<
async executeAlert(
alertId: string,
alert: AlertInstance<InstanceState, InstanceContext>,
alert: CreatedAlert<InstanceState, InstanceContext>,
executionHandler: ExecutionHandler<ActionGroupIds | RecoveryActionGroupId>
) {
const {
@ -333,8 +333,8 @@ export class TaskRunner<
const alerts = mapValues<
Record<string, RawAlertInstance>,
AlertInstance<InstanceState, InstanceContext>
>(alertRawInstances, (rawAlert) => new AlertInstance<InstanceState, InstanceContext>(rawAlert));
CreatedAlert<InstanceState, InstanceContext>
>(alertRawInstances, (rawAlert) => new CreatedAlert<InstanceState, InstanceContext>(rawAlert));
const originalAlerts = cloneDeep(alerts);
const originalAlertIds = new Set(Object.keys(originalAlerts));
@ -358,11 +358,13 @@ export class TaskRunner<
executionId: this.executionId,
services: {
...services,
alertInstanceFactory: createAlertInstanceFactory<
alertFactory: createAlertFactory<
InstanceState,
InstanceContext,
WithoutReservedActionGroups<ActionGroupIds, RecoveryActionGroupId>
>(alerts),
>({
alerts,
}),
shouldWriteAlerts: () => this.shouldLogAndScheduleActionsForAlerts(),
shouldStopExecution: () => this.cancelled,
search: createAbortableEsClientFactory({
@ -420,11 +422,11 @@ export class TaskRunner<
// Cleanup alerts that are no longer scheduling actions to avoid over populating the alertInstances object
const alertsWithScheduledActions = pickBy(
alerts,
(alert: AlertInstance<InstanceState, InstanceContext>) => alert.hasScheduledActions()
(alert: CreatedAlert<InstanceState, InstanceContext>) => alert.hasScheduledActions()
);
const recoveredAlerts = pickBy(
alerts,
(alert: AlertInstance<InstanceState, InstanceContext>, id) =>
(alert: CreatedAlert<InstanceState, InstanceContext>, id) =>
!alert.hasScheduledActions() && originalAlertIds.has(id)
);
@ -478,7 +480,7 @@ export class TaskRunner<
const alertsToExecute =
notifyWhen === 'onActionGroupChange'
? Object.entries(alertsWithScheduledActions).filter(
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
([alertName, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) => {
const shouldExecuteAction = alert.scheduledActionGroupOrSubgroupHasChanged();
if (!shouldExecuteAction) {
this.logger.debug(
@ -489,7 +491,7 @@ export class TaskRunner<
}
)
: Object.entries(alertsWithScheduledActions).filter(
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
([alertName, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) => {
const throttled = alert.isThrottled(throttle);
const muted = mutedAlertIdsSet.has(alertName);
const shouldExecuteAction = !throttled && !muted;
@ -506,7 +508,7 @@ export class TaskRunner<
const allTriggeredActions = await Promise.all(
alertsToExecute.map(
([alertId, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) =>
([alertId, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) =>
this.executeAlert(alertId, alert, executionHandler)
)
);
@ -533,7 +535,7 @@ export class TaskRunner<
triggeredActions,
alertTypeState: updatedRuleTypeState || undefined,
alertInstances: mapValues<
Record<string, AlertInstance<InstanceState, InstanceContext>>,
Record<string, CreatedAlert<InstanceState, InstanceContext>>,
RawAlertInstance
>(alertsWithScheduledActions, (alert) => alert.toRaw()),
};
@ -910,9 +912,9 @@ interface TrackAlertDurationsParams<
InstanceState extends AlertInstanceState,
InstanceContext extends AlertInstanceContext
> {
originalAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
currentAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
originalAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
currentAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
}
function trackAlertDurations<
@ -967,9 +969,9 @@ interface GenerateNewAndRecoveredAlertEventsParams<
> {
eventLogger: IEventLogger;
executionId: string;
originalAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
currentAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
originalAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
currentAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
ruleId: string;
ruleLabel: string;
namespace: string | undefined;
@ -1117,7 +1119,7 @@ interface ScheduleActionsForRecoveredAlertsParams<
> {
logger: Logger;
recoveryActionGroup: ActionGroup<RecoveryActionGroupId>;
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, RecoveryActionGroupId>>;
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, RecoveryActionGroupId>>;
executionHandler: ExecutionHandler<RecoveryActionGroupId | RecoveryActionGroupId>;
mutedAlertIdsSet: Set<string>;
ruleLabel: string;
@ -1173,8 +1175,8 @@ interface LogActiveAndRecoveredAlertsParams<
RecoveryActionGroupId extends string
> {
logger: Logger;
activeAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, ActionGroupIds>>;
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, RecoveryActionGroupId>>;
activeAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, ActionGroupIds>>;
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, RecoveryActionGroupId>>;
ruleLabel: string;
}

View file

@ -359,7 +359,7 @@ describe('Task Runner Cancel', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
// setting cancelAlertsOnRuleTimeout to false here
@ -393,7 +393,7 @@ describe('Task Runner Cancel', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
// setting cancelAlertsOnRuleTimeout for ruleType to false here
@ -427,7 +427,7 @@ describe('Task Runner Cancel', () => {
AlertInstanceContext,
string
>) => {
executorServices.alertInstanceFactory('1').scheduleActions('default');
executorServices.alertFactory.create('1').scheduleActions('default');
}
);
const taskRunner = new TaskRunner(

View file

@ -7,7 +7,7 @@
import type { IRouter, RequestHandlerContext, SavedObjectReference } from 'src/core/server';
import type { PublicMethodsOf } from '@kbn/utility-types';
import { PublicAlertInstance } from './alert_instance';
import { PublicAlert } from './alert';
import { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry';
import { PluginSetupContract, PluginStartContract } from './plugin';
import { RulesClient } from './rules_client';
@ -74,9 +74,9 @@ export interface AlertServices<
InstanceContext extends AlertInstanceContext = AlertInstanceContext,
ActionGroupIds extends string = never
> extends Services {
alertInstanceFactory: (
id: string
) => PublicAlertInstance<InstanceState, InstanceContext, ActionGroupIds>;
alertFactory: {
create: (id: string) => PublicAlert<InstanceState, InstanceContext, ActionGroupIds>;
};
shouldWriteAlerts: () => boolean;
shouldStopExecution: () => boolean;
search: IAbortableClusterClient;

View file

@ -39,7 +39,7 @@ describe('Error count alert', () => {
);
await executor({ params });
expect(services.alertInstanceFactory).not.toBeCalled();
expect(services.alertFactory.create).not.toBeCalled();
});
it('sends alerts with service name and environment for those that exceeded the threshold', async () => {
@ -138,7 +138,7 @@ describe('Error count alert', () => {
'apm.error_rate_foo_env-foo-2',
'apm.error_rate_bar_env-bar',
].forEach((instanceName) =>
expect(services.alertInstanceFactory).toHaveBeenCalledWith(instanceName)
expect(services.alertFactory.create).toHaveBeenCalledWith(instanceName)
);
expect(scheduleActions).toHaveBeenCalledTimes(3);

View file

@ -32,7 +32,7 @@ describe('Transaction duration anomaly alert', () => {
services.scopedClusterClient.asCurrentUser.search
).not.toHaveBeenCalled();
expect(services.alertInstanceFactory).not.toHaveBeenCalled();
expect(services.alertFactory.create).not.toHaveBeenCalled();
});
it('ml jobs are not available', async () => {
@ -59,7 +59,7 @@ describe('Transaction duration anomaly alert', () => {
services.scopedClusterClient.asCurrentUser.search
).not.toHaveBeenCalled();
expect(services.alertInstanceFactory).not.toHaveBeenCalled();
expect(services.alertFactory.create).not.toHaveBeenCalled();
});
it('anomaly is less than threshold', async () => {
@ -110,7 +110,7 @@ describe('Transaction duration anomaly alert', () => {
expect(
services.scopedClusterClient.asCurrentUser.search
).not.toHaveBeenCalled();
expect(services.alertInstanceFactory).not.toHaveBeenCalled();
expect(services.alertFactory.create).not.toHaveBeenCalled();
});
});
@ -183,9 +183,9 @@ describe('Transaction duration anomaly alert', () => {
await executor({ params });
expect(services.alertInstanceFactory).toHaveBeenCalledTimes(1);
expect(services.alertFactory.create).toHaveBeenCalledTimes(1);
expect(services.alertInstanceFactory).toHaveBeenCalledWith(
expect(services.alertFactory.create).toHaveBeenCalledWith(
'apm.transaction_duration_anomaly_foo_development_type-foo'
);

View file

@ -46,7 +46,7 @@ describe('Transaction error rate alert', () => {
);
await executor({ params });
expect(services.alertInstanceFactory).not.toBeCalled();
expect(services.alertFactory.create).not.toBeCalled();
});
it('sends alerts for services that exceeded the threshold', async () => {
@ -117,12 +117,12 @@ describe('Transaction error rate alert', () => {
await executor({ params });
expect(services.alertInstanceFactory).toHaveBeenCalledTimes(1);
expect(services.alertFactory.create).toHaveBeenCalledTimes(1);
expect(services.alertInstanceFactory).toHaveBeenCalledWith(
expect(services.alertFactory.create).toHaveBeenCalledWith(
'apm.transaction_error_rate_foo_type-foo_env-foo'
);
expect(services.alertInstanceFactory).not.toHaveBeenCalledWith(
expect(services.alertFactory.create).not.toHaveBeenCalledWith(
'apm.transaction_error_rate_bar_type-bar_env-bar'
);

View file

@ -42,7 +42,7 @@ export const createRuleTypeMocks = () => {
savedObjectsClient: {
get: () => ({ attributes: { consumer: APM_SERVER_FEATURE_ID } }),
},
alertInstanceFactory: jest.fn(() => ({ scheduleActions })),
alertFactory: { create: jest.fn(() => ({ scheduleActions })) },
alertWithLifecycle: jest.fn(),
logger: loggerMock,
shouldWriteAlerts: () => true,

View file

@ -16,10 +16,7 @@ import {
AlertInstanceState as AlertState,
RecoveredActionGroup,
} from '../../../../../alerting/common';
import {
AlertInstance as Alert,
AlertTypeState as RuleTypeState,
} from '../../../../../alerting/server';
import { Alert, AlertTypeState as RuleTypeState } from '../../../../../alerting/server';
import { AlertStates, InventoryMetricThresholdParams } from '../../../../common/alerting/metrics';
import { createFormatter } from '../../../../common/formatters';
import { getCustomMetricLabel } from '../../../../common/formatters/get_custom_metric_label';

View file

@ -422,7 +422,7 @@ describe('Log threshold executor', () => {
processUngroupedResults(
results,
ruleParams,
alertsMock.createAlertInstanceFactory,
alertsMock.createAlertFactory.create,
alertUpdaterMock
);
// First call, second argument
@ -486,7 +486,7 @@ describe('Log threshold executor', () => {
processGroupByResults(
results,
ruleParams,
alertsMock.createAlertInstanceFactory,
alertsMock.createAlertFactory.create,
alertUpdaterMock
);
expect(alertUpdaterMock.mock.calls.length).toBe(2);

View file

@ -16,7 +16,7 @@ import { ElasticsearchClient } from 'kibana/server';
import {
ActionGroup,
ActionGroupIdsOf,
AlertInstance as Alert,
Alert,
AlertInstanceContext as AlertContext,
AlertInstanceState as AlertState,
AlertTypeState as RuleTypeState,

View file

@ -83,7 +83,7 @@ export const createMetricAnomalyExecutor =
typical,
influencers,
} = first(data as MappedAnomalyHit[])!;
const alert = services.alertInstanceFactory(`${nodeType}-${metric}`);
const alert = services.alertFactory.create(`${nodeType}-${metric}`);
alert.scheduleActions(FIRED_ACTIONS_ID, {
alertState: stateToAlertMessage[AlertStates.ALERT],

View file

@ -840,9 +840,9 @@ services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId
});
const alertInstances = new Map<string, AlertTestInstance>();
services.alertInstanceFactory.mockImplementation((instanceID: string) => {
services.alertFactory.create.mockImplementation((instanceID: string) => {
const newAlertInstance: AlertTestInstance = {
instance: alertsMock.createAlertInstanceFactory(),
instance: alertsMock.createAlertFactory.create(),
actionQueue: [],
state: {},
};

View file

@ -15,10 +15,7 @@ import {
AlertInstanceState as AlertState,
RecoveredActionGroup,
} from '../../../../../alerting/common';
import {
AlertInstance as Alert,
AlertTypeState as RuleTypeState,
} from '../../../../../alerting/server';
import { Alert, AlertTypeState as RuleTypeState } from '../../../../../alerting/server';
import { AlertStates, Comparator } from '../../../../common/alerting/metrics';
import { createFormatter } from '../../../../common/formatters';
import { InfraBackendLibs } from '../../infra_types';

View file

@ -139,7 +139,7 @@ export function registerAnomalyDetectionAlertType({
if (executionResult) {
const alertInstanceName = executionResult.name;
const alertInstance = services.alertInstanceFactory(alertInstanceName);
const alertInstance = services.alertFactory.create(alertInstanceName);
alertInstance.scheduleActions(ANOMALY_SCORE_MATCH_GROUP_ID, executionResult);
}
},

View file

@ -159,7 +159,7 @@ export function registerJobsMonitoringRuleType({
);
executionResult.forEach(({ name: alertInstanceName, context }) => {
const alertInstance = services.alertInstanceFactory(alertInstanceName);
const alertInstance = services.alertFactory.create(alertInstanceName);
alertInstance.scheduleActions(ANOMALY_DETECTION_JOB_REALTIME_ISSUE, context);
});
}

View file

@ -10,11 +10,16 @@ import { i18n } from '@kbn/i18n';
import {
RuleType,
AlertExecutorOptions,
AlertInstance,
Alert,
RulesClient,
AlertServices,
} from '../../../alerting/server';
import { Alert, AlertTypeParams, RawAlertInstance, SanitizedAlert } from '../../../alerting/common';
import {
Alert as Rule,
AlertTypeParams,
RawAlertInstance,
SanitizedAlert,
} from '../../../alerting/common';
import { ActionsClient } from '../../../actions/server';
import {
AlertState,
@ -121,7 +126,7 @@ export class BaseRule {
});
if (existingRuleData.total > 0) {
return existingRuleData.data[0] as Alert;
return existingRuleData.data[0] as Rule;
}
const ruleActions = [];
@ -272,7 +277,7 @@ export class BaseRule {
for (const node of nodes) {
const newAlertStates: AlertNodeState[] = [];
// quick fix for now so that non node level alerts will use the cluster id
const instance = services.alertInstanceFactory(
const instance = services.alertFactory.create(
node.meta.nodeId || node.meta.instanceId || cluster.clusterUuid
);
@ -331,7 +336,7 @@ export class BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
instanceState: AlertInstanceState | AlertState | unknown,
item: AlertData | unknown,
cluster?: AlertCluster | unknown

View file

@ -116,13 +116,15 @@ describe('CCRReadExceptionsRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -21,7 +21,7 @@ import {
CommonAlertFilter,
CCRReadExceptionsStats,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_CCR_READ_EXCEPTIONS, RULE_DETAILS } from '../../common/constants';
import { fetchCCRReadExceptions } from '../lib/alerts/fetch_ccr_read_exceptions';
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
@ -209,7 +209,7 @@ export class CCRReadExceptionsRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -81,13 +81,15 @@ describe('ClusterHealthRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -18,7 +18,7 @@ import {
AlertClusterHealth,
AlertInstanceState,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_CLUSTER_HEALTH, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertMessageTokenType, AlertClusterHealthType, AlertSeverity } from '../../common/enums';
import { AlertingDefaults } from './alert_helpers';
@ -111,7 +111,7 @@ export class ClusterHealthRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -83,13 +83,15 @@ describe('CpuUsageRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -22,7 +22,7 @@ import {
CommonAlertParams,
CommonAlertFilter,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_CPU_USAGE, RULE_DETAILS } from '../../common/constants';
// @ts-ignore
import { ROUNDED_FLOAT } from '../../common/formatting';
@ -145,7 +145,7 @@ export class CpuUsageRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -96,13 +96,15 @@ describe('DiskUsageRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -22,7 +22,7 @@ import {
AlertDiskUsageNodeStats,
CommonAlertFilter,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_DISK_USAGE, RULE_DETAILS } from '../../common/constants';
// @ts-ignore
import { ROUNDED_FLOAT } from '../../common/formatting';
@ -152,7 +152,7 @@ export class DiskUsageRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -85,13 +85,15 @@ describe('ElasticsearchVersionMismatchAlert', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -17,7 +17,7 @@ import {
CommonAlertParams,
AlertVersions,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_ELASTICSEARCH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertSeverity } from '../../common/enums';
import { AlertingDefaults } from './alert_helpers';
@ -87,7 +87,7 @@ export class ElasticsearchVersionMismatchRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -88,13 +88,15 @@ describe('KibanaVersionMismatchRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -17,7 +17,7 @@ import {
CommonAlertParams,
AlertVersions,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_KIBANA_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertSeverity } from '../../common/enums';
import { AlertingDefaults } from './alert_helpers';
@ -97,7 +97,7 @@ export class KibanaVersionMismatchRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -96,13 +96,15 @@ describe('LargeShardSizeRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -21,7 +21,7 @@ import {
CommonAlertFilter,
IndexShardSizeStats,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_LARGE_SHARD_SIZE, RULE_DETAILS } from '../../common/constants';
import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size';
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
@ -149,7 +149,7 @@ export class LargeShardSizeRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -86,13 +86,15 @@ describe('LicenseExpirationRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -20,7 +20,7 @@ import {
AlertLicense,
AlertLicenseState,
} from '../../common/types/alerts';
import { AlertExecutorOptions, AlertInstance } from '../../../alerting/server';
import { AlertExecutorOptions, Alert } from '../../../alerting/server';
import { RULE_LICENSE_EXPIRATION, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
import { AlertingDefaults } from './alert_helpers';
@ -143,7 +143,7 @@ export class LicenseExpirationRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -86,13 +86,15 @@ describe('LogstashVersionMismatchRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -17,7 +17,7 @@ import {
CommonAlertParams,
AlertVersions,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_LOGSTASH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertSeverity } from '../../common/enums';
import { AlertingDefaults } from './alert_helpers';
@ -87,7 +87,7 @@ export class LogstashVersionMismatchRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -83,13 +83,15 @@ describe('MemoryUsageRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -22,7 +22,7 @@ import {
AlertMemoryUsageNodeStats,
CommonAlertFilter,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_MEMORY_USAGE, RULE_DETAILS } from '../../common/constants';
// @ts-ignore
import { ROUNDED_FLOAT } from '../../common/formatting';
@ -158,7 +158,7 @@ export class MemoryUsageRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -87,13 +87,15 @@ describe('MissingMonitoringDataRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -19,7 +19,7 @@ import {
CommonAlertFilter,
AlertNodeState,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_MISSING_MONITORING_DATA, RULE_DETAILS } from '../../common/constants';
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common';
@ -137,7 +137,7 @@ export class MissingMonitoringDataRule extends BaseRule {
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: { alertStates: AlertState[] },
item: AlertData | null,
cluster: AlertCluster

View file

@ -137,13 +137,15 @@ describe('NodesChangedAlert', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -19,7 +19,7 @@ import {
AlertInstanceState,
AlertNodesChangedState,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { RULE_NODES_CHANGED, LEGACY_RULE_DETAILS } from '../../common/constants';
import { AlertingDefaults } from './alert_helpers';
import { SanitizedAlert } from '../../../alerting/common';
@ -174,7 +174,7 @@ export class NodesChangedRule extends BaseRule {
}
protected async executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: AlertInstanceState,
item: AlertData | null,
cluster: AlertCluster

View file

@ -20,10 +20,10 @@ import {
AlertState,
AlertThreadPoolRejectionsStats,
} from '../../common/types/alerts';
import { AlertInstance } from '../../../alerting/server';
import { Alert } from '../../../alerting/server';
import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats';
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
import { Alert, RawAlertInstance } from '../../../alerting/common';
import { Alert as Rule, RawAlertInstance } from '../../../alerting/common';
import { AlertingDefaults, createLink } from './alert_helpers';
import { Globals } from '../static_globals';
@ -47,7 +47,7 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule {
}
constructor(
sanitizedRule: Alert | undefined = undefined,
sanitizedRule: Rule | undefined = undefined,
public readonly id: string,
public readonly threadPoolType: string,
public readonly name: string,
@ -176,7 +176,7 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule {
};
}
protected executeActions(
instance: AlertInstance,
instance: Alert,
{ alertStates }: { alertStates: AlertState[] },
item: AlertData | null,
cluster: AlertCluster

View file

@ -89,13 +89,15 @@ describe('ThreadpoolSearchRejectionsRule', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -89,13 +89,15 @@ describe('ThreadpoolWriteRejectionsAlert', () => {
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
alertFactory: {
create: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
},
state: {},
};

View file

@ -13,7 +13,7 @@ import { v4 } from 'uuid';
import { difference } from 'lodash';
import {
AlertExecutorOptions,
AlertInstance,
Alert,
AlertInstanceContext,
AlertInstanceState,
AlertTypeParams,
@ -62,7 +62,7 @@ export type LifecycleAlertService<
> = (alert: {
id: string;
fields: ExplicitAlertFields;
}) => AlertInstance<InstanceState, InstanceContext, ActionGroupIds>;
}) => Alert<InstanceState, InstanceContext, ActionGroupIds>;
export interface LifecycleAlertServices<
InstanceState extends AlertInstanceState = never,
@ -143,7 +143,7 @@ export const createLifecycleExecutor =
>
): Promise<WrappedLifecycleRuleState<State>> => {
const {
services: { alertInstanceFactory, shouldWriteAlerts },
services: { alertFactory, shouldWriteAlerts },
state: previousState,
} = options;
@ -165,7 +165,7 @@ export const createLifecycleExecutor =
> = {
alertWithLifecycle: ({ id, fields }) => {
currentAlerts[id] = fields;
return alertInstanceFactory(id);
return alertFactory.create(id);
},
};

View file

@ -66,10 +66,12 @@ function createRule(shouldWriteAlerts: boolean = true) {
const scheduleActions = jest.fn();
const alertInstanceFactory = () => {
return {
scheduleActions,
} as any;
const alertFactory = {
create: () => {
return {
scheduleActions,
} as any;
},
};
return {
@ -107,7 +109,7 @@ function createRule(shouldWriteAlerts: boolean = true) {
updatedBy: 'updatedBy',
},
services: {
alertInstanceFactory,
alertFactory,
savedObjectsClient: {} as any,
scopedClusterClient: {} as any,
shouldWriteAlerts: () => shouldWriteAlerts,

View file

@ -34,5 +34,5 @@ export const createLifecycleAlertServicesMock = <
>(
alertServices: AlertServices<InstanceState, InstanceContext>
): LifecycleAlertServices<InstanceState, InstanceContext, ActionGroupIds> => ({
alertWithLifecycle: ({ id }) => alertServices.alertInstanceFactory(id),
alertWithLifecycle: ({ id }) => alertServices.alertFactory.create(id),
});

View file

@ -67,8 +67,7 @@ export const createDefaultAlertExecutorOptions = <
params,
spaceId: 'SPACE_ID',
services: {
alertInstanceFactory: alertsMock.createAlertServices<InstanceState, InstanceContext>()
.alertInstanceFactory,
alertFactory: alertsMock.createAlertServices<InstanceState, InstanceContext>().alertFactory,
savedObjectsClient: savedObjectsClientMock.create(),
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
shouldWriteAlerts: () => shouldWriteAlerts,

View file

@ -136,9 +136,9 @@ describe('legacyRules_notification_alert_type', () => {
);
await alert.executor(payload);
expect(alertServices.alertInstanceFactory).toHaveBeenCalled();
expect(alertServices.alertFactory.create).toHaveBeenCalled();
const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results;
const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results;
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
'default',
expect.objectContaining({
@ -163,9 +163,9 @@ describe('legacyRules_notification_alert_type', () => {
)
);
await alert.executor(payload);
expect(alertServices.alertInstanceFactory).toHaveBeenCalled();
expect(alertServices.alertFactory.create).toHaveBeenCalled();
const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results;
const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results;
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
'default',
expect.objectContaining({
@ -192,9 +192,9 @@ describe('legacyRules_notification_alert_type', () => {
)
);
await alert.executor(payload);
expect(alertServices.alertInstanceFactory).toHaveBeenCalled();
expect(alertServices.alertFactory.create).toHaveBeenCalled();
const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results;
const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results;
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
'default',
expect.objectContaining({
@ -204,7 +204,7 @@ describe('legacyRules_notification_alert_type', () => {
);
});
it('should not call alertInstanceFactory if signalsCount was 0', async () => {
it('should not call alertFactory.create if signalsCount was 0', async () => {
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
alertServices.savedObjectsClient.get.mockResolvedValue({
id: 'id',
@ -218,7 +218,7 @@ describe('legacyRules_notification_alert_type', () => {
await alert.executor(payload);
expect(alertServices.alertInstanceFactory).not.toHaveBeenCalled();
expect(alertServices.alertFactory.create).not.toHaveBeenCalled();
});
it('should call scheduleActions if signalsCount was greater than 0', async () => {
@ -237,9 +237,9 @@ describe('legacyRules_notification_alert_type', () => {
await alert.executor(payload);
expect(alertServices.alertInstanceFactory).toHaveBeenCalled();
expect(alertServices.alertFactory.create).toHaveBeenCalled();
const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results;
const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results;
expect(alertInstanceMock.replaceState).toHaveBeenCalledWith(
expect.objectContaining({ signals_count: 100 })
);

View file

@ -119,7 +119,7 @@ export const legacyRulesNotificationAlertType = ({
);
if (signalsCount !== 0) {
const alertInstance = services.alertInstanceFactory(alertId);
const alertInstance = services.alertFactory.create(alertId);
scheduleNotificationActions({
alertInstance,
signalsCount,

View file

@ -54,7 +54,7 @@ describe('schedule_notification_actions', () => {
};
it('Should schedule actions with unflatted and legacy context', () => {
const alertInstance = alertServices.alertInstanceFactory(alertId);
const alertInstance = alertServices.alertFactory.create(alertId);
const signals = [sampleThresholdAlert._source, sampleThresholdAlert._source];
scheduleNotificationActions({
alertInstance,

View file

@ -6,7 +6,7 @@
*/
import { mapKeys, snakeCase } from 'lodash/fp';
import { AlertInstance } from '../../../../../alerting/server';
import { Alert } from '../../../../../alerting/server';
import { expandDottedObject } from '../../../../common/utils/expand_dotted';
import { RuleParams } from '../schemas/rule_schemas';
import aadFieldConversion from '../routes/index/signal_aad_mapping.json';
@ -46,7 +46,7 @@ const formatAlertsForNotificationActions = (alerts: unknown[]): unknown[] => {
};
interface ScheduleNotificationActions {
alertInstance: AlertInstance;
alertInstance: Alert;
signalsCount: number;
resultsLink: string;
ruleParams: NotificationRuleTypeParams;
@ -59,7 +59,7 @@ export const scheduleNotificationActions = ({
resultsLink = '',
ruleParams,
signals,
}: ScheduleNotificationActions): AlertInstance =>
}: ScheduleNotificationActions): Alert =>
alertInstance
.replaceState({
signals_count: signalsCount,

View file

@ -82,7 +82,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -107,7 +107,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [
@ -137,7 +137,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -166,7 +166,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -197,7 +197,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -235,7 +235,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -271,7 +271,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [],
@ -313,7 +313,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [
@ -375,7 +375,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [
@ -435,7 +435,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [
@ -497,7 +497,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [
@ -559,7 +559,7 @@ describe('schedule_throttle_notification_actions', () => {
},
})
),
alertInstance: alertsMock.createAlertInstanceFactory(),
alertInstance: alertsMock.createAlertFactory.create(),
notificationRuleParams,
logger,
signals: [

View file

@ -7,7 +7,7 @@
import { ElasticsearchClient, SavedObject, Logger } from 'src/core/server';
import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils';
import { AlertInstance } from '../../../../../alerting/server';
import { Alert } from '../../../../../alerting/server';
import { RuleParams } from '../schemas/rule_schemas';
import { deconflictSignalsAndResults, getNotificationResultsLink } from '../notifications/utils';
import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants';
@ -26,7 +26,7 @@ interface ScheduleThrottledNotificationActionsOptions {
outputIndex: RuleParams['outputIndex'];
ruleId: RuleParams['ruleId'];
esClient: ElasticsearchClient;
alertInstance: AlertInstance;
alertInstance: Alert;
notificationRuleParams: NotificationRuleTypeParams;
signals: unknown[];
logger: Logger;

View file

@ -34,7 +34,7 @@ import {
} from '../../../../../../alerting/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ExecutorType } from '../../../../../../alerting/server/types';
import { AlertInstance } from '../../../../../../alerting/server';
import { Alert } from '../../../../../../alerting/server';
import { ConfigType } from '../../../../config';
import { alertInstanceFactoryStub } from '../../signals/preview/alert_instance_factory_stub';
import { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps } from '../../rule_types/types';
@ -140,12 +140,14 @@ export const previewRulesRoute = async (
ruleTypeName: string,
params: TParams,
shouldWriteAlerts: () => boolean,
alertInstanceFactory: (
id: string
) => Pick<
AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>,
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
>
alertFactory: {
create: (
id: string
) => Pick<
Alert<TInstanceState, TInstanceContext, TActionGroupIds>,
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
>;
}
) => {
let statePreview = runState as TState;
@ -178,7 +180,7 @@ export const previewRulesRoute = async (
services: {
shouldWriteAlerts,
shouldStopExecution: () => false,
alertInstanceFactory,
alertFactory,
// Just use es client always for preview
search: context.core.elasticsearch.client,
savedObjectsClient: context.core.savedObjects.client,
@ -223,7 +225,7 @@ export const previewRulesRoute = async (
queryAlertType.name,
previewRuleParams,
() => true,
alertInstanceFactoryStub
{ create: alertInstanceFactoryStub }
);
break;
case 'threshold':
@ -236,7 +238,7 @@ export const previewRulesRoute = async (
thresholdAlertType.name,
previewRuleParams,
() => true,
alertInstanceFactoryStub
{ create: alertInstanceFactoryStub }
);
break;
case 'threat_match':
@ -249,7 +251,7 @@ export const previewRulesRoute = async (
threatMatchAlertType.name,
previewRuleParams,
() => true,
alertInstanceFactoryStub
{ create: alertInstanceFactoryStub }
);
break;
case 'eql':
@ -260,7 +262,7 @@ export const previewRulesRoute = async (
eqlAlertType.name,
previewRuleParams,
() => true,
alertInstanceFactoryStub
{ create: alertInstanceFactoryStub }
);
break;
case 'machine_learning':
@ -271,7 +273,7 @@ export const previewRulesRoute = async (
mlAlertType.name,
previewRuleParams,
() => true,
alertInstanceFactoryStub
{ create: alertInstanceFactoryStub }
);
break;
}

View file

@ -76,7 +76,7 @@ export const createRuleTypeMocks = (
search: elasticsearchServiceMock.createScopedClusterClient(),
savedObjectsClient: mockSavedObjectsClient,
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn(() => ({ scheduleActions })),
alertFactory: { create: jest.fn(() => ({ scheduleActions })) },
findAlerts: jest.fn(), // TODO: does this stay?
alertWithPersistence: jest.fn(),
logger: loggerMock,

View file

@ -315,7 +315,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
if (completeRule.ruleConfig.throttle != null) {
await scheduleThrottledNotificationActions({
alertInstance: services.alertInstanceFactory(alertId),
alertInstance: services.alertFactory.create(alertId),
throttle: completeRule.ruleConfig.throttle ?? '',
startedAt,
id: alertId,
@ -329,7 +329,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
logger,
});
} else if (createdSignalsCount) {
const alertInstance = services.alertInstanceFactory(alertId);
const alertInstance = services.alertFactory.create(alertId);
scheduleNotificationActions({
alertInstance,
signalsCount: createdSignalsCount,
@ -371,7 +371,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 (completeRule.ruleConfig.throttle != null) {
await scheduleThrottledNotificationActions({
alertInstance: services.alertInstanceFactory(alertId),
alertInstance: services.alertFactory.create(alertId),
throttle: completeRule.ruleConfig.throttle ?? '',
startedAt,
id: completeRule.alertId,
@ -403,7 +403,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 (completeRule.ruleConfig.throttle != null) {
await scheduleThrottledNotificationActions({
alertInstance: services.alertInstanceFactory(alertId),
alertInstance: services.alertFactory.create(alertId),
throttle: completeRule.ruleConfig.throttle ?? '',
startedAt,
id: completeRule.alertId,

View file

@ -12,7 +12,7 @@ import {
AlertTypeState,
} from '../../../../../../alerting/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AlertInstance } from '../../../../../../alerting/server/alert_instance';
import { Alert } from '../../../../../../alerting/server/alert';
export const alertInstanceFactoryStub = <
TParams extends RuleParams,
@ -27,13 +27,13 @@ export const alertInstanceFactoryStub = <
return {} as unknown as TInstanceState;
},
replaceState(state: TInstanceState) {
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
state: {} as TInstanceState,
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
});
},
scheduleActions(actionGroup: TActionGroupIds, alertcontext: TInstanceContext) {
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
state: {} as TInstanceState,
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
});
@ -43,7 +43,7 @@ export const alertInstanceFactoryStub = <
subgroup: string,
alertcontext: TInstanceContext
) {
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
state: {} as TInstanceState,
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
});

View file

@ -178,7 +178,7 @@ describe('alertType', () => {
},
});
expect(alertServices.alertInstanceFactory).not.toHaveBeenCalled();
expect(alertServices.alertFactory.create).not.toHaveBeenCalled();
expect(result).toMatchInlineSnapshot(`
Object {
@ -257,8 +257,8 @@ describe('alertType', () => {
},
});
expect(alertServices.alertInstanceFactory).toHaveBeenCalledWith(ConditionMetAlertInstanceId);
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
expect(alertServices.alertFactory.create).toHaveBeenCalledWith(ConditionMetAlertInstanceId);
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
latestTimestamp: undefined,
dateStart: expect.any(String),
@ -328,7 +328,7 @@ describe('alertType', () => {
},
});
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
// ensure the invalid "latestTimestamp" in the state is stored as an ISO string going forward
latestTimestamp: new Date(previousTimestamp).toISOString(),
@ -410,7 +410,7 @@ describe('alertType', () => {
},
});
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
latestTimestamp: undefined,
dateStart: expect.any(String),
@ -488,7 +488,7 @@ describe('alertType', () => {
};
const result = await alertType.executor(executorOptions);
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
latestTimestamp: undefined,
dateStart: expect.any(String),
@ -518,7 +518,7 @@ describe('alertType', () => {
state: result as EsQueryAlertState,
});
const existingInstance: AlertInstanceMock =
alertServices.alertInstanceFactory.mock.results[1].value;
alertServices.alertFactory.create.mock.results[1].value;
expect(existingInstance.replaceState).toHaveBeenCalledWith({
latestTimestamp: new Date(oldestDocumentTimestamp).toISOString(),
dateStart: expect.any(String),
@ -601,7 +601,7 @@ describe('alertType', () => {
},
});
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
latestTimestamp: undefined,
dateStart: expect.any(String),
@ -685,7 +685,7 @@ describe('alertType', () => {
},
});
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
expect(instance.replaceState).toHaveBeenCalledWith({
latestTimestamp: undefined,
dateStart: expect.any(String),

View file

@ -160,7 +160,7 @@ export function getAlertType(logger: Logger): RuleType<
>
) {
const { alertId, name, services, params, state } = options;
const { alertInstanceFactory, search } = services;
const { alertFactory, search } = services;
const previousTimestamp = state.latestTimestamp;
const abortableEsClient = search.asCurrentUser;
@ -255,7 +255,7 @@ export function getAlertType(logger: Logger): RuleType<
};
const actionContext = addMessages(options, baseContext, params);
const alertInstance = alertInstanceFactory(ConditionMetAlertInstanceId);
const alertInstance = alertFactory.create(ConditionMetAlertInstanceId);
alertInstance
// store the params we would need to recreate the query that led to this alert instance
.replaceState({ latestTimestamp: timestamp, dateStart, dateEnd })

View file

@ -87,11 +87,11 @@ export function transformResults(
export function getActiveEntriesAndGenerateAlerts(
prevLocationMap: Map<string, LatestEntityLocation[]>,
currLocationMap: Map<string, LatestEntityLocation[]>,
alertInstanceFactory: AlertServices<
alertFactory: AlertServices<
GeoContainmentInstanceState,
GeoContainmentInstanceContext,
typeof ActionGroupId
>['alertInstanceFactory'],
>['alertFactory'],
shapesIdsNamesMap: Record<string, unknown>,
currIntervalEndTime: Date
) {
@ -113,7 +113,7 @@ export function getActiveEntriesAndGenerateAlerts(
};
const alertInstanceId = `${entityName}-${context.containingBoundaryName}`;
if (shapeLocationId !== OTHER_CATEGORY) {
alertInstanceFactory(alertInstanceId).scheduleActions(ActionGroupId, context);
alertFactory.create(alertInstanceId).scheduleActions(ActionGroupId, context);
}
});
@ -189,7 +189,7 @@ export const getGeoContainmentExecutor = (log: Logger): GeoContainmentAlertType[
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
prevLocationMap,
currLocationMap,
services.alertInstanceFactory,
services.alertFactory,
shapesIdsNamesMap,
currIntervalEndTime
);

View file

@ -20,9 +20,9 @@ import { OTHER_CATEGORY } from '../es_query_builder';
import { GeoContainmentInstanceContext, GeoContainmentInstanceState } from '../alert_type';
import type { GeoContainmentParams } from '../alert_type';
const alertInstanceFactory =
(contextKeys: unknown[], testAlertActionArr: unknown[]) => (instanceId: string) => {
const alertInstance = alertsMock.createAlertInstanceFactory<
const alertFactory = (contextKeys: unknown[], testAlertActionArr: unknown[]) => ({
create: (instanceId: string) => {
const alertInstance = alertsMock.createAlertFactory.create<
GeoContainmentInstanceState,
GeoContainmentInstanceContext
>();
@ -39,7 +39,8 @@ const alertInstanceFactory =
}
);
return alertInstance;
};
},
});
describe('geo_containment', () => {
describe('transformResults', () => {
@ -253,7 +254,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
emptyPrevLocationMap,
currLocationMap,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -278,7 +279,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
prevLocationMapWithIdenticalEntityEntry,
currLocationMap,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -317,7 +318,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
prevLocationMapWithNonIdenticalEntityEntry,
currLocationMap,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -340,7 +341,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
emptyPrevLocationMap,
currLocationMapWithOther,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -373,7 +374,7 @@ describe('geo_containment', () => {
getActiveEntriesAndGenerateAlerts(
emptyPrevLocationMap,
currLocationMapWithThreeMore,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -410,7 +411,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
emptyPrevLocationMap,
currLocationMapWithOther,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -442,7 +443,7 @@ describe('geo_containment', () => {
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
emptyPrevLocationMap,
currLocationMapWithOther,
alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory(contextKeys, testAlertActionArr),
emptyShapesIdsNamesMap,
currentDateTime
);
@ -514,7 +515,7 @@ describe('geo_containment', () => {
const alertServicesWithSearchMock: AlertServicesMock = {
...alertsMock.createAlertServices(),
// @ts-ignore
alertInstanceFactory: alertInstanceFactory(contextKeys, testAlertActionArr),
alertFactory: alertFactory(contextKeys, testAlertActionArr),
scopedClusterClient: {
asCurrentUser: {
// @ts-ignore
@ -538,6 +539,7 @@ describe('geo_containment', () => {
it('should query for shapes if state does not contain shapes', async () => {
const executor = await getGeoContainmentExecutor(mockLogger);
// @ts-ignore
const executionResult = await executor({
previousStartedAt,
startedAt,
@ -557,6 +559,7 @@ describe('geo_containment', () => {
it('should not query for shapes if state contains shapes', async () => {
const executor = await getGeoContainmentExecutor(mockLogger);
// @ts-ignore
const executionResult = await executor({
previousStartedAt,
startedAt,
@ -575,6 +578,7 @@ describe('geo_containment', () => {
it('should carry through shapes filters in state to next call unmodified', async () => {
const executor = await getGeoContainmentExecutor(mockLogger);
// @ts-ignore
const executionResult = await executor({
previousStartedAt,
startedAt,
@ -610,6 +614,7 @@ describe('geo_containment', () => {
],
};
const executor = await getGeoContainmentExecutor(mockLogger);
// @ts-ignore
const executionResult = await executor({
previousStartedAt,
startedAt,

View file

@ -203,7 +203,7 @@ describe('alertType', () => {
},
});
expect(alertServices.alertInstanceFactory).toHaveBeenCalledWith('all documents');
expect(alertServices.alertFactory.create).toHaveBeenCalledWith('all documents');
});
it('should ensure a null result does not fire actions', async () => {
@ -269,7 +269,7 @@ describe('alertType', () => {
},
});
expect(customAlertServices.alertInstanceFactory).not.toHaveBeenCalled();
expect(customAlertServices.alertFactory.create).not.toHaveBeenCalled();
});
it('should ensure an undefined result does not fire actions', async () => {
@ -335,6 +335,6 @@ describe('alertType', () => {
},
});
expect(customAlertServices.alertInstanceFactory).not.toHaveBeenCalled();
expect(customAlertServices.alertFactory.create).not.toHaveBeenCalled();
});
});

View file

@ -134,7 +134,7 @@ export function getAlertType(
options: AlertExecutorOptions<Params, {}, {}, ActionContext, typeof ActionGroupId>
) {
const { alertId, name, services, params } = options;
const { alertInstanceFactory, search } = services;
const { alertFactory, search } = services;
const compareFn = ComparatorFns.get(params.thresholdComparator);
if (compareFn == null) {
@ -208,7 +208,7 @@ export function getAlertType(
conditions: humanFn,
};
const actionContext = addMessages(options, baseContext, params);
const alertInstance = alertInstanceFactory(instanceId);
const alertInstance = alertFactory.create(instanceId);
alertInstance.scheduleActions(ActionGroupId, actionContext);
logger.debug(`scheduled actionGroup: ${JSON.stringify(actionContext)}`);
}

View file

@ -100,7 +100,7 @@ export function getTransformHealthRuleType(): RuleType<
isExportable: true,
async executor(options) {
const {
services: { scopedClusterClient, alertInstanceFactory },
services: { scopedClusterClient, alertFactory },
params,
} = options;
@ -112,7 +112,7 @@ export function getTransformHealthRuleType(): RuleType<
if (executionResult.length > 0) {
executionResult.forEach(({ name: alertInstanceName, context }) => {
const alertInstance = alertInstanceFactory(alertInstanceName);
const alertInstance = alertFactory.create(alertInstanceName);
alertInstance.scheduleActions(TRANSFORM_ISSUE, context);
});
}

View file

@ -16,7 +16,7 @@ import { commonStateTranslations, tlsTranslations } from './translations';
import { ActionGroupIdsOf } from '../../../../alerting/common';
import { AlertInstanceContext } from '../../../../alerting/common';
import { AlertInstance } from '../../../../alerting/server';
import { Alert } from '../../../../alerting/server';
import { savedObjectsAdapter } from '../saved_objects/saved_objects';
import { createUptimeESClient } from '../lib';
@ -28,7 +28,7 @@ import {
export type ActionGroupIds = ActionGroupIdsOf<typeof TLS_LEGACY>;
type TLSAlertInstance = AlertInstance<Record<string, any>, AlertInstanceContext, ActionGroupIds>;
type TLSAlertInstance = Alert<Record<string, any>, AlertInstanceContext, ActionGroupIds>;
interface TlsAlertState {
count: number;
@ -113,10 +113,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
},
isExportable: true,
minimumLicenseRequired: 'basic',
async executor({
services: { alertInstanceFactory, scopedClusterClient, savedObjectsClient },
state,
}) {
async executor({ services: { alertFactory, scopedClusterClient, savedObjectsClient }, state }) {
const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings(savedObjectsClient);
const uptimeEsClient = createUptimeESClient({
@ -156,7 +153,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
'd'
)
.valueOf();
const alertInstance: TLSAlertInstance = alertInstanceFactory(TLS_LEGACY.id);
const alertInstance: TLSAlertInstance = alertFactory.create(TLS_LEGACY.id);
const summary = getCertSummary(certs, absoluteExpirationThreshold, absoluteAgeThreshold);
alertInstance.replaceState({
...updateState(state, foundCerts),

View file

@ -122,7 +122,7 @@ async function alwaysFiringExecutor(alertExecutorOptions: any) {
}
if (group) {
const instance = services.alertInstanceFactory('1').replaceState({ instanceStateValue: true });
const instance = services.alertFactory.create('1').replaceState({ instanceStateValue: true });
if (subgroup) {
instance.scheduleActionsWithSubGroup(group, subgroup, {
@ -177,8 +177,8 @@ function getCumulativeFiringAlertType() {
const runCount = (state.runCount || 0) + 1;
times(runCount, (index) => {
services
.alertInstanceFactory(`instance-${index}`)
services.alertFactory
.create(`instance-${index}`)
.replaceState({ instanceStateValue: true })
.scheduleActions(group);
});
@ -446,13 +446,13 @@ function getPatternFiringAlertType() {
for (const [instanceId, instancePattern] of Object.entries(pattern)) {
const scheduleByPattern = instancePattern[patternIndex];
if (scheduleByPattern === true) {
services.alertInstanceFactory(instanceId).scheduleActions('default', {
services.alertFactory.create(instanceId).scheduleActions('default', {
...EscapableStrings,
deep: DeepContextVariables,
});
} else if (typeof scheduleByPattern === 'string') {
services
.alertInstanceFactory(instanceId)
services.alertFactory
.create(instanceId)
.scheduleActionsWithSubGroup('default', scheduleByPattern);
}
}
@ -538,7 +538,7 @@ function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true
return {};
}
services.alertInstanceFactory('alert').scheduleActions('default', {});
services.alertFactory.create('alert').scheduleActions('default', {});
// run long if pattern says to
if (pattern[globalPatternIndex++] === true) {

View file

@ -54,8 +54,8 @@ export const alwaysFiringAlertType: RuleType<
const { services, state, params } = alertExecutorOptions;
(params.instances || []).forEach((instance: { id: string; state: any }) => {
services
.alertInstanceFactory(instance.id)
services.alertFactory
.create(instance.id)
.replaceState({ instanceStateValue: true, ...(instance.state || {}) })
.scheduleActions('default');
});

View file

@ -177,7 +177,7 @@ export default function createLifecycleExecutorApiTest({ getService }: FtrProvid
producer: 'observability.test',
},
services: {
alertInstanceFactory: sinon.stub(),
alertFactory: { create: sinon.stub() },
shouldWriteAlerts: sinon.stub().returns(true),
},
} as unknown as RuleExecutorOptions<