mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[RAM] Introduce maxScheduledPerMinute rule circuit breaker and route (#164791)
## Summary Resolves: https://github.com/elastic/kibana/issues/162262 This PR is the backend changes to add a circuit breaker `xpack.alerting.rules.maxScheduledPerMinute` to both serverless and other environments that limits the number of rules to 400 runs / minute and 10000 runs / minute, respectively. There will be another PR to follow this one that gives the user UI hints when creating/editing rules that go over this limit. This circuit breaker check is applied to the following routes: - Create Rule - Update Rule - Enable Rule - Bulk Enable Rule - Bulk Edit Rule Also adds a new route: `/internal/alerting/rules/_schedule_frequency` to get the current total schedules per minute (of enabled rules) and the remaining interval allotment. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: lcawl <lcawley@elastic.co> Co-authored-by: Xavier Mouligneau <xavier.mouligneau@elastic.co>
This commit is contained in:
parent
1a9bb19e57
commit
456f47f3ab
77 changed files with 1773 additions and 138 deletions
|
@ -171,6 +171,7 @@ enabled:
|
||||||
- x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts
|
- x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts
|
||||||
- x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts
|
- x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts
|
||||||
- x-pack/test/alerting_api_integration/security_and_spaces/group3/config.ts
|
- x-pack/test/alerting_api_integration/security_and_spaces/group3/config.ts
|
||||||
|
- x-pack/test/alerting_api_integration/security_and_spaces/group3/config_with_schedule_circuit_breaker.ts
|
||||||
- x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts
|
- x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts
|
||||||
- x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/config.ts
|
- x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/config.ts
|
||||||
- x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/config.ts
|
- x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/config.ts
|
||||||
|
|
|
@ -117,6 +117,7 @@ xpack.alerting.rules.run.ruleTypeOverrides:
|
||||||
- id: siem.indicatorRule
|
- id: siem.indicatorRule
|
||||||
timeout: 1m
|
timeout: 1m
|
||||||
xpack.alerting.rules.minimumScheduleInterval.enforce: true
|
xpack.alerting.rules.minimumScheduleInterval.enforce: true
|
||||||
|
xpack.alerting.rules.maxScheduledPerMinute: 400
|
||||||
xpack.actions.run.maxAttempts: 10
|
xpack.actions.run.maxAttempts: 10
|
||||||
|
|
||||||
# Disables ESQL in advanced settings (hides it from the UI)
|
# Disables ESQL in advanced settings (hides it from the UI)
|
||||||
|
|
|
@ -301,6 +301,9 @@ Specifies whether to skip writing alerts and scheduling actions if rule
|
||||||
processing was cancelled due to a timeout. Default: `true`. This setting can be
|
processing was cancelled due to a timeout. Default: `true`. This setting can be
|
||||||
overridden by individual rule types.
|
overridden by individual rule types.
|
||||||
|
|
||||||
|
`xpack.alerting.rules.maxScheduledPerMinute` {ess-icon}::
|
||||||
|
Specifies the maximum number of rules to run per minute. Default: 10000
|
||||||
|
|
||||||
`xpack.alerting.rules.minimumScheduleInterval.value` {ess-icon}::
|
`xpack.alerting.rules.minimumScheduleInterval.value` {ess-icon}::
|
||||||
Specifies the minimum schedule interval for rules. This minimum is applied to all rules created or updated after you set this value.
|
Specifies the minimum schedule interval for rules. This minimum is applied to all rules created or updated after you set this value.
|
||||||
The time is formatted as a number and a time unit (`s`, `m`, `h`, or `d`).
|
The time is formatted as a number and a time unit (`s`, `m`, `h`, or `d`).
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
formatDuration,
|
formatDuration,
|
||||||
getDurationNumberInItsUnit,
|
getDurationNumberInItsUnit,
|
||||||
getDurationUnitValue,
|
getDurationUnitValue,
|
||||||
|
convertDurationToFrequency,
|
||||||
} from './parse_duration';
|
} from './parse_duration';
|
||||||
|
|
||||||
test('parses seconds', () => {
|
test('parses seconds', () => {
|
||||||
|
@ -180,3 +181,26 @@ test('getDurationUnitValue hours', () => {
|
||||||
const result = getDurationUnitValue('100h');
|
const result = getDurationUnitValue('100h');
|
||||||
expect(result).toEqual('h');
|
expect(result).toEqual('h');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('convertDurationToFrequency converts duration', () => {
|
||||||
|
let result = convertDurationToFrequency('1m');
|
||||||
|
expect(result).toEqual(1);
|
||||||
|
result = convertDurationToFrequency('5m');
|
||||||
|
expect(result).toEqual(0.2);
|
||||||
|
result = convertDurationToFrequency('10s');
|
||||||
|
expect(result).toEqual(6);
|
||||||
|
result = convertDurationToFrequency('1s');
|
||||||
|
expect(result).toEqual(60);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convertDurationToFrequency throws when duration is invalid', () => {
|
||||||
|
expect(() => convertDurationToFrequency('0d')).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"Invalid duration \\"0d\\". Durations must be of the form {number}x. Example: 5s, 5m, 5h or 5d\\""`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('convertDurationToFrequency throws when denomination is 0', () => {
|
||||||
|
expect(() => convertDurationToFrequency('1s', 0)).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"Invalid denomination value: value cannot be 0"`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
@ -10,6 +10,8 @@ const MINUTES_REGEX = /^[1-9][0-9]*m$/;
|
||||||
const HOURS_REGEX = /^[1-9][0-9]*h$/;
|
const HOURS_REGEX = /^[1-9][0-9]*h$/;
|
||||||
const DAYS_REGEX = /^[1-9][0-9]*d$/;
|
const DAYS_REGEX = /^[1-9][0-9]*d$/;
|
||||||
|
|
||||||
|
const MS_PER_MINUTE = 60 * 1000;
|
||||||
|
|
||||||
// parse an interval string '{digit*}{s|m|h|d}' into milliseconds
|
// parse an interval string '{digit*}{s|m|h|d}' into milliseconds
|
||||||
export function parseDuration(duration: string): number {
|
export function parseDuration(duration: string): number {
|
||||||
const parsed = parseInt(duration, 10);
|
const parsed = parseInt(duration, 10);
|
||||||
|
@ -43,6 +45,19 @@ export function formatDuration(duration: string, fullUnit?: boolean): string {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertDurationToFrequency(
|
||||||
|
duration: string,
|
||||||
|
denomination: number = MS_PER_MINUTE
|
||||||
|
): number {
|
||||||
|
const durationInMs = parseDuration(duration);
|
||||||
|
if (denomination === 0) {
|
||||||
|
throw new Error(`Invalid denomination value: value cannot be 0`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const intervalInDenominationUnits = durationInMs / denomination;
|
||||||
|
return 1 / intervalInDenominationUnits;
|
||||||
|
}
|
||||||
|
|
||||||
export function getDurationNumberInItsUnit(duration: string): number {
|
export function getDurationNumberInItsUnit(duration: string): number {
|
||||||
return parseInt(duration.replace(/[^0-9.]/g, ''), 10);
|
return parseInt(duration.replace(/[^0-9.]/g, ''), 10);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {
|
||||||
|
getScheduleFrequencyResponseSchema,
|
||||||
|
getScheduleFrequencyResponseBodySchema,
|
||||||
|
} from './schemas/latest';
|
||||||
|
|
||||||
|
export type {
|
||||||
|
GetScheduleFrequencyResponse,
|
||||||
|
GetScheduleFrequencyResponseBody,
|
||||||
|
} from './types/latest';
|
||||||
|
|
||||||
|
export {
|
||||||
|
getScheduleFrequencyResponseSchema as getScheduleFrequencyResponseSchemaV1,
|
||||||
|
getScheduleFrequencyResponseBodySchema as getScheduleFrequencyResponseBodySchemaV1,
|
||||||
|
} from './schemas/v1';
|
||||||
|
|
||||||
|
export type {
|
||||||
|
GetScheduleFrequencyResponse as GetScheduleFrequencyResponseV1,
|
||||||
|
GetScheduleFrequencyResponseBody as GetScheduleFrequencyResponseBodyV1,
|
||||||
|
} from './types/v1';
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './v1';
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* 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 { schema } from '@kbn/config-schema';
|
||||||
|
|
||||||
|
export const getScheduleFrequencyResponseBodySchema = schema.object({
|
||||||
|
total_scheduled_per_minute: schema.number(),
|
||||||
|
remaining_schedules_per_minute: schema.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getScheduleFrequencyResponseSchema = schema.object({
|
||||||
|
body: getScheduleFrequencyResponseBodySchema,
|
||||||
|
});
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './v1';
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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 type { TypeOf } from '@kbn/config-schema';
|
||||||
|
import { getScheduleFrequencyResponseSchemaV1, getScheduleFrequencyResponseBodySchemaV1 } from '..';
|
||||||
|
|
||||||
|
export type GetScheduleFrequencyResponseBody = TypeOf<
|
||||||
|
typeof getScheduleFrequencyResponseBodySchemaV1
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type GetScheduleFrequencyResponse = TypeOf<typeof getScheduleFrequencyResponseSchemaV1>;
|
|
@ -10,7 +10,11 @@ import { omit } from 'lodash';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client';
|
import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
||||||
|
@ -56,7 +60,12 @@ jest.mock('uuid', () => {
|
||||||
return { v4: () => `${uuid++}` };
|
return { v4: () => `${uuid++}` };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const { isSnoozeActive } = jest.requireMock('../../../../lib/snooze/is_snooze_active');
|
const { isSnoozeActive } = jest.requireMock('../../../../lib/snooze/is_snooze_active');
|
||||||
|
const { validateScheduleLimit } = jest.requireMock('../get_schedule_frequency');
|
||||||
|
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
|
@ -65,6 +74,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.2.0';
|
const kibanaVersion = 'v8.2.0';
|
||||||
const createAPIKeyMock = jest.fn();
|
const createAPIKeyMock = jest.fn();
|
||||||
|
@ -82,11 +92,13 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: createAPIKeyMock,
|
createAPIKey: createAPIKeyMock,
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: isAuthenticationTypeApiKeyMock,
|
isAuthenticationTypeAPIKey: isAuthenticationTypeApiKeyMock,
|
||||||
getAuthenticationAPIKey: getAuthenticationApiKeyMock,
|
getAuthenticationAPIKey: getAuthenticationApiKeyMock,
|
||||||
|
@ -2495,6 +2507,66 @@ describe('bulkEdit()', () => {
|
||||||
`Error updating rule with ID "${existingDecryptedRule.id}": the interval 10m is longer than the action frequencies`
|
`Error updating rule with ID "${existingDecryptedRule.id}": the interval 10m is longer than the action frequencies`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should only validate schedule limit if schedule is being modified', async () => {
|
||||||
|
unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({
|
||||||
|
saved_objects: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'alert',
|
||||||
|
attributes: {
|
||||||
|
enabled: true,
|
||||||
|
tags: ['foo', 'test-1'],
|
||||||
|
alertTypeId: 'myType',
|
||||||
|
schedule: { interval: '1m' },
|
||||||
|
consumer: 'myApp',
|
||||||
|
scheduledTaskId: 'task-123',
|
||||||
|
executionStatus: {
|
||||||
|
lastExecutionDate: '2019-02-12T21:01:22.479Z',
|
||||||
|
status: 'pending',
|
||||||
|
},
|
||||||
|
params: {},
|
||||||
|
throttle: null,
|
||||||
|
notifyWhen: null,
|
||||||
|
actions: [],
|
||||||
|
revision: 0,
|
||||||
|
},
|
||||||
|
references: [],
|
||||||
|
version: '123',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await rulesClient.bulkEdit({
|
||||||
|
filter: '',
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
field: 'tags',
|
||||||
|
operation: 'add',
|
||||||
|
value: ['test-1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(validateScheduleLimit).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
await rulesClient.bulkEdit({
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
field: 'schedule',
|
||||||
|
operation: 'set',
|
||||||
|
value: { interval: '2m' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'tags',
|
||||||
|
operation: 'add',
|
||||||
|
value: ['test-1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(validateScheduleLimit).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('paramsModifier', () => {
|
describe('paramsModifier', () => {
|
||||||
|
|
|
@ -77,6 +77,11 @@ import {
|
||||||
transformRuleDomainToRuleAttributes,
|
transformRuleDomainToRuleAttributes,
|
||||||
transformRuleDomainToRule,
|
transformRuleDomainToRule,
|
||||||
} from '../../transforms';
|
} from '../../transforms';
|
||||||
|
import { validateScheduleLimit } from '../get_schedule_frequency';
|
||||||
|
|
||||||
|
const isValidInterval = (interval: string | undefined): interval is string => {
|
||||||
|
return interval !== undefined;
|
||||||
|
};
|
||||||
|
|
||||||
export const bulkEditFieldsToExcludeFromRevisionUpdates = new Set(['snoozeSchedule', 'apiKey']);
|
export const bulkEditFieldsToExcludeFromRevisionUpdates = new Set(['snoozeSchedule', 'apiKey']);
|
||||||
|
|
||||||
|
@ -286,8 +291,16 @@ async function bulkEditRulesOcc<Params extends RuleParams>(
|
||||||
const errors: BulkOperationError[] = [];
|
const errors: BulkOperationError[] = [];
|
||||||
const apiKeysMap: ApiKeysMap = new Map();
|
const apiKeysMap: ApiKeysMap = new Map();
|
||||||
const username = await context.getUserName();
|
const username = await context.getUserName();
|
||||||
|
const prevInterval: string[] = [];
|
||||||
|
|
||||||
for await (const response of rulesFinder.find()) {
|
for await (const response of rulesFinder.find()) {
|
||||||
|
const intervals = response.saved_objects
|
||||||
|
.filter((rule) => rule.attributes.enabled)
|
||||||
|
.map((rule) => rule.attributes.schedule?.interval)
|
||||||
|
.filter(isValidInterval);
|
||||||
|
|
||||||
|
prevInterval.concat(intervals);
|
||||||
|
|
||||||
await pMap(
|
await pMap(
|
||||||
response.saved_objects,
|
response.saved_objects,
|
||||||
async (rule: SavedObjectsFindResult<RuleAttributes>) =>
|
async (rule: SavedObjectsFindResult<RuleAttributes>) =>
|
||||||
|
@ -308,9 +321,44 @@ async function bulkEditRulesOcc<Params extends RuleParams>(
|
||||||
}
|
}
|
||||||
await rulesFinder.close();
|
await rulesFinder.close();
|
||||||
|
|
||||||
|
const updatedInterval = rules
|
||||||
|
.filter((rule) => rule.attributes.enabled)
|
||||||
|
.map((rule) => rule.attributes.schedule?.interval)
|
||||||
|
.filter(isValidInterval);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (operations.some((operation) => operation.field === 'schedule')) {
|
||||||
|
await validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
prevInterval,
|
||||||
|
updatedInterval,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
apiKeysToInvalidate: Array.from(apiKeysMap.values())
|
||||||
|
.filter((value) => value.newApiKey)
|
||||||
|
.map((value) => value.newApiKey as string),
|
||||||
|
resultSavedObjects: [],
|
||||||
|
rules: [],
|
||||||
|
errors: rules.map((rule) => ({
|
||||||
|
message: `Failed to bulk edit rule - ${error.message}`,
|
||||||
|
rule: {
|
||||||
|
id: rule.id,
|
||||||
|
name: rule.attributes.name || 'n/a',
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
skipped: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const { result, apiKeysToInvalidate } =
|
const { result, apiKeysToInvalidate } =
|
||||||
rules.length > 0
|
rules.length > 0
|
||||||
? await saveBulkUpdatedRules(context, rules, apiKeysMap)
|
? await saveBulkUpdatedRules({
|
||||||
|
context,
|
||||||
|
rules,
|
||||||
|
apiKeysMap,
|
||||||
|
})
|
||||||
: {
|
: {
|
||||||
result: { saved_objects: [] },
|
result: { saved_objects: [] },
|
||||||
apiKeysToInvalidate: [],
|
apiKeysToInvalidate: [],
|
||||||
|
@ -821,11 +869,15 @@ function updateAttributes(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveBulkUpdatedRules(
|
async function saveBulkUpdatedRules({
|
||||||
context: RulesClientContext,
|
context,
|
||||||
rules: Array<SavedObjectsBulkUpdateObject<RuleAttributes>>,
|
rules,
|
||||||
apiKeysMap: ApiKeysMap
|
apiKeysMap,
|
||||||
) {
|
}: {
|
||||||
|
context: RulesClientContext;
|
||||||
|
rules: Array<SavedObjectsBulkUpdateObject<RuleAttributes>>;
|
||||||
|
apiKeysMap: ApiKeysMap;
|
||||||
|
}) {
|
||||||
const apiKeysToInvalidate: string[] = [];
|
const apiKeysToInvalidate: string[] = [];
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { CreateRuleParams } from './create_rule';
|
import { CreateRuleParams } from './create_rule';
|
||||||
import { RulesClient, ConstructorOptions } from '../../../../rules_client';
|
import { RulesClient, ConstructorOptions } from '../../../../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
||||||
|
@ -43,6 +47,10 @@ jest.mock('uuid', () => {
|
||||||
return { v4: () => `${uuid++}` };
|
return { v4: () => `${uuid++}` };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
|
@ -50,6 +58,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.0.0';
|
const kibanaVersion = 'v8.0.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -63,11 +72,13 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -36,6 +36,7 @@ import { RuleAttributes } from '../../../../data/rule/types';
|
||||||
import type { CreateRuleData } from './types';
|
import type { CreateRuleData } from './types';
|
||||||
import { createRuleDataSchema } from './schemas';
|
import { createRuleDataSchema } from './schemas';
|
||||||
import { createRuleSavedObject } from '../../../../rules_client/lib';
|
import { createRuleSavedObject } from '../../../../rules_client/lib';
|
||||||
|
import { validateScheduleLimit } from '../get_schedule_frequency';
|
||||||
|
|
||||||
export interface CreateRuleOptions {
|
export interface CreateRuleOptions {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -60,6 +61,12 @@ export async function createRule<Params extends RuleParams = never>(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
createRuleDataSchema.validate(data);
|
createRuleDataSchema.validate(data);
|
||||||
|
if (data.enabled) {
|
||||||
|
await validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
updatedInterval: data.schedule.interval,
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw Boom.badRequest(`Error validating create data - ${error.message}`);
|
throw Boom.badRequest(`Error validating create data - ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* 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 { validateScheduleLimit } from './get_schedule_frequency';
|
||||||
|
import { RulesClient, ConstructorOptions } from '../../../../rules_client';
|
||||||
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
|
import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock';
|
||||||
|
import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock';
|
||||||
|
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
||||||
|
import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks';
|
||||||
|
import { AlertingAuthorization } from '../../../../authorization/alerting_authorization';
|
||||||
|
import { ActionsAuthorization } from '@kbn/actions-plugin/server';
|
||||||
|
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
|
||||||
|
|
||||||
|
const taskManager = taskManagerMock.createStart();
|
||||||
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
|
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
|
const authorization = alertingAuthorizationMock.create();
|
||||||
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
|
const kibanaVersion = 'v8.0.0';
|
||||||
|
|
||||||
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
taskManager,
|
||||||
|
ruleTypeRegistry,
|
||||||
|
unsecuredSavedObjectsClient,
|
||||||
|
authorization: authorization as unknown as AlertingAuthorization,
|
||||||
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
|
spaceId: 'default',
|
||||||
|
namespace: 'default',
|
||||||
|
getUserName: jest.fn(),
|
||||||
|
createAPIKey: jest.fn(),
|
||||||
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
|
getActionsClient: jest.fn(),
|
||||||
|
getEventLogClient: jest.fn(),
|
||||||
|
kibanaVersion,
|
||||||
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 100,
|
||||||
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMockAggregationResult = (
|
||||||
|
intervalAggs: Array<{
|
||||||
|
interval: string;
|
||||||
|
count: number;
|
||||||
|
}>
|
||||||
|
) => {
|
||||||
|
return {
|
||||||
|
aggregations: {
|
||||||
|
schedule_intervals: {
|
||||||
|
buckets: intervalAggs.map(({ interval, count }) => ({
|
||||||
|
key: interval,
|
||||||
|
doc_count: count,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
page: 1,
|
||||||
|
per_page: 20,
|
||||||
|
total: 1,
|
||||||
|
saved_objects: [],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('getScheduleFrequency()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([
|
||||||
|
{ interval: '1m', count: 1 },
|
||||||
|
{ interval: '1m', count: 2 },
|
||||||
|
{ interval: '1m', count: 3 },
|
||||||
|
{ interval: '5m', count: 5 },
|
||||||
|
{ interval: '5m', count: 10 },
|
||||||
|
{ interval: '5m', count: 15 },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the correct schedule frequency results', async () => {
|
||||||
|
const rulesClient = new RulesClient(rulesClientParams);
|
||||||
|
const result = await rulesClient.getScheduleFrequency();
|
||||||
|
|
||||||
|
// (1 * 6) + (1/5 * 30) = 12
|
||||||
|
expect(result.totalScheduledPerMinute).toEqual(12);
|
||||||
|
|
||||||
|
// 100 - 88
|
||||||
|
expect(result.remainingSchedulesPerMinute).toEqual(88);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty bucket correctly', async () => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue({
|
||||||
|
page: 1,
|
||||||
|
per_page: 20,
|
||||||
|
total: 1,
|
||||||
|
saved_objects: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const rulesClient = new RulesClient(rulesClientParams);
|
||||||
|
const result = await rulesClient.getScheduleFrequency();
|
||||||
|
|
||||||
|
expect(result.totalScheduledPerMinute).toEqual(0);
|
||||||
|
expect(result.remainingSchedulesPerMinute).toEqual(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle malformed schedule interval correctly', async () => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([
|
||||||
|
{ interval: '1m', count: 1 },
|
||||||
|
{ interval: '1m', count: 2 },
|
||||||
|
{ interval: '1m', count: 3 },
|
||||||
|
{ interval: '5m', count: 5 },
|
||||||
|
{ interval: '5m', count: 10 },
|
||||||
|
{ interval: '5m', count: 15 },
|
||||||
|
{ interval: 'invalid', count: 15 },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const rulesClient = new RulesClient(rulesClientParams);
|
||||||
|
const result = await rulesClient.getScheduleFrequency();
|
||||||
|
|
||||||
|
expect(result.totalScheduledPerMinute).toEqual(12);
|
||||||
|
expect(result.remainingSchedulesPerMinute).toEqual(88);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not go below 0 for remaining schedules', async () => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([
|
||||||
|
{ interval: '1m', count: 1 },
|
||||||
|
{ interval: '1m', count: 2 },
|
||||||
|
{ interval: '1m', count: 3 },
|
||||||
|
{ interval: '5m', count: 5 },
|
||||||
|
{ interval: '5m', count: 10 },
|
||||||
|
{ interval: '5m', count: 15 },
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const rulesClient = new RulesClient({
|
||||||
|
...rulesClientParams,
|
||||||
|
maxScheduledPerMinute: 10,
|
||||||
|
});
|
||||||
|
const result = await rulesClient.getScheduleFrequency();
|
||||||
|
expect(result.totalScheduledPerMinute).toEqual(12);
|
||||||
|
expect(result.remainingSchedulesPerMinute).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('validateScheduleLimit', () => {
|
||||||
|
const context = {
|
||||||
|
...rulesClientParams,
|
||||||
|
maxScheduledPerMinute: 5,
|
||||||
|
minimumScheduleIntervalInMs: 1000,
|
||||||
|
fieldsToExcludeFromPublicApi: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([{ interval: '1m', count: 2 }])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not throw if the updated interval does not exceed limits', () => {
|
||||||
|
return expect(
|
||||||
|
validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
updatedInterval: ['1m', '1m'],
|
||||||
|
})
|
||||||
|
).resolves.toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw if the updated interval exceeds limits', () => {
|
||||||
|
return expect(
|
||||||
|
validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
updatedInterval: ['1m', '1m', '1m', '2m'],
|
||||||
|
})
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"Run limit reached: The rule has 3.5 runs per minute; there are only 3 runs per minute available."`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not throw if previous interval was modified to be under the limit', () => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([{ interval: '1m', count: 6 }])
|
||||||
|
);
|
||||||
|
|
||||||
|
return expect(
|
||||||
|
validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
prevInterval: ['1m', '1m'],
|
||||||
|
updatedInterval: ['2m', '2m'],
|
||||||
|
})
|
||||||
|
).resolves.toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw if the previous interval was modified to exceed the limit', () => {
|
||||||
|
internalSavedObjectsRepository.find.mockResolvedValue(
|
||||||
|
getMockAggregationResult([{ interval: '1m', count: 5 }])
|
||||||
|
);
|
||||||
|
|
||||||
|
return expect(
|
||||||
|
validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
prevInterval: ['1m'],
|
||||||
|
updatedInterval: ['30s'],
|
||||||
|
})
|
||||||
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
||||||
|
`"Run limit reached: The rule has 2 runs per minute; there are only 1 runs per minute available."`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* 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 { RulesClientContext } from '../../../../rules_client/types';
|
||||||
|
import { RuleDomain } from '../../types';
|
||||||
|
import { convertDurationToFrequency } from '../../../../../common/parse_duration';
|
||||||
|
import { GetScheduleFrequencyResult } from './types';
|
||||||
|
import { getSchemaFrequencyResultSchema } from './schema';
|
||||||
|
|
||||||
|
export interface SchedulesIntervalAggregationResult {
|
||||||
|
schedule_intervals: {
|
||||||
|
buckets: Array<{
|
||||||
|
key: string;
|
||||||
|
doc_count: number;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const convertIntervalToFrequency = (context: RulesClientContext, schedule: string) => {
|
||||||
|
let scheduleFrequency = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Normalize the interval (period) in terms of minutes
|
||||||
|
scheduleFrequency = convertDurationToFrequency(schedule);
|
||||||
|
} catch (e) {
|
||||||
|
context.logger.warn(
|
||||||
|
`Failed to parse rule schedule interval for schedule frequency calculation: ${e.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scheduleFrequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getScheduleFrequency = async (
|
||||||
|
context: RulesClientContext
|
||||||
|
): Promise<GetScheduleFrequencyResult> => {
|
||||||
|
const response = await context.internalSavedObjectsRepository.find<
|
||||||
|
RuleDomain,
|
||||||
|
SchedulesIntervalAggregationResult
|
||||||
|
>({
|
||||||
|
type: 'alert',
|
||||||
|
filter: 'alert.attributes.enabled: true',
|
||||||
|
namespaces: ['*'],
|
||||||
|
aggs: {
|
||||||
|
schedule_intervals: {
|
||||||
|
terms: {
|
||||||
|
field: 'alert.attributes.schedule.interval',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const buckets = response.aggregations?.schedule_intervals.buckets ?? [];
|
||||||
|
|
||||||
|
const totalScheduledPerMinute = buckets.reduce((result, { key, doc_count: occurrence }) => {
|
||||||
|
const scheduleFrequency = convertIntervalToFrequency(context, key);
|
||||||
|
|
||||||
|
// Sum up all of the frequencies, since this is an aggregation.
|
||||||
|
return result + scheduleFrequency * occurrence;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
totalScheduledPerMinute,
|
||||||
|
remainingSchedulesPerMinute: Math.max(
|
||||||
|
context.maxScheduledPerMinute - totalScheduledPerMinute,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
getSchemaFrequencyResultSchema.validate(result);
|
||||||
|
} catch (e) {
|
||||||
|
context.logger.warn(`Error validating rule schedules per minute: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ValidateScheduleLimitParams {
|
||||||
|
context: RulesClientContext;
|
||||||
|
prevInterval?: string | string[];
|
||||||
|
updatedInterval: string | string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateScheduleLimit = async (params: ValidateScheduleLimitParams) => {
|
||||||
|
const { context, prevInterval = [], updatedInterval = [] } = params;
|
||||||
|
|
||||||
|
const prevIntervalArray = Array.isArray(prevInterval) ? prevInterval : [prevInterval];
|
||||||
|
const updatedIntervalArray = Array.isArray(updatedInterval) ? updatedInterval : [updatedInterval];
|
||||||
|
|
||||||
|
const prevSchedulePerMinute = prevIntervalArray.reduce((result, interval) => {
|
||||||
|
const scheduleFrequency = convertIntervalToFrequency(context, interval);
|
||||||
|
return result + scheduleFrequency;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const updatedSchedulesPerMinute = updatedIntervalArray.reduce((result, interval) => {
|
||||||
|
const scheduleFrequency = convertIntervalToFrequency(context, interval);
|
||||||
|
return result + scheduleFrequency;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const { remainingSchedulesPerMinute } = await getScheduleFrequency(context);
|
||||||
|
|
||||||
|
// Compute the new remaining schedules per minute if we are editing rules.
|
||||||
|
// So we add back the edited schedules, since we assume those are being edited.
|
||||||
|
const computedRemainingSchedulesPerMinute = remainingSchedulesPerMinute + prevSchedulePerMinute;
|
||||||
|
|
||||||
|
if (computedRemainingSchedulesPerMinute < updatedSchedulesPerMinute) {
|
||||||
|
throw new Error(
|
||||||
|
`Run limit reached: The rule has ${updatedSchedulesPerMinute} runs per minute; there are only ${computedRemainingSchedulesPerMinute} runs per minute available.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type { GetScheduleFrequencyResult } from './types';
|
||||||
|
|
||||||
|
export { getScheduleFrequency, validateScheduleLimit } from './get_schedule_frequency';
|
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* 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 { schema } from '@kbn/config-schema';
|
||||||
|
|
||||||
|
export const getSchemaFrequencyResultSchema = schema.object({
|
||||||
|
totalScheduledPerMinute: schema.number({ min: 0 }),
|
||||||
|
remainingSchedulesPerMinute: schema.number({ min: 0 }),
|
||||||
|
});
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { getSchemaFrequencyResultSchema } from './get_schedule_frequency_result_schema';
|
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* 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 { TypeOf } from '@kbn/config-schema';
|
||||||
|
import { getSchemaFrequencyResultSchema } from '../schema';
|
||||||
|
|
||||||
|
export type GetScheduleFrequencyResult = TypeOf<typeof getSchemaFrequencyResultSchema>;
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type { GetScheduleFrequencyResult } from './get_schedule_frequency_result';
|
|
@ -23,6 +23,7 @@ describe('config validation', () => {
|
||||||
},
|
},
|
||||||
"maxEphemeralActionsPerAlert": 10,
|
"maxEphemeralActionsPerAlert": 10,
|
||||||
"rules": Object {
|
"rules": Object {
|
||||||
|
"maxScheduledPerMinute": 10000,
|
||||||
"minimumScheduleInterval": Object {
|
"minimumScheduleInterval": Object {
|
||||||
"enforce": false,
|
"enforce": false,
|
||||||
"value": "1m",
|
"value": "1m",
|
||||||
|
|
|
@ -38,6 +38,7 @@ const rulesSchema = schema.object({
|
||||||
}),
|
}),
|
||||||
enforce: schema.boolean({ defaultValue: false }), // if enforce is false, only warnings will be shown
|
enforce: schema.boolean({ defaultValue: false }), // if enforce is false, only warnings will be shown
|
||||||
}),
|
}),
|
||||||
|
maxScheduledPerMinute: schema.number({ defaultValue: 10000, max: 10000, min: 0 }),
|
||||||
run: schema.object({
|
run: schema.object({
|
||||||
timeout: schema.maybe(schema.string({ validate: validateDurationSchema })),
|
timeout: schema.maybe(schema.string({ validate: validateDurationSchema })),
|
||||||
actions: schema.object({
|
actions: schema.object({
|
||||||
|
@ -70,7 +71,10 @@ export const configSchema = schema.object({
|
||||||
|
|
||||||
export type AlertingConfig = TypeOf<typeof configSchema>;
|
export type AlertingConfig = TypeOf<typeof configSchema>;
|
||||||
export type RulesConfig = TypeOf<typeof rulesSchema>;
|
export type RulesConfig = TypeOf<typeof rulesSchema>;
|
||||||
export type AlertingRulesConfig = Pick<AlertingConfig['rules'], 'minimumScheduleInterval'> & {
|
export type AlertingRulesConfig = Pick<
|
||||||
|
AlertingConfig['rules'],
|
||||||
|
'minimumScheduleInterval' | 'maxScheduledPerMinute'
|
||||||
|
> & {
|
||||||
isUsingSecurity: boolean;
|
isUsingSecurity: boolean;
|
||||||
};
|
};
|
||||||
export type ActionsConfig = RulesConfig['run']['actions'];
|
export type ActionsConfig = RulesConfig['run']['actions'];
|
||||||
|
|
|
@ -139,6 +139,7 @@ describe('Alerting Plugin', () => {
|
||||||
await waitForSetupComplete(setupMocks);
|
await waitForSetupComplete(setupMocks);
|
||||||
|
|
||||||
expect(setupContract.getConfig()).toEqual({
|
expect(setupContract.getConfig()).toEqual({
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
isUsingSecurity: false,
|
isUsingSecurity: false,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
});
|
});
|
||||||
|
|
|
@ -415,7 +415,7 @@ export class AlertingPlugin {
|
||||||
},
|
},
|
||||||
getConfig: () => {
|
getConfig: () => {
|
||||||
return {
|
return {
|
||||||
...pick(this.config.rules, 'minimumScheduleInterval'),
|
...pick(this.config.rules, ['minimumScheduleInterval', 'maxScheduledPerMinute']),
|
||||||
isUsingSecurity: this.licenseState ? !!this.licenseState.getIsSecurityEnabled() : false,
|
isUsingSecurity: this.licenseState ? !!this.licenseState.getIsSecurityEnabled() : false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -481,6 +481,7 @@ export class AlertingPlugin {
|
||||||
taskManager: plugins.taskManager,
|
taskManager: plugins.taskManager,
|
||||||
securityPluginSetup: security,
|
securityPluginSetup: security,
|
||||||
securityPluginStart: plugins.security,
|
securityPluginStart: plugins.security,
|
||||||
|
internalSavedObjectsRepository: core.savedObjects.createInternalRepository(['alert']),
|
||||||
encryptedSavedObjectsClient,
|
encryptedSavedObjectsClient,
|
||||||
spaceIdToNamespace,
|
spaceIdToNamespace,
|
||||||
getSpaceId(request: KibanaRequest) {
|
getSpaceId(request: KibanaRequest) {
|
||||||
|
@ -492,6 +493,7 @@ export class AlertingPlugin {
|
||||||
authorization: alertingAuthorizationClientFactory,
|
authorization: alertingAuthorizationClientFactory,
|
||||||
eventLogger: this.eventLogger,
|
eventLogger: this.eventLogger,
|
||||||
minimumScheduleInterval: this.config.rules.minimumScheduleInterval,
|
minimumScheduleInterval: this.config.rules.minimumScheduleInterval,
|
||||||
|
maxScheduledPerMinute: this.config.rules.maxScheduledPerMinute,
|
||||||
});
|
});
|
||||||
|
|
||||||
rulesSettingsClientFactory.initialize({
|
rulesSettingsClientFactory.initialize({
|
||||||
|
|
|
@ -47,6 +47,7 @@ import { cloneRuleRoute } from './clone_rule';
|
||||||
import { getFlappingSettingsRoute } from './get_flapping_settings';
|
import { getFlappingSettingsRoute } from './get_flapping_settings';
|
||||||
import { updateFlappingSettingsRoute } from './update_flapping_settings';
|
import { updateFlappingSettingsRoute } from './update_flapping_settings';
|
||||||
import { getRuleTagsRoute } from './get_rule_tags';
|
import { getRuleTagsRoute } from './get_rule_tags';
|
||||||
|
import { getScheduleFrequencyRoute } from './rule/apis/get_schedule_frequency';
|
||||||
|
|
||||||
import { createMaintenanceWindowRoute } from './maintenance_window/create_maintenance_window';
|
import { createMaintenanceWindowRoute } from './maintenance_window/create_maintenance_window';
|
||||||
import { getMaintenanceWindowRoute } from './maintenance_window/get_maintenance_window';
|
import { getMaintenanceWindowRoute } from './maintenance_window/get_maintenance_window';
|
||||||
|
@ -129,4 +130,5 @@ export function defineRoutes(opts: RouteOptions) {
|
||||||
registerRulesValueSuggestionsRoute(router, licenseState, config$!);
|
registerRulesValueSuggestionsRoute(router, licenseState, config$!);
|
||||||
registerFieldsRoute(router, licenseState);
|
registerFieldsRoute(router, licenseState);
|
||||||
bulkGetMaintenanceWindowRoute(router, licenseState);
|
bulkGetMaintenanceWindowRoute(router, licenseState);
|
||||||
|
getScheduleFrequencyRoute(router, licenseState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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 { getScheduleFrequencyRoute } from './get_schedule_frequency_route';
|
||||||
|
import { httpServiceMock } from '@kbn/core/server/mocks';
|
||||||
|
import { licenseStateMock } from '../../../../lib/license_state.mock';
|
||||||
|
import { mockHandlerArguments } from '../../../_mock_handler_arguments';
|
||||||
|
import { rulesClientMock } from '../../../../rules_client.mock';
|
||||||
|
|
||||||
|
const rulesClient = rulesClientMock.create();
|
||||||
|
|
||||||
|
jest.mock('../../../../lib/license_api_access', () => ({
|
||||||
|
verifyApiAccess: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getScheduleFrequencyRoute', () => {
|
||||||
|
it('gets the schedule frequency limit and remaining allotment', async () => {
|
||||||
|
const licenseState = licenseStateMock.create();
|
||||||
|
const router = httpServiceMock.createRouter();
|
||||||
|
|
||||||
|
getScheduleFrequencyRoute(router, licenseState);
|
||||||
|
|
||||||
|
const [config, handler] = router.get.mock.calls[0];
|
||||||
|
|
||||||
|
expect(config.path).toBe('/internal/alerting/rules/_schedule_frequency');
|
||||||
|
|
||||||
|
expect(config).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"path": "/internal/alerting/rules/_schedule_frequency",
|
||||||
|
"validate": Object {},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
rulesClient.getScheduleFrequency.mockResolvedValueOnce({
|
||||||
|
totalScheduledPerMinute: 9000,
|
||||||
|
remainingSchedulesPerMinute: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']);
|
||||||
|
|
||||||
|
await handler(context, req, res);
|
||||||
|
|
||||||
|
expect(rulesClient.getScheduleFrequency).toHaveBeenCalledTimes(1);
|
||||||
|
expect(res.ok).toHaveBeenCalledWith({
|
||||||
|
body: {
|
||||||
|
total_scheduled_per_minute: 9000,
|
||||||
|
remaining_schedules_per_minute: 1000,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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 { IRouter } from '@kbn/core/server';
|
||||||
|
import { ILicenseState } from '../../../../lib';
|
||||||
|
import { verifyAccessAndContext } from '../../../lib';
|
||||||
|
import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../../../../types';
|
||||||
|
import { GetScheduleFrequencyResponseV1 } from '../../../../../common/routes/rule/apis/get_schedule_frequency';
|
||||||
|
import { transformGetScheduleFrequencyResultV1 } from './transforms';
|
||||||
|
|
||||||
|
export const getScheduleFrequencyRoute = (
|
||||||
|
router: IRouter<AlertingRequestHandlerContext>,
|
||||||
|
licenseState: ILicenseState
|
||||||
|
) => {
|
||||||
|
router.get(
|
||||||
|
{
|
||||||
|
path: `${INTERNAL_BASE_ALERTING_API_PATH}/rules/_schedule_frequency`,
|
||||||
|
validate: {},
|
||||||
|
},
|
||||||
|
router.handleLegacyErrors(
|
||||||
|
verifyAccessAndContext(licenseState, async (context, req, res) => {
|
||||||
|
const rulesClient = (await context.alerting).getRulesClient();
|
||||||
|
|
||||||
|
const scheduleFrequencyResult = await rulesClient.getScheduleFrequency();
|
||||||
|
|
||||||
|
const response: GetScheduleFrequencyResponseV1 = {
|
||||||
|
body: transformGetScheduleFrequencyResultV1(scheduleFrequencyResult),
|
||||||
|
};
|
||||||
|
|
||||||
|
return res.ok(response);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { getScheduleFrequencyRoute } from './get_schedule_frequency_route';
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { transformGetScheduleFrequencyResult } from './transform_get_schedule_frequency_result/latest';
|
||||||
|
|
||||||
|
export { transformGetScheduleFrequencyResult as transformGetScheduleFrequencyResultV1 } from './transform_get_schedule_frequency_result/v1';
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './v1';
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* 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 type { GetScheduleFrequencyResponseBodyV1 } from '../../../../../../../common/routes/rule/apis/get_schedule_frequency';
|
||||||
|
import type { GetScheduleFrequencyResult } from '../../../../../../application/rule/methods/get_schedule_frequency';
|
||||||
|
|
||||||
|
export const transformGetScheduleFrequencyResult = (
|
||||||
|
result: GetScheduleFrequencyResult
|
||||||
|
): GetScheduleFrequencyResponseBodyV1 => {
|
||||||
|
return {
|
||||||
|
total_scheduled_per_minute: result.totalScheduledPerMinute,
|
||||||
|
remaining_schedules_per_minute: result.remainingSchedulesPerMinute,
|
||||||
|
};
|
||||||
|
};
|
|
@ -52,6 +52,7 @@ const createRulesClientMock = () => {
|
||||||
runSoon: jest.fn(),
|
runSoon: jest.fn(),
|
||||||
clone: jest.fn(),
|
clone: jest.fn(),
|
||||||
getAlertFromRaw: jest.fn(),
|
getAlertFromRaw: jest.fn(),
|
||||||
|
getScheduleFrequency: jest.fn(),
|
||||||
};
|
};
|
||||||
return mocked;
|
return mocked;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,11 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.0.0';
|
const kibanaVersion = 'v8.0.0';
|
||||||
const rulesClientParams: jest.Mocked<RulesClientContext> = {
|
const rulesClientParams: jest.Mocked<RulesClientContext> = {
|
||||||
|
@ -36,10 +41,12 @@ const rulesClientParams: jest.Mocked<RulesClientContext> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
minimumScheduleIntervalInMs: 1,
|
minimumScheduleIntervalInMs: 1,
|
||||||
fieldsToExcludeFromPublicApi: [],
|
fieldsToExcludeFromPublicApi: [],
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import pMap from 'p-map';
|
import pMap from 'p-map';
|
||||||
import { KueryNode, nodeBuilder } from '@kbn/es-query';
|
import { KueryNode, nodeBuilder } from '@kbn/es-query';
|
||||||
import { SavedObjectsBulkUpdateObject } from '@kbn/core/server';
|
import { SavedObjectsBulkUpdateObject, SavedObjectsFindResult } from '@kbn/core/server';
|
||||||
import { withSpan } from '@kbn/apm-utils';
|
import { withSpan } from '@kbn/apm-utils';
|
||||||
import { Logger } from '@kbn/core/server';
|
import { Logger } from '@kbn/core/server';
|
||||||
import { TaskManagerStartContract, TaskStatus } from '@kbn/task-manager-plugin/server';
|
import { TaskManagerStartContract, TaskStatus } from '@kbn/task-manager-plugin/server';
|
||||||
|
@ -28,6 +29,7 @@ import {
|
||||||
migrateLegacyActions,
|
migrateLegacyActions,
|
||||||
} from '../lib';
|
} from '../lib';
|
||||||
import { RulesClientContext, BulkOperationError, BulkOptions } from '../types';
|
import { RulesClientContext, BulkOperationError, BulkOptions } from '../types';
|
||||||
|
import { validateScheduleLimit } from '../../application/rule/methods/get_schedule_frequency';
|
||||||
|
|
||||||
const getShouldScheduleTask = async (
|
const getShouldScheduleTask = async (
|
||||||
context: RulesClientContext,
|
context: RulesClientContext,
|
||||||
|
@ -121,116 +123,136 @@ const bulkEnableRulesWithOCC = async (
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const rulesFinderRules: Array<SavedObjectsFindResult<RawRule>> = [];
|
||||||
const rulesToEnable: Array<SavedObjectsBulkUpdateObject<RawRule>> = [];
|
const rulesToEnable: Array<SavedObjectsBulkUpdateObject<RawRule>> = [];
|
||||||
const errors: BulkOperationError[] = [];
|
const errors: BulkOperationError[] = [];
|
||||||
const ruleNameToRuleIdMapping: Record<string, string> = {};
|
const ruleNameToRuleIdMapping: Record<string, string> = {};
|
||||||
const username = await context.getUserName();
|
const username = await context.getUserName();
|
||||||
|
let scheduleValidationError = '';
|
||||||
|
|
||||||
await withSpan(
|
await withSpan(
|
||||||
{ name: 'Get rules, collect them and their attributes', type: 'rules' },
|
{ name: 'Get rules, collect them and their attributes', type: 'rules' },
|
||||||
async () => {
|
async () => {
|
||||||
for await (const response of rulesFinder.find()) {
|
for await (const response of rulesFinder.find()) {
|
||||||
await pMap(response.saved_objects, async (rule) => {
|
rulesFinderRules.push(...response.saved_objects);
|
||||||
try {
|
|
||||||
if (rule.attributes.actions.length) {
|
|
||||||
try {
|
|
||||||
await context.actionsAuthorization.ensureAuthorized({ operation: 'execute' });
|
|
||||||
} catch (error) {
|
|
||||||
throw Error(`Rule not authorized for bulk enable - ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rule.attributes.name) {
|
|
||||||
ruleNameToRuleIdMapping[rule.id] = rule.attributes.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const migratedActions = await migrateLegacyActions(context, {
|
|
||||||
ruleId: rule.id,
|
|
||||||
actions: rule.attributes.actions,
|
|
||||||
references: rule.references,
|
|
||||||
attributes: rule.attributes,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedAttributes = updateMeta(context, {
|
|
||||||
...rule.attributes,
|
|
||||||
...(!rule.attributes.apiKey &&
|
|
||||||
(await createNewAPIKeySet(context, {
|
|
||||||
id: rule.attributes.alertTypeId,
|
|
||||||
ruleName: rule.attributes.name,
|
|
||||||
username,
|
|
||||||
shouldUpdateApiKey: true,
|
|
||||||
}))),
|
|
||||||
...(migratedActions.hasLegacyActions
|
|
||||||
? {
|
|
||||||
actions: migratedActions.resultedActions,
|
|
||||||
throttle: undefined,
|
|
||||||
notifyWhen: undefined,
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
enabled: true,
|
|
||||||
updatedBy: username,
|
|
||||||
updatedAt: new Date().toISOString(),
|
|
||||||
executionStatus: {
|
|
||||||
status: 'pending',
|
|
||||||
lastDuration: 0,
|
|
||||||
lastExecutionDate: new Date().toISOString(),
|
|
||||||
error: null,
|
|
||||||
warning: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const shouldScheduleTask = await getShouldScheduleTask(
|
|
||||||
context,
|
|
||||||
rule.attributes.scheduledTaskId
|
|
||||||
);
|
|
||||||
|
|
||||||
let scheduledTaskId;
|
|
||||||
if (shouldScheduleTask) {
|
|
||||||
const scheduledTask = await scheduleTask(context, {
|
|
||||||
id: rule.id,
|
|
||||||
consumer: rule.attributes.consumer,
|
|
||||||
ruleTypeId: rule.attributes.alertTypeId,
|
|
||||||
schedule: rule.attributes.schedule as IntervalSchedule,
|
|
||||||
throwOnConflict: false,
|
|
||||||
});
|
|
||||||
scheduledTaskId = scheduledTask.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
rulesToEnable.push({
|
|
||||||
...rule,
|
|
||||||
attributes: {
|
|
||||||
...updatedAttributes,
|
|
||||||
...(scheduledTaskId ? { scheduledTaskId } : undefined),
|
|
||||||
},
|
|
||||||
...(migratedActions.hasLegacyActions
|
|
||||||
? { references: migratedActions.resultedReferences }
|
|
||||||
: {}),
|
|
||||||
});
|
|
||||||
|
|
||||||
context.auditLogger?.log(
|
|
||||||
ruleAuditEvent({
|
|
||||||
action: RuleAuditAction.ENABLE,
|
|
||||||
outcome: 'unknown',
|
|
||||||
savedObject: { type: 'alert', id: rule.id },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
errors.push({
|
|
||||||
message: error.message,
|
|
||||||
rule: {
|
|
||||||
id: rule.id,
|
|
||||||
name: rule.attributes?.name,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
context.auditLogger?.log(
|
|
||||||
ruleAuditEvent({
|
|
||||||
action: RuleAuditAction.ENABLE,
|
|
||||||
error,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
await rulesFinder.close();
|
await rulesFinder.close();
|
||||||
|
|
||||||
|
const updatedInterval = rulesFinderRules
|
||||||
|
.filter((rule) => !rule.attributes.enabled)
|
||||||
|
.map((rule) => rule.attributes.schedule?.interval);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
updatedInterval,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
scheduleValidationError = `Error validating enable rule data - ${error.message}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await pMap(rulesFinderRules, async (rule) => {
|
||||||
|
try {
|
||||||
|
if (scheduleValidationError) {
|
||||||
|
throw Error(scheduleValidationError);
|
||||||
|
}
|
||||||
|
if (rule.attributes.actions.length) {
|
||||||
|
try {
|
||||||
|
await context.actionsAuthorization.ensureAuthorized({ operation: 'execute' });
|
||||||
|
} catch (error) {
|
||||||
|
throw Error(`Rule not authorized for bulk enable - ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rule.attributes.name) {
|
||||||
|
ruleNameToRuleIdMapping[rule.id] = rule.attributes.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const migratedActions = await migrateLegacyActions(context, {
|
||||||
|
ruleId: rule.id,
|
||||||
|
actions: rule.attributes.actions,
|
||||||
|
references: rule.references,
|
||||||
|
attributes: rule.attributes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedAttributes = updateMeta(context, {
|
||||||
|
...rule.attributes,
|
||||||
|
...(!rule.attributes.apiKey &&
|
||||||
|
(await createNewAPIKeySet(context, {
|
||||||
|
id: rule.attributes.alertTypeId,
|
||||||
|
ruleName: rule.attributes.name,
|
||||||
|
username,
|
||||||
|
shouldUpdateApiKey: true,
|
||||||
|
}))),
|
||||||
|
...(migratedActions.hasLegacyActions
|
||||||
|
? {
|
||||||
|
actions: migratedActions.resultedActions,
|
||||||
|
throttle: undefined,
|
||||||
|
notifyWhen: undefined,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
enabled: true,
|
||||||
|
updatedBy: username,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
executionStatus: {
|
||||||
|
status: 'pending',
|
||||||
|
lastDuration: 0,
|
||||||
|
lastExecutionDate: new Date().toISOString(),
|
||||||
|
error: null,
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldScheduleTask = await getShouldScheduleTask(
|
||||||
|
context,
|
||||||
|
rule.attributes.scheduledTaskId
|
||||||
|
);
|
||||||
|
|
||||||
|
let scheduledTaskId;
|
||||||
|
if (shouldScheduleTask) {
|
||||||
|
const scheduledTask = await scheduleTask(context, {
|
||||||
|
id: rule.id,
|
||||||
|
consumer: rule.attributes.consumer,
|
||||||
|
ruleTypeId: rule.attributes.alertTypeId,
|
||||||
|
schedule: rule.attributes.schedule as IntervalSchedule,
|
||||||
|
throwOnConflict: false,
|
||||||
|
});
|
||||||
|
scheduledTaskId = scheduledTask.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesToEnable.push({
|
||||||
|
...rule,
|
||||||
|
attributes: {
|
||||||
|
...updatedAttributes,
|
||||||
|
...(scheduledTaskId ? { scheduledTaskId } : undefined),
|
||||||
|
},
|
||||||
|
...(migratedActions.hasLegacyActions
|
||||||
|
? { references: migratedActions.resultedReferences }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
context.auditLogger?.log(
|
||||||
|
ruleAuditEvent({
|
||||||
|
action: RuleAuditAction.ENABLE,
|
||||||
|
outcome: 'unknown',
|
||||||
|
savedObject: { type: 'alert', id: rule.id },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
errors.push({
|
||||||
|
message: error.message,
|
||||||
|
rule: {
|
||||||
|
id: rule.id,
|
||||||
|
name: rule.attributes?.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
context.auditLogger?.log(
|
||||||
|
ruleAuditEvent({
|
||||||
|
action: RuleAuditAction.ENABLE,
|
||||||
|
error,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
import Boom from '@hapi/boom';
|
||||||
import type { SavedObjectReference } from '@kbn/core/server';
|
import type { SavedObjectReference } from '@kbn/core/server';
|
||||||
import { TaskStatus } from '@kbn/task-manager-plugin/server';
|
import { TaskStatus } from '@kbn/task-manager-plugin/server';
|
||||||
import { RawRule, IntervalSchedule } from '../../types';
|
import { RawRule, IntervalSchedule } from '../../types';
|
||||||
|
@ -13,6 +14,7 @@ import { retryIfConflicts } from '../../lib/retry_if_conflicts';
|
||||||
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
|
import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events';
|
||||||
import { RulesClientContext } from '../types';
|
import { RulesClientContext } from '../types';
|
||||||
import { updateMeta, createNewAPIKeySet, scheduleTask, migrateLegacyActions } from '../lib';
|
import { updateMeta, createNewAPIKeySet, scheduleTask, migrateLegacyActions } from '../lib';
|
||||||
|
import { validateScheduleLimit } from '../../application/rule/methods/get_schedule_frequency';
|
||||||
|
|
||||||
export async function enable(context: RulesClientContext, { id }: { id: string }): Promise<void> {
|
export async function enable(context: RulesClientContext, { id }: { id: string }): Promise<void> {
|
||||||
return await retryIfConflicts(
|
return await retryIfConflicts(
|
||||||
|
@ -46,6 +48,15 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string }
|
||||||
references = alert.references;
|
references = alert.references;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
updatedInterval: attributes.schedule.interval,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw Boom.badRequest(`Error validating enable rule data - ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await context.authorization.ensureAuthorized({
|
await context.authorization.ensureAuthorized({
|
||||||
ruleTypeId: attributes.alertTypeId,
|
ruleTypeId: attributes.alertTypeId,
|
||||||
|
|
|
@ -33,6 +33,7 @@ import {
|
||||||
createNewAPIKeySet,
|
createNewAPIKeySet,
|
||||||
migrateLegacyActions,
|
migrateLegacyActions,
|
||||||
} from '../lib';
|
} from '../lib';
|
||||||
|
import { validateScheduleLimit } from '../../application/rule/methods/get_schedule_frequency';
|
||||||
|
|
||||||
type ShouldIncrementRevision = (params?: RuleTypeParams) => boolean;
|
type ShouldIncrementRevision = (params?: RuleTypeParams) => boolean;
|
||||||
|
|
||||||
|
@ -88,6 +89,21 @@ async function updateWithOCC<Params extends RuleTypeParams>(
|
||||||
alertSavedObject = await context.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
alertSavedObject = await context.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
attributes: { enabled, schedule },
|
||||||
|
} = alertSavedObject;
|
||||||
|
try {
|
||||||
|
if (enabled && schedule.interval !== data.schedule.interval) {
|
||||||
|
await validateScheduleLimit({
|
||||||
|
context,
|
||||||
|
prevInterval: alertSavedObject.attributes.schedule?.interval,
|
||||||
|
updatedInterval: data.schedule.interval,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw Boom.badRequest(`Error validating update data - ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await context.authorization.ensureAuthorized({
|
await context.authorization.ensureAuthorized({
|
||||||
ruleTypeId: alertSavedObject.attributes.alertTypeId,
|
ruleTypeId: alertSavedObject.attributes.alertTypeId,
|
||||||
|
|
|
@ -57,6 +57,7 @@ import { runSoon } from './methods/run_soon';
|
||||||
import { listRuleTypes } from './methods/list_rule_types';
|
import { listRuleTypes } from './methods/list_rule_types';
|
||||||
import { getAlertFromRaw, GetAlertFromRawParams } from './lib/get_alert_from_raw';
|
import { getAlertFromRaw, GetAlertFromRawParams } from './lib/get_alert_from_raw';
|
||||||
import { getTags, GetTagsParams } from './methods/get_tags';
|
import { getTags, GetTagsParams } from './methods/get_tags';
|
||||||
|
import { getScheduleFrequency } from '../application/rule/methods/get_schedule_frequency/get_schedule_frequency';
|
||||||
|
|
||||||
export type ConstructorOptions = Omit<
|
export type ConstructorOptions = Omit<
|
||||||
RulesClientContext,
|
RulesClientContext,
|
||||||
|
@ -179,6 +180,8 @@ export class RulesClient {
|
||||||
|
|
||||||
public getTags = (params: GetTagsParams) => getTags(this.context, params);
|
public getTags = (params: GetTagsParams) => getTags(this.context, params);
|
||||||
|
|
||||||
|
public getScheduleFrequency = () => getScheduleFrequency(this.context);
|
||||||
|
|
||||||
public getAlertFromRaw = (params: GetAlertFromRawParams) =>
|
public getAlertFromRaw = (params: GetAlertFromRawParams) =>
|
||||||
getAlertFromRaw(
|
getAlertFromRaw(
|
||||||
this.context,
|
this.context,
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -32,12 +36,14 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
taskManager,
|
taskManager,
|
||||||
ruleTypeRegistry,
|
ruleTypeRegistry,
|
||||||
unsecuredSavedObjectsClient,
|
unsecuredSavedObjectsClient,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
authorization: authorization as unknown as AlertingAuthorization,
|
authorization: authorization as unknown as AlertingAuthorization,
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
|
@ -46,6 +52,7 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -53,6 +53,7 @@ const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
const logger = loggerMock.create();
|
const logger = loggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.2.0';
|
const kibanaVersion = 'v8.2.0';
|
||||||
const createAPIKeyMock = jest.fn();
|
const createAPIKeyMock = jest.fn();
|
||||||
|
@ -67,11 +68,13 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: createAPIKeyMock,
|
createAPIKey: createAPIKeyMock,
|
||||||
logger,
|
logger,
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import type { SavedObject } from '@kbn/core-saved-objects-server';
|
import type { SavedObject } from '@kbn/core-saved-objects-server';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
|
@ -61,6 +61,7 @@ const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
const logger = loggerMock.create();
|
const logger = loggerMock.create();
|
||||||
const eventLogger = eventLoggerMock.create();
|
const eventLogger = eventLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.2.0';
|
const kibanaVersion = 'v8.2.0';
|
||||||
const createAPIKeyMock = jest.fn();
|
const createAPIKeyMock = jest.fn();
|
||||||
|
@ -75,12 +76,14 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: createAPIKeyMock,
|
createAPIKey: createAPIKeyMock,
|
||||||
logger,
|
logger,
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
eventLogger,
|
eventLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -45,6 +45,10 @@ jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation
|
||||||
bulkMarkApiKeysForInvalidation: jest.fn(),
|
bulkMarkApiKeysForInvalidation: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../application/rule/methods/get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
|
@ -53,6 +57,7 @@ const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
const logger = loggerMock.create();
|
const logger = loggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v8.2.0';
|
const kibanaVersion = 'v8.2.0';
|
||||||
const createAPIKeyMock = jest.fn();
|
const createAPIKeyMock = jest.fn();
|
||||||
|
@ -67,11 +72,13 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: createAPIKeyMock,
|
createAPIKey: createAPIKeyMock,
|
||||||
logger,
|
logger,
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -40,6 +44,7 @@ const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
const eventLogger = eventLoggerMock.create();
|
const eventLogger = eventLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -50,10 +55,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -43,12 +47,14 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
taskManager,
|
taskManager,
|
||||||
ruleTypeRegistry,
|
ruleTypeRegistry,
|
||||||
unsecuredSavedObjectsClient,
|
unsecuredSavedObjectsClient,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
authorization: authorization as unknown as AlertingAuthorization,
|
authorization: authorization as unknown as AlertingAuthorization,
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
|
@ -57,6 +63,7 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -44,6 +48,7 @@ const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
const eventLogger = eventLoggerMock.create();
|
const eventLogger = eventLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -54,10 +59,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -31,6 +35,10 @@ jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation
|
||||||
bulkMarkApiKeysForInvalidation: jest.fn(),
|
bulkMarkApiKeysForInvalidation: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../application/rule/methods/get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
|
@ -38,6 +46,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -48,10 +57,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -36,6 +40,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -46,10 +51,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -33,6 +37,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -43,10 +48,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { GetActionErrorLogByIdParams } from '../methods/get_action_error_log';
|
import { GetActionErrorLogByIdParams } from '../methods/get_action_error_log';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { fromKueryExpression } from '@kbn/es-query';
|
import { fromKueryExpression } from '@kbn/es-query';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
|
@ -31,6 +35,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -41,10 +46,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -34,10 +39,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
import { omit, mean } from 'lodash';
|
import { omit, mean } from 'lodash';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -30,6 +34,7 @@ const eventLogClient = eventLogClientMock.create();
|
||||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -40,10 +45,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
|
|
||||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -32,6 +36,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -42,10 +47,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -27,12 +31,14 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
taskManager,
|
taskManager,
|
||||||
ruleTypeRegistry,
|
ruleTypeRegistry,
|
||||||
unsecuredSavedObjectsClient,
|
unsecuredSavedObjectsClient,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
authorization: authorization as unknown as AlertingAuthorization,
|
authorization: authorization as unknown as AlertingAuthorization,
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
|
@ -41,6 +47,7 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -28,6 +32,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -38,10 +43,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -34,10 +39,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -34,10 +39,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -33,6 +37,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -43,10 +48,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -25,6 +29,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -35,10 +40,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -34,10 +39,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -24,6 +28,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -34,10 +39,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -9,7 +9,11 @@ import { v4 as uuidv4 } from 'uuid';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { AlertConsumers } from '@kbn/rule-data-utils';
|
import { AlertConsumers } from '@kbn/rule-data-utils';
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -50,6 +54,10 @@ jest.mock('uuid', () => {
|
||||||
return { v4: () => `${uuid++}` };
|
return { v4: () => `${uuid++}` };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../../application/rule/methods/get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const bulkMarkApiKeysForInvalidationMock = bulkMarkApiKeysForInvalidation as jest.Mock;
|
const bulkMarkApiKeysForInvalidationMock = bulkMarkApiKeysForInvalidation as jest.Mock;
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
const ruleTypeRegistry = ruleTypeRegistryMock.create();
|
||||||
|
@ -58,6 +66,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -71,11 +80,13 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from '../rules_client';
|
import { RulesClient, ConstructorOptions } from '../rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../../rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock';
|
||||||
|
@ -30,6 +34,7 @@ const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
|
@ -40,10 +45,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization,
|
||||||
spaceId: 'default',
|
spaceId: 'default',
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
|
|
|
@ -6,7 +6,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { KueryNode } from '@kbn/es-query';
|
import { KueryNode } from '@kbn/es-query';
|
||||||
import { Logger, SavedObjectsClientContract, PluginInitializerContext } from '@kbn/core/server';
|
import {
|
||||||
|
Logger,
|
||||||
|
SavedObjectsClientContract,
|
||||||
|
PluginInitializerContext,
|
||||||
|
ISavedObjectsRepository,
|
||||||
|
} from '@kbn/core/server';
|
||||||
import { ActionsClient, ActionsAuthorization } from '@kbn/actions-plugin/server';
|
import { ActionsClient, ActionsAuthorization } from '@kbn/actions-plugin/server';
|
||||||
import {
|
import {
|
||||||
GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult,
|
GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult,
|
||||||
|
@ -55,11 +60,13 @@ export interface RulesClientContext {
|
||||||
readonly authorization: AlertingAuthorization;
|
readonly authorization: AlertingAuthorization;
|
||||||
readonly ruleTypeRegistry: RuleTypeRegistry;
|
readonly ruleTypeRegistry: RuleTypeRegistry;
|
||||||
readonly minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval'];
|
readonly minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval'];
|
||||||
|
readonly maxScheduledPerMinute: AlertingRulesConfig['maxScheduledPerMinute'];
|
||||||
readonly minimumScheduleIntervalInMs: number;
|
readonly minimumScheduleIntervalInMs: number;
|
||||||
readonly createAPIKey: (name: string) => Promise<CreateAPIKeyResult>;
|
readonly createAPIKey: (name: string) => Promise<CreateAPIKeyResult>;
|
||||||
readonly getActionsClient: () => Promise<ActionsClient>;
|
readonly getActionsClient: () => Promise<ActionsClient>;
|
||||||
readonly actionsAuthorization: ActionsAuthorization;
|
readonly actionsAuthorization: ActionsAuthorization;
|
||||||
readonly getEventLogClient: () => Promise<IEventLogClient>;
|
readonly getEventLogClient: () => Promise<IEventLogClient>;
|
||||||
|
readonly internalSavedObjectsRepository: ISavedObjectsRepository;
|
||||||
readonly encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
readonly encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||||
readonly kibanaVersion: PluginInitializerContext['env']['packageInfo']['version'];
|
readonly kibanaVersion: PluginInitializerContext['env']['packageInfo']['version'];
|
||||||
readonly auditLogger?: AuditLogger;
|
readonly auditLogger?: AuditLogger;
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
import { RulesClient, ConstructorOptions } from './rules_client';
|
import { RulesClient, ConstructorOptions } from './rules_client';
|
||||||
import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks';
|
import {
|
||||||
|
savedObjectsClientMock,
|
||||||
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
|
} from '@kbn/core/server/mocks';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
||||||
import { alertingAuthorizationMock } from './authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from './authorization/alerting_authorization.mock';
|
||||||
|
@ -21,6 +25,10 @@ import { RetryForConflictsAttempts } from './lib/retry_if_conflicts';
|
||||||
import { TaskStatus } from '@kbn/task-manager-plugin/server/task';
|
import { TaskStatus } from '@kbn/task-manager-plugin/server/task';
|
||||||
import { RecoveredActionGroup } from '../common';
|
import { RecoveredActionGroup } from '../common';
|
||||||
|
|
||||||
|
jest.mock('./application/rule/methods/get_schedule_frequency', () => ({
|
||||||
|
validateScheduleLimit: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
let rulesClient: RulesClient;
|
let rulesClient: RulesClient;
|
||||||
|
|
||||||
const MockAlertId = 'alert-id';
|
const MockAlertId = 'alert-id';
|
||||||
|
@ -34,6 +42,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
||||||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||||
const authorization = alertingAuthorizationMock.create();
|
const authorization = alertingAuthorizationMock.create();
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const kibanaVersion = 'v7.10.0';
|
const kibanaVersion = 'v7.10.0';
|
||||||
const logger = loggingSystemMock.create().get();
|
const logger = loggingSystemMock.create().get();
|
||||||
|
@ -48,10 +57,12 @@ const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
getUserName: jest.fn(),
|
getUserName: jest.fn(),
|
||||||
createAPIKey: jest.fn(),
|
createAPIKey: jest.fn(),
|
||||||
logger,
|
logger,
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjects,
|
encryptedSavedObjectsClient: encryptedSavedObjects,
|
||||||
getActionsClient: jest.fn(),
|
getActionsClient: jest.fn(),
|
||||||
getEventLogClient: jest.fn(),
|
getEventLogClient: jest.fn(),
|
||||||
kibanaVersion,
|
kibanaVersion,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: jest.fn(),
|
isAuthenticationTypeAPIKey: jest.fn(),
|
||||||
getAuthenticationAPIKey: jest.fn(),
|
getAuthenticationAPIKey: jest.fn(),
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
savedObjectsClientMock,
|
savedObjectsClientMock,
|
||||||
savedObjectsServiceMock,
|
savedObjectsServiceMock,
|
||||||
loggingSystemMock,
|
loggingSystemMock,
|
||||||
|
savedObjectsRepositoryMock,
|
||||||
} from '@kbn/core/server/mocks';
|
} from '@kbn/core/server/mocks';
|
||||||
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
|
||||||
import { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
import { AuthenticatedUser } from '@kbn/security-plugin/common/model';
|
||||||
|
@ -37,6 +38,7 @@ const securityPluginStart = securityMock.createStart();
|
||||||
|
|
||||||
const alertingAuthorization = alertingAuthorizationMock.create();
|
const alertingAuthorization = alertingAuthorizationMock.create();
|
||||||
const alertingAuthorizationClientFactory = alertingAuthorizationClientFactoryMock.createFactory();
|
const alertingAuthorizationClientFactory = alertingAuthorizationClientFactoryMock.createFactory();
|
||||||
|
const internalSavedObjectsRepository = savedObjectsRepositoryMock.create();
|
||||||
|
|
||||||
const rulesClientFactoryParams: jest.Mocked<RulesClientFactoryOpts> = {
|
const rulesClientFactoryParams: jest.Mocked<RulesClientFactoryOpts> = {
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
|
@ -44,7 +46,9 @@ const rulesClientFactoryParams: jest.Mocked<RulesClientFactoryOpts> = {
|
||||||
ruleTypeRegistry: ruleTypeRegistryMock.create(),
|
ruleTypeRegistry: ruleTypeRegistryMock.create(),
|
||||||
getSpaceId: jest.fn(),
|
getSpaceId: jest.fn(),
|
||||||
spaceIdToNamespace: jest.fn(),
|
spaceIdToNamespace: jest.fn(),
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
|
internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(),
|
encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(),
|
||||||
actions: actionsMock.createStart(),
|
actions: actionsMock.createStart(),
|
||||||
eventLog: eventLogMock.createStart(),
|
eventLog: eventLogMock.createStart(),
|
||||||
|
@ -101,8 +105,10 @@ test('creates a rules client with proper constructor arguments when security is
|
||||||
getActionsClient: expect.any(Function),
|
getActionsClient: expect.any(Function),
|
||||||
getEventLogClient: expect.any(Function),
|
getEventLogClient: expect.any(Function),
|
||||||
createAPIKey: expect.any(Function),
|
createAPIKey: expect.any(Function),
|
||||||
|
internalSavedObjectsRepository: rulesClientFactoryParams.internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: rulesClientFactoryParams.encryptedSavedObjectsClient,
|
encryptedSavedObjectsClient: rulesClientFactoryParams.encryptedSavedObjectsClient,
|
||||||
kibanaVersion: '7.10.0',
|
kibanaVersion: '7.10.0',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: expect.any(Function),
|
isAuthenticationTypeAPIKey: expect.any(Function),
|
||||||
getAuthenticationAPIKey: expect.any(Function),
|
getAuthenticationAPIKey: expect.any(Function),
|
||||||
|
@ -139,10 +145,12 @@ test('creates a rules client with proper constructor arguments', async () => {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
getUserName: expect.any(Function),
|
getUserName: expect.any(Function),
|
||||||
createAPIKey: expect.any(Function),
|
createAPIKey: expect.any(Function),
|
||||||
|
internalSavedObjectsRepository: rulesClientFactoryParams.internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: rulesClientFactoryParams.encryptedSavedObjectsClient,
|
encryptedSavedObjectsClient: rulesClientFactoryParams.encryptedSavedObjectsClient,
|
||||||
getActionsClient: expect.any(Function),
|
getActionsClient: expect.any(Function),
|
||||||
getEventLogClient: expect.any(Function),
|
getEventLogClient: expect.any(Function),
|
||||||
kibanaVersion: '7.10.0',
|
kibanaVersion: '7.10.0',
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
isAuthenticationTypeAPIKey: expect.any(Function),
|
isAuthenticationTypeAPIKey: expect.any(Function),
|
||||||
getAuthenticationAPIKey: expect.any(Function),
|
getAuthenticationAPIKey: expect.any(Function),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
Logger,
|
Logger,
|
||||||
SavedObjectsServiceStart,
|
SavedObjectsServiceStart,
|
||||||
PluginInitializerContext,
|
PluginInitializerContext,
|
||||||
|
ISavedObjectsRepository,
|
||||||
} from '@kbn/core/server';
|
} from '@kbn/core/server';
|
||||||
import { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server';
|
import { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server';
|
||||||
import {
|
import {
|
||||||
|
@ -34,12 +35,14 @@ export interface RulesClientFactoryOpts {
|
||||||
getSpaceId: (request: KibanaRequest) => string;
|
getSpaceId: (request: KibanaRequest) => string;
|
||||||
spaceIdToNamespace: SpaceIdToNamespaceFunction;
|
spaceIdToNamespace: SpaceIdToNamespaceFunction;
|
||||||
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
encryptedSavedObjectsClient: EncryptedSavedObjectsClient;
|
||||||
|
internalSavedObjectsRepository: ISavedObjectsRepository;
|
||||||
actions: ActionsPluginStartContract;
|
actions: ActionsPluginStartContract;
|
||||||
eventLog: IEventLogClientService;
|
eventLog: IEventLogClientService;
|
||||||
kibanaVersion: PluginInitializerContext['env']['packageInfo']['version'];
|
kibanaVersion: PluginInitializerContext['env']['packageInfo']['version'];
|
||||||
authorization: AlertingAuthorizationClientFactory;
|
authorization: AlertingAuthorizationClientFactory;
|
||||||
eventLogger?: IEventLogger;
|
eventLogger?: IEventLogger;
|
||||||
minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval'];
|
minimumScheduleInterval: AlertingRulesConfig['minimumScheduleInterval'];
|
||||||
|
maxScheduledPerMinute: AlertingRulesConfig['maxScheduledPerMinute'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RulesClientFactory {
|
export class RulesClientFactory {
|
||||||
|
@ -52,12 +55,14 @@ export class RulesClientFactory {
|
||||||
private getSpaceId!: (request: KibanaRequest) => string;
|
private getSpaceId!: (request: KibanaRequest) => string;
|
||||||
private spaceIdToNamespace!: SpaceIdToNamespaceFunction;
|
private spaceIdToNamespace!: SpaceIdToNamespaceFunction;
|
||||||
private encryptedSavedObjectsClient!: EncryptedSavedObjectsClient;
|
private encryptedSavedObjectsClient!: EncryptedSavedObjectsClient;
|
||||||
|
private internalSavedObjectsRepository!: ISavedObjectsRepository;
|
||||||
private actions!: ActionsPluginStartContract;
|
private actions!: ActionsPluginStartContract;
|
||||||
private eventLog!: IEventLogClientService;
|
private eventLog!: IEventLogClientService;
|
||||||
private kibanaVersion!: PluginInitializerContext['env']['packageInfo']['version'];
|
private kibanaVersion!: PluginInitializerContext['env']['packageInfo']['version'];
|
||||||
private authorization!: AlertingAuthorizationClientFactory;
|
private authorization!: AlertingAuthorizationClientFactory;
|
||||||
private eventLogger?: IEventLogger;
|
private eventLogger?: IEventLogger;
|
||||||
private minimumScheduleInterval!: AlertingRulesConfig['minimumScheduleInterval'];
|
private minimumScheduleInterval!: AlertingRulesConfig['minimumScheduleInterval'];
|
||||||
|
private maxScheduledPerMinute!: AlertingRulesConfig['maxScheduledPerMinute'];
|
||||||
|
|
||||||
public initialize(options: RulesClientFactoryOpts) {
|
public initialize(options: RulesClientFactoryOpts) {
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
|
@ -72,12 +77,14 @@ export class RulesClientFactory {
|
||||||
this.securityPluginStart = options.securityPluginStart;
|
this.securityPluginStart = options.securityPluginStart;
|
||||||
this.spaceIdToNamespace = options.spaceIdToNamespace;
|
this.spaceIdToNamespace = options.spaceIdToNamespace;
|
||||||
this.encryptedSavedObjectsClient = options.encryptedSavedObjectsClient;
|
this.encryptedSavedObjectsClient = options.encryptedSavedObjectsClient;
|
||||||
|
this.internalSavedObjectsRepository = options.internalSavedObjectsRepository;
|
||||||
this.actions = options.actions;
|
this.actions = options.actions;
|
||||||
this.eventLog = options.eventLog;
|
this.eventLog = options.eventLog;
|
||||||
this.kibanaVersion = options.kibanaVersion;
|
this.kibanaVersion = options.kibanaVersion;
|
||||||
this.authorization = options.authorization;
|
this.authorization = options.authorization;
|
||||||
this.eventLogger = options.eventLogger;
|
this.eventLogger = options.eventLogger;
|
||||||
this.minimumScheduleInterval = options.minimumScheduleInterval;
|
this.minimumScheduleInterval = options.minimumScheduleInterval;
|
||||||
|
this.maxScheduledPerMinute = options.maxScheduledPerMinute;
|
||||||
}
|
}
|
||||||
|
|
||||||
public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient {
|
public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient {
|
||||||
|
@ -95,6 +102,7 @@ export class RulesClientFactory {
|
||||||
taskManager: this.taskManager,
|
taskManager: this.taskManager,
|
||||||
ruleTypeRegistry: this.ruleTypeRegistry,
|
ruleTypeRegistry: this.ruleTypeRegistry,
|
||||||
minimumScheduleInterval: this.minimumScheduleInterval,
|
minimumScheduleInterval: this.minimumScheduleInterval,
|
||||||
|
maxScheduledPerMinute: this.maxScheduledPerMinute,
|
||||||
unsecuredSavedObjectsClient: savedObjects.getScopedClient(request, {
|
unsecuredSavedObjectsClient: savedObjects.getScopedClient(request, {
|
||||||
excludedExtensions: [SECURITY_EXTENSION_ID],
|
excludedExtensions: [SECURITY_EXTENSION_ID],
|
||||||
includedHiddenTypes: ['alert', 'api_key_pending_invalidation'],
|
includedHiddenTypes: ['alert', 'api_key_pending_invalidation'],
|
||||||
|
@ -102,6 +110,7 @@ export class RulesClientFactory {
|
||||||
authorization: this.authorization.create(request),
|
authorization: this.authorization.create(request),
|
||||||
actionsAuthorization: actions.getActionsAuthorizationWithRequest(request),
|
actionsAuthorization: actions.getActionsAuthorizationWithRequest(request),
|
||||||
namespace: this.spaceIdToNamespace(spaceId),
|
namespace: this.spaceIdToNamespace(spaceId),
|
||||||
|
internalSavedObjectsRepository: this.internalSavedObjectsRepository,
|
||||||
encryptedSavedObjectsClient: this.encryptedSavedObjectsClient,
|
encryptedSavedObjectsClient: this.encryptedSavedObjectsClient,
|
||||||
auditLogger: securityPluginSetup?.audit.asScoped(request),
|
auditLogger: securityPluginSetup?.audit.asScoped(request),
|
||||||
async getUserName() {
|
async getUserName() {
|
||||||
|
|
|
@ -60,6 +60,7 @@ export function generateAlertingConfig(): AlertingConfig {
|
||||||
maxEphemeralActionsPerAlert: 10,
|
maxEphemeralActionsPerAlert: 10,
|
||||||
cancelAlertsOnRuleTimeout: true,
|
cancelAlertsOnRuleTimeout: true,
|
||||||
rules: {
|
rules: {
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
run: {
|
run: {
|
||||||
actions: {
|
actions: {
|
||||||
|
|
|
@ -51,6 +51,7 @@ describe('createConfigRoute', () => {
|
||||||
baseRoute: `/internal/triggers_actions_ui`,
|
baseRoute: `/internal/triggers_actions_ui`,
|
||||||
alertingConfig: () => ({
|
alertingConfig: () => ({
|
||||||
isUsingSecurity: true,
|
isUsingSecurity: true,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
}),
|
}),
|
||||||
getRulesClientWithRequest: () => mockRulesClient,
|
getRulesClientWithRequest: () => mockRulesClient,
|
||||||
|
@ -64,7 +65,11 @@ describe('createConfigRoute', () => {
|
||||||
|
|
||||||
expect(mockResponse.ok).toBeCalled();
|
expect(mockResponse.ok).toBeCalled();
|
||||||
expect(mockResponse.ok.mock.calls[0][0]).toEqual({
|
expect(mockResponse.ok.mock.calls[0][0]).toEqual({
|
||||||
body: { isUsingSecurity: true, minimumScheduleInterval: { value: '1m', enforce: false } },
|
body: {
|
||||||
|
isUsingSecurity: true,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,6 +85,7 @@ describe('createConfigRoute', () => {
|
||||||
baseRoute: `/internal/triggers_actions_ui`,
|
baseRoute: `/internal/triggers_actions_ui`,
|
||||||
alertingConfig: () => ({
|
alertingConfig: () => ({
|
||||||
isUsingSecurity: true,
|
isUsingSecurity: true,
|
||||||
|
maxScheduledPerMinute: 10000,
|
||||||
minimumScheduleInterval: { value: '1m', enforce: false },
|
minimumScheduleInterval: { value: '1m', enforce: false },
|
||||||
}),
|
}),
|
||||||
getRulesClientWithRequest: () => mockRulesClient,
|
getRulesClientWithRequest: () => mockRulesClient,
|
||||||
|
|
|
@ -28,6 +28,7 @@ interface CreateTestConfigOptions {
|
||||||
reportName?: string;
|
reportName?: string;
|
||||||
useDedicatedTaskRunner: boolean;
|
useDedicatedTaskRunner: boolean;
|
||||||
enableFooterInEmail?: boolean;
|
enableFooterInEmail?: boolean;
|
||||||
|
maxScheduledPerMinute?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test.not-enabled is specifically not enabled
|
// test.not-enabled is specifically not enabled
|
||||||
|
@ -82,6 +83,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
||||||
reportName = undefined,
|
reportName = undefined,
|
||||||
useDedicatedTaskRunner,
|
useDedicatedTaskRunner,
|
||||||
enableFooterInEmail = true,
|
enableFooterInEmail = true,
|
||||||
|
maxScheduledPerMinute,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
return async ({ readConfigFile }: FtrConfigProviderContext) => {
|
return async ({ readConfigFile }: FtrConfigProviderContext) => {
|
||||||
|
@ -151,6 +153,11 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
||||||
? [`--xpack.actions.email.domain_allowlist=${JSON.stringify(emailDomainsAllowed)}`]
|
? [`--xpack.actions.email.domain_allowlist=${JSON.stringify(emailDomainsAllowed)}`]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
const maxScheduledPerMinuteSettings =
|
||||||
|
typeof maxScheduledPerMinute === 'number'
|
||||||
|
? [`--xpack.alerting.rules.maxScheduledPerMinute=${maxScheduledPerMinute}`]
|
||||||
|
: [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
testFiles: testFiles ? testFiles : [require.resolve(`../${name}/tests/`)],
|
testFiles: testFiles ? testFiles : [require.resolve(`../${name}/tests/`)],
|
||||||
servers,
|
servers,
|
||||||
|
@ -199,6 +206,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
|
||||||
...actionsProxyUrl,
|
...actionsProxyUrl,
|
||||||
...customHostSettings,
|
...customHostSettings,
|
||||||
...emailSettings,
|
...emailSettings,
|
||||||
|
...maxScheduledPerMinuteSettings,
|
||||||
'--xpack.eventLog.logEntries=true',
|
'--xpack.eventLog.logEntries=true',
|
||||||
'--xpack.task_manager.ephemeral_tasks.enabled=false',
|
'--xpack.task_manager.ephemeral_tasks.enabled=false',
|
||||||
`--xpack.task_manager.unsafe.exclude_task_types=${JSON.stringify([
|
`--xpack.task_manager.unsafe.exclude_task_types=${JSON.stringify([
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 { createTestConfig } from '../../common/config';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default createTestConfig('security_and_spaces', {
|
||||||
|
disabledPlugins: [],
|
||||||
|
license: 'trial',
|
||||||
|
ssl: true,
|
||||||
|
enableActionsProxy: true,
|
||||||
|
publicBaseUrl: true,
|
||||||
|
testFiles: [require.resolve('./tests/alerting/schedule_circuit_breaker')],
|
||||||
|
useDedicatedTaskRunner: true,
|
||||||
|
maxScheduledPerMinute: 10,
|
||||||
|
});
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* 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 expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function bulkEditWithCircuitBreakerTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('Bulk edit with circuit breaker', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being bulk edited if max schedules have been reached', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule3 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule3.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
ids: [createdRule2.id, createdRule3.id],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
operation: 'set',
|
||||||
|
field: 'schedule',
|
||||||
|
value: {
|
||||||
|
interval: '10s',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/_bulk_edit`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(payload)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.errors.length).eql(2);
|
||||||
|
expect(body.errors[0].message).eql(
|
||||||
|
'Failed to bulk edit rule - Run limit reached: The rule has 12 runs per minute; there are only 1 runs per minute available.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow disabled rules to go over the circuit breaker', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '20s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule3 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '20s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule3.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
ids: [createdRule2.id, createdRule3.id],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
operation: 'set',
|
||||||
|
field: 'schedule',
|
||||||
|
value: {
|
||||||
|
interval: '10s',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/internal/alerting/rules/_bulk_edit`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(payload)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.rules.length).eql(2);
|
||||||
|
expect(body.errors.length).eql(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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 expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function bulkEnableWithCircuitBreakerTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('Bulk enable with circuit breaker', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being bulk enabled if max schedules have been reached', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '20s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule3 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '10s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule3.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.patch(`${getUrlPrefix('space1')}/internal/alerting/rules/_bulk_enable`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send({ ids: [createdRule2.id, createdRule3.id] })
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(body.errors.length).eql(2);
|
||||||
|
expect(body.errors[0].message).eql(
|
||||||
|
'Error validating enable rule data - Run limit reached: The rule has 9 runs per minute; there are only 4 runs per minute available.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* 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 { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function createWithCircuitBreakerTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('Create with circuit breaker', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being created if max schedules have been reached', async () => {
|
||||||
|
const { body: createdRule } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being created across spaces', async () => {
|
||||||
|
const { body: createdRule } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space2')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow disabled rules to go over the circuit breaker', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '10s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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 expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function enableWithCircuitBreakerTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('Enable with circuit breaker', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being enabled if max schedules have been reached', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '10s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '5s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule/${createdRule2.id}/_enable`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.expect(400);
|
||||||
|
|
||||||
|
expect(body.message).eql(
|
||||||
|
'Error validating enable rule data - Run limit reached: The rule has 12 runs per minute; there are only 4 runs per minute available.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* 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 expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { UserAtSpaceScenarios } from '../../../../scenarios';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function getScheduleFrequencyTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const supertestWithoutAuth = getService('supertestWithoutAuth');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('getScheduleFrequency', () => {
|
||||||
|
before(async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '30s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '1m' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule3 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space2')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '2m' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space2', createdRule3.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule4 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space2')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '30s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space2', createdRule4.id, 'rule', 'alerting');
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const scenario of UserAtSpaceScenarios) {
|
||||||
|
const { user, space } = scenario;
|
||||||
|
|
||||||
|
describe(scenario.id, () => {
|
||||||
|
it('should get the total and remaining schedule frequency', async () => {
|
||||||
|
const { body } = await supertestWithoutAuth
|
||||||
|
.get(`${getUrlPrefix(space.id)}/internal/alerting/rules/_schedule_frequency`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send()
|
||||||
|
.auth(user.username, user.password);
|
||||||
|
|
||||||
|
switch (scenario.id) {
|
||||||
|
case 'no_kibana_privileges at space1':
|
||||||
|
case 'space_1_all at space2':
|
||||||
|
case 'global_read at space1':
|
||||||
|
case 'space_1_all_alerts_none_actions at space1':
|
||||||
|
case 'superuser at space1':
|
||||||
|
case 'space_1_all at space1':
|
||||||
|
case 'space_1_all_with_restricted_fixture at space1':
|
||||||
|
expect(body.total_scheduled_per_minute).eql(5.5);
|
||||||
|
expect(body.remaining_schedules_per_minute).eql(4.5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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 { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { setupSpacesAndUsers, tearDown } from '../../../../setup';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function alertingTests({ loadTestFile, getService }: FtrProviderContext) {
|
||||||
|
describe('Alerts - Group 3 - schedule circuit breaker', () => {
|
||||||
|
describe('alerts', () => {
|
||||||
|
before(async () => {
|
||||||
|
await setupSpacesAndUsers(getService);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await tearDown(getService);
|
||||||
|
});
|
||||||
|
|
||||||
|
loadTestFile(require.resolve('./get_schedule_frequency'));
|
||||||
|
loadTestFile(require.resolve('./create_with_circuit_breaker'));
|
||||||
|
loadTestFile(require.resolve('./update_with_circuit_breaker'));
|
||||||
|
loadTestFile(require.resolve('./enable_with_circuit_breaker'));
|
||||||
|
loadTestFile(require.resolve('./bulk_enable_with_circuit_breaker'));
|
||||||
|
loadTestFile(require.resolve('./bulk_edit_with_circuit_breaker'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* 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 expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
|
||||||
|
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../../common/lib';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default function updateWithCircuitBreakerTests({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const objectRemover = new ObjectRemover(supertest);
|
||||||
|
|
||||||
|
describe('Update with circuit breaker', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
await objectRemover.removeAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent rules from being updated if max schedules have been reached', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const updatedData = {
|
||||||
|
name: 'bcd',
|
||||||
|
tags: ['bar'],
|
||||||
|
params: {
|
||||||
|
foo: true,
|
||||||
|
},
|
||||||
|
schedule: { interval: '5s' },
|
||||||
|
actions: [],
|
||||||
|
throttle: '1m',
|
||||||
|
notify_when: 'onThrottleInterval',
|
||||||
|
};
|
||||||
|
|
||||||
|
const { body } = await supertest
|
||||||
|
.put(`${getUrlPrefix('space1')}/api/alerting/rule/${createdRule2.id}`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(updatedData)
|
||||||
|
.expect(400);
|
||||||
|
|
||||||
|
expect(body.message).eql(
|
||||||
|
'Error validating update data - Run limit reached: The rule has 12 runs per minute; there are only 7 runs per minute available.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow disabled rules to go over the circuit breaker', async () => {
|
||||||
|
const { body: createdRule1 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(getTestRuleData({ schedule: { interval: '20s' } }))
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule1.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const { body: createdRule2 } = await supertest
|
||||||
|
.post(`${getUrlPrefix('space1')}/api/alerting/rule`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(
|
||||||
|
getTestRuleData({
|
||||||
|
enabled: false,
|
||||||
|
schedule: { interval: '20s' },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.expect(200);
|
||||||
|
objectRemover.add('space1', createdRule2.id, 'rule', 'alerting');
|
||||||
|
|
||||||
|
const updatedData = {
|
||||||
|
name: 'bcd',
|
||||||
|
tags: ['bar'],
|
||||||
|
params: {
|
||||||
|
foo: true,
|
||||||
|
},
|
||||||
|
schedule: { interval: '5s' },
|
||||||
|
actions: [],
|
||||||
|
throttle: '1m',
|
||||||
|
notify_when: 'onThrottleInterval',
|
||||||
|
};
|
||||||
|
|
||||||
|
await supertest
|
||||||
|
.put(`${getUrlPrefix('space1')}/api/alerting/rule/${createdRule2.id}`)
|
||||||
|
.set('kbn-xsrf', 'foo')
|
||||||
|
.send(updatedData)
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue