mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[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:
parent
aedbc9f4c9
commit
270adf4958
82 changed files with 997 additions and 1065 deletions
|
@ -65,8 +65,8 @@ export const alertType: RuleType<
|
||||||
range(instances)
|
range(instances)
|
||||||
.map(() => uuid.v4())
|
.map(() => uuid.v4())
|
||||||
.forEach((id: string) => {
|
.forEach((id: string) => {
|
||||||
services
|
services.alertFactory
|
||||||
.alertInstanceFactory(id)
|
.create(id)
|
||||||
.replaceState({ triggerdOnCycle: count })
|
.replaceState({ triggerdOnCycle: count })
|
||||||
.scheduleActions(getTShirtSizeByIdAndThreshold(id, thresholds));
|
.scheduleActions(getTShirtSizeByIdAndThreshold(id, thresholds));
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const alertType: RuleType<
|
||||||
|
|
||||||
if (getOperator(op)(peopleInCraft.length, outerSpaceCapacity)) {
|
if (getOperator(op)(peopleInCraft.length, outerSpaceCapacity)) {
|
||||||
peopleInCraft.forEach(({ craft, name }) => {
|
peopleInCraft.forEach(({ craft, name }) => {
|
||||||
services.alertInstanceFactory(name).replaceState({ craft }).scheduleActions('default');
|
services.alertFactory.create(name).replaceState({ craft }).scheduleActions('default');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ Table of Contents
|
||||||
|
|
||||||
> References to `rule` and `rule type` entities are still named `AlertType` within the codebase.
|
> 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 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.
|
**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.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.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.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.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.|
|
|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
|
// scenario the provided server will be used. Also, this ID will be
|
||||||
// used to make `getState()` return previous state, if any, on
|
// used to make `getState()` return previous state, if any, on
|
||||||
// matching identifiers.
|
// 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
|
// State from the last execution. This will exist if an alert was
|
||||||
// created and executed in the previous execution
|
// created and executed in the previous execution
|
||||||
|
@ -731,13 +729,13 @@ Query:
|
||||||
|
|
||||||
## Alert Factory
|
## 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"`.
|
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|
|
|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.
|
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({
|
.replaceState({
|
||||||
cpuUsage: 80,
|
cpuUsage: 80,
|
||||||
})
|
})
|
||||||
|
|
488
x-pack/plugins/alerting/server/alert/alert.test.ts
Normal file
488
x-pack/plugins/alerting/server/alert/alert.test.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -27,16 +27,16 @@ interface ScheduledExecutionOptions<
|
||||||
state: State;
|
state: State;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PublicAlertInstance<
|
export type PublicAlert<
|
||||||
State extends AlertInstanceState = AlertInstanceState,
|
State extends AlertInstanceState = AlertInstanceState,
|
||||||
Context extends AlertInstanceContext = AlertInstanceContext,
|
Context extends AlertInstanceContext = AlertInstanceContext,
|
||||||
ActionGroupIds extends string = DefaultActionGroupId
|
ActionGroupIds extends string = DefaultActionGroupId
|
||||||
> = Pick<
|
> = Pick<
|
||||||
AlertInstance<State, Context, ActionGroupIds>,
|
Alert<State, Context, ActionGroupIds>,
|
||||||
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
|
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export class AlertInstance<
|
export class Alert<
|
||||||
State extends AlertInstanceState = AlertInstanceState,
|
State extends AlertInstanceState = AlertInstanceState,
|
||||||
Context extends AlertInstanceContext = AlertInstanceContext,
|
Context extends AlertInstanceContext = AlertInstanceContext,
|
||||||
ActionGroupIds extends string = never
|
ActionGroupIds extends string = never
|
|
@ -6,8 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { AlertInstance } from './alert_instance';
|
import { Alert } from './alert';
|
||||||
import { createAlertInstanceFactory } from './create_alert_instance_factory';
|
import { createAlertFactory } from './create_alert_factory';
|
||||||
|
|
||||||
let clock: sinon.SinonFakeTimers;
|
let clock: sinon.SinonFakeTimers;
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ beforeAll(() => {
|
||||||
beforeEach(() => clock.reset());
|
beforeEach(() => clock.reset());
|
||||||
afterAll(() => clock.restore());
|
afterAll(() => clock.restore());
|
||||||
|
|
||||||
test('creates new instances for ones not passed in', () => {
|
test('creates new alerts for ones not passed in', () => {
|
||||||
const alertInstanceFactory = createAlertInstanceFactory({});
|
const alertFactory = createAlertFactory({ alerts: {} });
|
||||||
const result = alertInstanceFactory('1');
|
const result = alertFactory.create('1');
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"meta": Object {},
|
"meta": Object {},
|
||||||
|
@ -28,15 +28,17 @@ test('creates new instances for ones not passed in', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reuses existing instances', () => {
|
test('reuses existing alerts', () => {
|
||||||
const alertInstance = new AlertInstance({
|
const alert = new Alert({
|
||||||
state: { foo: true },
|
state: { foo: true },
|
||||||
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
||||||
});
|
});
|
||||||
const alertInstanceFactory = createAlertInstanceFactory({
|
const alertFactory = createAlertFactory({
|
||||||
'1': alertInstance,
|
alerts: {
|
||||||
|
'1': alert,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const result = alertInstanceFactory('1');
|
const result = alertFactory.create('1');
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"meta": Object {
|
"meta": Object {
|
||||||
|
@ -52,11 +54,11 @@ test('reuses existing instances', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('mutates given instances', () => {
|
test('mutates given alerts', () => {
|
||||||
const alertInstances = {};
|
const alerts = {};
|
||||||
const alertInstanceFactory = createAlertInstanceFactory(alertInstances);
|
const alertFactory = createAlertFactory({ alerts });
|
||||||
alertInstanceFactory('1');
|
alertFactory.create('1');
|
||||||
expect(alertInstances).toMatchInlineSnapshot(`
|
expect(alerts).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"1": Object {
|
"1": Object {
|
||||||
"meta": Object {},
|
"meta": Object {},
|
33
x-pack/plugins/alerting/server/alert/create_alert_factory.ts
Normal file
33
x-pack/plugins/alerting/server/alert/create_alert_factory.ts
Normal 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];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,6 +5,6 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type { PublicAlertInstance } from './alert_instance';
|
export type { PublicAlert } from './alert';
|
||||||
export { AlertInstance } from './alert_instance';
|
export { Alert } from './alert';
|
||||||
export { createAlertInstanceFactory } from './create_alert_instance_factory';
|
export { createAlertFactory } from './create_alert_factory';
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -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];
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -32,7 +32,7 @@ export type {
|
||||||
export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config';
|
export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config';
|
||||||
export type { PluginSetupContract, PluginStartContract } from './plugin';
|
export type { PluginSetupContract, PluginStartContract } from './plugin';
|
||||||
export type { FindResult } from './rules_client';
|
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 { parseDuration } from './lib';
|
||||||
export { getEsErrorMessage } from './lib/errors';
|
export { getEsErrorMessage } from './lib/errors';
|
||||||
export type {
|
export type {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { rulesClientMock } from './rules_client.mock';
|
import { rulesClientMock } from './rules_client.mock';
|
||||||
import { PluginSetupContract, PluginStartContract } from './plugin';
|
import { PluginSetupContract, PluginStartContract } from './plugin';
|
||||||
import { AlertInstance } from './alert_instance';
|
import { Alert } from './alert';
|
||||||
import {
|
import {
|
||||||
elasticsearchServiceMock,
|
elasticsearchServiceMock,
|
||||||
savedObjectsClientMock,
|
savedObjectsClientMock,
|
||||||
|
@ -37,11 +37,13 @@ const createStartMock = () => {
|
||||||
export type AlertInstanceMock<
|
export type AlertInstanceMock<
|
||||||
State extends AlertInstanceState = AlertInstanceState,
|
State extends AlertInstanceState = AlertInstanceState,
|
||||||
Context extends AlertInstanceContext = AlertInstanceContext
|
Context extends AlertInstanceContext = AlertInstanceContext
|
||||||
> = jest.Mocked<AlertInstance<State, Context>>;
|
> = jest.Mocked<Alert<State, Context>>;
|
||||||
const createAlertInstanceFactoryMock = <
|
|
||||||
|
const createAlertFactoryMock = {
|
||||||
|
create: <
|
||||||
InstanceState extends AlertInstanceState = AlertInstanceState,
|
InstanceState extends AlertInstanceState = AlertInstanceState,
|
||||||
InstanceContext extends AlertInstanceContext = AlertInstanceContext
|
InstanceContext extends AlertInstanceContext = AlertInstanceContext
|
||||||
>() => {
|
>() => {
|
||||||
const mock = {
|
const mock = {
|
||||||
hasScheduledActions: jest.fn(),
|
hasScheduledActions: jest.fn(),
|
||||||
isThrottled: jest.fn(),
|
isThrottled: jest.fn(),
|
||||||
|
@ -61,6 +63,7 @@ const createAlertInstanceFactoryMock = <
|
||||||
mock.scheduleActions.mockReturnValue(mock);
|
mock.scheduleActions.mockReturnValue(mock);
|
||||||
|
|
||||||
return mock as unknown as AlertInstanceMock<InstanceState, InstanceContext>;
|
return mock as unknown as AlertInstanceMock<InstanceState, InstanceContext>;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAbortableSearchClientMock = () => {
|
const createAbortableSearchClientMock = () => {
|
||||||
|
@ -82,11 +85,11 @@ const createAlertServicesMock = <
|
||||||
InstanceState extends AlertInstanceState = AlertInstanceState,
|
InstanceState extends AlertInstanceState = AlertInstanceState,
|
||||||
InstanceContext extends AlertInstanceContext = AlertInstanceContext
|
InstanceContext extends AlertInstanceContext = AlertInstanceContext
|
||||||
>() => {
|
>() => {
|
||||||
const alertInstanceFactoryMock = createAlertInstanceFactoryMock<InstanceState, InstanceContext>();
|
const alertFactoryMockCreate = createAlertFactoryMock.create<InstanceState, InstanceContext>();
|
||||||
return {
|
return {
|
||||||
alertInstanceFactory: jest
|
alertFactory: {
|
||||||
.fn<jest.Mocked<AlertInstance<InstanceState, InstanceContext>>, [string]>()
|
create: jest.fn().mockReturnValue(alertFactoryMockCreate),
|
||||||
.mockReturnValue(alertInstanceFactoryMock),
|
},
|
||||||
savedObjectsClient: savedObjectsClientMock.create(),
|
savedObjectsClient: savedObjectsClientMock.create(),
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
shouldWriteAlerts: () => true,
|
shouldWriteAlerts: () => true,
|
||||||
|
@ -97,7 +100,7 @@ const createAlertServicesMock = <
|
||||||
export type AlertServicesMock = ReturnType<typeof createAlertServicesMock>;
|
export type AlertServicesMock = ReturnType<typeof createAlertServicesMock>;
|
||||||
|
|
||||||
export const alertsMock = {
|
export const alertsMock = {
|
||||||
createAlertInstanceFactory: createAlertInstanceFactoryMock,
|
createAlertFactory: createAlertFactoryMock,
|
||||||
createSetup: createSetupMock,
|
createSetup: createSetupMock,
|
||||||
createStart: createStartMock,
|
createStart: createStartMock,
|
||||||
createAlertServices: createAlertServicesMock,
|
createAlertServices: createAlertServicesMock,
|
||||||
|
|
|
@ -22,23 +22,23 @@ import {
|
||||||
import { esKuery } from '../../../../../src/plugins/data/server';
|
import { esKuery } from '../../../../../src/plugins/data/server';
|
||||||
import { ActionsClient, ActionsAuthorization } from '../../../actions/server';
|
import { ActionsClient, ActionsAuthorization } from '../../../actions/server';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert as Rule,
|
||||||
PartialAlert,
|
PartialAlert as PartialRule,
|
||||||
RawRule,
|
RawRule,
|
||||||
RuleTypeRegistry,
|
RuleTypeRegistry,
|
||||||
AlertAction,
|
AlertAction as RuleAction,
|
||||||
IntervalSchedule,
|
IntervalSchedule,
|
||||||
SanitizedAlert,
|
SanitizedAlert as SanitizedRule,
|
||||||
RuleTaskState,
|
RuleTaskState,
|
||||||
AlertSummary,
|
AlertSummary,
|
||||||
AlertExecutionStatusValues,
|
AlertExecutionStatusValues as RuleExecutionStatusValues,
|
||||||
AlertNotifyWhenType,
|
AlertNotifyWhenType as RuleNotifyWhenType,
|
||||||
AlertTypeParams,
|
AlertTypeParams as RuleTypeParams,
|
||||||
ResolvedSanitizedRule,
|
ResolvedSanitizedRule,
|
||||||
AlertWithLegacyId,
|
AlertWithLegacyId as RuleWithLegacyId,
|
||||||
SanitizedRuleWithLegacyId,
|
SanitizedRuleWithLegacyId,
|
||||||
PartialAlertWithLegacyId,
|
PartialAlertWithLegacyId as PartialRuleWithLegacyId,
|
||||||
RawAlertInstance,
|
RawAlertInstance as RawAlert,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getAlertNotifyWhenType } from '../lib';
|
import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getAlertNotifyWhenType } from '../lib';
|
||||||
import {
|
import {
|
||||||
|
@ -74,7 +74,7 @@ import { ruleAuditEvent, RuleAuditAction } from './audit_events';
|
||||||
import { KueryNode, nodeBuilder } from '../../../../../src/plugins/data/common';
|
import { KueryNode, nodeBuilder } from '../../../../../src/plugins/data/common';
|
||||||
import { mapSortField, validateOperationOnAttributes } from './lib';
|
import { mapSortField, validateOperationOnAttributes } from './lib';
|
||||||
import { getRuleExecutionStatusPending } from '../lib/rule_execution_status';
|
import { getRuleExecutionStatusPending } from '../lib/rule_execution_status';
|
||||||
import { AlertInstance } from '../alert_instance';
|
import { Alert } from '../alert';
|
||||||
import { EVENT_LOG_ACTIONS } from '../plugin';
|
import { EVENT_LOG_ACTIONS } from '../plugin';
|
||||||
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
||||||
import { getDefaultRuleMonitoring } from '../task_runner/task_runner';
|
import { getDefaultRuleMonitoring } from '../task_runner/task_runner';
|
||||||
|
@ -82,7 +82,7 @@ import { getDefaultRuleMonitoring } from '../task_runner/task_runner';
|
||||||
export interface RegistryAlertTypeWithAuth extends RegistryRuleType {
|
export interface RegistryAlertTypeWithAuth extends RegistryRuleType {
|
||||||
authorizedConsumers: string[];
|
authorizedConsumers: string[];
|
||||||
}
|
}
|
||||||
type NormalizedAlertAction = Omit<AlertAction, 'actionTypeId'>;
|
type NormalizedAlertAction = Omit<RuleAction, 'actionTypeId'>;
|
||||||
export type CreateAPIKeyResult =
|
export type CreateAPIKeyResult =
|
||||||
| { apiKeysEnabled: false }
|
| { apiKeysEnabled: false }
|
||||||
| { apiKeysEnabled: true; result: SecurityPluginGrantAPIKeyResult };
|
| { apiKeysEnabled: true; result: SecurityPluginGrantAPIKeyResult };
|
||||||
|
@ -174,16 +174,16 @@ export interface AggregateResult {
|
||||||
ruleMutedStatus?: { muted: number; unmuted: number };
|
ruleMutedStatus?: { muted: number; unmuted: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FindResult<Params extends AlertTypeParams> {
|
export interface FindResult<Params extends RuleTypeParams> {
|
||||||
page: number;
|
page: number;
|
||||||
perPage: number;
|
perPage: number;
|
||||||
total: 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<
|
data: Omit<
|
||||||
Alert<Params>,
|
Rule<Params>,
|
||||||
| 'id'
|
| 'id'
|
||||||
| 'createdBy'
|
| 'createdBy'
|
||||||
| 'updatedBy'
|
| '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;
|
id: string;
|
||||||
data: {
|
data: {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -211,7 +211,7 @@ export interface UpdateOptions<Params extends AlertTypeParams> {
|
||||||
actions: NormalizedAlertAction[];
|
actions: NormalizedAlertAction[];
|
||||||
params: Params;
|
params: Params;
|
||||||
throttle: string | null;
|
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 kibanaVersion!: PluginInitializerContext['env']['packageInfo']['version'];
|
||||||
private readonly auditLogger?: AuditLogger;
|
private readonly auditLogger?: AuditLogger;
|
||||||
private readonly eventLogger?: IEventLogger;
|
private readonly eventLogger?: IEventLogger;
|
||||||
private readonly fieldsToExcludeFromPublicApi: Array<keyof SanitizedAlert> = ['monitoring'];
|
private readonly fieldsToExcludeFromPublicApi: Array<keyof SanitizedRule> = ['monitoring'];
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
ruleTypeRegistry,
|
ruleTypeRegistry,
|
||||||
|
@ -286,10 +286,10 @@ export class RulesClient {
|
||||||
this.eventLogger = eventLogger;
|
this.eventLogger = eventLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async create<Params extends AlertTypeParams = never>({
|
public async create<Params extends RuleTypeParams = never>({
|
||||||
data,
|
data,
|
||||||
options,
|
options,
|
||||||
}: CreateOptions<Params>): Promise<SanitizedAlert<Params>> {
|
}: CreateOptions<Params>): Promise<SanitizedRule<Params>> {
|
||||||
const id = options?.id || SavedObjectsUtils.generateId();
|
const id = options?.id || SavedObjectsUtils.generateId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -432,7 +432,7 @@ export class RulesClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get<Params extends AlertTypeParams = never>({
|
public async get<Params extends RuleTypeParams = never>({
|
||||||
id,
|
id,
|
||||||
includeLegacyId = false,
|
includeLegacyId = false,
|
||||||
excludeFromPublicApi = false,
|
excludeFromPublicApi = false,
|
||||||
|
@ -440,7 +440,7 @@ export class RulesClient {
|
||||||
id: string;
|
id: string;
|
||||||
includeLegacyId?: boolean;
|
includeLegacyId?: boolean;
|
||||||
excludeFromPublicApi?: boolean;
|
excludeFromPublicApi?: boolean;
|
||||||
}): Promise<SanitizedAlert<Params> | SanitizedRuleWithLegacyId<Params>> {
|
}): Promise<SanitizedRule<Params> | SanitizedRuleWithLegacyId<Params>> {
|
||||||
const result = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
const result = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
try {
|
try {
|
||||||
await this.authorization.ensureAuthorized({
|
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,
|
id,
|
||||||
includeLegacyId,
|
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 } = {},
|
options: { fields, ...options } = {},
|
||||||
excludeFromPublicApi = false,
|
excludeFromPublicApi = false,
|
||||||
}: { options?: FindOptions; excludeFromPublicApi?: boolean } = {}): Promise<FindResult<Params>> {
|
}: { 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;
|
placeholder.alertExecutionStatus[key] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +783,7 @@ export class RulesClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill missing keys with zeroes
|
// Fill missing keys with zeroes
|
||||||
for (const key of AlertExecutionStatusValues) {
|
for (const key of RuleExecutionStatusValues) {
|
||||||
if (!ret.alertExecutionStatus.hasOwnProperty(key)) {
|
if (!ret.alertExecutionStatus.hasOwnProperty(key)) {
|
||||||
ret.alertExecutionStatus[key] = 0;
|
ret.alertExecutionStatus[key] = 0;
|
||||||
}
|
}
|
||||||
|
@ -878,10 +878,10 @@ export class RulesClient {
|
||||||
return removeResult;
|
return removeResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async update<Params extends AlertTypeParams = never>({
|
public async update<Params extends RuleTypeParams = never>({
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
|
}: UpdateOptions<Params>): Promise<PartialRule<Params>> {
|
||||||
return await retryIfConflicts(
|
return await retryIfConflicts(
|
||||||
this.logger,
|
this.logger,
|
||||||
`rulesClient.update('${id}')`,
|
`rulesClient.update('${id}')`,
|
||||||
|
@ -889,10 +889,10 @@ export class RulesClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateWithOCC<Params extends AlertTypeParams>({
|
private async updateWithOCC<Params extends RuleTypeParams>({
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
|
}: UpdateOptions<Params>): Promise<PartialRule<Params>> {
|
||||||
let alertSavedObject: SavedObject<RawRule>;
|
let alertSavedObject: SavedObject<RawRule>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -974,10 +974,10 @@ export class RulesClient {
|
||||||
return updateResult;
|
return updateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateAlert<Params extends AlertTypeParams>(
|
private async updateAlert<Params extends RuleTypeParams>(
|
||||||
{ id, data }: UpdateOptions<Params>,
|
{ id, data }: UpdateOptions<Params>,
|
||||||
{ attributes, version }: SavedObject<RawRule>
|
{ attributes, version }: SavedObject<RawRule>
|
||||||
): Promise<PartialAlert<Params>> {
|
): Promise<PartialRule<Params>> {
|
||||||
const ruleType = this.ruleTypeRegistry.get(attributes.alertTypeId);
|
const ruleType = this.ruleTypeRegistry.get(attributes.alertTypeId);
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
|
@ -1048,7 +1048,7 @@ export class RulesClient {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getPartialAlertFromRaw(
|
return this.getPartialRuleFromRaw(
|
||||||
id,
|
id,
|
||||||
ruleType,
|
ruleType,
|
||||||
updatedObject.attributes,
|
updatedObject.attributes,
|
||||||
|
@ -1332,12 +1332,12 @@ export class RulesClient {
|
||||||
try {
|
try {
|
||||||
const { state } = taskInstanceToAlertTaskInstance(
|
const { state } = taskInstanceToAlertTaskInstance(
|
||||||
await this.taskManager.get(attributes.scheduledTaskId),
|
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 ?? {},
|
state.alertInstances ?? {},
|
||||||
(rawAlertInstance) => new AlertInstance(rawAlertInstance)
|
(rawAlertInstance) => new Alert(rawAlertInstance)
|
||||||
);
|
);
|
||||||
const recoveredAlertInstanceIds = Object.keys(recoveredAlertInstances);
|
const recoveredAlertInstanceIds = Object.keys(recoveredAlertInstances);
|
||||||
|
|
||||||
|
@ -1568,7 +1568,7 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async muteInstanceWithOCC({ alertId, alertInstanceId }: MuteOptions) {
|
private async muteInstanceWithOCC({ alertId, alertInstanceId }: MuteOptions) {
|
||||||
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Alert>(
|
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Rule>(
|
||||||
'alert',
|
'alert',
|
||||||
alertId
|
alertId
|
||||||
);
|
);
|
||||||
|
@ -1636,7 +1636,7 @@ export class RulesClient {
|
||||||
alertId: string;
|
alertId: string;
|
||||||
alertInstanceId: string;
|
alertInstanceId: string;
|
||||||
}) {
|
}) {
|
||||||
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Alert>(
|
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<Rule>(
|
||||||
'alert',
|
'alert',
|
||||||
alertId
|
alertId
|
||||||
);
|
);
|
||||||
|
@ -1751,22 +1751,22 @@ export class RulesClient {
|
||||||
...omit(action, 'actionRef'),
|
...omit(action, 'actionRef'),
|
||||||
id: reference.id,
|
id: reference.id,
|
||||||
};
|
};
|
||||||
}) as Alert['actions'];
|
}) as Rule['actions'];
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAlertFromRaw<Params extends AlertTypeParams>(
|
private getAlertFromRaw<Params extends RuleTypeParams>(
|
||||||
id: string,
|
id: string,
|
||||||
ruleTypeId: string,
|
ruleTypeId: string,
|
||||||
rawRule: RawRule,
|
rawRule: RawRule,
|
||||||
references: SavedObjectReference[] | undefined,
|
references: SavedObjectReference[] | undefined,
|
||||||
includeLegacyId: boolean = false,
|
includeLegacyId: boolean = false,
|
||||||
excludeFromPublicApi: boolean = false
|
excludeFromPublicApi: boolean = false
|
||||||
): Alert | AlertWithLegacyId {
|
): Rule | RuleWithLegacyId {
|
||||||
const ruleType = this.ruleTypeRegistry.get(ruleTypeId);
|
const ruleType = this.ruleTypeRegistry.get(ruleTypeId);
|
||||||
// In order to support the partial update API of Saved Objects we have to support
|
// 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
|
// partial updates of an Alert, but when we receive an actual RawRule, it is safe
|
||||||
// to cast the result to an Alert
|
// to cast the result to an Alert
|
||||||
const res = this.getPartialAlertFromRaw<Params>(
|
const res = this.getPartialRuleFromRaw<Params>(
|
||||||
id,
|
id,
|
||||||
ruleType,
|
ruleType,
|
||||||
rawRule,
|
rawRule,
|
||||||
|
@ -1776,13 +1776,13 @@ export class RulesClient {
|
||||||
);
|
);
|
||||||
// include to result because it is for internal rules client usage
|
// include to result because it is for internal rules client usage
|
||||||
if (includeLegacyId) {
|
if (includeLegacyId) {
|
||||||
return res as AlertWithLegacyId;
|
return res as RuleWithLegacyId;
|
||||||
}
|
}
|
||||||
// exclude from result because it is an internal variable
|
// 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,
|
id: string,
|
||||||
ruleType: UntypedNormalizedRuleType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
{
|
{
|
||||||
|
@ -1801,7 +1801,7 @@ export class RulesClient {
|
||||||
references: SavedObjectReference[] | undefined,
|
references: SavedObjectReference[] | undefined,
|
||||||
includeLegacyId: boolean = false,
|
includeLegacyId: boolean = false,
|
||||||
excludeFromPublicApi: boolean = false
|
excludeFromPublicApi: boolean = false
|
||||||
): PartialAlert<Params> | PartialAlertWithLegacyId<Params> {
|
): PartialRule<Params> | PartialRuleWithLegacyId<Params> {
|
||||||
const rule = {
|
const rule = {
|
||||||
id,
|
id,
|
||||||
notifyWhen,
|
notifyWhen,
|
||||||
|
@ -1820,8 +1820,8 @@ export class RulesClient {
|
||||||
};
|
};
|
||||||
|
|
||||||
return includeLegacyId
|
return includeLegacyId
|
||||||
? ({ ...rule, legacyId } as PartialAlertWithLegacyId<Params>)
|
? ({ ...rule, legacyId } as PartialRuleWithLegacyId<Params>)
|
||||||
: (rule as PartialAlert<Params>);
|
: (rule as PartialRule<Params>);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateActions(
|
private async validateActions(
|
||||||
|
@ -1873,8 +1873,8 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async extractReferences<
|
private async extractReferences<
|
||||||
Params extends AlertTypeParams,
|
Params extends RuleTypeParams,
|
||||||
ExtractedParams extends AlertTypeParams
|
ExtractedParams extends RuleTypeParams
|
||||||
>(
|
>(
|
||||||
ruleType: UntypedNormalizedRuleType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
ruleActions: NormalizedAlertAction[],
|
ruleActions: NormalizedAlertAction[],
|
||||||
|
@ -1909,8 +1909,8 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private injectReferencesIntoParams<
|
private injectReferencesIntoParams<
|
||||||
Params extends AlertTypeParams,
|
Params extends RuleTypeParams,
|
||||||
ExtractedParams extends AlertTypeParams
|
ExtractedParams extends RuleTypeParams
|
||||||
>(
|
>(
|
||||||
ruleId: string,
|
ruleId: string,
|
||||||
ruleType: UntypedNormalizedRuleType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
|
|
|
@ -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.scopedClusterClient).toBeTruthy();
|
||||||
expect(call.services).toBeTruthy();
|
expect(call.services).toBeTruthy();
|
||||||
|
|
||||||
|
@ -427,8 +427,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices
|
executorServices.alertFactory
|
||||||
.alertInstanceFactory('1')
|
.create('1')
|
||||||
.scheduleActionsWithSubGroup('default', 'subDefault');
|
.scheduleActionsWithSubGroup('default', 'subDefault');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -708,7 +708,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -934,8 +934,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
executorServices.alertFactory.create('2').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -991,7 +991,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -1192,7 +1192,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -1268,8 +1268,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices
|
executorServices.alertFactory
|
||||||
.alertInstanceFactory('1')
|
.create('1')
|
||||||
.scheduleActionsWithSubGroup('default', 'subgroup1');
|
.scheduleActionsWithSubGroup('default', 'subgroup1');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1350,7 +1350,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -1672,7 +1672,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -2080,10 +2080,10 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
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
|
// 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(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -2186,7 +2186,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -2297,7 +2297,7 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const date = new Date().toISOString();
|
const date = new Date().toISOString();
|
||||||
|
@ -3692,8 +3692,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
executorServices.alertFactory.create('2').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -4006,8 +4006,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
executorServices.alertFactory.create('2').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
@ -4251,8 +4251,8 @@ describe('Task Runner', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
executorServices.alertFactory.create('2').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
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.scopedClusterClient).toBeTruthy();
|
||||||
expect(call.services).toBeTruthy();
|
expect(call.services).toBeTruthy();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { Logger, KibanaRequest } from '../../../../../src/core/server';
|
||||||
import { TaskRunnerContext } from './task_runner_factory';
|
import { TaskRunnerContext } from './task_runner_factory';
|
||||||
import { ConcreteTaskInstance, throwUnrecoverableError } from '../../../task_manager/server';
|
import { ConcreteTaskInstance, throwUnrecoverableError } from '../../../task_manager/server';
|
||||||
import { createExecutionHandler, ExecutionHandler } from './create_execution_handler';
|
import { createExecutionHandler, ExecutionHandler } from './create_execution_handler';
|
||||||
import { AlertInstance, createAlertInstanceFactory } from '../alert_instance';
|
import { Alert as CreatedAlert, createAlertFactory } from '../alert';
|
||||||
import {
|
import {
|
||||||
validateRuleTypeParams,
|
validateRuleTypeParams,
|
||||||
executionStatusFromState,
|
executionStatusFromState,
|
||||||
|
@ -285,7 +285,7 @@ export class TaskRunner<
|
||||||
|
|
||||||
async executeAlert(
|
async executeAlert(
|
||||||
alertId: string,
|
alertId: string,
|
||||||
alert: AlertInstance<InstanceState, InstanceContext>,
|
alert: CreatedAlert<InstanceState, InstanceContext>,
|
||||||
executionHandler: ExecutionHandler<ActionGroupIds | RecoveryActionGroupId>
|
executionHandler: ExecutionHandler<ActionGroupIds | RecoveryActionGroupId>
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
|
@ -333,8 +333,8 @@ export class TaskRunner<
|
||||||
|
|
||||||
const alerts = mapValues<
|
const alerts = mapValues<
|
||||||
Record<string, RawAlertInstance>,
|
Record<string, RawAlertInstance>,
|
||||||
AlertInstance<InstanceState, InstanceContext>
|
CreatedAlert<InstanceState, InstanceContext>
|
||||||
>(alertRawInstances, (rawAlert) => new AlertInstance<InstanceState, InstanceContext>(rawAlert));
|
>(alertRawInstances, (rawAlert) => new CreatedAlert<InstanceState, InstanceContext>(rawAlert));
|
||||||
const originalAlerts = cloneDeep(alerts);
|
const originalAlerts = cloneDeep(alerts);
|
||||||
const originalAlertIds = new Set(Object.keys(originalAlerts));
|
const originalAlertIds = new Set(Object.keys(originalAlerts));
|
||||||
|
|
||||||
|
@ -358,11 +358,13 @@ export class TaskRunner<
|
||||||
executionId: this.executionId,
|
executionId: this.executionId,
|
||||||
services: {
|
services: {
|
||||||
...services,
|
...services,
|
||||||
alertInstanceFactory: createAlertInstanceFactory<
|
alertFactory: createAlertFactory<
|
||||||
InstanceState,
|
InstanceState,
|
||||||
InstanceContext,
|
InstanceContext,
|
||||||
WithoutReservedActionGroups<ActionGroupIds, RecoveryActionGroupId>
|
WithoutReservedActionGroups<ActionGroupIds, RecoveryActionGroupId>
|
||||||
>(alerts),
|
>({
|
||||||
|
alerts,
|
||||||
|
}),
|
||||||
shouldWriteAlerts: () => this.shouldLogAndScheduleActionsForAlerts(),
|
shouldWriteAlerts: () => this.shouldLogAndScheduleActionsForAlerts(),
|
||||||
shouldStopExecution: () => this.cancelled,
|
shouldStopExecution: () => this.cancelled,
|
||||||
search: createAbortableEsClientFactory({
|
search: createAbortableEsClientFactory({
|
||||||
|
@ -420,11 +422,11 @@ export class TaskRunner<
|
||||||
// Cleanup alerts that are no longer scheduling actions to avoid over populating the alertInstances object
|
// Cleanup alerts that are no longer scheduling actions to avoid over populating the alertInstances object
|
||||||
const alertsWithScheduledActions = pickBy(
|
const alertsWithScheduledActions = pickBy(
|
||||||
alerts,
|
alerts,
|
||||||
(alert: AlertInstance<InstanceState, InstanceContext>) => alert.hasScheduledActions()
|
(alert: CreatedAlert<InstanceState, InstanceContext>) => alert.hasScheduledActions()
|
||||||
);
|
);
|
||||||
const recoveredAlerts = pickBy(
|
const recoveredAlerts = pickBy(
|
||||||
alerts,
|
alerts,
|
||||||
(alert: AlertInstance<InstanceState, InstanceContext>, id) =>
|
(alert: CreatedAlert<InstanceState, InstanceContext>, id) =>
|
||||||
!alert.hasScheduledActions() && originalAlertIds.has(id)
|
!alert.hasScheduledActions() && originalAlertIds.has(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -478,7 +480,7 @@ export class TaskRunner<
|
||||||
const alertsToExecute =
|
const alertsToExecute =
|
||||||
notifyWhen === 'onActionGroupChange'
|
notifyWhen === 'onActionGroupChange'
|
||||||
? Object.entries(alertsWithScheduledActions).filter(
|
? Object.entries(alertsWithScheduledActions).filter(
|
||||||
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
|
([alertName, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) => {
|
||||||
const shouldExecuteAction = alert.scheduledActionGroupOrSubgroupHasChanged();
|
const shouldExecuteAction = alert.scheduledActionGroupOrSubgroupHasChanged();
|
||||||
if (!shouldExecuteAction) {
|
if (!shouldExecuteAction) {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
|
@ -489,7 +491,7 @@ export class TaskRunner<
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
: Object.entries(alertsWithScheduledActions).filter(
|
: Object.entries(alertsWithScheduledActions).filter(
|
||||||
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
|
([alertName, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) => {
|
||||||
const throttled = alert.isThrottled(throttle);
|
const throttled = alert.isThrottled(throttle);
|
||||||
const muted = mutedAlertIdsSet.has(alertName);
|
const muted = mutedAlertIdsSet.has(alertName);
|
||||||
const shouldExecuteAction = !throttled && !muted;
|
const shouldExecuteAction = !throttled && !muted;
|
||||||
|
@ -506,7 +508,7 @@ export class TaskRunner<
|
||||||
|
|
||||||
const allTriggeredActions = await Promise.all(
|
const allTriggeredActions = await Promise.all(
|
||||||
alertsToExecute.map(
|
alertsToExecute.map(
|
||||||
([alertId, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) =>
|
([alertId, alert]: [string, CreatedAlert<InstanceState, InstanceContext>]) =>
|
||||||
this.executeAlert(alertId, alert, executionHandler)
|
this.executeAlert(alertId, alert, executionHandler)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -533,7 +535,7 @@ export class TaskRunner<
|
||||||
triggeredActions,
|
triggeredActions,
|
||||||
alertTypeState: updatedRuleTypeState || undefined,
|
alertTypeState: updatedRuleTypeState || undefined,
|
||||||
alertInstances: mapValues<
|
alertInstances: mapValues<
|
||||||
Record<string, AlertInstance<InstanceState, InstanceContext>>,
|
Record<string, CreatedAlert<InstanceState, InstanceContext>>,
|
||||||
RawAlertInstance
|
RawAlertInstance
|
||||||
>(alertsWithScheduledActions, (alert) => alert.toRaw()),
|
>(alertsWithScheduledActions, (alert) => alert.toRaw()),
|
||||||
};
|
};
|
||||||
|
@ -910,9 +912,9 @@ interface TrackAlertDurationsParams<
|
||||||
InstanceState extends AlertInstanceState,
|
InstanceState extends AlertInstanceState,
|
||||||
InstanceContext extends AlertInstanceContext
|
InstanceContext extends AlertInstanceContext
|
||||||
> {
|
> {
|
||||||
originalAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
originalAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
currentAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
currentAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackAlertDurations<
|
function trackAlertDurations<
|
||||||
|
@ -967,9 +969,9 @@ interface GenerateNewAndRecoveredAlertEventsParams<
|
||||||
> {
|
> {
|
||||||
eventLogger: IEventLogger;
|
eventLogger: IEventLogger;
|
||||||
executionId: string;
|
executionId: string;
|
||||||
originalAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
originalAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
currentAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
currentAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext>>;
|
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext>>;
|
||||||
ruleId: string;
|
ruleId: string;
|
||||||
ruleLabel: string;
|
ruleLabel: string;
|
||||||
namespace: string | undefined;
|
namespace: string | undefined;
|
||||||
|
@ -1117,7 +1119,7 @@ interface ScheduleActionsForRecoveredAlertsParams<
|
||||||
> {
|
> {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
recoveryActionGroup: ActionGroup<RecoveryActionGroupId>;
|
recoveryActionGroup: ActionGroup<RecoveryActionGroupId>;
|
||||||
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, RecoveryActionGroupId>>;
|
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, RecoveryActionGroupId>>;
|
||||||
executionHandler: ExecutionHandler<RecoveryActionGroupId | RecoveryActionGroupId>;
|
executionHandler: ExecutionHandler<RecoveryActionGroupId | RecoveryActionGroupId>;
|
||||||
mutedAlertIdsSet: Set<string>;
|
mutedAlertIdsSet: Set<string>;
|
||||||
ruleLabel: string;
|
ruleLabel: string;
|
||||||
|
@ -1173,8 +1175,8 @@ interface LogActiveAndRecoveredAlertsParams<
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
> {
|
> {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
activeAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, ActionGroupIds>>;
|
activeAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, ActionGroupIds>>;
|
||||||
recoveredAlerts: Dictionary<AlertInstance<InstanceState, InstanceContext, RecoveryActionGroupId>>;
|
recoveredAlerts: Dictionary<CreatedAlert<InstanceState, InstanceContext, RecoveryActionGroupId>>;
|
||||||
ruleLabel: string;
|
ruleLabel: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -359,7 +359,7 @@ describe('Task Runner Cancel', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// setting cancelAlertsOnRuleTimeout to false here
|
// setting cancelAlertsOnRuleTimeout to false here
|
||||||
|
@ -393,7 +393,7 @@ describe('Task Runner Cancel', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// setting cancelAlertsOnRuleTimeout for ruleType to false here
|
// setting cancelAlertsOnRuleTimeout for ruleType to false here
|
||||||
|
@ -427,7 +427,7 @@ describe('Task Runner Cancel', () => {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
string
|
string
|
||||||
>) => {
|
>) => {
|
||||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
executorServices.alertFactory.create('1').scheduleActions('default');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const taskRunner = new TaskRunner(
|
const taskRunner = new TaskRunner(
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import type { IRouter, RequestHandlerContext, SavedObjectReference } from 'src/core/server';
|
import type { IRouter, RequestHandlerContext, SavedObjectReference } from 'src/core/server';
|
||||||
import type { PublicMethodsOf } from '@kbn/utility-types';
|
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 { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry';
|
||||||
import { PluginSetupContract, PluginStartContract } from './plugin';
|
import { PluginSetupContract, PluginStartContract } from './plugin';
|
||||||
import { RulesClient } from './rules_client';
|
import { RulesClient } from './rules_client';
|
||||||
|
@ -74,9 +74,9 @@ export interface AlertServices<
|
||||||
InstanceContext extends AlertInstanceContext = AlertInstanceContext,
|
InstanceContext extends AlertInstanceContext = AlertInstanceContext,
|
||||||
ActionGroupIds extends string = never
|
ActionGroupIds extends string = never
|
||||||
> extends Services {
|
> extends Services {
|
||||||
alertInstanceFactory: (
|
alertFactory: {
|
||||||
id: string
|
create: (id: string) => PublicAlert<InstanceState, InstanceContext, ActionGroupIds>;
|
||||||
) => PublicAlertInstance<InstanceState, InstanceContext, ActionGroupIds>;
|
};
|
||||||
shouldWriteAlerts: () => boolean;
|
shouldWriteAlerts: () => boolean;
|
||||||
shouldStopExecution: () => boolean;
|
shouldStopExecution: () => boolean;
|
||||||
search: IAbortableClusterClient;
|
search: IAbortableClusterClient;
|
||||||
|
|
|
@ -39,7 +39,7 @@ describe('Error count alert', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await executor({ params });
|
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 () => {
|
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_foo_env-foo-2',
|
||||||
'apm.error_rate_bar_env-bar',
|
'apm.error_rate_bar_env-bar',
|
||||||
].forEach((instanceName) =>
|
].forEach((instanceName) =>
|
||||||
expect(services.alertInstanceFactory).toHaveBeenCalledWith(instanceName)
|
expect(services.alertFactory.create).toHaveBeenCalledWith(instanceName)
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(scheduleActions).toHaveBeenCalledTimes(3);
|
expect(scheduleActions).toHaveBeenCalledTimes(3);
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe('Transaction duration anomaly alert', () => {
|
||||||
services.scopedClusterClient.asCurrentUser.search
|
services.scopedClusterClient.asCurrentUser.search
|
||||||
).not.toHaveBeenCalled();
|
).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(services.alertInstanceFactory).not.toHaveBeenCalled();
|
expect(services.alertFactory.create).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ml jobs are not available', async () => {
|
it('ml jobs are not available', async () => {
|
||||||
|
@ -59,7 +59,7 @@ describe('Transaction duration anomaly alert', () => {
|
||||||
services.scopedClusterClient.asCurrentUser.search
|
services.scopedClusterClient.asCurrentUser.search
|
||||||
).not.toHaveBeenCalled();
|
).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(services.alertInstanceFactory).not.toHaveBeenCalled();
|
expect(services.alertFactory.create).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('anomaly is less than threshold', async () => {
|
it('anomaly is less than threshold', async () => {
|
||||||
|
@ -110,7 +110,7 @@ describe('Transaction duration anomaly alert', () => {
|
||||||
expect(
|
expect(
|
||||||
services.scopedClusterClient.asCurrentUser.search
|
services.scopedClusterClient.asCurrentUser.search
|
||||||
).not.toHaveBeenCalled();
|
).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 });
|
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'
|
'apm.transaction_duration_anomaly_foo_development_type-foo'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ describe('Transaction error rate alert', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await executor({ params });
|
await executor({ params });
|
||||||
expect(services.alertInstanceFactory).not.toBeCalled();
|
expect(services.alertFactory.create).not.toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends alerts for services that exceeded the threshold', async () => {
|
it('sends alerts for services that exceeded the threshold', async () => {
|
||||||
|
@ -117,12 +117,12 @@ describe('Transaction error rate alert', () => {
|
||||||
|
|
||||||
await executor({ params });
|
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'
|
'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'
|
'apm.transaction_error_rate_bar_type-bar_env-bar'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ export const createRuleTypeMocks = () => {
|
||||||
savedObjectsClient: {
|
savedObjectsClient: {
|
||||||
get: () => ({ attributes: { consumer: APM_SERVER_FEATURE_ID } }),
|
get: () => ({ attributes: { consumer: APM_SERVER_FEATURE_ID } }),
|
||||||
},
|
},
|
||||||
alertInstanceFactory: jest.fn(() => ({ scheduleActions })),
|
alertFactory: { create: jest.fn(() => ({ scheduleActions })) },
|
||||||
alertWithLifecycle: jest.fn(),
|
alertWithLifecycle: jest.fn(),
|
||||||
logger: loggerMock,
|
logger: loggerMock,
|
||||||
shouldWriteAlerts: () => true,
|
shouldWriteAlerts: () => true,
|
||||||
|
|
|
@ -16,10 +16,7 @@ import {
|
||||||
AlertInstanceState as AlertState,
|
AlertInstanceState as AlertState,
|
||||||
RecoveredActionGroup,
|
RecoveredActionGroup,
|
||||||
} from '../../../../../alerting/common';
|
} from '../../../../../alerting/common';
|
||||||
import {
|
import { Alert, AlertTypeState as RuleTypeState } from '../../../../../alerting/server';
|
||||||
AlertInstance as Alert,
|
|
||||||
AlertTypeState as RuleTypeState,
|
|
||||||
} from '../../../../../alerting/server';
|
|
||||||
import { AlertStates, InventoryMetricThresholdParams } from '../../../../common/alerting/metrics';
|
import { AlertStates, InventoryMetricThresholdParams } from '../../../../common/alerting/metrics';
|
||||||
import { createFormatter } from '../../../../common/formatters';
|
import { createFormatter } from '../../../../common/formatters';
|
||||||
import { getCustomMetricLabel } from '../../../../common/formatters/get_custom_metric_label';
|
import { getCustomMetricLabel } from '../../../../common/formatters/get_custom_metric_label';
|
||||||
|
|
|
@ -422,7 +422,7 @@ describe('Log threshold executor', () => {
|
||||||
processUngroupedResults(
|
processUngroupedResults(
|
||||||
results,
|
results,
|
||||||
ruleParams,
|
ruleParams,
|
||||||
alertsMock.createAlertInstanceFactory,
|
alertsMock.createAlertFactory.create,
|
||||||
alertUpdaterMock
|
alertUpdaterMock
|
||||||
);
|
);
|
||||||
// First call, second argument
|
// First call, second argument
|
||||||
|
@ -486,7 +486,7 @@ describe('Log threshold executor', () => {
|
||||||
processGroupByResults(
|
processGroupByResults(
|
||||||
results,
|
results,
|
||||||
ruleParams,
|
ruleParams,
|
||||||
alertsMock.createAlertInstanceFactory,
|
alertsMock.createAlertFactory.create,
|
||||||
alertUpdaterMock
|
alertUpdaterMock
|
||||||
);
|
);
|
||||||
expect(alertUpdaterMock.mock.calls.length).toBe(2);
|
expect(alertUpdaterMock.mock.calls.length).toBe(2);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { ElasticsearchClient } from 'kibana/server';
|
||||||
import {
|
import {
|
||||||
ActionGroup,
|
ActionGroup,
|
||||||
ActionGroupIdsOf,
|
ActionGroupIdsOf,
|
||||||
AlertInstance as Alert,
|
Alert,
|
||||||
AlertInstanceContext as AlertContext,
|
AlertInstanceContext as AlertContext,
|
||||||
AlertInstanceState as AlertState,
|
AlertInstanceState as AlertState,
|
||||||
AlertTypeState as RuleTypeState,
|
AlertTypeState as RuleTypeState,
|
||||||
|
|
|
@ -83,7 +83,7 @@ export const createMetricAnomalyExecutor =
|
||||||
typical,
|
typical,
|
||||||
influencers,
|
influencers,
|
||||||
} = first(data as MappedAnomalyHit[])!;
|
} = first(data as MappedAnomalyHit[])!;
|
||||||
const alert = services.alertInstanceFactory(`${nodeType}-${metric}`);
|
const alert = services.alertFactory.create(`${nodeType}-${metric}`);
|
||||||
|
|
||||||
alert.scheduleActions(FIRED_ACTIONS_ID, {
|
alert.scheduleActions(FIRED_ACTIONS_ID, {
|
||||||
alertState: stateToAlertMessage[AlertStates.ALERT],
|
alertState: stateToAlertMessage[AlertStates.ALERT],
|
||||||
|
|
|
@ -840,9 +840,9 @@ services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId
|
||||||
});
|
});
|
||||||
|
|
||||||
const alertInstances = new Map<string, AlertTestInstance>();
|
const alertInstances = new Map<string, AlertTestInstance>();
|
||||||
services.alertInstanceFactory.mockImplementation((instanceID: string) => {
|
services.alertFactory.create.mockImplementation((instanceID: string) => {
|
||||||
const newAlertInstance: AlertTestInstance = {
|
const newAlertInstance: AlertTestInstance = {
|
||||||
instance: alertsMock.createAlertInstanceFactory(),
|
instance: alertsMock.createAlertFactory.create(),
|
||||||
actionQueue: [],
|
actionQueue: [],
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,10 +15,7 @@ import {
|
||||||
AlertInstanceState as AlertState,
|
AlertInstanceState as AlertState,
|
||||||
RecoveredActionGroup,
|
RecoveredActionGroup,
|
||||||
} from '../../../../../alerting/common';
|
} from '../../../../../alerting/common';
|
||||||
import {
|
import { Alert, AlertTypeState as RuleTypeState } from '../../../../../alerting/server';
|
||||||
AlertInstance as Alert,
|
|
||||||
AlertTypeState as RuleTypeState,
|
|
||||||
} from '../../../../../alerting/server';
|
|
||||||
import { AlertStates, Comparator } from '../../../../common/alerting/metrics';
|
import { AlertStates, Comparator } from '../../../../common/alerting/metrics';
|
||||||
import { createFormatter } from '../../../../common/formatters';
|
import { createFormatter } from '../../../../common/formatters';
|
||||||
import { InfraBackendLibs } from '../../infra_types';
|
import { InfraBackendLibs } from '../../infra_types';
|
||||||
|
|
|
@ -139,7 +139,7 @@ export function registerAnomalyDetectionAlertType({
|
||||||
|
|
||||||
if (executionResult) {
|
if (executionResult) {
|
||||||
const alertInstanceName = executionResult.name;
|
const alertInstanceName = executionResult.name;
|
||||||
const alertInstance = services.alertInstanceFactory(alertInstanceName);
|
const alertInstance = services.alertFactory.create(alertInstanceName);
|
||||||
alertInstance.scheduleActions(ANOMALY_SCORE_MATCH_GROUP_ID, executionResult);
|
alertInstance.scheduleActions(ANOMALY_SCORE_MATCH_GROUP_ID, executionResult);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -159,7 +159,7 @@ export function registerJobsMonitoringRuleType({
|
||||||
);
|
);
|
||||||
|
|
||||||
executionResult.forEach(({ name: alertInstanceName, context }) => {
|
executionResult.forEach(({ name: alertInstanceName, context }) => {
|
||||||
const alertInstance = services.alertInstanceFactory(alertInstanceName);
|
const alertInstance = services.alertFactory.create(alertInstanceName);
|
||||||
alertInstance.scheduleActions(ANOMALY_DETECTION_JOB_REALTIME_ISSUE, context);
|
alertInstance.scheduleActions(ANOMALY_DETECTION_JOB_REALTIME_ISSUE, context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,16 @@ import { i18n } from '@kbn/i18n';
|
||||||
import {
|
import {
|
||||||
RuleType,
|
RuleType,
|
||||||
AlertExecutorOptions,
|
AlertExecutorOptions,
|
||||||
AlertInstance,
|
Alert,
|
||||||
RulesClient,
|
RulesClient,
|
||||||
AlertServices,
|
AlertServices,
|
||||||
} from '../../../alerting/server';
|
} 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 { ActionsClient } from '../../../actions/server';
|
||||||
import {
|
import {
|
||||||
AlertState,
|
AlertState,
|
||||||
|
@ -121,7 +126,7 @@ export class BaseRule {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingRuleData.total > 0) {
|
if (existingRuleData.total > 0) {
|
||||||
return existingRuleData.data[0] as Alert;
|
return existingRuleData.data[0] as Rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ruleActions = [];
|
const ruleActions = [];
|
||||||
|
@ -272,7 +277,7 @@ export class BaseRule {
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const newAlertStates: AlertNodeState[] = [];
|
const newAlertStates: AlertNodeState[] = [];
|
||||||
// quick fix for now so that non node level alerts will use the cluster id
|
// 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
|
node.meta.nodeId || node.meta.instanceId || cluster.clusterUuid
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -331,7 +336,7 @@ export class BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
instanceState: AlertInstanceState | AlertState | unknown,
|
instanceState: AlertInstanceState | AlertState | unknown,
|
||||||
item: AlertData | unknown,
|
item: AlertData | unknown,
|
||||||
cluster?: AlertCluster | unknown
|
cluster?: AlertCluster | unknown
|
||||||
|
|
|
@ -116,7 +116,8 @@ describe('CCRReadExceptionsRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -124,6 +125,7 @@ describe('CCRReadExceptionsRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
CCRReadExceptionsStats,
|
CCRReadExceptionsStats,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_CCR_READ_EXCEPTIONS, RULE_DETAILS } from '../../common/constants';
|
||||||
import { fetchCCRReadExceptions } from '../lib/alerts/fetch_ccr_read_exceptions';
|
import { fetchCCRReadExceptions } from '../lib/alerts/fetch_ccr_read_exceptions';
|
||||||
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
||||||
|
@ -209,7 +209,7 @@ export class CCRReadExceptionsRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -81,7 +81,8 @@ describe('ClusterHealthRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -89,6 +90,7 @@ describe('ClusterHealthRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
AlertClusterHealth,
|
AlertClusterHealth,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_CLUSTER_HEALTH, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertMessageTokenType, AlertClusterHealthType, AlertSeverity } from '../../common/enums';
|
import { AlertMessageTokenType, AlertClusterHealthType, AlertSeverity } from '../../common/enums';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
|
@ -111,7 +111,7 @@ export class ClusterHealthRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -83,7 +83,8 @@ describe('CpuUsageRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -91,6 +92,7 @@ describe('CpuUsageRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
CommonAlertParams,
|
CommonAlertParams,
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
} from '../../common/types/alerts';
|
} from '../../common/types/alerts';
|
||||||
import { AlertInstance } from '../../../alerting/server';
|
import { Alert } from '../../../alerting/server';
|
||||||
import { RULE_CPU_USAGE, RULE_DETAILS } from '../../common/constants';
|
import { RULE_CPU_USAGE, RULE_DETAILS } from '../../common/constants';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ROUNDED_FLOAT } from '../../common/formatting';
|
import { ROUNDED_FLOAT } from '../../common/formatting';
|
||||||
|
@ -145,7 +145,7 @@ export class CpuUsageRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -96,7 +96,8 @@ describe('DiskUsageRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -104,6 +105,7 @@ describe('DiskUsageRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
AlertDiskUsageNodeStats,
|
AlertDiskUsageNodeStats,
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
} from '../../common/types/alerts';
|
} from '../../common/types/alerts';
|
||||||
import { AlertInstance } from '../../../alerting/server';
|
import { Alert } from '../../../alerting/server';
|
||||||
import { RULE_DISK_USAGE, RULE_DETAILS } from '../../common/constants';
|
import { RULE_DISK_USAGE, RULE_DETAILS } from '../../common/constants';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ROUNDED_FLOAT } from '../../common/formatting';
|
import { ROUNDED_FLOAT } from '../../common/formatting';
|
||||||
|
@ -152,7 +152,7 @@ export class DiskUsageRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -85,7 +85,8 @@ describe('ElasticsearchVersionMismatchAlert', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -93,6 +94,7 @@ describe('ElasticsearchVersionMismatchAlert', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
CommonAlertParams,
|
CommonAlertParams,
|
||||||
AlertVersions,
|
AlertVersions,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_ELASTICSEARCH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertSeverity } from '../../common/enums';
|
import { AlertSeverity } from '../../common/enums';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
|
@ -87,7 +87,7 @@ export class ElasticsearchVersionMismatchRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -88,7 +88,8 @@ describe('KibanaVersionMismatchRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -96,6 +97,7 @@ describe('KibanaVersionMismatchRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
CommonAlertParams,
|
CommonAlertParams,
|
||||||
AlertVersions,
|
AlertVersions,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_KIBANA_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertSeverity } from '../../common/enums';
|
import { AlertSeverity } from '../../common/enums';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
|
@ -97,7 +97,7 @@ export class KibanaVersionMismatchRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -96,7 +96,8 @@ describe('LargeShardSizeRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -104,6 +105,7 @@ describe('LargeShardSizeRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
IndexShardSizeStats,
|
IndexShardSizeStats,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_LARGE_SHARD_SIZE, RULE_DETAILS } from '../../common/constants';
|
||||||
import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size';
|
import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size';
|
||||||
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
||||||
|
@ -149,7 +149,7 @@ export class LargeShardSizeRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -86,7 +86,8 @@ describe('LicenseExpirationRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -94,6 +95,7 @@ describe('LicenseExpirationRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
AlertLicense,
|
AlertLicense,
|
||||||
AlertLicenseState,
|
AlertLicenseState,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_LICENSE_EXPIRATION, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
|
@ -143,7 +143,7 @@ export class LicenseExpirationRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -86,7 +86,8 @@ describe('LogstashVersionMismatchRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -94,6 +95,7 @@ describe('LogstashVersionMismatchRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
CommonAlertParams,
|
CommonAlertParams,
|
||||||
AlertVersions,
|
AlertVersions,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_LOGSTASH_VERSION_MISMATCH, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertSeverity } from '../../common/enums';
|
import { AlertSeverity } from '../../common/enums';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
|
@ -87,7 +87,7 @@ export class LogstashVersionMismatchRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -83,7 +83,8 @@ describe('MemoryUsageRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -91,6 +92,7 @@ describe('MemoryUsageRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
AlertMemoryUsageNodeStats,
|
AlertMemoryUsageNodeStats,
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
} from '../../common/types/alerts';
|
} from '../../common/types/alerts';
|
||||||
import { AlertInstance } from '../../../alerting/server';
|
import { Alert } from '../../../alerting/server';
|
||||||
import { RULE_MEMORY_USAGE, RULE_DETAILS } from '../../common/constants';
|
import { RULE_MEMORY_USAGE, RULE_DETAILS } from '../../common/constants';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { ROUNDED_FLOAT } from '../../common/formatting';
|
import { ROUNDED_FLOAT } from '../../common/formatting';
|
||||||
|
@ -158,7 +158,7 @@ export class MemoryUsageRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -87,7 +87,8 @@ describe('MissingMonitoringDataRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -95,6 +96,7 @@ describe('MissingMonitoringDataRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
CommonAlertFilter,
|
CommonAlertFilter,
|
||||||
AlertNodeState,
|
AlertNodeState,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_MISSING_MONITORING_DATA, RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
||||||
import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common';
|
import { RawAlertInstance, SanitizedAlert } from '../../../alerting/common';
|
||||||
|
@ -137,7 +137,7 @@ export class MissingMonitoringDataRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: { alertStates: AlertState[] },
|
{ alertStates }: { alertStates: AlertState[] },
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -137,7 +137,8 @@ describe('NodesChangedAlert', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -145,6 +146,7 @@ describe('NodesChangedAlert', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertNodesChangedState,
|
AlertNodesChangedState,
|
||||||
} from '../../common/types/alerts';
|
} 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 { RULE_NODES_CHANGED, LEGACY_RULE_DETAILS } from '../../common/constants';
|
||||||
import { AlertingDefaults } from './alert_helpers';
|
import { AlertingDefaults } from './alert_helpers';
|
||||||
import { SanitizedAlert } from '../../../alerting/common';
|
import { SanitizedAlert } from '../../../alerting/common';
|
||||||
|
@ -174,7 +174,7 @@ export class NodesChangedRule extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async executeActions(
|
protected async executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: AlertInstanceState,
|
{ alertStates }: AlertInstanceState,
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -20,10 +20,10 @@ import {
|
||||||
AlertState,
|
AlertState,
|
||||||
AlertThreadPoolRejectionsStats,
|
AlertThreadPoolRejectionsStats,
|
||||||
} from '../../common/types/alerts';
|
} 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 { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats';
|
||||||
import { AlertMessageTokenType, AlertSeverity } from '../../common/enums';
|
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 { AlertingDefaults, createLink } from './alert_helpers';
|
||||||
import { Globals } from '../static_globals';
|
import { Globals } from '../static_globals';
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
sanitizedRule: Alert | undefined = undefined,
|
sanitizedRule: Rule | undefined = undefined,
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
public readonly threadPoolType: string,
|
public readonly threadPoolType: string,
|
||||||
public readonly name: string,
|
public readonly name: string,
|
||||||
|
@ -176,7 +176,7 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
protected executeActions(
|
protected executeActions(
|
||||||
instance: AlertInstance,
|
instance: Alert,
|
||||||
{ alertStates }: { alertStates: AlertState[] },
|
{ alertStates }: { alertStates: AlertState[] },
|
||||||
item: AlertData | null,
|
item: AlertData | null,
|
||||||
cluster: AlertCluster
|
cluster: AlertCluster
|
||||||
|
|
|
@ -89,7 +89,8 @@ describe('ThreadpoolSearchRejectionsRule', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -97,6 +98,7 @@ describe('ThreadpoolSearchRejectionsRule', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,8 @@ describe('ThreadpoolWriteRejectionsAlert', () => {
|
||||||
const executorOptions = {
|
const executorOptions = {
|
||||||
services: {
|
services: {
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn().mockImplementation(() => {
|
alertFactory: {
|
||||||
|
create: jest.fn().mockImplementation(() => {
|
||||||
return {
|
return {
|
||||||
replaceState,
|
replaceState,
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
|
@ -97,6 +98,7 @@ describe('ThreadpoolWriteRejectionsAlert', () => {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
state: {},
|
state: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { v4 } from 'uuid';
|
||||||
import { difference } from 'lodash';
|
import { difference } from 'lodash';
|
||||||
import {
|
import {
|
||||||
AlertExecutorOptions,
|
AlertExecutorOptions,
|
||||||
AlertInstance,
|
Alert,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
|
@ -62,7 +62,7 @@ export type LifecycleAlertService<
|
||||||
> = (alert: {
|
> = (alert: {
|
||||||
id: string;
|
id: string;
|
||||||
fields: ExplicitAlertFields;
|
fields: ExplicitAlertFields;
|
||||||
}) => AlertInstance<InstanceState, InstanceContext, ActionGroupIds>;
|
}) => Alert<InstanceState, InstanceContext, ActionGroupIds>;
|
||||||
|
|
||||||
export interface LifecycleAlertServices<
|
export interface LifecycleAlertServices<
|
||||||
InstanceState extends AlertInstanceState = never,
|
InstanceState extends AlertInstanceState = never,
|
||||||
|
@ -143,7 +143,7 @@ export const createLifecycleExecutor =
|
||||||
>
|
>
|
||||||
): Promise<WrappedLifecycleRuleState<State>> => {
|
): Promise<WrappedLifecycleRuleState<State>> => {
|
||||||
const {
|
const {
|
||||||
services: { alertInstanceFactory, shouldWriteAlerts },
|
services: { alertFactory, shouldWriteAlerts },
|
||||||
state: previousState,
|
state: previousState,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ export const createLifecycleExecutor =
|
||||||
> = {
|
> = {
|
||||||
alertWithLifecycle: ({ id, fields }) => {
|
alertWithLifecycle: ({ id, fields }) => {
|
||||||
currentAlerts[id] = fields;
|
currentAlerts[id] = fields;
|
||||||
return alertInstanceFactory(id);
|
return alertFactory.create(id);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,12 @@ function createRule(shouldWriteAlerts: boolean = true) {
|
||||||
|
|
||||||
const scheduleActions = jest.fn();
|
const scheduleActions = jest.fn();
|
||||||
|
|
||||||
const alertInstanceFactory = () => {
|
const alertFactory = {
|
||||||
|
create: () => {
|
||||||
return {
|
return {
|
||||||
scheduleActions,
|
scheduleActions,
|
||||||
} as any;
|
} as any;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -107,7 +109,7 @@ function createRule(shouldWriteAlerts: boolean = true) {
|
||||||
updatedBy: 'updatedBy',
|
updatedBy: 'updatedBy',
|
||||||
},
|
},
|
||||||
services: {
|
services: {
|
||||||
alertInstanceFactory,
|
alertFactory,
|
||||||
savedObjectsClient: {} as any,
|
savedObjectsClient: {} as any,
|
||||||
scopedClusterClient: {} as any,
|
scopedClusterClient: {} as any,
|
||||||
shouldWriteAlerts: () => shouldWriteAlerts,
|
shouldWriteAlerts: () => shouldWriteAlerts,
|
||||||
|
|
|
@ -34,5 +34,5 @@ export const createLifecycleAlertServicesMock = <
|
||||||
>(
|
>(
|
||||||
alertServices: AlertServices<InstanceState, InstanceContext>
|
alertServices: AlertServices<InstanceState, InstanceContext>
|
||||||
): LifecycleAlertServices<InstanceState, InstanceContext, ActionGroupIds> => ({
|
): LifecycleAlertServices<InstanceState, InstanceContext, ActionGroupIds> => ({
|
||||||
alertWithLifecycle: ({ id }) => alertServices.alertInstanceFactory(id),
|
alertWithLifecycle: ({ id }) => alertServices.alertFactory.create(id),
|
||||||
});
|
});
|
||||||
|
|
|
@ -67,8 +67,7 @@ export const createDefaultAlertExecutorOptions = <
|
||||||
params,
|
params,
|
||||||
spaceId: 'SPACE_ID',
|
spaceId: 'SPACE_ID',
|
||||||
services: {
|
services: {
|
||||||
alertInstanceFactory: alertsMock.createAlertServices<InstanceState, InstanceContext>()
|
alertFactory: alertsMock.createAlertServices<InstanceState, InstanceContext>().alertFactory,
|
||||||
.alertInstanceFactory,
|
|
||||||
savedObjectsClient: savedObjectsClientMock.create(),
|
savedObjectsClient: savedObjectsClientMock.create(),
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
shouldWriteAlerts: () => shouldWriteAlerts,
|
shouldWriteAlerts: () => shouldWriteAlerts,
|
||||||
|
|
|
@ -136,9 +136,9 @@ describe('legacyRules_notification_alert_type', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await alert.executor(payload);
|
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(
|
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
|
||||||
'default',
|
'default',
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
|
@ -163,9 +163,9 @@ describe('legacyRules_notification_alert_type', () => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
await alert.executor(payload);
|
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(
|
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
|
||||||
'default',
|
'default',
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
|
@ -192,9 +192,9 @@ describe('legacyRules_notification_alert_type', () => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
await alert.executor(payload);
|
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(
|
expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith(
|
||||||
'default',
|
'default',
|
||||||
expect.objectContaining({
|
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());
|
const ruleAlert = getAlertMock(isRuleRegistryEnabled, getQueryRuleParams());
|
||||||
alertServices.savedObjectsClient.get.mockResolvedValue({
|
alertServices.savedObjectsClient.get.mockResolvedValue({
|
||||||
id: 'id',
|
id: 'id',
|
||||||
|
@ -218,7 +218,7 @@ describe('legacyRules_notification_alert_type', () => {
|
||||||
|
|
||||||
await alert.executor(payload);
|
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 () => {
|
it('should call scheduleActions if signalsCount was greater than 0', async () => {
|
||||||
|
@ -237,9 +237,9 @@ describe('legacyRules_notification_alert_type', () => {
|
||||||
|
|
||||||
await alert.executor(payload);
|
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(alertInstanceMock.replaceState).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ signals_count: 100 })
|
expect.objectContaining({ signals_count: 100 })
|
||||||
);
|
);
|
||||||
|
|
|
@ -119,7 +119,7 @@ export const legacyRulesNotificationAlertType = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
if (signalsCount !== 0) {
|
if (signalsCount !== 0) {
|
||||||
const alertInstance = services.alertInstanceFactory(alertId);
|
const alertInstance = services.alertFactory.create(alertId);
|
||||||
scheduleNotificationActions({
|
scheduleNotificationActions({
|
||||||
alertInstance,
|
alertInstance,
|
||||||
signalsCount,
|
signalsCount,
|
||||||
|
|
|
@ -54,7 +54,7 @@ describe('schedule_notification_actions', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
it('Should schedule actions with unflatted and legacy context', () => {
|
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];
|
const signals = [sampleThresholdAlert._source, sampleThresholdAlert._source];
|
||||||
scheduleNotificationActions({
|
scheduleNotificationActions({
|
||||||
alertInstance,
|
alertInstance,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { mapKeys, snakeCase } from 'lodash/fp';
|
import { mapKeys, snakeCase } from 'lodash/fp';
|
||||||
import { AlertInstance } from '../../../../../alerting/server';
|
import { Alert } from '../../../../../alerting/server';
|
||||||
import { expandDottedObject } from '../../../../common/utils/expand_dotted';
|
import { expandDottedObject } from '../../../../common/utils/expand_dotted';
|
||||||
import { RuleParams } from '../schemas/rule_schemas';
|
import { RuleParams } from '../schemas/rule_schemas';
|
||||||
import aadFieldConversion from '../routes/index/signal_aad_mapping.json';
|
import aadFieldConversion from '../routes/index/signal_aad_mapping.json';
|
||||||
|
@ -46,7 +46,7 @@ const formatAlertsForNotificationActions = (alerts: unknown[]): unknown[] => {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ScheduleNotificationActions {
|
interface ScheduleNotificationActions {
|
||||||
alertInstance: AlertInstance;
|
alertInstance: Alert;
|
||||||
signalsCount: number;
|
signalsCount: number;
|
||||||
resultsLink: string;
|
resultsLink: string;
|
||||||
ruleParams: NotificationRuleTypeParams;
|
ruleParams: NotificationRuleTypeParams;
|
||||||
|
@ -59,7 +59,7 @@ export const scheduleNotificationActions = ({
|
||||||
resultsLink = '',
|
resultsLink = '',
|
||||||
ruleParams,
|
ruleParams,
|
||||||
signals,
|
signals,
|
||||||
}: ScheduleNotificationActions): AlertInstance =>
|
}: ScheduleNotificationActions): Alert =>
|
||||||
alertInstance
|
alertInstance
|
||||||
.replaceState({
|
.replaceState({
|
||||||
signals_count: signalsCount,
|
signals_count: signalsCount,
|
||||||
|
|
|
@ -82,7 +82,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -107,7 +107,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
@ -137,7 +137,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -166,7 +166,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -197,7 +197,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -235,7 +235,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -271,7 +271,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [],
|
signals: [],
|
||||||
|
@ -313,7 +313,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
@ -375,7 +375,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
@ -435,7 +435,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
@ -497,7 +497,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
@ -559,7 +559,7 @@ describe('schedule_throttle_notification_actions', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
alertInstance: alertsMock.createAlertInstanceFactory(),
|
alertInstance: alertsMock.createAlertFactory.create(),
|
||||||
notificationRuleParams,
|
notificationRuleParams,
|
||||||
logger,
|
logger,
|
||||||
signals: [
|
signals: [
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { ElasticsearchClient, SavedObject, Logger } from 'src/core/server';
|
import { ElasticsearchClient, SavedObject, Logger } from 'src/core/server';
|
||||||
import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils';
|
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 { RuleParams } from '../schemas/rule_schemas';
|
||||||
import { deconflictSignalsAndResults, getNotificationResultsLink } from '../notifications/utils';
|
import { deconflictSignalsAndResults, getNotificationResultsLink } from '../notifications/utils';
|
||||||
import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants';
|
import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants';
|
||||||
|
@ -26,7 +26,7 @@ interface ScheduleThrottledNotificationActionsOptions {
|
||||||
outputIndex: RuleParams['outputIndex'];
|
outputIndex: RuleParams['outputIndex'];
|
||||||
ruleId: RuleParams['ruleId'];
|
ruleId: RuleParams['ruleId'];
|
||||||
esClient: ElasticsearchClient;
|
esClient: ElasticsearchClient;
|
||||||
alertInstance: AlertInstance;
|
alertInstance: Alert;
|
||||||
notificationRuleParams: NotificationRuleTypeParams;
|
notificationRuleParams: NotificationRuleTypeParams;
|
||||||
signals: unknown[];
|
signals: unknown[];
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
|
|
@ -34,7 +34,7 @@ import {
|
||||||
} from '../../../../../../alerting/common';
|
} from '../../../../../../alerting/common';
|
||||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||||
import { ExecutorType } from '../../../../../../alerting/server/types';
|
import { ExecutorType } from '../../../../../../alerting/server/types';
|
||||||
import { AlertInstance } from '../../../../../../alerting/server';
|
import { Alert } from '../../../../../../alerting/server';
|
||||||
import { ConfigType } from '../../../../config';
|
import { ConfigType } from '../../../../config';
|
||||||
import { alertInstanceFactoryStub } from '../../signals/preview/alert_instance_factory_stub';
|
import { alertInstanceFactoryStub } from '../../signals/preview/alert_instance_factory_stub';
|
||||||
import { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps } from '../../rule_types/types';
|
import { CreateRuleOptions, CreateSecurityRuleTypeWrapperProps } from '../../rule_types/types';
|
||||||
|
@ -140,12 +140,14 @@ export const previewRulesRoute = async (
|
||||||
ruleTypeName: string,
|
ruleTypeName: string,
|
||||||
params: TParams,
|
params: TParams,
|
||||||
shouldWriteAlerts: () => boolean,
|
shouldWriteAlerts: () => boolean,
|
||||||
alertInstanceFactory: (
|
alertFactory: {
|
||||||
|
create: (
|
||||||
id: string
|
id: string
|
||||||
) => Pick<
|
) => Pick<
|
||||||
AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>,
|
Alert<TInstanceState, TInstanceContext, TActionGroupIds>,
|
||||||
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
|
'getState' | 'replaceState' | 'scheduleActions' | 'scheduleActionsWithSubGroup'
|
||||||
>
|
>;
|
||||||
|
}
|
||||||
) => {
|
) => {
|
||||||
let statePreview = runState as TState;
|
let statePreview = runState as TState;
|
||||||
|
|
||||||
|
@ -178,7 +180,7 @@ export const previewRulesRoute = async (
|
||||||
services: {
|
services: {
|
||||||
shouldWriteAlerts,
|
shouldWriteAlerts,
|
||||||
shouldStopExecution: () => false,
|
shouldStopExecution: () => false,
|
||||||
alertInstanceFactory,
|
alertFactory,
|
||||||
// Just use es client always for preview
|
// Just use es client always for preview
|
||||||
search: context.core.elasticsearch.client,
|
search: context.core.elasticsearch.client,
|
||||||
savedObjectsClient: context.core.savedObjects.client,
|
savedObjectsClient: context.core.savedObjects.client,
|
||||||
|
@ -223,7 +225,7 @@ export const previewRulesRoute = async (
|
||||||
queryAlertType.name,
|
queryAlertType.name,
|
||||||
previewRuleParams,
|
previewRuleParams,
|
||||||
() => true,
|
() => true,
|
||||||
alertInstanceFactoryStub
|
{ create: alertInstanceFactoryStub }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'threshold':
|
case 'threshold':
|
||||||
|
@ -236,7 +238,7 @@ export const previewRulesRoute = async (
|
||||||
thresholdAlertType.name,
|
thresholdAlertType.name,
|
||||||
previewRuleParams,
|
previewRuleParams,
|
||||||
() => true,
|
() => true,
|
||||||
alertInstanceFactoryStub
|
{ create: alertInstanceFactoryStub }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'threat_match':
|
case 'threat_match':
|
||||||
|
@ -249,7 +251,7 @@ export const previewRulesRoute = async (
|
||||||
threatMatchAlertType.name,
|
threatMatchAlertType.name,
|
||||||
previewRuleParams,
|
previewRuleParams,
|
||||||
() => true,
|
() => true,
|
||||||
alertInstanceFactoryStub
|
{ create: alertInstanceFactoryStub }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'eql':
|
case 'eql':
|
||||||
|
@ -260,7 +262,7 @@ export const previewRulesRoute = async (
|
||||||
eqlAlertType.name,
|
eqlAlertType.name,
|
||||||
previewRuleParams,
|
previewRuleParams,
|
||||||
() => true,
|
() => true,
|
||||||
alertInstanceFactoryStub
|
{ create: alertInstanceFactoryStub }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'machine_learning':
|
case 'machine_learning':
|
||||||
|
@ -271,7 +273,7 @@ export const previewRulesRoute = async (
|
||||||
mlAlertType.name,
|
mlAlertType.name,
|
||||||
previewRuleParams,
|
previewRuleParams,
|
||||||
() => true,
|
() => true,
|
||||||
alertInstanceFactoryStub
|
{ create: alertInstanceFactoryStub }
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ export const createRuleTypeMocks = (
|
||||||
search: elasticsearchServiceMock.createScopedClusterClient(),
|
search: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
savedObjectsClient: mockSavedObjectsClient,
|
savedObjectsClient: mockSavedObjectsClient,
|
||||||
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
|
||||||
alertInstanceFactory: jest.fn(() => ({ scheduleActions })),
|
alertFactory: { create: jest.fn(() => ({ scheduleActions })) },
|
||||||
findAlerts: jest.fn(), // TODO: does this stay?
|
findAlerts: jest.fn(), // TODO: does this stay?
|
||||||
alertWithPersistence: jest.fn(),
|
alertWithPersistence: jest.fn(),
|
||||||
logger: loggerMock,
|
logger: loggerMock,
|
||||||
|
|
|
@ -315,7 +315,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
||||||
|
|
||||||
if (completeRule.ruleConfig.throttle != null) {
|
if (completeRule.ruleConfig.throttle != null) {
|
||||||
await scheduleThrottledNotificationActions({
|
await scheduleThrottledNotificationActions({
|
||||||
alertInstance: services.alertInstanceFactory(alertId),
|
alertInstance: services.alertFactory.create(alertId),
|
||||||
throttle: completeRule.ruleConfig.throttle ?? '',
|
throttle: completeRule.ruleConfig.throttle ?? '',
|
||||||
startedAt,
|
startedAt,
|
||||||
id: alertId,
|
id: alertId,
|
||||||
|
@ -329,7 +329,7 @@ export const createSecurityRuleTypeWrapper: CreateSecurityRuleTypeWrapper =
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
} else if (createdSignalsCount) {
|
} else if (createdSignalsCount) {
|
||||||
const alertInstance = services.alertInstanceFactory(alertId);
|
const alertInstance = services.alertFactory.create(alertId);
|
||||||
scheduleNotificationActions({
|
scheduleNotificationActions({
|
||||||
alertInstance,
|
alertInstance,
|
||||||
signalsCount: createdSignalsCount,
|
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
|
// 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) {
|
if (completeRule.ruleConfig.throttle != null) {
|
||||||
await scheduleThrottledNotificationActions({
|
await scheduleThrottledNotificationActions({
|
||||||
alertInstance: services.alertInstanceFactory(alertId),
|
alertInstance: services.alertFactory.create(alertId),
|
||||||
throttle: completeRule.ruleConfig.throttle ?? '',
|
throttle: completeRule.ruleConfig.throttle ?? '',
|
||||||
startedAt,
|
startedAt,
|
||||||
id: completeRule.alertId,
|
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
|
// 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) {
|
if (completeRule.ruleConfig.throttle != null) {
|
||||||
await scheduleThrottledNotificationActions({
|
await scheduleThrottledNotificationActions({
|
||||||
alertInstance: services.alertInstanceFactory(alertId),
|
alertInstance: services.alertFactory.create(alertId),
|
||||||
throttle: completeRule.ruleConfig.throttle ?? '',
|
throttle: completeRule.ruleConfig.throttle ?? '',
|
||||||
startedAt,
|
startedAt,
|
||||||
id: completeRule.alertId,
|
id: completeRule.alertId,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
} from '../../../../../../alerting/common';
|
} from '../../../../../../alerting/common';
|
||||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
// 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 = <
|
export const alertInstanceFactoryStub = <
|
||||||
TParams extends RuleParams,
|
TParams extends RuleParams,
|
||||||
|
@ -27,13 +27,13 @@ export const alertInstanceFactoryStub = <
|
||||||
return {} as unknown as TInstanceState;
|
return {} as unknown as TInstanceState;
|
||||||
},
|
},
|
||||||
replaceState(state: TInstanceState) {
|
replaceState(state: TInstanceState) {
|
||||||
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
|
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
|
||||||
state: {} as TInstanceState,
|
state: {} as TInstanceState,
|
||||||
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
scheduleActions(actionGroup: TActionGroupIds, alertcontext: TInstanceContext) {
|
scheduleActions(actionGroup: TActionGroupIds, alertcontext: TInstanceContext) {
|
||||||
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
|
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
|
||||||
state: {} as TInstanceState,
|
state: {} as TInstanceState,
|
||||||
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ export const alertInstanceFactoryStub = <
|
||||||
subgroup: string,
|
subgroup: string,
|
||||||
alertcontext: TInstanceContext
|
alertcontext: TInstanceContext
|
||||||
) {
|
) {
|
||||||
return new AlertInstance<TInstanceState, TInstanceContext, TActionGroupIds>({
|
return new Alert<TInstanceState, TInstanceContext, TActionGroupIds>({
|
||||||
state: {} as TInstanceState,
|
state: {} as TInstanceState,
|
||||||
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
meta: { lastScheduledActions: { group: 'default', date: new Date() } },
|
||||||
});
|
});
|
||||||
|
|
|
@ -178,7 +178,7 @@ describe('alertType', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(alertServices.alertInstanceFactory).not.toHaveBeenCalled();
|
expect(alertServices.alertFactory.create).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
|
@ -257,8 +257,8 @@ describe('alertType', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(alertServices.alertInstanceFactory).toHaveBeenCalledWith(ConditionMetAlertInstanceId);
|
expect(alertServices.alertFactory.create).toHaveBeenCalledWith(ConditionMetAlertInstanceId);
|
||||||
const instance: AlertInstanceMock = alertServices.alertInstanceFactory.mock.results[0].value;
|
const instance: AlertInstanceMock = alertServices.alertFactory.create.mock.results[0].value;
|
||||||
expect(instance.replaceState).toHaveBeenCalledWith({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: undefined,
|
latestTimestamp: undefined,
|
||||||
dateStart: expect.any(String),
|
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({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
// ensure the invalid "latestTimestamp" in the state is stored as an ISO string going forward
|
// ensure the invalid "latestTimestamp" in the state is stored as an ISO string going forward
|
||||||
latestTimestamp: new Date(previousTimestamp).toISOString(),
|
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({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: undefined,
|
latestTimestamp: undefined,
|
||||||
dateStart: expect.any(String),
|
dateStart: expect.any(String),
|
||||||
|
@ -488,7 +488,7 @@ describe('alertType', () => {
|
||||||
};
|
};
|
||||||
const result = await alertType.executor(executorOptions);
|
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({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: undefined,
|
latestTimestamp: undefined,
|
||||||
dateStart: expect.any(String),
|
dateStart: expect.any(String),
|
||||||
|
@ -518,7 +518,7 @@ describe('alertType', () => {
|
||||||
state: result as EsQueryAlertState,
|
state: result as EsQueryAlertState,
|
||||||
});
|
});
|
||||||
const existingInstance: AlertInstanceMock =
|
const existingInstance: AlertInstanceMock =
|
||||||
alertServices.alertInstanceFactory.mock.results[1].value;
|
alertServices.alertFactory.create.mock.results[1].value;
|
||||||
expect(existingInstance.replaceState).toHaveBeenCalledWith({
|
expect(existingInstance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: new Date(oldestDocumentTimestamp).toISOString(),
|
latestTimestamp: new Date(oldestDocumentTimestamp).toISOString(),
|
||||||
dateStart: expect.any(String),
|
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({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: undefined,
|
latestTimestamp: undefined,
|
||||||
dateStart: expect.any(String),
|
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({
|
expect(instance.replaceState).toHaveBeenCalledWith({
|
||||||
latestTimestamp: undefined,
|
latestTimestamp: undefined,
|
||||||
dateStart: expect.any(String),
|
dateStart: expect.any(String),
|
||||||
|
|
|
@ -160,7 +160,7 @@ export function getAlertType(logger: Logger): RuleType<
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
const { alertId, name, services, params, state } = options;
|
const { alertId, name, services, params, state } = options;
|
||||||
const { alertInstanceFactory, search } = services;
|
const { alertFactory, search } = services;
|
||||||
const previousTimestamp = state.latestTimestamp;
|
const previousTimestamp = state.latestTimestamp;
|
||||||
|
|
||||||
const abortableEsClient = search.asCurrentUser;
|
const abortableEsClient = search.asCurrentUser;
|
||||||
|
@ -255,7 +255,7 @@ export function getAlertType(logger: Logger): RuleType<
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionContext = addMessages(options, baseContext, params);
|
const actionContext = addMessages(options, baseContext, params);
|
||||||
const alertInstance = alertInstanceFactory(ConditionMetAlertInstanceId);
|
const alertInstance = alertFactory.create(ConditionMetAlertInstanceId);
|
||||||
alertInstance
|
alertInstance
|
||||||
// store the params we would need to recreate the query that led to this alert instance
|
// store the params we would need to recreate the query that led to this alert instance
|
||||||
.replaceState({ latestTimestamp: timestamp, dateStart, dateEnd })
|
.replaceState({ latestTimestamp: timestamp, dateStart, dateEnd })
|
||||||
|
|
|
@ -87,11 +87,11 @@ export function transformResults(
|
||||||
export function getActiveEntriesAndGenerateAlerts(
|
export function getActiveEntriesAndGenerateAlerts(
|
||||||
prevLocationMap: Map<string, LatestEntityLocation[]>,
|
prevLocationMap: Map<string, LatestEntityLocation[]>,
|
||||||
currLocationMap: Map<string, LatestEntityLocation[]>,
|
currLocationMap: Map<string, LatestEntityLocation[]>,
|
||||||
alertInstanceFactory: AlertServices<
|
alertFactory: AlertServices<
|
||||||
GeoContainmentInstanceState,
|
GeoContainmentInstanceState,
|
||||||
GeoContainmentInstanceContext,
|
GeoContainmentInstanceContext,
|
||||||
typeof ActionGroupId
|
typeof ActionGroupId
|
||||||
>['alertInstanceFactory'],
|
>['alertFactory'],
|
||||||
shapesIdsNamesMap: Record<string, unknown>,
|
shapesIdsNamesMap: Record<string, unknown>,
|
||||||
currIntervalEndTime: Date
|
currIntervalEndTime: Date
|
||||||
) {
|
) {
|
||||||
|
@ -113,7 +113,7 @@ export function getActiveEntriesAndGenerateAlerts(
|
||||||
};
|
};
|
||||||
const alertInstanceId = `${entityName}-${context.containingBoundaryName}`;
|
const alertInstanceId = `${entityName}-${context.containingBoundaryName}`;
|
||||||
if (shapeLocationId !== OTHER_CATEGORY) {
|
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(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
prevLocationMap,
|
prevLocationMap,
|
||||||
currLocationMap,
|
currLocationMap,
|
||||||
services.alertInstanceFactory,
|
services.alertFactory,
|
||||||
shapesIdsNamesMap,
|
shapesIdsNamesMap,
|
||||||
currIntervalEndTime
|
currIntervalEndTime
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,9 +20,9 @@ import { OTHER_CATEGORY } from '../es_query_builder';
|
||||||
import { GeoContainmentInstanceContext, GeoContainmentInstanceState } from '../alert_type';
|
import { GeoContainmentInstanceContext, GeoContainmentInstanceState } from '../alert_type';
|
||||||
import type { GeoContainmentParams } from '../alert_type';
|
import type { GeoContainmentParams } from '../alert_type';
|
||||||
|
|
||||||
const alertInstanceFactory =
|
const alertFactory = (contextKeys: unknown[], testAlertActionArr: unknown[]) => ({
|
||||||
(contextKeys: unknown[], testAlertActionArr: unknown[]) => (instanceId: string) => {
|
create: (instanceId: string) => {
|
||||||
const alertInstance = alertsMock.createAlertInstanceFactory<
|
const alertInstance = alertsMock.createAlertFactory.create<
|
||||||
GeoContainmentInstanceState,
|
GeoContainmentInstanceState,
|
||||||
GeoContainmentInstanceContext
|
GeoContainmentInstanceContext
|
||||||
>();
|
>();
|
||||||
|
@ -39,7 +39,8 @@ const alertInstanceFactory =
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return alertInstance;
|
return alertInstance;
|
||||||
};
|
},
|
||||||
|
});
|
||||||
|
|
||||||
describe('geo_containment', () => {
|
describe('geo_containment', () => {
|
||||||
describe('transformResults', () => {
|
describe('transformResults', () => {
|
||||||
|
@ -253,7 +254,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
emptyPrevLocationMap,
|
emptyPrevLocationMap,
|
||||||
currLocationMap,
|
currLocationMap,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -278,7 +279,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
prevLocationMapWithIdenticalEntityEntry,
|
prevLocationMapWithIdenticalEntityEntry,
|
||||||
currLocationMap,
|
currLocationMap,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -317,7 +318,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
prevLocationMapWithNonIdenticalEntityEntry,
|
prevLocationMapWithNonIdenticalEntityEntry,
|
||||||
currLocationMap,
|
currLocationMap,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -340,7 +341,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
emptyPrevLocationMap,
|
emptyPrevLocationMap,
|
||||||
currLocationMapWithOther,
|
currLocationMapWithOther,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -373,7 +374,7 @@ describe('geo_containment', () => {
|
||||||
getActiveEntriesAndGenerateAlerts(
|
getActiveEntriesAndGenerateAlerts(
|
||||||
emptyPrevLocationMap,
|
emptyPrevLocationMap,
|
||||||
currLocationMapWithThreeMore,
|
currLocationMapWithThreeMore,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -410,7 +411,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
emptyPrevLocationMap,
|
emptyPrevLocationMap,
|
||||||
currLocationMapWithOther,
|
currLocationMapWithOther,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -442,7 +443,7 @@ describe('geo_containment', () => {
|
||||||
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts(
|
||||||
emptyPrevLocationMap,
|
emptyPrevLocationMap,
|
||||||
currLocationMapWithOther,
|
currLocationMapWithOther,
|
||||||
alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory(contextKeys, testAlertActionArr),
|
||||||
emptyShapesIdsNamesMap,
|
emptyShapesIdsNamesMap,
|
||||||
currentDateTime
|
currentDateTime
|
||||||
);
|
);
|
||||||
|
@ -514,7 +515,7 @@ describe('geo_containment', () => {
|
||||||
const alertServicesWithSearchMock: AlertServicesMock = {
|
const alertServicesWithSearchMock: AlertServicesMock = {
|
||||||
...alertsMock.createAlertServices(),
|
...alertsMock.createAlertServices(),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
alertInstanceFactory: alertInstanceFactory(contextKeys, testAlertActionArr),
|
alertFactory: alertFactory(contextKeys, testAlertActionArr),
|
||||||
scopedClusterClient: {
|
scopedClusterClient: {
|
||||||
asCurrentUser: {
|
asCurrentUser: {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -538,6 +539,7 @@ describe('geo_containment', () => {
|
||||||
|
|
||||||
it('should query for shapes if state does not contain shapes', async () => {
|
it('should query for shapes if state does not contain shapes', async () => {
|
||||||
const executor = await getGeoContainmentExecutor(mockLogger);
|
const executor = await getGeoContainmentExecutor(mockLogger);
|
||||||
|
// @ts-ignore
|
||||||
const executionResult = await executor({
|
const executionResult = await executor({
|
||||||
previousStartedAt,
|
previousStartedAt,
|
||||||
startedAt,
|
startedAt,
|
||||||
|
@ -557,6 +559,7 @@ describe('geo_containment', () => {
|
||||||
|
|
||||||
it('should not query for shapes if state contains shapes', async () => {
|
it('should not query for shapes if state contains shapes', async () => {
|
||||||
const executor = await getGeoContainmentExecutor(mockLogger);
|
const executor = await getGeoContainmentExecutor(mockLogger);
|
||||||
|
// @ts-ignore
|
||||||
const executionResult = await executor({
|
const executionResult = await executor({
|
||||||
previousStartedAt,
|
previousStartedAt,
|
||||||
startedAt,
|
startedAt,
|
||||||
|
@ -575,6 +578,7 @@ describe('geo_containment', () => {
|
||||||
|
|
||||||
it('should carry through shapes filters in state to next call unmodified', async () => {
|
it('should carry through shapes filters in state to next call unmodified', async () => {
|
||||||
const executor = await getGeoContainmentExecutor(mockLogger);
|
const executor = await getGeoContainmentExecutor(mockLogger);
|
||||||
|
// @ts-ignore
|
||||||
const executionResult = await executor({
|
const executionResult = await executor({
|
||||||
previousStartedAt,
|
previousStartedAt,
|
||||||
startedAt,
|
startedAt,
|
||||||
|
@ -610,6 +614,7 @@ describe('geo_containment', () => {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
const executor = await getGeoContainmentExecutor(mockLogger);
|
const executor = await getGeoContainmentExecutor(mockLogger);
|
||||||
|
// @ts-ignore
|
||||||
const executionResult = await executor({
|
const executionResult = await executor({
|
||||||
previousStartedAt,
|
previousStartedAt,
|
||||||
startedAt,
|
startedAt,
|
||||||
|
|
|
@ -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 () => {
|
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 () => {
|
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -134,7 +134,7 @@ export function getAlertType(
|
||||||
options: AlertExecutorOptions<Params, {}, {}, ActionContext, typeof ActionGroupId>
|
options: AlertExecutorOptions<Params, {}, {}, ActionContext, typeof ActionGroupId>
|
||||||
) {
|
) {
|
||||||
const { alertId, name, services, params } = options;
|
const { alertId, name, services, params } = options;
|
||||||
const { alertInstanceFactory, search } = services;
|
const { alertFactory, search } = services;
|
||||||
|
|
||||||
const compareFn = ComparatorFns.get(params.thresholdComparator);
|
const compareFn = ComparatorFns.get(params.thresholdComparator);
|
||||||
if (compareFn == null) {
|
if (compareFn == null) {
|
||||||
|
@ -208,7 +208,7 @@ export function getAlertType(
|
||||||
conditions: humanFn,
|
conditions: humanFn,
|
||||||
};
|
};
|
||||||
const actionContext = addMessages(options, baseContext, params);
|
const actionContext = addMessages(options, baseContext, params);
|
||||||
const alertInstance = alertInstanceFactory(instanceId);
|
const alertInstance = alertFactory.create(instanceId);
|
||||||
alertInstance.scheduleActions(ActionGroupId, actionContext);
|
alertInstance.scheduleActions(ActionGroupId, actionContext);
|
||||||
logger.debug(`scheduled actionGroup: ${JSON.stringify(actionContext)}`);
|
logger.debug(`scheduled actionGroup: ${JSON.stringify(actionContext)}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ export function getTransformHealthRuleType(): RuleType<
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
async executor(options) {
|
async executor(options) {
|
||||||
const {
|
const {
|
||||||
services: { scopedClusterClient, alertInstanceFactory },
|
services: { scopedClusterClient, alertFactory },
|
||||||
params,
|
params,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ export function getTransformHealthRuleType(): RuleType<
|
||||||
|
|
||||||
if (executionResult.length > 0) {
|
if (executionResult.length > 0) {
|
||||||
executionResult.forEach(({ name: alertInstanceName, context }) => {
|
executionResult.forEach(({ name: alertInstanceName, context }) => {
|
||||||
const alertInstance = alertInstanceFactory(alertInstanceName);
|
const alertInstance = alertFactory.create(alertInstanceName);
|
||||||
alertInstance.scheduleActions(TRANSFORM_ISSUE, context);
|
alertInstance.scheduleActions(TRANSFORM_ISSUE, context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { commonStateTranslations, tlsTranslations } from './translations';
|
||||||
import { ActionGroupIdsOf } from '../../../../alerting/common';
|
import { ActionGroupIdsOf } from '../../../../alerting/common';
|
||||||
|
|
||||||
import { AlertInstanceContext } 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 { savedObjectsAdapter } from '../saved_objects/saved_objects';
|
||||||
import { createUptimeESClient } from '../lib';
|
import { createUptimeESClient } from '../lib';
|
||||||
|
@ -28,7 +28,7 @@ import {
|
||||||
|
|
||||||
export type ActionGroupIds = ActionGroupIdsOf<typeof TLS_LEGACY>;
|
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 {
|
interface TlsAlertState {
|
||||||
count: number;
|
count: number;
|
||||||
|
@ -113,10 +113,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
|
||||||
},
|
},
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
async executor({
|
async executor({ services: { alertFactory, scopedClusterClient, savedObjectsClient }, state }) {
|
||||||
services: { alertInstanceFactory, scopedClusterClient, savedObjectsClient },
|
|
||||||
state,
|
|
||||||
}) {
|
|
||||||
const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings(savedObjectsClient);
|
const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings(savedObjectsClient);
|
||||||
|
|
||||||
const uptimeEsClient = createUptimeESClient({
|
const uptimeEsClient = createUptimeESClient({
|
||||||
|
@ -156,7 +153,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
|
||||||
'd'
|
'd'
|
||||||
)
|
)
|
||||||
.valueOf();
|
.valueOf();
|
||||||
const alertInstance: TLSAlertInstance = alertInstanceFactory(TLS_LEGACY.id);
|
const alertInstance: TLSAlertInstance = alertFactory.create(TLS_LEGACY.id);
|
||||||
const summary = getCertSummary(certs, absoluteExpirationThreshold, absoluteAgeThreshold);
|
const summary = getCertSummary(certs, absoluteExpirationThreshold, absoluteAgeThreshold);
|
||||||
alertInstance.replaceState({
|
alertInstance.replaceState({
|
||||||
...updateState(state, foundCerts),
|
...updateState(state, foundCerts),
|
||||||
|
|
|
@ -122,7 +122,7 @@ async function alwaysFiringExecutor(alertExecutorOptions: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
const instance = services.alertInstanceFactory('1').replaceState({ instanceStateValue: true });
|
const instance = services.alertFactory.create('1').replaceState({ instanceStateValue: true });
|
||||||
|
|
||||||
if (subgroup) {
|
if (subgroup) {
|
||||||
instance.scheduleActionsWithSubGroup(group, subgroup, {
|
instance.scheduleActionsWithSubGroup(group, subgroup, {
|
||||||
|
@ -177,8 +177,8 @@ function getCumulativeFiringAlertType() {
|
||||||
const runCount = (state.runCount || 0) + 1;
|
const runCount = (state.runCount || 0) + 1;
|
||||||
|
|
||||||
times(runCount, (index) => {
|
times(runCount, (index) => {
|
||||||
services
|
services.alertFactory
|
||||||
.alertInstanceFactory(`instance-${index}`)
|
.create(`instance-${index}`)
|
||||||
.replaceState({ instanceStateValue: true })
|
.replaceState({ instanceStateValue: true })
|
||||||
.scheduleActions(group);
|
.scheduleActions(group);
|
||||||
});
|
});
|
||||||
|
@ -446,13 +446,13 @@ function getPatternFiringAlertType() {
|
||||||
for (const [instanceId, instancePattern] of Object.entries(pattern)) {
|
for (const [instanceId, instancePattern] of Object.entries(pattern)) {
|
||||||
const scheduleByPattern = instancePattern[patternIndex];
|
const scheduleByPattern = instancePattern[patternIndex];
|
||||||
if (scheduleByPattern === true) {
|
if (scheduleByPattern === true) {
|
||||||
services.alertInstanceFactory(instanceId).scheduleActions('default', {
|
services.alertFactory.create(instanceId).scheduleActions('default', {
|
||||||
...EscapableStrings,
|
...EscapableStrings,
|
||||||
deep: DeepContextVariables,
|
deep: DeepContextVariables,
|
||||||
});
|
});
|
||||||
} else if (typeof scheduleByPattern === 'string') {
|
} else if (typeof scheduleByPattern === 'string') {
|
||||||
services
|
services.alertFactory
|
||||||
.alertInstanceFactory(instanceId)
|
.create(instanceId)
|
||||||
.scheduleActionsWithSubGroup('default', scheduleByPattern);
|
.scheduleActionsWithSubGroup('default', scheduleByPattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,7 +538,7 @@ function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
services.alertInstanceFactory('alert').scheduleActions('default', {});
|
services.alertFactory.create('alert').scheduleActions('default', {});
|
||||||
|
|
||||||
// run long if pattern says to
|
// run long if pattern says to
|
||||||
if (pattern[globalPatternIndex++] === true) {
|
if (pattern[globalPatternIndex++] === true) {
|
||||||
|
|
|
@ -54,8 +54,8 @@ export const alwaysFiringAlertType: RuleType<
|
||||||
const { services, state, params } = alertExecutorOptions;
|
const { services, state, params } = alertExecutorOptions;
|
||||||
|
|
||||||
(params.instances || []).forEach((instance: { id: string; state: any }) => {
|
(params.instances || []).forEach((instance: { id: string; state: any }) => {
|
||||||
services
|
services.alertFactory
|
||||||
.alertInstanceFactory(instance.id)
|
.create(instance.id)
|
||||||
.replaceState({ instanceStateValue: true, ...(instance.state || {}) })
|
.replaceState({ instanceStateValue: true, ...(instance.state || {}) })
|
||||||
.scheduleActions('default');
|
.scheduleActions('default');
|
||||||
});
|
});
|
||||||
|
|
|
@ -177,7 +177,7 @@ export default function createLifecycleExecutorApiTest({ getService }: FtrProvid
|
||||||
producer: 'observability.test',
|
producer: 'observability.test',
|
||||||
},
|
},
|
||||||
services: {
|
services: {
|
||||||
alertInstanceFactory: sinon.stub(),
|
alertFactory: { create: sinon.stub() },
|
||||||
shouldWriteAlerts: sinon.stub().returns(true),
|
shouldWriteAlerts: sinon.stub().returns(true),
|
||||||
},
|
},
|
||||||
} as unknown as RuleExecutorOptions<
|
} as unknown as RuleExecutorOptions<
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue