mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[Alerting] Renaming AlertType to RuleType and updating Alerting Task Runner (#120661)
* Renaming AlertType to RuleType and updating Alerting Task Runner * Fixing types * Fixing types * holy cannoli * Fixing types * Fixing types and tests * Fixing types and tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f14540ff63
commit
7c27163d6a
82 changed files with 1163 additions and 1202 deletions
|
@ -15,7 +15,7 @@ Rules and connectors log to the Kibana logger with tags of [alerting] and [actio
|
||||||
|
|
||||||
[source, txt]
|
[source, txt]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
server log [11:39:40.389] [error][alerting][alerting][plugins][plugins] Executing Alert "5b6237b0-c6f6-11eb-b0ff-a1a0cbcf29b6" has resulted in Error: Saved object [action/fdbc8610-c6f5-11eb-b0ff-a1a0cbcf29b6] not found
|
server log [11:39:40.389] [error][alerting][alerting][plugins][plugins] Executing Rule "5b6237b0-c6f6-11eb-b0ff-a1a0cbcf29b6" has resulted in Error: Saved object [action/fdbc8610-c6f5-11eb-b0ff-a1a0cbcf29b6] not found
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
Some of the resources, such as saved objects and API keys, may no longer be available or valid, yielding error messages about those missing resources.
|
Some of the resources, such as saved objects and API keys, may no longer be available or valid, yielding error messages about those missing resources.
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ And see the errors for the rules you might provide the next search query:
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"message": "alert executed: .index-threshold:30d856c0-b14b-11eb-9a7c-9df284da9f99: 'test'",
|
"message": "rule executed: .index-threshold:30d856c0-b14b-11eb-9a7c-9df284da9f99: 'test'",
|
||||||
"error" : {
|
"error" : {
|
||||||
"message" : "Saved object [action/ef0e2530-b14a-11eb-9a7c-9df284da9f99] not found"
|
"message" : "Saved object [action/ef0e2530-b14a-11eb-9a7c-9df284da9f99] not found"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1020,7 +1020,7 @@ This log message tells us that when Task Manager was running one of our rules, i
|
||||||
|
|
||||||
For example, in this case, we’d expect to see a corresponding log line from the Alerting framework itself, saying that the rule failed. You should look in the Kibana log for a line similar to the log line below (probably shortly before the Task Manager log line):
|
For example, in this case, we’d expect to see a corresponding log line from the Alerting framework itself, saying that the rule failed. You should look in the Kibana log for a line similar to the log line below (probably shortly before the Task Manager log line):
|
||||||
|
|
||||||
Executing Alert "27559295-44e4-4983-aa1b-94fe043ab4f9" has resulted in Error: Unable to load resource ‘/api/something’
|
Executing Rule "27559295-44e4-4983-aa1b-94fe043ab4f9" has resulted in Error: Unable to load resource ‘/api/something’
|
||||||
|
|
||||||
This would confirm that the error did in fact happen in the rule itself (rather than the Task Manager) and it would help us pin-point the specific ID of the rule which failed: 27559295-44e4-4983-aa1b-94fe043ab4f9
|
This would confirm that the error did in fact happen in the rule itself (rather than the Task Manager) and it would help us pin-point the specific ID of the rule which failed: 27559295-44e4-4983-aa1b-94fe043ab4f9
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { isEmpty } from 'lodash';
|
||||||
import { ALERTING_EXAMPLE_APP_ID } from '../../common/constants';
|
import { ALERTING_EXAMPLE_APP_ID } from '../../common/constants';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
LEGACY_BASE_ALERT_API_PATH,
|
LEGACY_BASE_ALERT_API_PATH,
|
||||||
} from '../../../../plugins/alerting/common';
|
} from '../../../../plugins/alerting/common';
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ type Props = RouteComponentProps & {
|
||||||
};
|
};
|
||||||
export const ViewAlertPage = withRouter(({ http, id }: Props) => {
|
export const ViewAlertPage = withRouter(({ http, id }: Props) => {
|
||||||
const [alert, setAlert] = useState<Alert | null>(null);
|
const [alert, setAlert] = useState<Alert | null>(null);
|
||||||
const [alertState, setAlertState] = useState<AlertTaskState | null>(null);
|
const [alertState, setAlertState] = useState<RuleTaskState | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!alert) {
|
if (!alert) {
|
||||||
|
@ -42,7 +42,7 @@ export const ViewAlertPage = withRouter(({ http, id }: Props) => {
|
||||||
}
|
}
|
||||||
if (!alertState) {
|
if (!alertState) {
|
||||||
http
|
http
|
||||||
.get<AlertTaskState | null>(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`)
|
.get<RuleTaskState | null>(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`)
|
||||||
.then(setAlertState);
|
.then(setAlertState);
|
||||||
}
|
}
|
||||||
}, [alert, alertState, http, id]);
|
}, [alert, alertState, http, id]);
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { isEmpty } from 'lodash';
|
||||||
import { ALERTING_EXAMPLE_APP_ID, AlwaysFiringParams } from '../../common/constants';
|
import { ALERTING_EXAMPLE_APP_ID, AlwaysFiringParams } from '../../common/constants';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
LEGACY_BASE_ALERT_API_PATH,
|
LEGACY_BASE_ALERT_API_PATH,
|
||||||
} from '../../../../plugins/alerting/common';
|
} from '../../../../plugins/alerting/common';
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ function hasCraft(state: any): state is { craft: string } {
|
||||||
}
|
}
|
||||||
export const ViewPeopleInSpaceAlertPage = withRouter(({ http, id }: Props) => {
|
export const ViewPeopleInSpaceAlertPage = withRouter(({ http, id }: Props) => {
|
||||||
const [alert, setAlert] = useState<Alert<AlwaysFiringParams> | null>(null);
|
const [alert, setAlert] = useState<Alert<AlwaysFiringParams> | null>(null);
|
||||||
const [alertState, setAlertState] = useState<AlertTaskState | null>(null);
|
const [alertState, setAlertState] = useState<RuleTaskState | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!alert) {
|
if (!alert) {
|
||||||
|
@ -50,7 +50,7 @@ export const ViewPeopleInSpaceAlertPage = withRouter(({ http, id }: Props) => {
|
||||||
}
|
}
|
||||||
if (!alertState) {
|
if (!alertState) {
|
||||||
http
|
http
|
||||||
.get<AlertTaskState | null>(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`)
|
.get<RuleTaskState | null>(`${LEGACY_BASE_ALERT_API_PATH}/alert/${id}/state`)
|
||||||
.then(setAlertState);
|
.then(setAlertState);
|
||||||
}
|
}
|
||||||
}, [alert, alertState, http, id]);
|
}, [alert, alertState, http, id]);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
import { range } from 'lodash';
|
import { range } from 'lodash';
|
||||||
import { AlertType } from '../../../../plugins/alerting/server';
|
import { RuleType } from '../../../../plugins/alerting/server';
|
||||||
import {
|
import {
|
||||||
DEFAULT_INSTANCES_TO_GENERATE,
|
DEFAULT_INSTANCES_TO_GENERATE,
|
||||||
ALERTING_EXAMPLE_APP_ID,
|
ALERTING_EXAMPLE_APP_ID,
|
||||||
|
@ -37,7 +37,7 @@ function getTShirtSizeByIdAndThreshold(
|
||||||
return DEFAULT_ACTION_GROUP;
|
return DEFAULT_ACTION_GROUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const alertType: AlertType<
|
export const alertType: RuleType<
|
||||||
AlwaysFiringParams,
|
AlwaysFiringParams,
|
||||||
never,
|
never,
|
||||||
{ count?: number },
|
{ count?: number },
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { AlertType } from '../../../../plugins/alerting/server';
|
import { RuleType } from '../../../../plugins/alerting/server';
|
||||||
import { Operator, Craft, ALERTING_EXAMPLE_APP_ID } from '../../common/constants';
|
import { Operator, Craft, ALERTING_EXAMPLE_APP_ID } from '../../common/constants';
|
||||||
|
|
||||||
interface PeopleInSpace {
|
interface PeopleInSpace {
|
||||||
|
@ -39,7 +39,7 @@ function getCraftFilter(craft: string) {
|
||||||
craft === Craft.OuterSpace ? true : craft === person.craft;
|
craft === Craft.OuterSpace ? true : craft === person.craft;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const alertType: AlertType<
|
export const alertType: RuleType<
|
||||||
{ outerSpaceCapacity: number; craft: string; op: string },
|
{ outerSpaceCapacity: number; craft: string; op: string },
|
||||||
never,
|
never,
|
||||||
{ peopleInSpace: number },
|
{ peopleInSpace: number },
|
||||||
|
|
|
@ -230,7 +230,7 @@ interface MyRuleTypeAlertContext extends AlertInstanceContext {
|
||||||
|
|
||||||
type MyRuleTypeActionGroups = 'default' | 'warning';
|
type MyRuleTypeActionGroups = 'default' | 'warning';
|
||||||
|
|
||||||
const myRuleType: AlertType<
|
const myRuleType: RuleType<
|
||||||
MyRuleTypeParams,
|
MyRuleTypeParams,
|
||||||
MyRuleTypeExtractedParams,
|
MyRuleTypeExtractedParams,
|
||||||
MyRuleTypeState,
|
MyRuleTypeState,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { ActionGroup } from './alert_type';
|
import { ActionGroup } from './rule_type';
|
||||||
|
|
||||||
export type DefaultActionGroupId = 'default';
|
export type DefaultActionGroupId = 'default';
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
import { AlertsHealth } from './alert';
|
import { AlertsHealth } from './alert';
|
||||||
|
|
||||||
export * from './alert';
|
export * from './alert';
|
||||||
export * from './alert_type';
|
export * from './rule_type';
|
||||||
export * from './alert_instance';
|
export * from './alert_instance';
|
||||||
export * from './alert_task_instance';
|
export * from './rule_task_instance';
|
||||||
export * from './alert_navigation';
|
export * from './alert_navigation';
|
||||||
export * from './alert_summary';
|
export * from './alert_summary';
|
||||||
export * from './builtin_action_groups';
|
export * from './builtin_action_groups';
|
||||||
|
|
|
@ -9,15 +9,15 @@ import * as t from 'io-ts';
|
||||||
import { rawAlertInstance } from './alert_instance';
|
import { rawAlertInstance } from './alert_instance';
|
||||||
import { DateFromString } from './date_from_string';
|
import { DateFromString } from './date_from_string';
|
||||||
|
|
||||||
export const alertStateSchema = t.partial({
|
export const ruleStateSchema = t.partial({
|
||||||
alertTypeState: t.record(t.string, t.unknown),
|
alertTypeState: t.record(t.string, t.unknown),
|
||||||
alertInstances: t.record(t.string, rawAlertInstance),
|
alertInstances: t.record(t.string, rawAlertInstance),
|
||||||
previousStartedAt: t.union([t.null, DateFromString]),
|
previousStartedAt: t.union([t.null, DateFromString]),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AlertTaskState = t.TypeOf<typeof alertStateSchema>;
|
export type RuleTaskState = t.TypeOf<typeof ruleStateSchema>;
|
||||||
|
|
||||||
export const alertParamsSchema = t.intersection([
|
export const ruleParamsSchema = t.intersection([
|
||||||
t.type({
|
t.type({
|
||||||
alertId: t.string,
|
alertId: t.string,
|
||||||
}),
|
}),
|
||||||
|
@ -25,4 +25,4 @@ export const alertParamsSchema = t.intersection([
|
||||||
spaceId: t.string,
|
spaceId: t.string,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
export type AlertTaskParams = t.TypeOf<typeof alertParamsSchema>;
|
export type RuleTaskParams = t.TypeOf<typeof ruleParamsSchema>;
|
|
@ -8,7 +8,7 @@
|
||||||
import { LicenseType } from '../../licensing/common/types';
|
import { LicenseType } from '../../licensing/common/types';
|
||||||
import { RecoveredActionGroupId, DefaultActionGroupId } from './builtin_action_groups';
|
import { RecoveredActionGroupId, DefaultActionGroupId } from './builtin_action_groups';
|
||||||
|
|
||||||
export interface AlertType<
|
export interface RuleType<
|
||||||
ActionGroupIds extends Exclude<string, RecoveredActionGroupId> = DefaultActionGroupId,
|
ActionGroupIds extends Exclude<string, RecoveredActionGroupId> = DefaultActionGroupId,
|
||||||
RecoveryActionGroupId extends string = RecoveredActionGroupId
|
RecoveryActionGroupId extends string = RecoveredActionGroupId
|
||||||
> {
|
> {
|
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AlertType, RecoveredActionGroup } from '../common';
|
import { RuleType, RecoveredActionGroup } from '../common';
|
||||||
import { httpServiceMock } from '../../../../src/core/public/mocks';
|
import { httpServiceMock } from '../../../../src/core/public/mocks';
|
||||||
import { loadAlert, loadAlertType, loadAlertTypes } from './alert_api';
|
import { loadAlert, loadAlertType, loadAlertTypes } from './alert_api';
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
@ -16,7 +16,7 @@ beforeEach(() => jest.resetAllMocks());
|
||||||
|
|
||||||
describe('loadAlertTypes', () => {
|
describe('loadAlertTypes', () => {
|
||||||
test('should call get alert types API', async () => {
|
test('should call get alert types API', async () => {
|
||||||
const resolvedValue: AlertType[] = [
|
const resolvedValue: RuleType[] = [
|
||||||
{
|
{
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
|
@ -43,7 +43,7 @@ describe('loadAlertTypes', () => {
|
||||||
|
|
||||||
describe('loadAlertType', () => {
|
describe('loadAlertType', () => {
|
||||||
test('should call get alert types API', async () => {
|
test('should call get alert types API', async () => {
|
||||||
const alertType: AlertType = {
|
const alertType: RuleType = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionVariables: ['var1'],
|
actionVariables: ['var1'],
|
||||||
|
@ -66,7 +66,7 @@ describe('loadAlertType', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should find the required alertType', async () => {
|
test('should find the required alertType', async () => {
|
||||||
const alertType: AlertType = {
|
const alertType: RuleType = {
|
||||||
id: 'test-another',
|
id: 'test-another',
|
||||||
name: 'Test Another',
|
name: 'Test Another',
|
||||||
actionVariables: [],
|
actionVariables: [],
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
import { HttpSetup } from 'kibana/public';
|
import { HttpSetup } from 'kibana/public';
|
||||||
import { LEGACY_BASE_ALERT_API_PATH } from '../common';
|
import { LEGACY_BASE_ALERT_API_PATH } from '../common';
|
||||||
import type { Alert, AlertType } from '../common';
|
import type { Alert, RuleType } from '../common';
|
||||||
|
|
||||||
export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise<AlertType[]> {
|
export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise<RuleType[]> {
|
||||||
return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`);
|
return await http.get(`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,11 +18,11 @@ export async function loadAlertType({
|
||||||
id,
|
id,
|
||||||
}: {
|
}: {
|
||||||
http: HttpSetup;
|
http: HttpSetup;
|
||||||
id: AlertType['id'];
|
id: RuleType['id'];
|
||||||
}): Promise<AlertType | undefined> {
|
}): Promise<RuleType | undefined> {
|
||||||
const alertTypes = (await http.get(
|
const alertTypes = (await http.get(
|
||||||
`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`
|
`${LEGACY_BASE_ALERT_API_PATH}/list_alert_types`
|
||||||
)) as AlertType[];
|
)) as RuleType[];
|
||||||
return alertTypes.find((type) => type.id === id);
|
return alertTypes.find((type) => type.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AlertNavigationRegistry } from './alert_navigation_registry';
|
import { AlertNavigationRegistry } from './alert_navigation_registry';
|
||||||
import { AlertType, RecoveredActionGroup, SanitizedAlert } from '../../common';
|
import { RuleType, RecoveredActionGroup, SanitizedAlert } from '../../common';
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
|
||||||
beforeEach(() => jest.resetAllMocks());
|
beforeEach(() => jest.resetAllMocks());
|
||||||
|
|
||||||
const mockAlertType = (id: string): AlertType => ({
|
const mockAlertType = (id: string): RuleType => ({
|
||||||
id,
|
id,
|
||||||
name: id,
|
name: id,
|
||||||
actionGroups: [],
|
actionGroups: [],
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { AlertType } from '../../common';
|
import { RuleType } from '../../common';
|
||||||
import { AlertNavigationHandler } from './types';
|
import { AlertNavigationHandler } from './types';
|
||||||
|
|
||||||
const DEFAULT_HANDLER = Symbol('*');
|
const DEFAULT_HANDLER = Symbol('*');
|
||||||
|
@ -14,7 +14,7 @@ export class AlertNavigationRegistry {
|
||||||
private readonly alertNavigations: Map<string, Map<string | symbol, AlertNavigationHandler>> =
|
private readonly alertNavigations: Map<string, Map<string | symbol, AlertNavigationHandler>> =
|
||||||
new Map();
|
new Map();
|
||||||
|
|
||||||
public has(consumer: string, alertType: AlertType) {
|
public has(consumer: string, alertType: RuleType) {
|
||||||
return this.hasTypedHandler(consumer, alertType.id) || this.hasDefaultHandler(consumer);
|
return this.hasTypedHandler(consumer, alertType.id) || this.hasDefaultHandler(consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ export class AlertNavigationRegistry {
|
||||||
consumerNavigations.set(ruleTypeId, handler);
|
consumerNavigations.set(ruleTypeId, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(consumer: string, alertType: AlertType): AlertNavigationHandler {
|
public get(consumer: string, alertType: RuleType): AlertNavigationHandler {
|
||||||
if (this.has(consumer, alertType)) {
|
if (this.has(consumer, alertType)) {
|
||||||
const consumerHandlers = this.alertNavigations.get(consumer)!;
|
const consumerHandlers = this.alertNavigations.get(consumer)!;
|
||||||
return (consumerHandlers.get(alertType.id) ?? consumerHandlers.get(DEFAULT_HANDLER))!;
|
return (consumerHandlers.get(alertType.id) ?? consumerHandlers.get(DEFAULT_HANDLER))!;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISavedObjectsRepository, SavedObjectsServiceStart } from 'src/core/server';
|
import { ISavedObjectsRepository, SavedObjectsServiceStart } from 'src/core/server';
|
||||||
import { AlertsHealth, HealthStatus, RawAlert, AlertExecutionStatusErrorReasons } from '../types';
|
import { AlertsHealth, HealthStatus, RawRule, AlertExecutionStatusErrorReasons } from '../types';
|
||||||
|
|
||||||
export const getHealth = async (
|
export const getHealth = async (
|
||||||
internalSavedObjectsRepository: ISavedObjectsRepository
|
internalSavedObjectsRepository: ISavedObjectsRepository
|
||||||
|
@ -26,7 +26,7 @@ export const getHealth = async (
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const { saved_objects: decryptErrorData } = await internalSavedObjectsRepository.find<RawAlert>({
|
const { saved_objects: decryptErrorData } = await internalSavedObjectsRepository.find<RawRule>({
|
||||||
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Decrypt}`,
|
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Decrypt}`,
|
||||||
fields: ['executionStatus'],
|
fields: ['executionStatus'],
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
|
@ -44,7 +44,7 @@ export const getHealth = async (
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { saved_objects: executeErrorData } = await internalSavedObjectsRepository.find<RawAlert>({
|
const { saved_objects: executeErrorData } = await internalSavedObjectsRepository.find<RawRule>({
|
||||||
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Execute}`,
|
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Execute}`,
|
||||||
fields: ['executionStatus'],
|
fields: ['executionStatus'],
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
|
@ -62,7 +62,7 @@ export const getHealth = async (
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { saved_objects: readErrorData } = await internalSavedObjectsRepository.find<RawAlert>({
|
const { saved_objects: readErrorData } = await internalSavedObjectsRepository.find<RawRule>({
|
||||||
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Read}`,
|
filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Read}`,
|
||||||
fields: ['executionStatus'],
|
fields: ['executionStatus'],
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
|
@ -80,7 +80,7 @@ export const getHealth = async (
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { saved_objects: noErrorData } = await internalSavedObjectsRepository.find<RawAlert>({
|
const { saved_objects: noErrorData } = await internalSavedObjectsRepository.find<RawRule>({
|
||||||
filter: 'not alert.attributes.executionStatus.status:error',
|
filter: 'not alert.attributes.executionStatus.status:error',
|
||||||
fields: ['executionStatus'],
|
fields: ['executionStatus'],
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { AlertsConfigType } from './types';
|
||||||
export type RulesClient = PublicMethodsOf<RulesClientClass>;
|
export type RulesClient = PublicMethodsOf<RulesClientClass>;
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
AlertType,
|
RuleType,
|
||||||
ActionGroup,
|
ActionGroup,
|
||||||
ActionGroupIdsOf,
|
ActionGroupIdsOf,
|
||||||
AlertingPlugin,
|
AlertingPlugin,
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createAlertEventLogRecordObject } from './create_alert_event_log_record_object';
|
import { createAlertEventLogRecordObject } from './create_alert_event_log_record_object';
|
||||||
import { UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
import { RecoveredActionGroup } from '../types';
|
import { RecoveredActionGroup } from '../types';
|
||||||
|
|
||||||
describe('createAlertEventLogRecordObject', () => {
|
describe('createAlertEventLogRecordObject', () => {
|
||||||
const ruleType: jest.Mocked<UntypedNormalizedAlertType> = {
|
const ruleType: jest.Mocked<UntypedNormalizedRuleType> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'My test alert',
|
name: 'My test alert',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup],
|
actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup],
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
import { AlertInstanceState } from '../types';
|
import { AlertInstanceState } from '../types';
|
||||||
import { IEvent } from '../../../event_log/server';
|
import { IEvent } from '../../../event_log/server';
|
||||||
import { UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
|
|
||||||
export type Event = Exclude<IEvent, undefined>;
|
export type Event = Exclude<IEvent, undefined>;
|
||||||
|
|
||||||
interface CreateAlertEventLogRecordParams {
|
interface CreateAlertEventLogRecordParams {
|
||||||
ruleId: string;
|
ruleId: string;
|
||||||
ruleType: UntypedNormalizedAlertType;
|
ruleType: UntypedNormalizedRuleType;
|
||||||
action: string;
|
action: string;
|
||||||
ruleName?: string;
|
ruleName?: string;
|
||||||
instanceId?: string;
|
instanceId?: string;
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function getAlertTypeFeatureUsageName(alertTypeName: string) {
|
export function getRuleTypeFeatureUsageName(ruleTypeName: string) {
|
||||||
return `Alert: ${alertTypeName}`;
|
return `Rule: ${ruleTypeName}`;
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
export { parseDuration, validateDurationSchema } from '../../common/parse_duration';
|
export { parseDuration, validateDurationSchema } from '../../common/parse_duration';
|
||||||
export type { ILicenseState } from './license_state';
|
export type { ILicenseState } from './license_state';
|
||||||
export { LicenseState } from './license_state';
|
export { LicenseState } from './license_state';
|
||||||
export { validateAlertTypeParams } from './validate_alert_type_params';
|
export { validateRuleTypeParams } from './validate_rule_type_params';
|
||||||
export { getAlertNotifyWhenType } from './get_alert_notify_when_type';
|
export { getAlertNotifyWhenType } from './get_alert_notify_when_type';
|
||||||
export { verifyApiAccess } from './license_api_access';
|
export { verifyApiAccess } from './license_api_access';
|
||||||
export { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason';
|
export { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason';
|
||||||
|
@ -21,6 +21,6 @@ export { AlertTypeDisabledError, isErrorThatHandlesItsOwnResponse } from './erro
|
||||||
export {
|
export {
|
||||||
executionStatusFromState,
|
executionStatusFromState,
|
||||||
executionStatusFromError,
|
executionStatusFromError,
|
||||||
alertExecutionStatusToRaw,
|
ruleExecutionStatusToRaw,
|
||||||
alertExecutionStatusFromRaw,
|
ruleExecutionStatusFromRaw,
|
||||||
} from './alert_execution_status';
|
} from './rule_execution_status';
|
||||||
|
|
|
@ -11,8 +11,8 @@ export const createLicenseStateMock = () => {
|
||||||
const licenseState: jest.Mocked<ILicenseState> = {
|
const licenseState: jest.Mocked<ILicenseState> = {
|
||||||
clean: jest.fn(),
|
clean: jest.fn(),
|
||||||
getLicenseInformation: jest.fn(),
|
getLicenseInformation: jest.fn(),
|
||||||
ensureLicenseForAlertType: jest.fn(),
|
ensureLicenseForRuleType: jest.fn(),
|
||||||
getLicenseCheckForAlertType: jest.fn().mockResolvedValue({
|
getLicenseCheckForRuleType: jest.fn().mockResolvedValue({
|
||||||
isValid: true,
|
isValid: true,
|
||||||
}),
|
}),
|
||||||
checkLicense: jest.fn().mockResolvedValue({
|
checkLicense: jest.fn().mockResolvedValue({
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AlertType } from '../types';
|
import { RuleType } from '../types';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { LicenseState, ILicenseState } from './license_state';
|
import { LicenseState, ILicenseState } from './license_state';
|
||||||
import { licensingMock } from '../../../licensing/server/mocks';
|
import { licensingMock } from '../../../licensing/server/mocks';
|
||||||
|
@ -53,11 +53,11 @@ describe('checkLicense()', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getLicenseCheckForAlertType', () => {
|
describe('getLicenseCheckForRuleType', () => {
|
||||||
let license: Subject<ILicense>;
|
let license: Subject<ILicense>;
|
||||||
let licenseState: ILicenseState;
|
let licenseState: ILicenseState;
|
||||||
const mockNotifyUsage = jest.fn();
|
const mockNotifyUsage = jest.fn();
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default', 'recovered'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default', 'recovered'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -82,10 +82,10 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
|
|
||||||
test('should return false when license not defined', () => {
|
test('should return false when license not defined', () => {
|
||||||
expect(
|
expect(
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
)
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
isValid: false,
|
isValid: false,
|
||||||
|
@ -96,10 +96,10 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
test('should return false when license not available', () => {
|
test('should return false when license not available', () => {
|
||||||
license.next(createUnavailableLicense());
|
license.next(createUnavailableLicense());
|
||||||
expect(
|
expect(
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
)
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
isValid: false,
|
isValid: false,
|
||||||
|
@ -111,10 +111,10 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
const expiredLicense = licensingMock.createLicense({ license: { status: 'expired' } });
|
const expiredLicense = licensingMock.createLicense({ license: { status: 'expired' } });
|
||||||
license.next(expiredLicense);
|
license.next(expiredLicense);
|
||||||
expect(
|
expect(
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
)
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
isValid: false,
|
isValid: false,
|
||||||
|
@ -128,10 +128,10 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
});
|
});
|
||||||
license.next(basicLicense);
|
license.next(basicLicense);
|
||||||
expect(
|
expect(
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
)
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
isValid: false,
|
isValid: false,
|
||||||
|
@ -145,10 +145,10 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
});
|
});
|
||||||
license.next(goldLicense);
|
license.next(goldLicense);
|
||||||
expect(
|
expect(
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
)
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
isValid: true,
|
isValid: true,
|
||||||
|
@ -160,7 +160,7 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
license: { status: 'active', type: 'gold' },
|
license: { status: 'active', type: 'gold' },
|
||||||
});
|
});
|
||||||
license.next(goldLicense);
|
license.next(goldLicense);
|
||||||
licenseState.getLicenseCheckForAlertType(alertType.id, alertType.name, 'gold');
|
licenseState.getLicenseCheckForRuleType(ruleType.id, ruleType.name, 'gold');
|
||||||
expect(mockNotifyUsage).not.toHaveBeenCalled();
|
expect(mockNotifyUsage).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
license: { status: 'active', type: 'basic' },
|
license: { status: 'active', type: 'basic' },
|
||||||
});
|
});
|
||||||
license.next(basicLicense);
|
license.next(basicLicense);
|
||||||
licenseState.getLicenseCheckForAlertType(alertType.id, alertType.name, 'basic');
|
licenseState.getLicenseCheckForRuleType(ruleType.id, ruleType.name, 'basic');
|
||||||
expect(mockNotifyUsage).not.toHaveBeenCalled();
|
expect(mockNotifyUsage).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -178,21 +178,21 @@ describe('getLicenseCheckForAlertType', () => {
|
||||||
license: { status: 'active', type: 'gold' },
|
license: { status: 'active', type: 'gold' },
|
||||||
});
|
});
|
||||||
license.next(goldLicense);
|
license.next(goldLicense);
|
||||||
licenseState.getLicenseCheckForAlertType(
|
licenseState.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired,
|
ruleType.minimumLicenseRequired,
|
||||||
{ notifyUsage: true }
|
{ notifyUsage: true }
|
||||||
);
|
);
|
||||||
expect(mockNotifyUsage).toHaveBeenCalledWith('Alert: Test');
|
expect(mockNotifyUsage).toHaveBeenCalledWith('Rule: Test');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ensureLicenseForAlertType()', () => {
|
describe('ensureLicenseForRuleType()', () => {
|
||||||
let license: Subject<ILicense>;
|
let license: Subject<ILicense>;
|
||||||
let licenseState: ILicenseState;
|
let licenseState: ILicenseState;
|
||||||
const mockNotifyUsage = jest.fn();
|
const mockNotifyUsage = jest.fn();
|
||||||
const alertType: AlertType<never, never, never, never, never, string, string> = {
|
const ruleType: RuleType<never, never, never, never, never, string, string> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -217,18 +217,18 @@ describe('ensureLicenseForAlertType()', () => {
|
||||||
|
|
||||||
test('should throw when license not defined', () => {
|
test('should throw when license not defined', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
licenseState.ensureLicenseForAlertType(alertType)
|
licenseState.ensureLicenseForRuleType(ruleType)
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Alert type test is disabled because license information is not available at this time."`
|
`"Rule type test is disabled because license information is not available at this time."`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should throw when license not available', () => {
|
test('should throw when license not available', () => {
|
||||||
license.next(createUnavailableLicense());
|
license.next(createUnavailableLicense());
|
||||||
expect(() =>
|
expect(() =>
|
||||||
licenseState.ensureLicenseForAlertType(alertType)
|
licenseState.ensureLicenseForRuleType(ruleType)
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Alert type test is disabled because license information is not available at this time."`
|
`"Rule type test is disabled because license information is not available at this time."`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,9 +236,9 @@ describe('ensureLicenseForAlertType()', () => {
|
||||||
const expiredLicense = licensingMock.createLicense({ license: { status: 'expired' } });
|
const expiredLicense = licensingMock.createLicense({ license: { status: 'expired' } });
|
||||||
license.next(expiredLicense);
|
license.next(expiredLicense);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
licenseState.ensureLicenseForAlertType(alertType)
|
licenseState.ensureLicenseForRuleType(ruleType)
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Alert type test is disabled because your basic license has expired."`
|
`"Rule type test is disabled because your basic license has expired."`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -248,9 +248,9 @@ describe('ensureLicenseForAlertType()', () => {
|
||||||
});
|
});
|
||||||
license.next(basicLicense);
|
license.next(basicLicense);
|
||||||
expect(() =>
|
expect(() =>
|
||||||
licenseState.ensureLicenseForAlertType(alertType)
|
licenseState.ensureLicenseForRuleType(ruleType)
|
||||||
).toThrowErrorMatchingInlineSnapshot(
|
).toThrowErrorMatchingInlineSnapshot(
|
||||||
`"Alert test is disabled because it requires a Gold license. Go to License Management to view upgrade options."`
|
`"Rule test is disabled because it requires a Gold license. Go to License Management to view upgrade options."`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ describe('ensureLicenseForAlertType()', () => {
|
||||||
license: { status: 'active', type: 'gold' },
|
license: { status: 'active', type: 'gold' },
|
||||||
});
|
});
|
||||||
license.next(goldLicense);
|
license.next(goldLicense);
|
||||||
licenseState.ensureLicenseForAlertType(alertType);
|
licenseState.ensureLicenseForRuleType(ruleType);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call notifyUsage', () => {
|
test('should call notifyUsage', () => {
|
||||||
|
@ -267,8 +267,8 @@ describe('ensureLicenseForAlertType()', () => {
|
||||||
license: { status: 'active', type: 'gold' },
|
license: { status: 'active', type: 'gold' },
|
||||||
});
|
});
|
||||||
license.next(goldLicense);
|
license.next(goldLicense);
|
||||||
licenseState.ensureLicenseForAlertType(alertType);
|
licenseState.ensureLicenseForRuleType(ruleType);
|
||||||
expect(mockNotifyUsage).toHaveBeenCalledWith('Alert: Test');
|
expect(mockNotifyUsage).toHaveBeenCalledWith('Rule: Test');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,9 @@ import { Observable, Subscription } from 'rxjs';
|
||||||
import { LicensingPluginStart } from '../../../licensing/server';
|
import { LicensingPluginStart } from '../../../licensing/server';
|
||||||
import { ILicense, LicenseType } from '../../../licensing/common/types';
|
import { ILicense, LicenseType } from '../../../licensing/common/types';
|
||||||
import { PLUGIN } from '../constants/plugin';
|
import { PLUGIN } from '../constants/plugin';
|
||||||
import { getAlertTypeFeatureUsageName } from './get_alert_type_feature_usage_name';
|
import { getRuleTypeFeatureUsageName } from './get_rule_type_feature_usage_name';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
|
@ -68,21 +68,21 @@ export class LicenseState {
|
||||||
this._notifyUsage = notifyUsage;
|
this._notifyUsage = notifyUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLicenseCheckForAlertType(
|
public getLicenseCheckForRuleType(
|
||||||
alertTypeId: string,
|
ruleTypeId: string,
|
||||||
alertTypeName: string,
|
ruleTypeName: string,
|
||||||
minimumLicenseRequired: LicenseType,
|
minimumLicenseRequired: LicenseType,
|
||||||
{ notifyUsage }: { notifyUsage: boolean } = { notifyUsage: false }
|
{ notifyUsage }: { notifyUsage: boolean } = { notifyUsage: false }
|
||||||
): { isValid: true } | { isValid: false; reason: 'unavailable' | 'expired' | 'invalid' } {
|
): { isValid: true } | { isValid: false; reason: 'unavailable' | 'expired' | 'invalid' } {
|
||||||
if (notifyUsage) {
|
if (notifyUsage) {
|
||||||
this.notifyUsage(alertTypeName, minimumLicenseRequired);
|
this.notifyUsage(ruleTypeName, minimumLicenseRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.license?.isAvailable) {
|
if (!this.license?.isAvailable) {
|
||||||
return { isValid: false, reason: 'unavailable' };
|
return { isValid: false, reason: 'unavailable' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const check = this.license.check(alertTypeId, minimumLicenseRequired);
|
const check = this.license.check(ruleTypeId, minimumLicenseRequired);
|
||||||
|
|
||||||
switch (check.state) {
|
switch (check.state) {
|
||||||
case 'expired':
|
case 'expired':
|
||||||
|
@ -98,10 +98,10 @@ export class LicenseState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private notifyUsage(alertTypeName: string, minimumLicenseRequired: LicenseType) {
|
private notifyUsage(ruleTypeName: string, minimumLicenseRequired: LicenseType) {
|
||||||
// No need to notify usage on basic alert types
|
// No need to notify usage on basic alert types
|
||||||
if (this._notifyUsage && minimumLicenseRequired !== 'basic') {
|
if (this._notifyUsage && minimumLicenseRequired !== 'basic') {
|
||||||
this._notifyUsage(getAlertTypeFeatureUsageName(alertTypeName));
|
this._notifyUsage(getRuleTypeFeatureUsageName(ruleTypeName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ export class LicenseState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ensureLicenseForAlertType<
|
public ensureLicenseForRuleType<
|
||||||
Params extends AlertTypeParams,
|
Params extends AlertTypeParams,
|
||||||
ExtractedParams extends AlertTypeParams,
|
ExtractedParams extends AlertTypeParams,
|
||||||
State extends AlertTypeState,
|
State extends AlertTypeState,
|
||||||
|
@ -156,7 +156,7 @@ export class LicenseState {
|
||||||
ActionGroupIds extends string,
|
ActionGroupIds extends string,
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
>(
|
>(
|
||||||
alertType: AlertType<
|
ruleType: RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -166,12 +166,12 @@ export class LicenseState {
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
this.notifyUsage(alertType.name, alertType.minimumLicenseRequired);
|
this.notifyUsage(ruleType.name, ruleType.minimumLicenseRequired);
|
||||||
|
|
||||||
const check = this.getLicenseCheckForAlertType(
|
const check = this.getLicenseCheckForRuleType(
|
||||||
alertType.id,
|
ruleType.id,
|
||||||
alertType.name,
|
ruleType.name,
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
);
|
);
|
||||||
|
|
||||||
if (check.isValid) {
|
if (check.isValid) {
|
||||||
|
@ -182,9 +182,9 @@ export class LicenseState {
|
||||||
throw new AlertTypeDisabledError(
|
throw new AlertTypeDisabledError(
|
||||||
i18n.translate('xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage', {
|
i18n.translate('xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage', {
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
'Alert type {alertTypeId} is disabled because license information is not available at this time.',
|
'Rule type {ruleTypeId} is disabled because license information is not available at this time.',
|
||||||
values: {
|
values: {
|
||||||
alertTypeId: alertType.id,
|
ruleTypeId: ruleType.id,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'license_unavailable'
|
'license_unavailable'
|
||||||
|
@ -193,8 +193,8 @@ export class LicenseState {
|
||||||
throw new AlertTypeDisabledError(
|
throw new AlertTypeDisabledError(
|
||||||
i18n.translate('xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage', {
|
i18n.translate('xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage', {
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
'Alert type {alertTypeId} is disabled because your {licenseType} license has expired.',
|
'Rule type {ruleTypeId} is disabled because your {licenseType} license has expired.',
|
||||||
values: { alertTypeId: alertType.id, licenseType: this.license!.type },
|
values: { ruleTypeId: ruleType.id, licenseType: this.license!.type },
|
||||||
}),
|
}),
|
||||||
'license_expired'
|
'license_expired'
|
||||||
);
|
);
|
||||||
|
@ -202,10 +202,10 @@ export class LicenseState {
|
||||||
throw new AlertTypeDisabledError(
|
throw new AlertTypeDisabledError(
|
||||||
i18n.translate('xpack.alerting.serverSideErrors.invalidLicenseErrorMessage', {
|
i18n.translate('xpack.alerting.serverSideErrors.invalidLicenseErrorMessage', {
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
'Alert {alertTypeId} is disabled because it requires a {licenseType} license. Go to License Management to view upgrade options.',
|
'Rule {ruleTypeId} is disabled because it requires a {licenseType} license. Go to License Management to view upgrade options.',
|
||||||
values: {
|
values: {
|
||||||
alertTypeId: alertType.id,
|
ruleTypeId: ruleType.id,
|
||||||
licenseType: capitalize(alertType.minimumLicenseRequired),
|
licenseType: capitalize(ruleType.minimumLicenseRequired),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'license_invalid'
|
'license_invalid'
|
||||||
|
|
|
@ -10,14 +10,14 @@ import { AlertExecutionStatusErrorReasons } from '../types';
|
||||||
import {
|
import {
|
||||||
executionStatusFromState,
|
executionStatusFromState,
|
||||||
executionStatusFromError,
|
executionStatusFromError,
|
||||||
alertExecutionStatusToRaw,
|
ruleExecutionStatusToRaw,
|
||||||
alertExecutionStatusFromRaw,
|
ruleExecutionStatusFromRaw,
|
||||||
} from './alert_execution_status';
|
} from './rule_execution_status';
|
||||||
import { ErrorWithReason } from './error_with_reason';
|
import { ErrorWithReason } from './error_with_reason';
|
||||||
|
|
||||||
const MockLogger = loggingSystemMock.create().get();
|
const MockLogger = loggingSystemMock.create().get();
|
||||||
|
|
||||||
describe('AlertExecutionStatus', () => {
|
describe('RuleExecutionStatus', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
@ -71,14 +71,14 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('alertExecutionStatusToRaw()', () => {
|
describe('ruleExecutionStatusToRaw()', () => {
|
||||||
const date = new Date('2020-09-03T16:26:58Z');
|
const date = new Date('2020-09-03T16:26:58Z');
|
||||||
const status = 'ok';
|
const status = 'ok';
|
||||||
const reason = AlertExecutionStatusErrorReasons.Decrypt;
|
const reason = AlertExecutionStatusErrorReasons.Decrypt;
|
||||||
const error = { reason, message: 'wops' };
|
const error = { reason, message: 'wops' };
|
||||||
|
|
||||||
test('status without an error', () => {
|
test('status without an error', () => {
|
||||||
expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status })).toMatchInlineSnapshot(`
|
expect(ruleExecutionStatusToRaw({ lastExecutionDate: date, status })).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"error": null,
|
"error": null,
|
||||||
"lastDuration": 0,
|
"lastDuration": 0,
|
||||||
|
@ -89,7 +89,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('status with an error', () => {
|
test('status with an error', () => {
|
||||||
expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status, error }))
|
expect(ruleExecutionStatusToRaw({ lastExecutionDate: date, status, error }))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"error": Object {
|
"error": Object {
|
||||||
|
@ -104,7 +104,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('status with a duration', () => {
|
test('status with a duration', () => {
|
||||||
expect(alertExecutionStatusToRaw({ lastExecutionDate: date, status, lastDuration: 1234 }))
|
expect(ruleExecutionStatusToRaw({ lastExecutionDate: date, status, lastDuration: 1234 }))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"error": null,
|
"error": null,
|
||||||
|
@ -116,41 +116,41 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('alertExecutionStatusFromRaw()', () => {
|
describe('ruleExecutionStatusFromRaw()', () => {
|
||||||
const date = new Date('2020-09-03T16:26:58Z').toISOString();
|
const date = new Date('2020-09-03T16:26:58Z').toISOString();
|
||||||
const status = 'active';
|
const status = 'active';
|
||||||
const reason = AlertExecutionStatusErrorReasons.Execute;
|
const reason = AlertExecutionStatusErrorReasons.Execute;
|
||||||
const error = { reason, message: 'wops' };
|
const error = { reason, message: 'wops' };
|
||||||
|
|
||||||
test('no input', () => {
|
test('no input', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id');
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id');
|
||||||
expect(result).toBe(undefined);
|
expect(result).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('undefined input', () => {
|
test('undefined input', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', undefined);
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', undefined);
|
||||||
expect(result).toBe(undefined);
|
expect(result).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('null input', () => {
|
test('null input', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', null);
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', null);
|
||||||
expect(result).toBe(undefined);
|
expect(result).toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invalid date', () => {
|
test('invalid date', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
lastExecutionDate: 'an invalid date',
|
lastExecutionDate: 'an invalid date',
|
||||||
})!;
|
})!;
|
||||||
checkDateIsNearNow(result.lastExecutionDate);
|
checkDateIsNearNow(result.lastExecutionDate);
|
||||||
expect(result.status).toBe('unknown');
|
expect(result.status).toBe('unknown');
|
||||||
expect(result.error).toBe(undefined);
|
expect(result.error).toBe(undefined);
|
||||||
expect(MockLogger.debug).toBeCalledWith(
|
expect(MockLogger.debug).toBeCalledWith(
|
||||||
'invalid alertExecutionStatus lastExecutionDate "an invalid date" in raw alert alert-id'
|
'invalid ruleExecutionStatus lastExecutionDate "an invalid date" in raw rule rule-id'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid date', () => {
|
test('valid date', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
lastExecutionDate: date,
|
lastExecutionDate: date,
|
||||||
});
|
});
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
|
@ -162,7 +162,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid status and date', () => {
|
test('valid status and date', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
status,
|
status,
|
||||||
lastExecutionDate: date,
|
lastExecutionDate: date,
|
||||||
});
|
});
|
||||||
|
@ -175,7 +175,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid status, date and error', () => {
|
test('valid status, date and error', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
status,
|
status,
|
||||||
lastExecutionDate: date,
|
lastExecutionDate: date,
|
||||||
error,
|
error,
|
||||||
|
@ -193,7 +193,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid status, date and duration', () => {
|
test('valid status, date and duration', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
status,
|
status,
|
||||||
lastExecutionDate: date,
|
lastExecutionDate: date,
|
||||||
lastDuration: 1234,
|
lastDuration: 1234,
|
||||||
|
@ -208,7 +208,7 @@ describe('AlertExecutionStatus', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('valid status, date, error and duration', () => {
|
test('valid status, date, error and duration', () => {
|
||||||
const result = alertExecutionStatusFromRaw(MockLogger, 'alert-id', {
|
const result = ruleExecutionStatusFromRaw(MockLogger, 'rule-id', {
|
||||||
status,
|
status,
|
||||||
lastExecutionDate: date,
|
lastExecutionDate: date,
|
||||||
error,
|
error,
|
|
@ -6,16 +6,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Logger } from 'src/core/server';
|
import { Logger } from 'src/core/server';
|
||||||
import { AlertTaskState, AlertExecutionStatus, RawAlertExecutionStatus } from '../types';
|
import { RuleTaskState, AlertExecutionStatus, RawRuleExecutionStatus } from '../types';
|
||||||
import { getReasonFromError } from './error_with_reason';
|
import { getReasonFromError } from './error_with_reason';
|
||||||
import { getEsErrorMessage } from './errors';
|
import { getEsErrorMessage } from './errors';
|
||||||
import { AlertExecutionStatuses } from '../../common';
|
import { AlertExecutionStatuses } from '../../common';
|
||||||
|
|
||||||
export function executionStatusFromState(state: AlertTaskState): AlertExecutionStatus {
|
export function executionStatusFromState(state: RuleTaskState): AlertExecutionStatus {
|
||||||
const instanceIds = Object.keys(state.alertInstances ?? {});
|
const alertIds = Object.keys(state.alertInstances ?? {});
|
||||||
return {
|
return {
|
||||||
lastExecutionDate: new Date(),
|
lastExecutionDate: new Date(),
|
||||||
status: instanceIds.length === 0 ? 'ok' : 'active',
|
status: alertIds.length === 0 ? 'ok' : 'active',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +30,12 @@ export function executionStatusFromError(error: Error): AlertExecutionStatus {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function alertExecutionStatusToRaw({
|
export function ruleExecutionStatusToRaw({
|
||||||
lastExecutionDate,
|
lastExecutionDate,
|
||||||
lastDuration,
|
lastDuration,
|
||||||
status,
|
status,
|
||||||
error,
|
error,
|
||||||
}: AlertExecutionStatus): RawAlertExecutionStatus {
|
}: AlertExecutionStatus): RawRuleExecutionStatus {
|
||||||
return {
|
return {
|
||||||
lastExecutionDate: lastExecutionDate.toISOString(),
|
lastExecutionDate: lastExecutionDate.toISOString(),
|
||||||
lastDuration: lastDuration ?? 0,
|
lastDuration: lastDuration ?? 0,
|
||||||
|
@ -45,19 +45,19 @@ export function alertExecutionStatusToRaw({
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function alertExecutionStatusFromRaw(
|
export function ruleExecutionStatusFromRaw(
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
alertId: string,
|
ruleId: string,
|
||||||
rawAlertExecutionStatus?: Partial<RawAlertExecutionStatus> | null | undefined
|
rawRuleExecutionStatus?: Partial<RawRuleExecutionStatus> | null | undefined
|
||||||
): AlertExecutionStatus | undefined {
|
): AlertExecutionStatus | undefined {
|
||||||
if (!rawAlertExecutionStatus) return undefined;
|
if (!rawRuleExecutionStatus) return undefined;
|
||||||
|
|
||||||
const { lastExecutionDate, lastDuration, status = 'unknown', error } = rawAlertExecutionStatus;
|
const { lastExecutionDate, lastDuration, status = 'unknown', error } = rawRuleExecutionStatus;
|
||||||
|
|
||||||
let parsedDateMillis = lastExecutionDate ? Date.parse(lastExecutionDate) : Date.now();
|
let parsedDateMillis = lastExecutionDate ? Date.parse(lastExecutionDate) : Date.now();
|
||||||
if (isNaN(parsedDateMillis)) {
|
if (isNaN(parsedDateMillis)) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`invalid alertExecutionStatus lastExecutionDate "${lastExecutionDate}" in raw alert ${alertId}`
|
`invalid ruleExecutionStatus lastExecutionDate "${lastExecutionDate}" in raw rule ${ruleId}`
|
||||||
);
|
);
|
||||||
parsedDateMillis = Date.now();
|
parsedDateMillis = Date.now();
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ export function alertExecutionStatusFromRaw(
|
||||||
return executionStatus;
|
return executionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAlertExecutionStatusPending = (lastExecutionDate: string) => ({
|
export const getRuleExecutionStatusPending = (lastExecutionDate: string) => ({
|
||||||
status: 'pending' as AlertExecutionStatuses,
|
status: 'pending' as AlertExecutionStatuses,
|
||||||
lastExecutionDate,
|
lastExecutionDate,
|
||||||
error: null,
|
error: null,
|
|
@ -6,17 +6,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { validateAlertTypeParams } from './validate_alert_type_params';
|
import { validateRuleTypeParams } from './validate_rule_type_params';
|
||||||
|
|
||||||
test('should return passed in params when validation not defined', () => {
|
test('should return passed in params when validation not defined', () => {
|
||||||
const result = validateAlertTypeParams({
|
const result = validateRuleTypeParams({
|
||||||
foo: true,
|
foo: true,
|
||||||
});
|
});
|
||||||
expect(result).toEqual({ foo: true });
|
expect(result).toEqual({ foo: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should validate and apply defaults when params is valid', () => {
|
test('should validate and apply defaults when params is valid', () => {
|
||||||
const result = validateAlertTypeParams(
|
const result = validateRuleTypeParams(
|
||||||
{ param1: 'value' },
|
{ param1: 'value' },
|
||||||
schema.object({
|
schema.object({
|
||||||
param1: schema.string(),
|
param1: schema.string(),
|
||||||
|
@ -31,7 +31,7 @@ test('should validate and apply defaults when params is valid', () => {
|
||||||
|
|
||||||
test('should validate and throw error when params is invalid', () => {
|
test('should validate and throw error when params is invalid', () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
validateAlertTypeParams(
|
validateRuleTypeParams(
|
||||||
{},
|
{},
|
||||||
schema.object({
|
schema.object({
|
||||||
param1: schema.string(),
|
param1: schema.string(),
|
|
@ -8,7 +8,7 @@
|
||||||
import Boom from '@hapi/boom';
|
import Boom from '@hapi/boom';
|
||||||
import { AlertTypeParams, AlertTypeParamsValidator } from '../types';
|
import { AlertTypeParams, AlertTypeParamsValidator } from '../types';
|
||||||
|
|
||||||
export function validateAlertTypeParams<Params extends AlertTypeParams>(
|
export function validateRuleTypeParams<Params extends AlertTypeParams>(
|
||||||
params: Record<string, unknown>,
|
params: Record<string, unknown>,
|
||||||
validator?: AlertTypeParamsValidator<Params>
|
validator?: AlertTypeParamsValidator<Params>
|
||||||
): Params {
|
): Params {
|
|
@ -16,7 +16,7 @@ import { KibanaRequest } from 'kibana/server';
|
||||||
import { featuresPluginMock } from '../../features/server/mocks';
|
import { featuresPluginMock } from '../../features/server/mocks';
|
||||||
import { KibanaFeature } from '../../features/server';
|
import { KibanaFeature } from '../../features/server';
|
||||||
import { AlertsConfig } from './config';
|
import { AlertsConfig } from './config';
|
||||||
import { AlertType } from './types';
|
import { RuleType } from './types';
|
||||||
import { eventLogMock } from '../../event_log/server/mocks';
|
import { eventLogMock } from '../../event_log/server/mocks';
|
||||||
import { actionsMock } from '../../actions/server/mocks';
|
import { actionsMock } from '../../actions/server/mocks';
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ describe('Alerting Plugin', () => {
|
||||||
|
|
||||||
describe('registerType()', () => {
|
describe('registerType()', () => {
|
||||||
let setup: PluginSetupContract;
|
let setup: PluginSetupContract;
|
||||||
const sampleAlertType: AlertType<never, never, never, never, never, 'default'> = {
|
const sampleRuleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'test',
|
name: 'test',
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
|
@ -126,7 +126,7 @@ describe('Alerting Plugin', () => {
|
||||||
it('should throw error when license type is invalid', async () => {
|
it('should throw error when license type is invalid', async () => {
|
||||||
expect(() =>
|
expect(() =>
|
||||||
setup.registerType({
|
setup.registerType({
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
minimumLicenseRequired: 'foo' as any,
|
minimumLicenseRequired: 'foo' as any,
|
||||||
})
|
})
|
||||||
|
@ -135,52 +135,52 @@ describe('Alerting Plugin', () => {
|
||||||
|
|
||||||
it('should not throw when license type is gold', async () => {
|
it('should not throw when license type is gold', async () => {
|
||||||
setup.registerType({
|
setup.registerType({
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'gold',
|
minimumLicenseRequired: 'gold',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw when license type is basic', async () => {
|
it('should not throw when license type is basic', async () => {
|
||||||
setup.registerType({
|
setup.registerType({
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply default config value for ruleTaskTimeout if no value is specified', async () => {
|
it('should apply default config value for ruleTaskTimeout if no value is specified', async () => {
|
||||||
const ruleType = {
|
const ruleType = {
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
} as AlertType<never, never, never, never, never, 'default', never>;
|
} as RuleType<never, never, never, never, never, 'default', never>;
|
||||||
await setup.registerType(ruleType);
|
await setup.registerType(ruleType);
|
||||||
expect(ruleType.ruleTaskTimeout).toBe('5m');
|
expect(ruleType.ruleTaskTimeout).toBe('5m');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply value for ruleTaskTimeout if specified', async () => {
|
it('should apply value for ruleTaskTimeout if specified', async () => {
|
||||||
const ruleType = {
|
const ruleType = {
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
ruleTaskTimeout: '20h',
|
ruleTaskTimeout: '20h',
|
||||||
} as AlertType<never, never, never, never, never, 'default', never>;
|
} as RuleType<never, never, never, never, never, 'default', never>;
|
||||||
await setup.registerType(ruleType);
|
await setup.registerType(ruleType);
|
||||||
expect(ruleType.ruleTaskTimeout).toBe('20h');
|
expect(ruleType.ruleTaskTimeout).toBe('20h');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply default config value for cancelAlertsOnRuleTimeout if no value is specified', async () => {
|
it('should apply default config value for cancelAlertsOnRuleTimeout if no value is specified', async () => {
|
||||||
const ruleType = {
|
const ruleType = {
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
} as AlertType<never, never, never, never, never, 'default', never>;
|
} as RuleType<never, never, never, never, never, 'default', never>;
|
||||||
await setup.registerType(ruleType);
|
await setup.registerType(ruleType);
|
||||||
expect(ruleType.cancelAlertsOnRuleTimeout).toBe(true);
|
expect(ruleType.cancelAlertsOnRuleTimeout).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply value for cancelAlertsOnRuleTimeout if specified', async () => {
|
it('should apply value for cancelAlertsOnRuleTimeout if specified', async () => {
|
||||||
const ruleType = {
|
const ruleType = {
|
||||||
...sampleAlertType,
|
...sampleRuleType,
|
||||||
minimumLicenseRequired: 'basic',
|
minimumLicenseRequired: 'basic',
|
||||||
cancelAlertsOnRuleTimeout: false,
|
cancelAlertsOnRuleTimeout: false,
|
||||||
} as AlertType<never, never, never, never, never, 'default', never>;
|
} as RuleType<never, never, never, never, never, 'default', never>;
|
||||||
await setup.registerType(ruleType);
|
await setup.registerType(ruleType);
|
||||||
expect(ruleType.cancelAlertsOnRuleTimeout).toBe(false);
|
expect(ruleType.cancelAlertsOnRuleTimeout).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,7 +46,7 @@ import {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertsHealth,
|
AlertsHealth,
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
Services,
|
Services,
|
||||||
|
@ -91,7 +91,7 @@ export interface PluginSetupContract {
|
||||||
ActionGroupIds extends string = never,
|
ActionGroupIds extends string = never,
|
||||||
RecoveryActionGroupId extends string = never
|
RecoveryActionGroupId extends string = never
|
||||||
>(
|
>(
|
||||||
alertType: AlertType<
|
ruleType: RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -273,7 +273,7 @@ export class AlertingPlugin {
|
||||||
ActionGroupIds extends string = never,
|
ActionGroupIds extends string = never,
|
||||||
RecoveryActionGroupId extends string = never
|
RecoveryActionGroupId extends string = never
|
||||||
>(
|
>(
|
||||||
alertType: AlertType<
|
ruleType: RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -283,15 +283,15 @@ export class AlertingPlugin {
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
if (!(alertType.minimumLicenseRequired in LICENSE_TYPE)) {
|
if (!(ruleType.minimumLicenseRequired in LICENSE_TYPE)) {
|
||||||
throw new Error(`"${alertType.minimumLicenseRequired}" is not a valid license type`);
|
throw new Error(`"${ruleType.minimumLicenseRequired}" is not a valid license type`);
|
||||||
}
|
}
|
||||||
|
|
||||||
alertingConfig.then((config) => {
|
alertingConfig.then((config) => {
|
||||||
alertType.ruleTaskTimeout = alertType.ruleTaskTimeout ?? config.defaultRuleTaskTimeout;
|
ruleType.ruleTaskTimeout = ruleType.ruleTaskTimeout ?? config.defaultRuleTaskTimeout;
|
||||||
alertType.cancelAlertsOnRuleTimeout =
|
ruleType.cancelAlertsOnRuleTimeout =
|
||||||
alertType.cancelAlertsOnRuleTimeout ?? config.cancelAlertsOnRuleTimeout;
|
ruleType.cancelAlertsOnRuleTimeout ?? config.cancelAlertsOnRuleTimeout;
|
||||||
ruleTypeRegistry.register(alertType);
|
ruleTypeRegistry.register(ruleType);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getSecurityHealth: async () => {
|
getSecurityHealth: async () => {
|
||||||
|
@ -390,7 +390,7 @@ export class AlertingPlugin {
|
||||||
ruleTypeRegistry: this.ruleTypeRegistry!,
|
ruleTypeRegistry: this.ruleTypeRegistry!,
|
||||||
kibanaBaseUrl: this.kibanaBaseUrl,
|
kibanaBaseUrl: this.kibanaBaseUrl,
|
||||||
supportsEphemeralTasks: plugins.taskManager.supportsEphemeralTasks(),
|
supportsEphemeralTasks: plugins.taskManager.supportsEphemeralTasks(),
|
||||||
maxEphemeralActionsPerAlert: config.maxEphemeralActionsPerAlert,
|
maxEphemeralActionsPerRule: config.maxEphemeralActionsPerAlert,
|
||||||
cancelAlertsOnRuleTimeout: config.cancelAlertsOnRuleTimeout,
|
cancelAlertsOnRuleTimeout: config.cancelAlertsOnRuleTimeout,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { identity } from 'lodash';
|
||||||
import type { MethodKeysOf } from '@kbn/utility-types';
|
import type { MethodKeysOf } from '@kbn/utility-types';
|
||||||
import { httpServerMock } from '../../../../../src/core/server/mocks';
|
import { httpServerMock } from '../../../../../src/core/server/mocks';
|
||||||
import { rulesClientMock, RulesClientMock } from '../rules_client.mock';
|
import { rulesClientMock, RulesClientMock } from '../rules_client.mock';
|
||||||
import { AlertsHealth, AlertType } from '../../common';
|
import { AlertsHealth, RuleType } from '../../common';
|
||||||
import type { AlertingRequestHandlerContext } from '../types';
|
import type { AlertingRequestHandlerContext } from '../types';
|
||||||
|
|
||||||
export function mockHandlerArguments(
|
export function mockHandlerArguments(
|
||||||
|
@ -21,7 +21,7 @@ export function mockHandlerArguments(
|
||||||
areApiKeysEnabled,
|
areApiKeysEnabled,
|
||||||
}: {
|
}: {
|
||||||
rulesClient?: RulesClientMock;
|
rulesClient?: RulesClientMock;
|
||||||
listTypes?: AlertType[];
|
listTypes?: RuleType[];
|
||||||
getFrameworkHealth?: jest.MockInstance<Promise<AlertsHealth>, []> &
|
getFrameworkHealth?: jest.MockInstance<Promise<AlertsHealth>, []> &
|
||||||
(() => Promise<AlertsHealth>);
|
(() => Promise<AlertsHealth>);
|
||||||
areApiKeysEnabled?: () => Promise<boolean>;
|
areApiKeysEnabled?: () => Promise<boolean>;
|
||||||
|
|
|
@ -12,14 +12,14 @@ import { RewriteResponseCase, verifyAccessAndContext } from './lib';
|
||||||
import {
|
import {
|
||||||
AlertingRequestHandlerContext,
|
AlertingRequestHandlerContext,
|
||||||
INTERNAL_BASE_ALERTING_API_PATH,
|
INTERNAL_BASE_ALERTING_API_PATH,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
const paramSchema = schema.object({
|
const paramSchema = schema.object({
|
||||||
id: schema.string(),
|
id: schema.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const rewriteBodyRes: RewriteResponseCase<AlertTaskState> = ({
|
const rewriteBodyRes: RewriteResponseCase<RuleTaskState> = ({
|
||||||
alertTypeState,
|
alertTypeState,
|
||||||
alertInstances,
|
alertInstances,
|
||||||
previousStartedAt,
|
previousStartedAt,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { TaskRunnerFactory } from './task_runner';
|
import { TaskRunnerFactory } from './task_runner';
|
||||||
import { RuleTypeRegistry, ConstructorOptions } from './rule_type_registry';
|
import { RuleTypeRegistry, ConstructorOptions } from './rule_type_registry';
|
||||||
import { ActionGroup, AlertType } from './types';
|
import { ActionGroup, RuleType } from './types';
|
||||||
import { taskManagerMock } from '../../task_manager/server/mocks';
|
import { taskManagerMock } from '../../task_manager/server/mocks';
|
||||||
import { ILicenseState } from './lib/license_state';
|
import { ILicenseState } from './lib/license_state';
|
||||||
import { licenseStateMock } from './lib/license_state.mock';
|
import { licenseStateMock } from './lib/license_state.mock';
|
||||||
|
@ -56,8 +56,8 @@ describe('has()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('register()', () => {
|
describe('register()', () => {
|
||||||
test('throws if AlertType Id contains invalid characters', () => {
|
test('throws if RuleType Id contains invalid characters', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -76,21 +76,21 @@ describe('register()', () => {
|
||||||
|
|
||||||
const invalidCharacters = [' ', ':', '*', '*', '/'];
|
const invalidCharacters = [' ', ':', '*', '*', '/'];
|
||||||
for (const char of invalidCharacters) {
|
for (const char of invalidCharacters) {
|
||||||
expect(() => registry.register({ ...alertType, id: `${alertType.id}${char}` })).toThrowError(
|
expect(() => registry.register({ ...ruleType, id: `${ruleType.id}${char}` })).toThrowError(
|
||||||
new Error(`expected AlertType Id not to include invalid character: ${char}`)
|
new Error(`expected RuleType Id not to include invalid character: ${char}`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [first, second] = invalidCharacters;
|
const [first, second] = invalidCharacters;
|
||||||
expect(() =>
|
expect(() =>
|
||||||
registry.register({ ...alertType, id: `${first}${alertType.id}${second}` })
|
registry.register({ ...ruleType, id: `${first}${ruleType.id}${second}` })
|
||||||
).toThrowError(
|
).toThrowError(
|
||||||
new Error(`expected AlertType Id not to include invalid characters: ${first}, ${second}`)
|
new Error(`expected RuleType Id not to include invalid characters: ${first}, ${second}`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if AlertType Id isnt a string', () => {
|
test('throws if RuleType Id isnt a string', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: 123 as unknown as string,
|
id: 123 as unknown as string,
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -107,13 +107,13 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(`expected value of type [string] but got [number]`)
|
new Error(`expected value of type [string] but got [number]`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if AlertType ruleTaskTimeout is not a valid duration', () => {
|
test('throws if RuleType ruleTaskTimeout is not a valid duration', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: '123',
|
id: '123',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -131,7 +131,7 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(
|
new Error(
|
||||||
`Rule type \"123\" has invalid timeout: string is not a valid duration: 23 milisec.`
|
`Rule type \"123\" has invalid timeout: string is not a valid duration: 23 milisec.`
|
||||||
)
|
)
|
||||||
|
@ -139,7 +139,7 @@ describe('register()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if defaultScheduleInterval isnt valid', () => {
|
test('throws if defaultScheduleInterval isnt valid', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: '123',
|
id: '123',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -158,7 +158,7 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(
|
new Error(
|
||||||
`Rule type \"123\" has invalid default interval: string is not a valid duration: foobar.`
|
`Rule type \"123\" has invalid default interval: string is not a valid duration: foobar.`
|
||||||
)
|
)
|
||||||
|
@ -166,7 +166,7 @@ describe('register()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if minimumScheduleInterval isnt valid', () => {
|
test('throws if minimumScheduleInterval isnt valid', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: '123',
|
id: '123',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -184,7 +184,7 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(
|
new Error(
|
||||||
`Rule type \"123\" has invalid minimum interval: string is not a valid duration: foobar.`
|
`Rule type \"123\" has invalid minimum interval: string is not a valid duration: foobar.`
|
||||||
)
|
)
|
||||||
|
@ -192,7 +192,7 @@ describe('register()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if RuleType action groups contains reserved group id', () => {
|
test('throws if RuleType action groups contains reserved group id', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default' | 'NotReserved'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default' | 'NotReserved'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -217,15 +217,15 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(
|
new Error(
|
||||||
`Rule type [id="${alertType.id}"] cannot be registered. Action groups [recovered] are reserved by the framework.`
|
`Rule type [id="${ruleType.id}"] cannot be registered. Action groups [recovered] are reserved by the framework.`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('allows an AlertType to specify a custom recovery group', () => {
|
test('allows an RuleType to specify a custom recovery group', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default', 'backToAwesome'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default', 'backToAwesome'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -245,7 +245,7 @@ describe('register()', () => {
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertType);
|
registry.register(ruleType);
|
||||||
expect(registry.get('test').actionGroups).toMatchInlineSnapshot(`
|
expect(registry.get('test').actionGroups).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
|
@ -260,8 +260,8 @@ describe('register()', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('allows an AlertType to specify a custom rule task timeout', () => {
|
test('allows an RuleType to specify a custom rule task timeout', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default', 'backToAwesome'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default', 'backToAwesome'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -278,12 +278,12 @@ describe('register()', () => {
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertType);
|
registry.register(ruleType);
|
||||||
expect(registry.get('test').ruleTaskTimeout).toBe('13m');
|
expect(registry.get('test').ruleTaskTimeout).toBe('13m');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throws if the custom recovery group is contained in the AlertType action groups', () => {
|
test('throws if the custom recovery group is contained in the RuleType action groups', () => {
|
||||||
const alertType: AlertType<
|
const ruleType: RuleType<
|
||||||
never,
|
never,
|
||||||
never,
|
never,
|
||||||
never,
|
never,
|
||||||
|
@ -316,15 +316,15 @@ describe('register()', () => {
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
|
|
||||||
expect(() => registry.register(alertType)).toThrowError(
|
expect(() => registry.register(ruleType)).toThrowError(
|
||||||
new Error(
|
new Error(
|
||||||
`Rule type [id="${alertType.id}"] cannot be registered. Action group [backToAwesome] cannot be used as both a recovery and an active action group.`
|
`Rule type [id="${ruleType.id}"] cannot be registered. Action group [backToAwesome] cannot be used as both a recovery and an active action group.`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('registers the executor with the task manager', () => {
|
test('registers the executor with the task manager', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -341,7 +341,7 @@ describe('register()', () => {
|
||||||
ruleTaskTimeout: '20m',
|
ruleTaskTimeout: '20m',
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertType);
|
registry.register(ruleType);
|
||||||
expect(taskManager.registerTaskDefinitions).toHaveBeenCalledTimes(1);
|
expect(taskManager.registerTaskDefinitions).toHaveBeenCalledTimes(1);
|
||||||
expect(taskManager.registerTaskDefinitions.mock.calls[0]).toMatchInlineSnapshot(`
|
expect(taskManager.registerTaskDefinitions.mock.calls[0]).toMatchInlineSnapshot(`
|
||||||
Array [
|
Array [
|
||||||
|
@ -357,7 +357,7 @@ describe('register()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('shallow clones the given rule type', () => {
|
test('shallow clones the given rule type', () => {
|
||||||
const alertType: AlertType<never, never, never, never, never, 'default'> = {
|
const ruleType: RuleType<never, never, never, never, never, 'default'> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -373,8 +373,8 @@ describe('register()', () => {
|
||||||
producer: 'alerts',
|
producer: 'alerts',
|
||||||
};
|
};
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertType);
|
registry.register(ruleType);
|
||||||
alertType.name = 'Changed';
|
ruleType.name = 'Changed';
|
||||||
expect(registry.get('test').name).toEqual('Test');
|
expect(registry.get('test').name).toEqual('Test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -433,8 +433,8 @@ describe('get()', () => {
|
||||||
executor: jest.fn(),
|
executor: jest.fn(),
|
||||||
producer: 'alerts',
|
producer: 'alerts',
|
||||||
});
|
});
|
||||||
const alertType = registry.get('test');
|
const ruleType = registry.get('test');
|
||||||
expect(alertType).toMatchInlineSnapshot(`
|
expect(ruleType).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"actionGroups": Array [
|
"actionGroups": Array [
|
||||||
Object {
|
Object {
|
||||||
|
@ -539,12 +539,12 @@ describe('list()', () => {
|
||||||
|
|
||||||
test('should return action variables state and empty context', () => {
|
test('should return action variables state and empty context', () => {
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertTypeWithVariables('x', '', 's'));
|
registry.register(ruleTypeWithVariables('x', '', 's'));
|
||||||
const alertType = registry.get('x');
|
const ruleType = registry.get('x');
|
||||||
expect(alertType.actionVariables).toBeTruthy();
|
expect(ruleType.actionVariables).toBeTruthy();
|
||||||
|
|
||||||
const context = alertType.actionVariables!.context;
|
const context = ruleType.actionVariables!.context;
|
||||||
const state = alertType.actionVariables!.state;
|
const state = ruleType.actionVariables!.state;
|
||||||
|
|
||||||
expect(context).toBeTruthy();
|
expect(context).toBeTruthy();
|
||||||
expect(context!.length).toBe(0);
|
expect(context!.length).toBe(0);
|
||||||
|
@ -556,12 +556,12 @@ describe('list()', () => {
|
||||||
|
|
||||||
test('should return action variables context and empty state', () => {
|
test('should return action variables context and empty state', () => {
|
||||||
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);
|
||||||
registry.register(alertTypeWithVariables('x', 'c', ''));
|
registry.register(ruleTypeWithVariables('x', 'c', ''));
|
||||||
const alertType = registry.get('x');
|
const ruleType = registry.get('x');
|
||||||
expect(alertType.actionVariables).toBeTruthy();
|
expect(ruleType.actionVariables).toBeTruthy();
|
||||||
|
|
||||||
const context = alertType.actionVariables!.context;
|
const context = ruleType.actionVariables!.context;
|
||||||
const state = alertType.actionVariables!.state;
|
const state = ruleType.actionVariables!.state;
|
||||||
|
|
||||||
expect(state).toBeTruthy();
|
expect(state).toBeTruthy();
|
||||||
expect(state!.length).toBe(0);
|
expect(state!.length).toBe(0);
|
||||||
|
@ -597,11 +597,11 @@ describe('ensureRuleTypeEnabled', () => {
|
||||||
|
|
||||||
test('should call ensureLicenseForAlertType on the license state', async () => {
|
test('should call ensureLicenseForAlertType on the license state', async () => {
|
||||||
ruleTypeRegistry.ensureRuleTypeEnabled('test');
|
ruleTypeRegistry.ensureRuleTypeEnabled('test');
|
||||||
expect(mockedLicenseState.ensureLicenseForAlertType).toHaveBeenCalled();
|
expect(mockedLicenseState.ensureLicenseForRuleType).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should throw when ensureLicenseForAlertType throws', async () => {
|
test('should throw when ensureLicenseForAlertType throws', async () => {
|
||||||
mockedLicenseState.ensureLicenseForAlertType.mockImplementation(() => {
|
mockedLicenseState.ensureLicenseForRuleType.mockImplementation(() => {
|
||||||
throw new Error('Fail');
|
throw new Error('Fail');
|
||||||
});
|
});
|
||||||
expect(() => ruleTypeRegistry.ensureRuleTypeEnabled('test')).toThrowErrorMatchingInlineSnapshot(
|
expect(() => ruleTypeRegistry.ensureRuleTypeEnabled('test')).toThrowErrorMatchingInlineSnapshot(
|
||||||
|
@ -610,12 +610,12 @@ describe('ensureRuleTypeEnabled', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function alertTypeWithVariables<ActionGroupIds extends string>(
|
function ruleTypeWithVariables<ActionGroupIds extends string>(
|
||||||
id: ActionGroupIds,
|
id: ActionGroupIds,
|
||||||
context: string,
|
context: string,
|
||||||
state: string
|
state: string
|
||||||
): AlertType<never, never, never, never, never, ActionGroupIds> {
|
): RuleType<never, never, never, never, never, ActionGroupIds> {
|
||||||
const baseAlert: AlertType<never, never, never, never, never, ActionGroupIds> = {
|
const baseAlert: RuleType<never, never, never, never, never, ActionGroupIds> = {
|
||||||
id,
|
id,
|
||||||
name: `${id}-name`,
|
name: `${id}-name`,
|
||||||
actionGroups: [],
|
actionGroups: [],
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { LicensingPluginSetup } from '../../licensing/server';
|
||||||
import { RunContext, TaskManagerSetupContract } from '../../task_manager/server';
|
import { RunContext, TaskManagerSetupContract } from '../../task_manager/server';
|
||||||
import { TaskRunnerFactory } from './task_runner';
|
import { TaskRunnerFactory } from './task_runner';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
|
@ -28,7 +28,7 @@ import {
|
||||||
validateDurationSchema,
|
validateDurationSchema,
|
||||||
} from '../common';
|
} from '../common';
|
||||||
import { ILicenseState } from './lib/license_state';
|
import { ILicenseState } from './lib/license_state';
|
||||||
import { getAlertTypeFeatureUsageName } from './lib/get_alert_type_feature_usage_name';
|
import { getRuleTypeFeatureUsageName } from './lib/get_rule_type_feature_usage_name';
|
||||||
|
|
||||||
export interface ConstructorOptions {
|
export interface ConstructorOptions {
|
||||||
taskManager: TaskManagerSetupContract;
|
taskManager: TaskManagerSetupContract;
|
||||||
|
@ -39,7 +39,7 @@ export interface ConstructorOptions {
|
||||||
|
|
||||||
export interface RegistryRuleType
|
export interface RegistryRuleType
|
||||||
extends Pick<
|
extends Pick<
|
||||||
UntypedNormalizedAlertType,
|
UntypedNormalizedRuleType,
|
||||||
| 'name'
|
| 'name'
|
||||||
| 'actionGroups'
|
| 'actionGroups'
|
||||||
| 'recoveryActionGroup'
|
| 'recoveryActionGroup'
|
||||||
|
@ -57,26 +57,26 @@ export interface RegistryRuleType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AlertType IDs are used as part of the authorization strings used to
|
* RuleType IDs are used as part of the authorization strings used to
|
||||||
* grant users privileged operations. There is a limited range of characters
|
* grant users privileged operations. There is a limited range of characters
|
||||||
* we can use in these auth strings, so we apply these same limitations to
|
* we can use in these auth strings, so we apply these same limitations to
|
||||||
* the AlertType Ids.
|
* the RuleType Ids.
|
||||||
* If you wish to change this, please confer with the Kibana security team.
|
* If you wish to change this, please confer with the Kibana security team.
|
||||||
*/
|
*/
|
||||||
const alertIdSchema = schema.string({
|
const ruleTypeIdSchema = schema.string({
|
||||||
validate(value: string): string | void {
|
validate(value: string): string | void {
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return `expected AlertType Id of type [string] but got [${typeDetect(value)}]`;
|
return `expected RuleType Id of type [string] but got [${typeDetect(value)}]`;
|
||||||
} else if (!value.match(/^[a-zA-Z0-9_\-\.]*$/)) {
|
} else if (!value.match(/^[a-zA-Z0-9_\-\.]*$/)) {
|
||||||
const invalid = value.match(/[^a-zA-Z0-9_\-\.]+/g)!;
|
const invalid = value.match(/[^a-zA-Z0-9_\-\.]+/g)!;
|
||||||
return `expected AlertType Id not to include invalid character${
|
return `expected RuleType Id not to include invalid character${
|
||||||
invalid.length > 1 ? `s` : ``
|
invalid.length > 1 ? `s` : ``
|
||||||
}: ${invalid?.join(`, `)}`;
|
}: ${invalid?.join(`, `)}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export type NormalizedAlertType<
|
export type NormalizedRuleType<
|
||||||
Params extends AlertTypeParams,
|
Params extends AlertTypeParams,
|
||||||
ExtractedParams extends AlertTypeParams,
|
ExtractedParams extends AlertTypeParams,
|
||||||
State extends AlertTypeState,
|
State extends AlertTypeState,
|
||||||
|
@ -87,7 +87,7 @@ export type NormalizedAlertType<
|
||||||
> = {
|
> = {
|
||||||
actionGroups: Array<ActionGroup<ActionGroupIds | RecoveryActionGroupId>>;
|
actionGroups: Array<ActionGroup<ActionGroupIds | RecoveryActionGroupId>>;
|
||||||
} & Omit<
|
} & Omit<
|
||||||
AlertType<
|
RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -100,7 +100,7 @@ export type NormalizedAlertType<
|
||||||
> &
|
> &
|
||||||
Pick<
|
Pick<
|
||||||
Required<
|
Required<
|
||||||
AlertType<
|
RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -113,7 +113,7 @@ export type NormalizedAlertType<
|
||||||
'recoveryActionGroup'
|
'recoveryActionGroup'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type UntypedNormalizedAlertType = NormalizedAlertType<
|
export type UntypedNormalizedRuleType = NormalizedRuleType<
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -125,7 +125,7 @@ export type UntypedNormalizedAlertType = NormalizedAlertType<
|
||||||
|
|
||||||
export class RuleTypeRegistry {
|
export class RuleTypeRegistry {
|
||||||
private readonly taskManager: TaskManagerSetupContract;
|
private readonly taskManager: TaskManagerSetupContract;
|
||||||
private readonly ruleTypes: Map<string, UntypedNormalizedAlertType> = new Map();
|
private readonly ruleTypes: Map<string, UntypedNormalizedRuleType> = new Map();
|
||||||
private readonly taskRunnerFactory: TaskRunnerFactory;
|
private readonly taskRunnerFactory: TaskRunnerFactory;
|
||||||
private readonly licenseState: ILicenseState;
|
private readonly licenseState: ILicenseState;
|
||||||
private readonly licensing: LicensingPluginSetup;
|
private readonly licensing: LicensingPluginSetup;
|
||||||
|
@ -142,7 +142,7 @@ export class RuleTypeRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ensureRuleTypeEnabled(id: string) {
|
public ensureRuleTypeEnabled(id: string) {
|
||||||
this.licenseState.ensureLicenseForAlertType(this.get(id));
|
this.licenseState.ensureLicenseForRuleType(this.get(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public register<
|
public register<
|
||||||
|
@ -154,7 +154,7 @@ export class RuleTypeRegistry {
|
||||||
ActionGroupIds extends string,
|
ActionGroupIds extends string,
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
>(
|
>(
|
||||||
alertType: AlertType<
|
ruleType: RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -164,44 +164,44 @@ export class RuleTypeRegistry {
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>
|
>
|
||||||
) {
|
) {
|
||||||
if (this.has(alertType.id)) {
|
if (this.has(ruleType.id)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
i18n.translate('xpack.alerting.ruleTypeRegistry.register.duplicateAlertTypeError', {
|
i18n.translate('xpack.alerting.ruleTypeRegistry.register.duplicateRuleTypeError', {
|
||||||
defaultMessage: 'Rule type "{id}" is already registered.',
|
defaultMessage: 'Rule type "{id}" is already registered.',
|
||||||
values: {
|
values: {
|
||||||
id: alertType.id,
|
id: ruleType.id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// validate ruleTypeTimeout here
|
// validate ruleTypeTimeout here
|
||||||
if (alertType.ruleTaskTimeout) {
|
if (ruleType.ruleTaskTimeout) {
|
||||||
const invalidTimeout = validateDurationSchema(alertType.ruleTaskTimeout);
|
const invalidTimeout = validateDurationSchema(ruleType.ruleTaskTimeout);
|
||||||
if (invalidTimeout) {
|
if (invalidTimeout) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
i18n.translate('xpack.alerting.ruleTypeRegistry.register.invalidTimeoutAlertTypeError', {
|
i18n.translate('xpack.alerting.ruleTypeRegistry.register.invalidTimeoutRuleTypeError', {
|
||||||
defaultMessage: 'Rule type "{id}" has invalid timeout: {errorMessage}.',
|
defaultMessage: 'Rule type "{id}" has invalid timeout: {errorMessage}.',
|
||||||
values: {
|
values: {
|
||||||
id: alertType.id,
|
id: ruleType.id,
|
||||||
errorMessage: invalidTimeout,
|
errorMessage: invalidTimeout,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alertType.actionVariables = normalizedActionVariables(alertType.actionVariables);
|
ruleType.actionVariables = normalizedActionVariables(ruleType.actionVariables);
|
||||||
|
|
||||||
// validate defaultScheduleInterval here
|
// validate defaultScheduleInterval here
|
||||||
if (alertType.defaultScheduleInterval) {
|
if (ruleType.defaultScheduleInterval) {
|
||||||
const invalidDefaultTimeout = validateDurationSchema(alertType.defaultScheduleInterval);
|
const invalidDefaultTimeout = validateDurationSchema(ruleType.defaultScheduleInterval);
|
||||||
if (invalidDefaultTimeout) {
|
if (invalidDefaultTimeout) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
i18n.translate(
|
i18n.translate(
|
||||||
'xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutAlertTypeError',
|
'xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutRuleTypeError',
|
||||||
{
|
{
|
||||||
defaultMessage: 'Rule type "{id}" has invalid default interval: {errorMessage}.',
|
defaultMessage: 'Rule type "{id}" has invalid default interval: {errorMessage}.',
|
||||||
values: {
|
values: {
|
||||||
id: alertType.id,
|
id: ruleType.id,
|
||||||
errorMessage: invalidDefaultTimeout,
|
errorMessage: invalidDefaultTimeout,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -211,16 +211,16 @@ export class RuleTypeRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate minimumScheduleInterval here
|
// validate minimumScheduleInterval here
|
||||||
if (alertType.minimumScheduleInterval) {
|
if (ruleType.minimumScheduleInterval) {
|
||||||
const invalidMinimumTimeout = validateDurationSchema(alertType.minimumScheduleInterval);
|
const invalidMinimumTimeout = validateDurationSchema(ruleType.minimumScheduleInterval);
|
||||||
if (invalidMinimumTimeout) {
|
if (invalidMinimumTimeout) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
i18n.translate(
|
i18n.translate(
|
||||||
'xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutAlertTypeError',
|
'xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutRuleTypeError',
|
||||||
{
|
{
|
||||||
defaultMessage: 'Rule type "{id}" has invalid minimum interval: {errorMessage}.',
|
defaultMessage: 'Rule type "{id}" has invalid minimum interval: {errorMessage}.',
|
||||||
values: {
|
values: {
|
||||||
id: alertType.id,
|
id: ruleType.id,
|
||||||
errorMessage: invalidMinimumTimeout,
|
errorMessage: invalidMinimumTimeout,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ export class RuleTypeRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedAlertType = augmentActionGroupsWithReserved<
|
const normalizedRuleType = augmentActionGroupsWithReserved<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -237,17 +237,17 @@ export class RuleTypeRegistry {
|
||||||
InstanceContext,
|
InstanceContext,
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>(alertType);
|
>(ruleType);
|
||||||
|
|
||||||
this.ruleTypes.set(
|
this.ruleTypes.set(
|
||||||
alertIdSchema.validate(alertType.id),
|
ruleTypeIdSchema.validate(ruleType.id),
|
||||||
/** stripping the typing is required in order to store the AlertTypes in a Map */
|
/** stripping the typing is required in order to store the RuleTypes in a Map */
|
||||||
normalizedAlertType as unknown as UntypedNormalizedAlertType
|
normalizedRuleType as unknown as UntypedNormalizedRuleType
|
||||||
);
|
);
|
||||||
this.taskManager.registerTaskDefinitions({
|
this.taskManager.registerTaskDefinitions({
|
||||||
[`alerting:${alertType.id}`]: {
|
[`alerting:${ruleType.id}`]: {
|
||||||
title: alertType.name,
|
title: ruleType.name,
|
||||||
timeout: alertType.ruleTaskTimeout,
|
timeout: ruleType.ruleTaskTimeout,
|
||||||
createTaskRunner: (context: RunContext) =>
|
createTaskRunner: (context: RunContext) =>
|
||||||
this.taskRunnerFactory.create<
|
this.taskRunnerFactory.create<
|
||||||
Params,
|
Params,
|
||||||
|
@ -257,14 +257,14 @@ export class RuleTypeRegistry {
|
||||||
InstanceContext,
|
InstanceContext,
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveryActionGroupId | RecoveredActionGroupId
|
RecoveryActionGroupId | RecoveredActionGroupId
|
||||||
>(normalizedAlertType, context),
|
>(normalizedRuleType, context),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// No need to notify usage on basic alert types
|
// No need to notify usage on basic alert types
|
||||||
if (alertType.minimumLicenseRequired !== 'basic') {
|
if (ruleType.minimumLicenseRequired !== 'basic') {
|
||||||
this.licensing.featureUsage.register(
|
this.licensing.featureUsage.register(
|
||||||
getAlertTypeFeatureUsageName(alertType.name),
|
getRuleTypeFeatureUsageName(ruleType.name),
|
||||||
alertType.minimumLicenseRequired
|
ruleType.minimumLicenseRequired
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ export class RuleTypeRegistry {
|
||||||
RecoveryActionGroupId extends string = string
|
RecoveryActionGroupId extends string = string
|
||||||
>(
|
>(
|
||||||
id: string
|
id: string
|
||||||
): NormalizedAlertType<
|
): NormalizedRuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -290,7 +290,7 @@ export class RuleTypeRegistry {
|
||||||
> {
|
> {
|
||||||
if (!this.has(id)) {
|
if (!this.has(id)) {
|
||||||
throw Boom.badRequest(
|
throw Boom.badRequest(
|
||||||
i18n.translate('xpack.alerting.ruleTypeRegistry.get.missingAlertTypeError', {
|
i18n.translate('xpack.alerting.ruleTypeRegistry.get.missingRuleTypeError', {
|
||||||
defaultMessage: 'Rule type "{id}" is not registered.',
|
defaultMessage: 'Rule type "{id}" is not registered.',
|
||||||
values: {
|
values: {
|
||||||
id,
|
id,
|
||||||
|
@ -299,11 +299,11 @@ export class RuleTypeRegistry {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* When we store the AlertTypes in the Map we strip the typing.
|
* When we store the RuleTypes in the Map we strip the typing.
|
||||||
* This means that returning a typed AlertType in `get` is an inherently
|
* This means that returning a typed RuleType in `get` is an inherently
|
||||||
* unsafe operation. Down casting to `unknown` is the only way to achieve this.
|
* unsafe operation. Down casting to `unknown` is the only way to achieve this.
|
||||||
*/
|
*/
|
||||||
return this.ruleTypes.get(id)! as unknown as NormalizedAlertType<
|
return this.ruleTypes.get(id)! as unknown as NormalizedRuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -332,7 +332,7 @@ export class RuleTypeRegistry {
|
||||||
minimumScheduleInterval,
|
minimumScheduleInterval,
|
||||||
defaultScheduleInterval,
|
defaultScheduleInterval,
|
||||||
},
|
},
|
||||||
]: [string, UntypedNormalizedAlertType]) => ({
|
]: [string, UntypedNormalizedRuleType]) => ({
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
actionGroups,
|
actionGroups,
|
||||||
|
@ -345,7 +345,7 @@ export class RuleTypeRegistry {
|
||||||
ruleTaskTimeout,
|
ruleTaskTimeout,
|
||||||
minimumScheduleInterval,
|
minimumScheduleInterval,
|
||||||
defaultScheduleInterval,
|
defaultScheduleInterval,
|
||||||
enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType(
|
enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType(
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
minimumLicenseRequired
|
minimumLicenseRequired
|
||||||
|
@ -356,7 +356,7 @@ export class RuleTypeRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizedActionVariables(actionVariables: AlertType['actionVariables']) {
|
function normalizedActionVariables(actionVariables: RuleType['actionVariables']) {
|
||||||
return {
|
return {
|
||||||
context: actionVariables?.context ?? [],
|
context: actionVariables?.context ?? [],
|
||||||
state: actionVariables?.state ?? [],
|
state: actionVariables?.state ?? [],
|
||||||
|
@ -373,7 +373,7 @@ function augmentActionGroupsWithReserved<
|
||||||
ActionGroupIds extends string,
|
ActionGroupIds extends string,
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
>(
|
>(
|
||||||
alertType: AlertType<
|
ruleType: RuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -382,7 +382,7 @@ function augmentActionGroupsWithReserved<
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>
|
>
|
||||||
): NormalizedAlertType<
|
): NormalizedRuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -391,8 +391,8 @@ function augmentActionGroupsWithReserved<
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveredActionGroupId | RecoveryActionGroupId
|
RecoveredActionGroupId | RecoveryActionGroupId
|
||||||
> {
|
> {
|
||||||
const reservedActionGroups = getBuiltinActionGroups(alertType.recoveryActionGroup);
|
const reservedActionGroups = getBuiltinActionGroups(ruleType.recoveryActionGroup);
|
||||||
const { id, actionGroups, recoveryActionGroup } = alertType;
|
const { id, actionGroups, recoveryActionGroup } = ruleType;
|
||||||
|
|
||||||
const activeActionGroups = new Set<string>(actionGroups.map((item) => item.id));
|
const activeActionGroups = new Set<string>(actionGroups.map((item) => item.id));
|
||||||
const intersectingReservedActionGroups = intersection<string>(
|
const intersectingReservedActionGroups = intersection<string>(
|
||||||
|
@ -427,7 +427,7 @@ function augmentActionGroupsWithReserved<
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...alertType,
|
...ruleType,
|
||||||
actionGroups: [...actionGroups, ...reservedActionGroups],
|
actionGroups: [...actionGroups, ...reservedActionGroups],
|
||||||
recoveryActionGroup: recoveryActionGroup ?? RecoveredActionGroup,
|
recoveryActionGroup: recoveryActionGroup ?? RecoveredActionGroup,
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,27 +24,23 @@ import { ActionsClient, ActionsAuthorization } from '../../../actions/server';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
PartialAlert,
|
PartialAlert,
|
||||||
RawAlert,
|
RawRule,
|
||||||
RuleTypeRegistry,
|
RuleTypeRegistry,
|
||||||
AlertAction,
|
AlertAction,
|
||||||
IntervalSchedule,
|
IntervalSchedule,
|
||||||
SanitizedAlert,
|
SanitizedAlert,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
AlertSummary,
|
AlertSummary,
|
||||||
AlertExecutionStatusValues,
|
AlertExecutionStatusValues,
|
||||||
AlertNotifyWhenType,
|
AlertNotifyWhenType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
ResolvedSanitizedRule,
|
ResolvedSanitizedRule,
|
||||||
AlertWithLegacyId,
|
AlertWithLegacyId,
|
||||||
SanitizedAlertWithLegacyId,
|
SanitizedRuleWithLegacyId,
|
||||||
PartialAlertWithLegacyId,
|
PartialAlertWithLegacyId,
|
||||||
RawAlertInstance,
|
RawAlertInstance,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {
|
import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getAlertNotifyWhenType } from '../lib';
|
||||||
validateAlertTypeParams,
|
|
||||||
alertExecutionStatusFromRaw,
|
|
||||||
getAlertNotifyWhenType,
|
|
||||||
} from '../lib';
|
|
||||||
import {
|
import {
|
||||||
GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult,
|
GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult,
|
||||||
InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult,
|
InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult,
|
||||||
|
@ -52,7 +48,7 @@ import {
|
||||||
import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server';
|
import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server';
|
||||||
import { TaskManagerStartContract } from '../../../task_manager/server';
|
import { TaskManagerStartContract } from '../../../task_manager/server';
|
||||||
import { taskInstanceToAlertTaskInstance } from '../task_runner/alert_task_instance';
|
import { taskInstanceToAlertTaskInstance } from '../task_runner/alert_task_instance';
|
||||||
import { RegistryRuleType, UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { RegistryRuleType, UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
import {
|
import {
|
||||||
AlertingAuthorization,
|
AlertingAuthorization,
|
||||||
WriteOperations,
|
WriteOperations,
|
||||||
|
@ -77,7 +73,7 @@ import { markApiKeyForInvalidation } from '../invalidate_pending_api_keys/mark_a
|
||||||
import { ruleAuditEvent, RuleAuditAction } from './audit_events';
|
import { ruleAuditEvent, RuleAuditAction } from './audit_events';
|
||||||
import { KueryNode, nodeBuilder } from '../../../../../src/plugins/data/common';
|
import { KueryNode, nodeBuilder } from '../../../../../src/plugins/data/common';
|
||||||
import { mapSortField } from './lib';
|
import { mapSortField } from './lib';
|
||||||
import { getAlertExecutionStatusPending } from '../lib/alert_execution_status';
|
import { getRuleExecutionStatusPending } from '../lib/rule_execution_status';
|
||||||
import { AlertInstance } from '../alert_instance';
|
import { AlertInstance } from '../alert_instance';
|
||||||
import { EVENT_LOG_ACTIONS } from '../plugin';
|
import { EVENT_LOG_ACTIONS } from '../plugin';
|
||||||
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
||||||
|
@ -316,10 +312,7 @@ export class RulesClient {
|
||||||
// Throws an error if alert type isn't registered
|
// Throws an error if alert type isn't registered
|
||||||
const ruleType = this.ruleTypeRegistry.get(data.alertTypeId);
|
const ruleType = this.ruleTypeRegistry.get(data.alertTypeId);
|
||||||
|
|
||||||
const validatedAlertTypeParams = validateAlertTypeParams(
|
const validatedAlertTypeParams = validateRuleTypeParams(data.params, ruleType.validate?.params);
|
||||||
data.params,
|
|
||||||
ruleType.validate?.params
|
|
||||||
);
|
|
||||||
const username = await this.getUserName();
|
const username = await this.getUserName();
|
||||||
|
|
||||||
let createdAPIKey = null;
|
let createdAPIKey = null;
|
||||||
|
@ -355,7 +348,7 @@ export class RulesClient {
|
||||||
const legacyId = Semver.lt(this.kibanaVersion, '8.0.0') ? id : null;
|
const legacyId = Semver.lt(this.kibanaVersion, '8.0.0') ? id : null;
|
||||||
const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle);
|
const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle);
|
||||||
|
|
||||||
const rawAlert: RawAlert = {
|
const rawRule: RawRule = {
|
||||||
...data,
|
...data,
|
||||||
...this.apiKeyAsAlertAttributes(createdAPIKey, username),
|
...this.apiKeyAsAlertAttributes(createdAPIKey, username),
|
||||||
legacyId,
|
legacyId,
|
||||||
|
@ -364,11 +357,11 @@ export class RulesClient {
|
||||||
updatedBy: username,
|
updatedBy: username,
|
||||||
createdAt: new Date(createTime).toISOString(),
|
createdAt: new Date(createTime).toISOString(),
|
||||||
updatedAt: new Date(createTime).toISOString(),
|
updatedAt: new Date(createTime).toISOString(),
|
||||||
params: updatedParams as RawAlert['params'],
|
params: updatedParams as RawRule['params'],
|
||||||
muteAll: false,
|
muteAll: false,
|
||||||
mutedInstanceIds: [],
|
mutedInstanceIds: [],
|
||||||
notifyWhen,
|
notifyWhen,
|
||||||
executionStatus: getAlertExecutionStatusPending(new Date().toISOString()),
|
executionStatus: getRuleExecutionStatusPending(new Date().toISOString()),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.auditLogger?.log(
|
this.auditLogger?.log(
|
||||||
|
@ -379,11 +372,11 @@ export class RulesClient {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let createdAlert: SavedObject<RawAlert>;
|
let createdAlert: SavedObject<RawRule>;
|
||||||
try {
|
try {
|
||||||
createdAlert = await this.unsecuredSavedObjectsClient.create(
|
createdAlert = await this.unsecuredSavedObjectsClient.create(
|
||||||
'alert',
|
'alert',
|
||||||
this.updateMeta(rawAlert),
|
this.updateMeta(rawRule),
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
references,
|
references,
|
||||||
|
@ -393,7 +386,7 @@ export class RulesClient {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Avoid unused API key
|
// Avoid unused API key
|
||||||
markApiKeyForInvalidation(
|
markApiKeyForInvalidation(
|
||||||
{ apiKey: rawAlert.apiKey },
|
{ apiKey: rawRule.apiKey },
|
||||||
this.logger,
|
this.logger,
|
||||||
this.unsecuredSavedObjectsClient
|
this.unsecuredSavedObjectsClient
|
||||||
);
|
);
|
||||||
|
@ -404,7 +397,7 @@ export class RulesClient {
|
||||||
try {
|
try {
|
||||||
scheduledTask = await this.scheduleRule(
|
scheduledTask = await this.scheduleRule(
|
||||||
createdAlert.id,
|
createdAlert.id,
|
||||||
rawAlert.alertTypeId,
|
rawRule.alertTypeId,
|
||||||
data.schedule,
|
data.schedule,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
@ -420,7 +413,7 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
await this.unsecuredSavedObjectsClient.update<RawAlert>('alert', createdAlert.id, {
|
await this.unsecuredSavedObjectsClient.update<RawRule>('alert', createdAlert.id, {
|
||||||
scheduledTaskId: scheduledTask.id,
|
scheduledTaskId: scheduledTask.id,
|
||||||
});
|
});
|
||||||
createdAlert.attributes.scheduledTaskId = scheduledTask.id;
|
createdAlert.attributes.scheduledTaskId = scheduledTask.id;
|
||||||
|
@ -439,8 +432,8 @@ export class RulesClient {
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
includeLegacyId?: boolean;
|
includeLegacyId?: boolean;
|
||||||
}): Promise<SanitizedAlert<Params> | SanitizedAlertWithLegacyId<Params>> {
|
}): Promise<SanitizedAlert<Params> | SanitizedRuleWithLegacyId<Params>> {
|
||||||
const result = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
const result = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
try {
|
try {
|
||||||
await this.authorization.ensureAuthorized({
|
await this.authorization.ensureAuthorized({
|
||||||
ruleTypeId: result.attributes.alertTypeId,
|
ruleTypeId: result.attributes.alertTypeId,
|
||||||
|
@ -481,7 +474,7 @@ export class RulesClient {
|
||||||
includeLegacyId?: boolean;
|
includeLegacyId?: boolean;
|
||||||
}): Promise<ResolvedSanitizedRule<Params>> {
|
}): Promise<ResolvedSanitizedRule<Params>> {
|
||||||
const { saved_object: result, ...resolveResponse } =
|
const { saved_object: result, ...resolveResponse } =
|
||||||
await this.unsecuredSavedObjectsClient.resolve<RawAlert>('alert', id);
|
await this.unsecuredSavedObjectsClient.resolve<RawRule>('alert', id);
|
||||||
try {
|
try {
|
||||||
await this.authorization.ensureAuthorized({
|
await this.authorization.ensureAuthorized({
|
||||||
ruleTypeId: result.attributes.alertTypeId,
|
ruleTypeId: result.attributes.alertTypeId,
|
||||||
|
@ -520,7 +513,7 @@ export class RulesClient {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAlertState({ id }: { id: string }): Promise<AlertTaskState | void> {
|
public async getAlertState({ id }: { id: string }): Promise<RuleTaskState | void> {
|
||||||
const alert = await this.get({ id });
|
const alert = await this.get({ id });
|
||||||
await this.authorization.ensureAuthorized({
|
await this.authorization.ensureAuthorized({
|
||||||
ruleTypeId: alert.alertTypeId,
|
ruleTypeId: alert.alertTypeId,
|
||||||
|
@ -539,7 +532,7 @@ export class RulesClient {
|
||||||
|
|
||||||
public async getAlertSummary({ id, dateStart }: GetAlertSummaryParams): Promise<AlertSummary> {
|
public async getAlertSummary({ id, dateStart }: GetAlertSummaryParams): Promise<AlertSummary> {
|
||||||
this.logger.debug(`getAlertSummary(): getting alert ${id}`);
|
this.logger.debug(`getAlertSummary(): getting alert ${id}`);
|
||||||
const rule = (await this.get({ id, includeLegacyId: true })) as SanitizedAlertWithLegacyId;
|
const rule = (await this.get({ id, includeLegacyId: true })) as SanitizedRuleWithLegacyId;
|
||||||
|
|
||||||
await this.authorization.ensureAuthorized({
|
await this.authorization.ensureAuthorized({
|
||||||
ruleTypeId: rule.alertTypeId,
|
ruleTypeId: rule.alertTypeId,
|
||||||
|
@ -612,7 +605,7 @@ export class RulesClient {
|
||||||
per_page: perPage,
|
per_page: perPage,
|
||||||
total,
|
total,
|
||||||
saved_objects: data,
|
saved_objects: data,
|
||||||
} = await this.unsecuredSavedObjectsClient.find<RawAlert>({
|
} = await this.unsecuredSavedObjectsClient.find<RawRule>({
|
||||||
...options,
|
...options,
|
||||||
sortField: mapSortField(options.sortField),
|
sortField: mapSortField(options.sortField),
|
||||||
filter:
|
filter:
|
||||||
|
@ -646,7 +639,7 @@ export class RulesClient {
|
||||||
return this.getAlertFromRaw<Params>(
|
return this.getAlertFromRaw<Params>(
|
||||||
id,
|
id,
|
||||||
attributes.alertTypeId,
|
attributes.alertTypeId,
|
||||||
fields ? (pick(attributes, fields) as RawAlert) : attributes,
|
fields ? (pick(attributes, fields) as RawRule) : attributes,
|
||||||
references
|
references
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -687,7 +680,7 @@ export class RulesClient {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const { filter: authorizationFilter } = authorizationTuple;
|
const { filter: authorizationFilter } = authorizationTuple;
|
||||||
const resp = await this.unsecuredSavedObjectsClient.find<RawAlert, RuleAggregation>({
|
const resp = await this.unsecuredSavedObjectsClient.find<RawRule, RuleAggregation>({
|
||||||
...options,
|
...options,
|
||||||
filter:
|
filter:
|
||||||
(authorizationFilter && filter
|
(authorizationFilter && filter
|
||||||
|
@ -776,11 +769,11 @@ export class RulesClient {
|
||||||
private async deleteWithOCC({ id }: { id: string }) {
|
private async deleteWithOCC({ id }: { id: string }) {
|
||||||
let taskIdToRemove: string | undefined | null;
|
let taskIdToRemove: string | undefined | null;
|
||||||
let apiKeyToInvalidate: string | null = null;
|
let apiKeyToInvalidate: string | null = null;
|
||||||
let attributes: RawAlert;
|
let attributes: RawRule;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decryptedAlert =
|
const decryptedAlert =
|
||||||
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>('alert', id, {
|
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>('alert', id, {
|
||||||
namespace: this.namespace,
|
namespace: this.namespace,
|
||||||
});
|
});
|
||||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||||
|
@ -792,7 +785,7 @@ export class RulesClient {
|
||||||
`delete(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
`delete(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
||||||
);
|
);
|
||||||
// Still attempt to load the scheduledTaskId using SOC
|
// Still attempt to load the scheduledTaskId using SOC
|
||||||
const alert = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
const alert = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
taskIdToRemove = alert.attributes.scheduledTaskId;
|
taskIdToRemove = alert.attributes.scheduledTaskId;
|
||||||
attributes = alert.attributes;
|
attributes = alert.attributes;
|
||||||
}
|
}
|
||||||
|
@ -854,20 +847,23 @@ export class RulesClient {
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
|
}: UpdateOptions<Params>): Promise<PartialAlert<Params>> {
|
||||||
let alertSavedObject: SavedObject<RawAlert>;
|
let alertSavedObject: SavedObject<RawRule>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
alertSavedObject =
|
alertSavedObject = await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>(
|
||||||
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>('alert', id, {
|
'alert',
|
||||||
|
id,
|
||||||
|
{
|
||||||
namespace: this.namespace,
|
namespace: this.namespace,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// We'll skip invalidating the API key since we failed to load the decrypted saved object
|
// We'll skip invalidating the API key since we failed to load the decrypted saved object
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`update(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
`update(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
||||||
);
|
);
|
||||||
// Still attempt to load the object using SOC
|
// Still attempt to load the object using SOC
|
||||||
alertSavedObject = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
alertSavedObject = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -934,15 +930,12 @@ export class RulesClient {
|
||||||
|
|
||||||
private async updateAlert<Params extends AlertTypeParams>(
|
private async updateAlert<Params extends AlertTypeParams>(
|
||||||
{ id, data }: UpdateOptions<Params>,
|
{ id, data }: UpdateOptions<Params>,
|
||||||
{ attributes, version }: SavedObject<RawAlert>
|
{ attributes, version }: SavedObject<RawRule>
|
||||||
): Promise<PartialAlert<Params>> {
|
): Promise<PartialAlert<Params>> {
|
||||||
const ruleType = this.ruleTypeRegistry.get(attributes.alertTypeId);
|
const ruleType = this.ruleTypeRegistry.get(attributes.alertTypeId);
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
const validatedAlertTypeParams = validateAlertTypeParams(
|
const validatedAlertTypeParams = validateRuleTypeParams(data.params, ruleType.validate?.params);
|
||||||
data.params,
|
|
||||||
ruleType.validate?.params
|
|
||||||
);
|
|
||||||
await this.validateActions(ruleType, data.actions);
|
await this.validateActions(ruleType, data.actions);
|
||||||
|
|
||||||
// Validate intervals, if configured
|
// Validate intervals, if configured
|
||||||
|
@ -977,19 +970,19 @@ export class RulesClient {
|
||||||
const apiKeyAttributes = this.apiKeyAsAlertAttributes(createdAPIKey, username);
|
const apiKeyAttributes = this.apiKeyAsAlertAttributes(createdAPIKey, username);
|
||||||
const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle);
|
const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle);
|
||||||
|
|
||||||
let updatedObject: SavedObject<RawAlert>;
|
let updatedObject: SavedObject<RawRule>;
|
||||||
const createAttributes = this.updateMeta({
|
const createAttributes = this.updateMeta({
|
||||||
...attributes,
|
...attributes,
|
||||||
...data,
|
...data,
|
||||||
...apiKeyAttributes,
|
...apiKeyAttributes,
|
||||||
params: updatedParams as RawAlert['params'],
|
params: updatedParams as RawRule['params'],
|
||||||
actions,
|
actions,
|
||||||
notifyWhen,
|
notifyWhen,
|
||||||
updatedBy: username,
|
updatedBy: username,
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
updatedObject = await this.unsecuredSavedObjectsClient.create<RawAlert>(
|
updatedObject = await this.unsecuredSavedObjectsClient.create<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
createAttributes,
|
createAttributes,
|
||||||
{
|
{
|
||||||
|
@ -1020,7 +1013,7 @@ export class RulesClient {
|
||||||
private apiKeyAsAlertAttributes(
|
private apiKeyAsAlertAttributes(
|
||||||
apiKey: CreateAPIKeyResult | null,
|
apiKey: CreateAPIKeyResult | null,
|
||||||
username: string | null
|
username: string | null
|
||||||
): Pick<RawAlert, 'apiKey' | 'apiKeyOwner'> {
|
): Pick<RawRule, 'apiKey' | 'apiKeyOwner'> {
|
||||||
return apiKey && apiKey.apiKeysEnabled
|
return apiKey && apiKey.apiKeysEnabled
|
||||||
? {
|
? {
|
||||||
apiKeyOwner: username,
|
apiKeyOwner: username,
|
||||||
|
@ -1042,12 +1035,12 @@ export class RulesClient {
|
||||||
|
|
||||||
private async updateApiKeyWithOCC({ id }: { id: string }) {
|
private async updateApiKeyWithOCC({ id }: { id: string }) {
|
||||||
let apiKeyToInvalidate: string | null = null;
|
let apiKeyToInvalidate: string | null = null;
|
||||||
let attributes: RawAlert;
|
let attributes: RawRule;
|
||||||
let version: string | undefined;
|
let version: string | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decryptedAlert =
|
const decryptedAlert =
|
||||||
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>('alert', id, {
|
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>('alert', id, {
|
||||||
namespace: this.namespace,
|
namespace: this.namespace,
|
||||||
});
|
});
|
||||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||||
|
@ -1059,7 +1052,7 @@ export class RulesClient {
|
||||||
`updateApiKey(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
`updateApiKey(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
||||||
);
|
);
|
||||||
// Still attempt to load the attributes and version using SOC
|
// Still attempt to load the attributes and version using SOC
|
||||||
const alert = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
const alert = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
attributes = alert.attributes;
|
attributes = alert.attributes;
|
||||||
version = alert.version;
|
version = alert.version;
|
||||||
}
|
}
|
||||||
|
@ -1146,12 +1139,12 @@ export class RulesClient {
|
||||||
|
|
||||||
private async enableWithOCC({ id }: { id: string }) {
|
private async enableWithOCC({ id }: { id: string }) {
|
||||||
let apiKeyToInvalidate: string | null = null;
|
let apiKeyToInvalidate: string | null = null;
|
||||||
let attributes: RawAlert;
|
let attributes: RawRule;
|
||||||
let version: string | undefined;
|
let version: string | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decryptedAlert =
|
const decryptedAlert =
|
||||||
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>('alert', id, {
|
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>('alert', id, {
|
||||||
namespace: this.namespace,
|
namespace: this.namespace,
|
||||||
});
|
});
|
||||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||||
|
@ -1163,7 +1156,7 @@ export class RulesClient {
|
||||||
`enable(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
`enable(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
||||||
);
|
);
|
||||||
// Still attempt to load the attributes and version using SOC
|
// Still attempt to load the attributes and version using SOC
|
||||||
const alert = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
const alert = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
attributes = alert.attributes;
|
attributes = alert.attributes;
|
||||||
version = alert.version;
|
version = alert.version;
|
||||||
}
|
}
|
||||||
|
@ -1265,12 +1258,12 @@ export class RulesClient {
|
||||||
|
|
||||||
private async disableWithOCC({ id }: { id: string }) {
|
private async disableWithOCC({ id }: { id: string }) {
|
||||||
let apiKeyToInvalidate: string | null = null;
|
let apiKeyToInvalidate: string | null = null;
|
||||||
let attributes: RawAlert;
|
let attributes: RawRule;
|
||||||
let version: string | undefined;
|
let version: string | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decryptedAlert =
|
const decryptedAlert =
|
||||||
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawAlert>('alert', id, {
|
await this.encryptedSavedObjectsClient.getDecryptedAsInternalUser<RawRule>('alert', id, {
|
||||||
namespace: this.namespace,
|
namespace: this.namespace,
|
||||||
});
|
});
|
||||||
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
apiKeyToInvalidate = decryptedAlert.attributes.apiKey;
|
||||||
|
@ -1282,7 +1275,7 @@ export class RulesClient {
|
||||||
`disable(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
`disable(): Failed to load API key to invalidate on alert ${id}: ${e.message}`
|
||||||
);
|
);
|
||||||
// Still attempt to load the attributes and version using SOC
|
// Still attempt to load the attributes and version using SOC
|
||||||
const alert = await this.unsecuredSavedObjectsClient.get<RawAlert>('alert', id);
|
const alert = await this.unsecuredSavedObjectsClient.get<RawRule>('alert', id);
|
||||||
attributes = alert.attributes;
|
attributes = alert.attributes;
|
||||||
version = alert.version;
|
version = alert.version;
|
||||||
}
|
}
|
||||||
|
@ -1403,7 +1396,7 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async muteAllWithOCC({ id }: { id: string }) {
|
private async muteAllWithOCC({ id }: { id: string }) {
|
||||||
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<RawAlert>(
|
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
@ -1465,7 +1458,7 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async unmuteAllWithOCC({ id }: { id: string }) {
|
private async unmuteAllWithOCC({ id }: { id: string }) {
|
||||||
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<RawAlert>(
|
const { attributes, version } = await this.unsecuredSavedObjectsClient.get<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
@ -1633,7 +1626,7 @@ export class RulesClient {
|
||||||
|
|
||||||
const mutedInstanceIds = attributes.mutedInstanceIds || [];
|
const mutedInstanceIds = attributes.mutedInstanceIds || [];
|
||||||
if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) {
|
if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) {
|
||||||
await this.unsecuredSavedObjectsClient.update<RawAlert>(
|
await this.unsecuredSavedObjectsClient.update<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
alertId,
|
alertId,
|
||||||
this.updateMeta({
|
this.updateMeta({
|
||||||
|
@ -1691,7 +1684,7 @@ export class RulesClient {
|
||||||
|
|
||||||
private injectReferencesIntoActions(
|
private injectReferencesIntoActions(
|
||||||
alertId: string,
|
alertId: string,
|
||||||
actions: RawAlert['actions'],
|
actions: RawRule['actions'],
|
||||||
references: SavedObjectReference[]
|
references: SavedObjectReference[]
|
||||||
) {
|
) {
|
||||||
return actions.map((action) => {
|
return actions.map((action) => {
|
||||||
|
@ -1716,18 +1709,18 @@ export class RulesClient {
|
||||||
private getAlertFromRaw<Params extends AlertTypeParams>(
|
private getAlertFromRaw<Params extends AlertTypeParams>(
|
||||||
id: string,
|
id: string,
|
||||||
ruleTypeId: string,
|
ruleTypeId: string,
|
||||||
rawAlert: RawAlert,
|
rawRule: RawRule,
|
||||||
references: SavedObjectReference[] | undefined,
|
references: SavedObjectReference[] | undefined,
|
||||||
includeLegacyId: boolean = false
|
includeLegacyId: boolean = false
|
||||||
): Alert | AlertWithLegacyId {
|
): Alert | AlertWithLegacyId {
|
||||||
const ruleType = this.ruleTypeRegistry.get(ruleTypeId);
|
const ruleType = this.ruleTypeRegistry.get(ruleTypeId);
|
||||||
// In order to support the partial update API of Saved Objects we have to support
|
// In order to support the partial update API of Saved Objects we have to support
|
||||||
// partial updates of an Alert, but when we receive an actual RawAlert, it is safe
|
// partial updates of an Alert, but when we receive an actual RawRule, it is safe
|
||||||
// to cast the result to an Alert
|
// to cast the result to an Alert
|
||||||
const res = this.getPartialAlertFromRaw<Params>(
|
const res = this.getPartialAlertFromRaw<Params>(
|
||||||
id,
|
id,
|
||||||
ruleType,
|
ruleType,
|
||||||
rawAlert,
|
rawRule,
|
||||||
references,
|
references,
|
||||||
includeLegacyId
|
includeLegacyId
|
||||||
);
|
);
|
||||||
|
@ -1741,7 +1734,7 @@ export class RulesClient {
|
||||||
|
|
||||||
private getPartialAlertFromRaw<Params extends AlertTypeParams>(
|
private getPartialAlertFromRaw<Params extends AlertTypeParams>(
|
||||||
id: string,
|
id: string,
|
||||||
ruleType: UntypedNormalizedAlertType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
{
|
{
|
||||||
createdAt,
|
createdAt,
|
||||||
updatedAt,
|
updatedAt,
|
||||||
|
@ -1753,15 +1746,15 @@ export class RulesClient {
|
||||||
executionStatus,
|
executionStatus,
|
||||||
schedule,
|
schedule,
|
||||||
actions,
|
actions,
|
||||||
...partialRawAlert
|
...partialRawRule
|
||||||
}: Partial<RawAlert>,
|
}: Partial<RawRule>,
|
||||||
references: SavedObjectReference[] | undefined,
|
references: SavedObjectReference[] | undefined,
|
||||||
includeLegacyId: boolean = false
|
includeLegacyId: boolean = false
|
||||||
): PartialAlert<Params> | PartialAlertWithLegacyId<Params> {
|
): PartialAlert<Params> | PartialAlertWithLegacyId<Params> {
|
||||||
const rule = {
|
const rule = {
|
||||||
id,
|
id,
|
||||||
notifyWhen,
|
notifyWhen,
|
||||||
...partialRawAlert,
|
...partialRawRule,
|
||||||
// we currently only support the Interval Schedule type
|
// we currently only support the Interval Schedule type
|
||||||
// Once we support additional types, this type signature will likely change
|
// Once we support additional types, this type signature will likely change
|
||||||
schedule: schedule as IntervalSchedule,
|
schedule: schedule as IntervalSchedule,
|
||||||
|
@ -1771,7 +1764,7 @@ export class RulesClient {
|
||||||
...(createdAt ? { createdAt: new Date(createdAt) } : {}),
|
...(createdAt ? { createdAt: new Date(createdAt) } : {}),
|
||||||
...(scheduledTaskId ? { scheduledTaskId } : {}),
|
...(scheduledTaskId ? { scheduledTaskId } : {}),
|
||||||
...(executionStatus
|
...(executionStatus
|
||||||
? { executionStatus: alertExecutionStatusFromRaw(this.logger, id, executionStatus) }
|
? { executionStatus: ruleExecutionStatusFromRaw(this.logger, id, executionStatus) }
|
||||||
: {}),
|
: {}),
|
||||||
};
|
};
|
||||||
return includeLegacyId
|
return includeLegacyId
|
||||||
|
@ -1780,7 +1773,7 @@ export class RulesClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateActions(
|
private async validateActions(
|
||||||
alertType: UntypedNormalizedAlertType,
|
alertType: UntypedNormalizedRuleType,
|
||||||
actions: NormalizedAlertAction[]
|
actions: NormalizedAlertAction[]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (actions.length === 0) {
|
if (actions.length === 0) {
|
||||||
|
@ -1831,11 +1824,11 @@ export class RulesClient {
|
||||||
Params extends AlertTypeParams,
|
Params extends AlertTypeParams,
|
||||||
ExtractedParams extends AlertTypeParams
|
ExtractedParams extends AlertTypeParams
|
||||||
>(
|
>(
|
||||||
ruleType: UntypedNormalizedAlertType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
ruleActions: NormalizedAlertAction[],
|
ruleActions: NormalizedAlertAction[],
|
||||||
ruleParams: Params
|
ruleParams: Params
|
||||||
): Promise<{
|
): Promise<{
|
||||||
actions: RawAlert['actions'];
|
actions: RawRule['actions'];
|
||||||
params: ExtractedParams;
|
params: ExtractedParams;
|
||||||
references: SavedObjectReference[];
|
references: SavedObjectReference[];
|
||||||
}> {
|
}> {
|
||||||
|
@ -1868,7 +1861,7 @@ export class RulesClient {
|
||||||
ExtractedParams extends AlertTypeParams
|
ExtractedParams extends AlertTypeParams
|
||||||
>(
|
>(
|
||||||
ruleId: string,
|
ruleId: string,
|
||||||
ruleType: UntypedNormalizedAlertType,
|
ruleType: UntypedNormalizedRuleType,
|
||||||
ruleParams: SavedObjectAttributes | undefined,
|
ruleParams: SavedObjectAttributes | undefined,
|
||||||
references: SavedObjectReference[]
|
references: SavedObjectReference[]
|
||||||
): Params {
|
): Params {
|
||||||
|
@ -1896,9 +1889,9 @@ export class RulesClient {
|
||||||
|
|
||||||
private async denormalizeActions(
|
private async denormalizeActions(
|
||||||
alertActions: NormalizedAlertAction[]
|
alertActions: NormalizedAlertAction[]
|
||||||
): Promise<{ actions: RawAlert['actions']; references: SavedObjectReference[] }> {
|
): Promise<{ actions: RawRule['actions']; references: SavedObjectReference[] }> {
|
||||||
const references: SavedObjectReference[] = [];
|
const references: SavedObjectReference[] = [];
|
||||||
const actions: RawAlert['actions'] = [];
|
const actions: RawRule['actions'] = [];
|
||||||
if (alertActions.length) {
|
if (alertActions.length) {
|
||||||
const actionsClient = await this.getActionsClient();
|
const actionsClient = await this.getActionsClient();
|
||||||
const actionIds = [...new Set(alertActions.map((alertAction) => alertAction.id))];
|
const actionIds = [...new Set(alertActions.map((alertAction) => alertAction.id))];
|
||||||
|
@ -1953,7 +1946,7 @@ export class RulesClient {
|
||||||
return truncate(`Alerting: ${alertTypeId}/${trim(alertName)}`, { length: 256 });
|
return truncate(`Alerting: ${alertTypeId}/${trim(alertName)}`, { length: 256 });
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateMeta<T extends Partial<RawAlert>>(alertAttributes: T): T {
|
private updateMeta<T extends Partial<RawRule>>(alertAttributes: T): T {
|
||||||
if (alertAttributes.hasOwnProperty('apiKey') || alertAttributes.hasOwnProperty('apiKeyOwner')) {
|
if (alertAttributes.hasOwnProperty('apiKey') || alertAttributes.hasOwnProperty('apiKeyOwner')) {
|
||||||
alertAttributes.meta = alertAttributes.meta ?? {};
|
alertAttributes.meta = alertAttributes.meta ?? {};
|
||||||
alertAttributes.meta.versionApiKeyLastmodified = this.kibanaVersion;
|
alertAttributes.meta.versionApiKeyLastmodified = this.kibanaVersion;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { eventLogClientMock } from '../../../../event_log/server/mocks';
|
||||||
import { QueryEventsBySavedObjectResult } from '../../../../event_log/server';
|
import { QueryEventsBySavedObjectResult } from '../../../../event_log/server';
|
||||||
import { SavedObject } from 'kibana/server';
|
import { SavedObject } from 'kibana/server';
|
||||||
import { EventsFactory } from '../../lib/alert_summary_from_event_log.test';
|
import { EventsFactory } from '../../lib/alert_summary_from_event_log.test';
|
||||||
import { RawAlert } from '../../types';
|
import { RawRule } from '../../types';
|
||||||
import { getBeforeSetup, mockedDateString, setGlobalDate } from './lib';
|
import { getBeforeSetup, mockedDateString, setGlobalDate } from './lib';
|
||||||
|
|
||||||
const taskManager = taskManagerMock.createStart();
|
const taskManager = taskManagerMock.createStart();
|
||||||
|
@ -64,7 +64,7 @@ const AlertSummaryFindEventsResult: QueryEventsBySavedObjectResult = {
|
||||||
|
|
||||||
const RuleIntervalSeconds = 1;
|
const RuleIntervalSeconds = 1;
|
||||||
|
|
||||||
const BaseRuleSavedObject: SavedObject<RawAlert> = {
|
const BaseRuleSavedObject: SavedObject<RawRule> = {
|
||||||
id: '1',
|
id: '1',
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -96,7 +96,7 @@ const BaseRuleSavedObject: SavedObject<RawAlert> = {
|
||||||
references: [],
|
references: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
function getRuleSavedObject(attributes: Partial<RawAlert> = {}): SavedObject<RawAlert> {
|
function getRuleSavedObject(attributes: Partial<RawRule> = {}): SavedObject<RawRule> {
|
||||||
return {
|
return {
|
||||||
...BaseRuleSavedObject,
|
...BaseRuleSavedObject,
|
||||||
attributes: { ...BaseRuleSavedObject.attributes, ...attributes },
|
attributes: { ...BaseRuleSavedObject.attributes, ...attributes },
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
} from 'kibana/server';
|
} from 'kibana/server';
|
||||||
import { AlertTypeParams } from '../../index';
|
import { AlertTypeParams } from '../../index';
|
||||||
import { Query } from '../../../../../../src/plugins/data/common/query';
|
import { Query } from '../../../../../../src/plugins/data/common/query';
|
||||||
import { RawAlert } from '../../types';
|
import { RawRule } from '../../types';
|
||||||
|
|
||||||
// These definitions are dupes of the SO-types in stack_alerts/geo_containment
|
// These definitions are dupes of the SO-types in stack_alerts/geo_containment
|
||||||
// There are not exported to avoid deep imports from stack_alerts plugins into here
|
// There are not exported to avoid deep imports from stack_alerts plugins into here
|
||||||
|
@ -69,8 +69,8 @@ export function extractEntityAndBoundaryReferences(params: GeoContainmentParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractRefsFromGeoContainmentAlert(
|
export function extractRefsFromGeoContainmentAlert(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
if (doc.attributes.alertTypeId !== GEO_CONTAINMENT_ID) {
|
if (doc.attributes.alertTypeId !== GEO_CONTAINMENT_ID) {
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObject } from 'kibana/server';
|
import { SavedObject } from 'kibana/server';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
import { getImportWarnings } from './get_import_warnings';
|
import { getImportWarnings } from './get_import_warnings';
|
||||||
|
|
||||||
describe('getImportWarnings', () => {
|
describe('getImportWarnings', () => {
|
||||||
|
@ -71,13 +71,13 @@ describe('getImportWarnings', () => {
|
||||||
references: [],
|
references: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const warnings = getImportWarnings(savedObjectRules as unknown as Array<SavedObject<RawAlert>>);
|
const warnings = getImportWarnings(savedObjectRules as unknown as Array<SavedObject<RawRule>>);
|
||||||
expect(warnings[0].message).toBe('2 rules must be enabled after the import.');
|
expect(warnings[0].message).toBe('2 rules must be enabled after the import.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('return no warning messages if no rules were imported', () => {
|
it('return no warning messages if no rules were imported', () => {
|
||||||
const savedObjectRules = [] as Array<SavedObject<RawAlert>>;
|
const savedObjectRules = [] as Array<SavedObject<RawRule>>;
|
||||||
const warnings = getImportWarnings(savedObjectRules as unknown as Array<SavedObject<RawAlert>>);
|
const warnings = getImportWarnings(savedObjectRules as unknown as Array<SavedObject<RawRule>>);
|
||||||
expect(warnings.length).toBe(0);
|
expect(warnings.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@ import mappings from './mappings.json';
|
||||||
import { getMigrations } from './migrations';
|
import { getMigrations } from './migrations';
|
||||||
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
|
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
|
||||||
import { transformRulesForExport } from './transform_rule_for_export';
|
import { transformRulesForExport } from './transform_rule_for_export';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
import { getImportWarnings } from './get_import_warnings';
|
import { getImportWarnings } from './get_import_warnings';
|
||||||
import { isRuleExportable } from './is_rule_exportable';
|
import { isRuleExportable } from './is_rule_exportable';
|
||||||
import { RuleTypeRegistry } from '../rule_type_registry';
|
import { RuleTypeRegistry } from '../rule_type_registry';
|
||||||
|
@ -60,7 +60,7 @@ export function setupSavedObjects(
|
||||||
management: {
|
management: {
|
||||||
displayName: 'rule',
|
displayName: 'rule',
|
||||||
importableAndExportable: true,
|
importableAndExportable: true,
|
||||||
getTitle(ruleSavedObject: SavedObject<RawAlert>) {
|
getTitle(ruleSavedObject: SavedObject<RawRule>) {
|
||||||
return `Rule: [${ruleSavedObject.attributes.name}]`;
|
return `Rule: [${ruleSavedObject.attributes.name}]`;
|
||||||
},
|
},
|
||||||
onImport(ruleSavedObjects) {
|
onImport(ruleSavedObjects) {
|
||||||
|
@ -68,13 +68,13 @@ export function setupSavedObjects(
|
||||||
warnings: getImportWarnings(ruleSavedObjects),
|
warnings: getImportWarnings(ruleSavedObjects),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onExport<RawAlert>(
|
onExport<RawRule>(
|
||||||
context: SavedObjectsExportTransformContext,
|
context: SavedObjectsExportTransformContext,
|
||||||
objects: Array<SavedObject<RawAlert>>
|
objects: Array<SavedObject<RawRule>>
|
||||||
) {
|
) {
|
||||||
return transformRulesForExport(objects);
|
return transformRulesForExport(objects);
|
||||||
},
|
},
|
||||||
isExportable<RawAlert>(ruleSavedObject: SavedObject<RawAlert>) {
|
isExportable<RawRule>(ruleSavedObject: SavedObject<RawRule>) {
|
||||||
return isRuleExportable(ruleSavedObject, ruleTypeRegistry, logger);
|
return isRuleExportable(ruleSavedObject, ruleTypeRegistry, logger);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Logger, SavedObject } from 'kibana/server';
|
import { Logger, SavedObject } from 'kibana/server';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
import { RuleTypeRegistry } from '../rule_type_registry';
|
import { RuleTypeRegistry } from '../rule_type_registry';
|
||||||
|
|
||||||
export function isRuleExportable(
|
export function isRuleExportable(
|
||||||
|
@ -14,7 +14,7 @@ export function isRuleExportable(
|
||||||
ruleTypeRegistry: RuleTypeRegistry,
|
ruleTypeRegistry: RuleTypeRegistry,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
): boolean {
|
): boolean {
|
||||||
const ruleSO = rule as SavedObject<RawAlert>;
|
const ruleSO = rule as SavedObject<RawRule>;
|
||||||
try {
|
try {
|
||||||
const ruleType = ruleTypeRegistry.get(ruleSO.attributes.alertTypeId);
|
const ruleType = ruleTypeRegistry.get(ruleSO.attributes.alertTypeId);
|
||||||
if (!ruleType.isExportable) {
|
if (!ruleType.isExportable) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
import { getMigrations, isAnyActionSupportIncidents } from './migrations';
|
import { getMigrations, isAnyActionSupportIncidents } from './migrations';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
import { SavedObjectUnsanitizedDoc } from 'kibana/server';
|
import { SavedObjectUnsanitizedDoc } from 'kibana/server';
|
||||||
import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks';
|
import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks';
|
||||||
import { migrationMocks } from 'src/core/server/mocks';
|
import { migrationMocks } from 'src/core/server/mocks';
|
||||||
|
@ -512,7 +512,7 @@ describe('successful migrations', () => {
|
||||||
(actionTypeId) => {
|
(actionTypeId) => {
|
||||||
const doc = {
|
const doc = {
|
||||||
attributes: { actions: [{ actionTypeId }, { actionTypeId: '.server-log' }] },
|
attributes: { actions: [{ actionTypeId }, { actionTypeId: '.server-log' }] },
|
||||||
} as SavedObjectUnsanitizedDoc<RawAlert>;
|
} as SavedObjectUnsanitizedDoc<RawRule>;
|
||||||
expect(isAnyActionSupportIncidents(doc)).toBe(true);
|
expect(isAnyActionSupportIncidents(doc)).toBe(true);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -520,7 +520,7 @@ describe('successful migrations', () => {
|
||||||
test('isAnyActionSupportIncidents should return false when there is no connector that supports incidents', () => {
|
test('isAnyActionSupportIncidents should return false when there is no connector that supports incidents', () => {
|
||||||
const doc = {
|
const doc = {
|
||||||
attributes: { actions: [{ actionTypeId: '.server-log' }] },
|
attributes: { actions: [{ actionTypeId: '.server-log' }] },
|
||||||
} as SavedObjectUnsanitizedDoc<RawAlert>;
|
} as SavedObjectUnsanitizedDoc<RawRule>;
|
||||||
expect(isAnyActionSupportIncidents(doc)).toBe(false);
|
expect(isAnyActionSupportIncidents(doc)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2254,7 +2254,7 @@ function getUpdatedAt(): string {
|
||||||
function getMockData(
|
function getMockData(
|
||||||
overwrites: Record<string, unknown> = {},
|
overwrites: Record<string, unknown> = {},
|
||||||
withSavedObjectUpdatedAt: boolean = false
|
withSavedObjectUpdatedAt: boolean = false
|
||||||
): SavedObjectUnsanitizedDoc<Partial<RawAlert>> {
|
): SavedObjectUnsanitizedDoc<Partial<RawRule>> {
|
||||||
return {
|
return {
|
||||||
attributes: {
|
attributes: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
SavedObjectAttribute,
|
SavedObjectAttribute,
|
||||||
SavedObjectReference,
|
SavedObjectReference,
|
||||||
} from '../../../../../src/core/server';
|
} from '../../../../../src/core/server';
|
||||||
import { RawAlert, RawAlertAction } from '../types';
|
import { RawRule, RawAlertAction } from '../types';
|
||||||
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
|
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
|
||||||
import type { IsMigrationNeededPredicate } from '../../../encrypted_saved_objects/server';
|
import type { IsMigrationNeededPredicate } from '../../../encrypted_saved_objects/server';
|
||||||
import { extractRefsFromGeoContainmentAlert } from './geo_containment/migrations';
|
import { extractRefsFromGeoContainmentAlert } from './geo_containment/migrations';
|
||||||
|
@ -28,19 +28,19 @@ export const LEGACY_LAST_MODIFIED_VERSION = 'pre-7.10.0';
|
||||||
export const FILEBEAT_7X_INDICATOR_PATH = 'threatintel.indicator';
|
export const FILEBEAT_7X_INDICATOR_PATH = 'threatintel.indicator';
|
||||||
|
|
||||||
interface AlertLogMeta extends LogMeta {
|
interface AlertLogMeta extends LogMeta {
|
||||||
migrations: { alertDocument: SavedObjectUnsanitizedDoc<RawAlert> };
|
migrations: { alertDocument: SavedObjectUnsanitizedDoc<RawRule> };
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertMigration = (
|
type AlertMigration = (
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
) => SavedObjectUnsanitizedDoc<RawAlert>;
|
) => SavedObjectUnsanitizedDoc<RawRule>;
|
||||||
|
|
||||||
function createEsoMigration(
|
function createEsoMigration(
|
||||||
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup,
|
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup,
|
||||||
isMigrationNeededPredicate: IsMigrationNeededPredicate<RawAlert, RawAlert>,
|
isMigrationNeededPredicate: IsMigrationNeededPredicate<RawRule, RawRule>,
|
||||||
migrationFunc: AlertMigration
|
migrationFunc: AlertMigration
|
||||||
) {
|
) {
|
||||||
return encryptedSavedObjects.createMigration<RawAlert, RawAlert>({
|
return encryptedSavedObjects.createMigration<RawRule, RawRule>({
|
||||||
isMigrationNeededPredicate,
|
isMigrationNeededPredicate,
|
||||||
migration: migrationFunc,
|
migration: migrationFunc,
|
||||||
shouldMigrateIfDecryptionFails: true, // shouldMigrateIfDecryptionFails flag that applies the migration to undecrypted document if decryption fails
|
shouldMigrateIfDecryptionFails: true, // shouldMigrateIfDecryptionFails flag that applies the migration to undecrypted document if decryption fails
|
||||||
|
@ -49,13 +49,13 @@ function createEsoMigration(
|
||||||
|
|
||||||
const SUPPORT_INCIDENTS_ACTION_TYPES = ['.servicenow', '.jira', '.resilient'];
|
const SUPPORT_INCIDENTS_ACTION_TYPES = ['.servicenow', '.jira', '.resilient'];
|
||||||
|
|
||||||
export const isAnyActionSupportIncidents = (doc: SavedObjectUnsanitizedDoc<RawAlert>): boolean =>
|
export const isAnyActionSupportIncidents = (doc: SavedObjectUnsanitizedDoc<RawRule>): boolean =>
|
||||||
doc.attributes.actions.some((action) =>
|
doc.attributes.actions.some((action) =>
|
||||||
SUPPORT_INCIDENTS_ACTION_TYPES.includes(action.actionTypeId)
|
SUPPORT_INCIDENTS_ACTION_TYPES.includes(action.actionTypeId)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Deprecated in 8.0
|
// Deprecated in 8.0
|
||||||
export const isSiemSignalsRuleType = (doc: SavedObjectUnsanitizedDoc<RawAlert>): boolean =>
|
export const isSiemSignalsRuleType = (doc: SavedObjectUnsanitizedDoc<RawRule>): boolean =>
|
||||||
doc.attributes.alertTypeId === 'siem.signals';
|
doc.attributes.alertTypeId === 'siem.signals';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,7 +66,7 @@ export const isSiemSignalsRuleType = (doc: SavedObjectUnsanitizedDoc<RawAlert>):
|
||||||
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
||||||
*/
|
*/
|
||||||
export const isSecuritySolutionLegacyNotification = (
|
export const isSecuritySolutionLegacyNotification = (
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): boolean => doc.attributes.alertTypeId === 'siem.notifications';
|
): boolean => doc.attributes.alertTypeId === 'siem.notifications';
|
||||||
|
|
||||||
export function getMigrations(
|
export function getMigrations(
|
||||||
|
@ -76,7 +76,7 @@ export function getMigrations(
|
||||||
const migrationWhenRBACWasIntroduced = createEsoMigration(
|
const migrationWhenRBACWasIntroduced = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
// migrate all documents in 7.10 in order to add the "meta" RBAC field
|
// migrate all documents in 7.10 in order to add the "meta" RBAC field
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => true,
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
|
||||||
pipeMigrations(
|
pipeMigrations(
|
||||||
markAsLegacyAndChangeConsumer,
|
markAsLegacyAndChangeConsumer,
|
||||||
setAlertIdAsDefaultDedupkeyOnPagerDutyActions,
|
setAlertIdAsDefaultDedupkeyOnPagerDutyActions,
|
||||||
|
@ -87,37 +87,37 @@ export function getMigrations(
|
||||||
const migrationAlertUpdatedAtAndNotifyWhen = createEsoMigration(
|
const migrationAlertUpdatedAtAndNotifyWhen = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
// migrate all documents in 7.11 in order to add the "updatedAt" and "notifyWhen" fields
|
// migrate all documents in 7.11 in order to add the "updatedAt" and "notifyWhen" fields
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => true,
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
|
||||||
pipeMigrations(setAlertUpdatedAtDate, setNotifyWhen)
|
pipeMigrations(setAlertUpdatedAtDate, setNotifyWhen)
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationActions7112 = createEsoMigration(
|
const migrationActions7112 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => isAnyActionSupportIncidents(doc),
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => isAnyActionSupportIncidents(doc),
|
||||||
pipeMigrations(restructureConnectorsThatSupportIncident)
|
pipeMigrations(restructureConnectorsThatSupportIncident)
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationSecurityRules713 = createEsoMigration(
|
const migrationSecurityRules713 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => isSiemSignalsRuleType(doc),
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => isSiemSignalsRuleType(doc),
|
||||||
pipeMigrations(removeNullsFromSecurityRules)
|
pipeMigrations(removeNullsFromSecurityRules)
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationSecurityRules714 = createEsoMigration(
|
const migrationSecurityRules714 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => isSiemSignalsRuleType(doc),
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => isSiemSignalsRuleType(doc),
|
||||||
pipeMigrations(removeNullAuthorFromSecurityRules)
|
pipeMigrations(removeNullAuthorFromSecurityRules)
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrationSecurityRules715 = createEsoMigration(
|
const migrationSecurityRules715 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => isSiemSignalsRuleType(doc),
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => isSiemSignalsRuleType(doc),
|
||||||
pipeMigrations(addExceptionListsToReferences)
|
pipeMigrations(addExceptionListsToReferences)
|
||||||
);
|
);
|
||||||
|
|
||||||
const migrateRules716 = createEsoMigration(
|
const migrateRules716 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> => true,
|
(doc): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
|
||||||
pipeMigrations(
|
pipeMigrations(
|
||||||
setLegacyId,
|
setLegacyId,
|
||||||
getRemovePreconfiguredConnectorsFromReferencesFn(isPreconfigured),
|
getRemovePreconfiguredConnectorsFromReferencesFn(isPreconfigured),
|
||||||
|
@ -128,7 +128,7 @@ export function getMigrations(
|
||||||
|
|
||||||
const migrationRules800 = createEsoMigration(
|
const migrationRules800 = createEsoMigration(
|
||||||
encryptedSavedObjects,
|
encryptedSavedObjects,
|
||||||
(doc: SavedObjectUnsanitizedDoc<RawAlert>): doc is SavedObjectUnsanitizedDoc<RawAlert> => true,
|
(doc: SavedObjectUnsanitizedDoc<RawRule>): doc is SavedObjectUnsanitizedDoc<RawRule> => true,
|
||||||
pipeMigrations(
|
pipeMigrations(
|
||||||
addThreatIndicatorPathToThreatMatchRules,
|
addThreatIndicatorPathToThreatMatchRules,
|
||||||
addRACRuleTypes,
|
addRACRuleTypes,
|
||||||
|
@ -149,10 +149,10 @@ export function getMigrations(
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeMigrationWithErrorHandling(
|
function executeMigrationWithErrorHandling(
|
||||||
migrationFunc: SavedObjectMigrationFn<RawAlert, RawAlert>,
|
migrationFunc: SavedObjectMigrationFn<RawRule, RawRule>,
|
||||||
version: string
|
version: string
|
||||||
) {
|
) {
|
||||||
return (doc: SavedObjectUnsanitizedDoc<RawAlert>, context: SavedObjectMigrationContext) => {
|
return (doc: SavedObjectUnsanitizedDoc<RawRule>, context: SavedObjectMigrationContext) => {
|
||||||
try {
|
try {
|
||||||
return migrationFunc(doc, context);
|
return migrationFunc(doc, context);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
@ -170,8 +170,8 @@ function executeMigrationWithErrorHandling(
|
||||||
}
|
}
|
||||||
|
|
||||||
const setAlertUpdatedAtDate = (
|
const setAlertUpdatedAtDate = (
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> => {
|
): SavedObjectUnsanitizedDoc<RawRule> => {
|
||||||
const updatedAt = doc.updated_at || doc.attributes.createdAt;
|
const updatedAt = doc.updated_at || doc.attributes.createdAt;
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -183,8 +183,8 @@ const setAlertUpdatedAtDate = (
|
||||||
};
|
};
|
||||||
|
|
||||||
const setNotifyWhen = (
|
const setNotifyWhen = (
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> => {
|
): SavedObjectUnsanitizedDoc<RawRule> => {
|
||||||
const notifyWhen = doc.attributes.throttle ? 'onThrottleInterval' : 'onActiveAlert';
|
const notifyWhen = doc.attributes.throttle ? 'onThrottleInterval' : 'onActiveAlert';
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -204,8 +204,8 @@ const consumersToChange: Map<string, string> = new Map(
|
||||||
);
|
);
|
||||||
|
|
||||||
function markAsLegacyAndChangeConsumer(
|
function markAsLegacyAndChangeConsumer(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: { consumer },
|
attributes: { consumer },
|
||||||
} = doc;
|
} = doc;
|
||||||
|
@ -223,8 +223,8 @@ function markAsLegacyAndChangeConsumer(
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAlertIdAsDefaultDedupkeyOnPagerDutyActions(
|
function setAlertIdAsDefaultDedupkeyOnPagerDutyActions(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const { attributes } = doc;
|
const { attributes } = doc;
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -251,8 +251,8 @@ function setAlertIdAsDefaultDedupkeyOnPagerDutyActions(
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeExecutionStatus(
|
function initializeExecutionStatus(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const { attributes } = doc;
|
const { attributes } = doc;
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -277,8 +277,8 @@ function isEmptyObject(obj: {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function restructureConnectorsThatSupportIncident(
|
function restructureConnectorsThatSupportIncident(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const { actions } = doc.attributes;
|
const { actions } = doc.attributes;
|
||||||
const newActions = actions.reduce((acc, action) => {
|
const newActions = actions.reduce((acc, action) => {
|
||||||
if (
|
if (
|
||||||
|
@ -416,8 +416,8 @@ function convertNullToUndefined(attribute: SavedObjectAttribute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeNullsFromSecurityRules(
|
function removeNullsFromSecurityRules(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: { params },
|
attributes: { params },
|
||||||
} = doc;
|
} = doc;
|
||||||
|
@ -490,8 +490,8 @@ function removeNullsFromSecurityRules(
|
||||||
* @returns The document with the author field fleshed in.
|
* @returns The document with the author field fleshed in.
|
||||||
*/
|
*/
|
||||||
function removeNullAuthorFromSecurityRules(
|
function removeNullAuthorFromSecurityRules(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: { params },
|
attributes: { params },
|
||||||
} = doc;
|
} = doc;
|
||||||
|
@ -519,8 +519,8 @@ function removeNullAuthorFromSecurityRules(
|
||||||
* @returns The document migrated with saved object references
|
* @returns The document migrated with saved object references
|
||||||
*/
|
*/
|
||||||
function addExceptionListsToReferences(
|
function addExceptionListsToReferences(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: {
|
attributes: {
|
||||||
params: { exceptionsList },
|
params: { exceptionsList },
|
||||||
|
@ -610,8 +610,8 @@ function removeMalformedExceptionsList(
|
||||||
* @returns The document migrated with saved object references
|
* @returns The document migrated with saved object references
|
||||||
*/
|
*/
|
||||||
function addRuleIdsToLegacyNotificationReferences(
|
function addRuleIdsToLegacyNotificationReferences(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: {
|
attributes: {
|
||||||
params: { ruleAlertId },
|
params: { ruleAlertId },
|
||||||
|
@ -641,9 +641,7 @@ function addRuleIdsToLegacyNotificationReferences(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLegacyId(
|
function setLegacyId(doc: SavedObjectUnsanitizedDoc<RawRule>): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
|
||||||
const { id } = doc;
|
const { id } = doc;
|
||||||
return {
|
return {
|
||||||
...doc,
|
...doc,
|
||||||
|
@ -655,8 +653,8 @@ function setLegacyId(
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRACRuleTypes(
|
function addRACRuleTypes(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const ruleType = doc.attributes.params.type;
|
const ruleType = doc.attributes.params.type;
|
||||||
return isSiemSignalsRuleType(doc) && isRuleType(ruleType)
|
return isSiemSignalsRuleType(doc) && isRuleType(ruleType)
|
||||||
? {
|
? {
|
||||||
|
@ -674,8 +672,8 @@ function addRACRuleTypes(
|
||||||
}
|
}
|
||||||
|
|
||||||
function addThreatIndicatorPathToThreatMatchRules(
|
function addThreatIndicatorPathToThreatMatchRules(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
return isSiemSignalsRuleType(doc) &&
|
return isSiemSignalsRuleType(doc) &&
|
||||||
doc.attributes.params?.type === 'threat_match' &&
|
doc.attributes.params?.type === 'threat_match' &&
|
||||||
!doc.attributes.params.threatIndicatorPath
|
!doc.attributes.params.threatIndicatorPath
|
||||||
|
@ -695,15 +693,15 @@ function addThreatIndicatorPathToThreatMatchRules(
|
||||||
function getRemovePreconfiguredConnectorsFromReferencesFn(
|
function getRemovePreconfiguredConnectorsFromReferencesFn(
|
||||||
isPreconfigured: (connectorId: string) => boolean
|
isPreconfigured: (connectorId: string) => boolean
|
||||||
) {
|
) {
|
||||||
return (doc: SavedObjectUnsanitizedDoc<RawAlert>) => {
|
return (doc: SavedObjectUnsanitizedDoc<RawRule>) => {
|
||||||
return removePreconfiguredConnectorsFromReferences(doc, isPreconfigured);
|
return removePreconfiguredConnectorsFromReferences(doc, isPreconfigured);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePreconfiguredConnectorsFromReferences(
|
function removePreconfiguredConnectorsFromReferences(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>,
|
doc: SavedObjectUnsanitizedDoc<RawRule>,
|
||||||
isPreconfigured: (connectorId: string) => boolean
|
isPreconfigured: (connectorId: string) => boolean
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
const {
|
const {
|
||||||
attributes: { actions },
|
attributes: { actions },
|
||||||
references,
|
references,
|
||||||
|
@ -719,7 +717,7 @@ function removePreconfiguredConnectorsFromReferences(
|
||||||
);
|
);
|
||||||
|
|
||||||
const updatedConnectorReferences: SavedObjectReference[] = [];
|
const updatedConnectorReferences: SavedObjectReference[] = [];
|
||||||
const updatedActions: RawAlert['actions'] = [];
|
const updatedActions: RawRule['actions'] = [];
|
||||||
|
|
||||||
// For each connector reference, check if connector is preconfigured
|
// For each connector reference, check if connector is preconfigured
|
||||||
// If yes, we need to remove from the references array and update
|
// If yes, we need to remove from the references array and update
|
||||||
|
@ -758,8 +756,8 @@ function removePreconfiguredConnectorsFromReferences(
|
||||||
// This fixes an issue whereby metrics.alert.inventory.threshold rules had the
|
// This fixes an issue whereby metrics.alert.inventory.threshold rules had the
|
||||||
// group for actions incorrectly spelt as metrics.invenotry_threshold.fired vs metrics.inventory_threshold.fired
|
// group for actions incorrectly spelt as metrics.invenotry_threshold.fired vs metrics.inventory_threshold.fired
|
||||||
function fixInventoryThresholdGroupId(
|
function fixInventoryThresholdGroupId(
|
||||||
doc: SavedObjectUnsanitizedDoc<RawAlert>
|
doc: SavedObjectUnsanitizedDoc<RawRule>
|
||||||
): SavedObjectUnsanitizedDoc<RawAlert> {
|
): SavedObjectUnsanitizedDoc<RawRule> {
|
||||||
if (doc.attributes.alertTypeId === 'metrics.alert.inventory.threshold') {
|
if (doc.attributes.alertTypeId === 'metrics.alert.inventory.threshold') {
|
||||||
const {
|
const {
|
||||||
attributes: { actions },
|
attributes: { actions },
|
||||||
|
@ -805,6 +803,6 @@ function getCorrespondingAction(
|
||||||
}
|
}
|
||||||
|
|
||||||
function pipeMigrations(...migrations: AlertMigration[]): AlertMigration {
|
function pipeMigrations(...migrations: AlertMigration[]): AlertMigration {
|
||||||
return (doc: SavedObjectUnsanitizedDoc<RawAlert>) =>
|
return (doc: SavedObjectUnsanitizedDoc<RawRule>) =>
|
||||||
migrations.reduce((migratedDoc, nextMigration) => nextMigration(migratedDoc), doc);
|
migrations.reduce((migratedDoc, nextMigration) => nextMigration(migratedDoc), doc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SavedObjectsClient,
|
SavedObjectsClient,
|
||||||
|
@ -17,7 +17,7 @@ import {
|
||||||
import { AlertAttributesExcludedFromAAD, AlertAttributesExcludedFromAADType } from './index';
|
import { AlertAttributesExcludedFromAAD, AlertAttributesExcludedFromAADType } from './index';
|
||||||
|
|
||||||
export type PartiallyUpdateableAlertAttributes = Partial<
|
export type PartiallyUpdateableAlertAttributes = Partial<
|
||||||
Pick<RawAlert, AlertAttributesExcludedFromAADType>
|
Pick<RawRule, AlertAttributesExcludedFromAADType>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface PartiallyUpdateAlertSavedObjectOptions {
|
export interface PartiallyUpdateAlertSavedObjectOptions {
|
||||||
|
@ -40,7 +40,7 @@ export async function partiallyUpdateAlert(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// ensure we only have the valid attributes excluded from AAD
|
// ensure we only have the valid attributes excluded from AAD
|
||||||
const attributeUpdates = pick(attributes, AlertAttributesExcludedFromAAD);
|
const attributeUpdates = pick(attributes, AlertAttributesExcludedFromAAD);
|
||||||
const updateOptions: SavedObjectsUpdateOptions<RawAlert> = pick(
|
const updateOptions: SavedObjectsUpdateOptions<RawRule> = pick(
|
||||||
options,
|
options,
|
||||||
'namespace',
|
'namespace',
|
||||||
'version',
|
'version',
|
||||||
|
@ -48,7 +48,7 @@ export async function partiallyUpdateAlert(
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await savedObjectsClient.update<RawAlert>('alert', id, attributeUpdates, updateOptions);
|
await savedObjectsClient.update<RawRule>('alert', id, attributeUpdates, updateOptions);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (options?.ignore404 && SavedObjectsErrorHelpers.isNotFoundError(err)) {
|
if (options?.ignore404 && SavedObjectsErrorHelpers.isNotFoundError(err)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { transformRulesForExport } from './transform_rule_for_export';
|
import { transformRulesForExport } from './transform_rule_for_export';
|
||||||
jest.mock('../lib/alert_execution_status', () => ({
|
jest.mock('../lib/rule_execution_status', () => ({
|
||||||
getAlertExecutionStatusPending: () => ({
|
getRuleExecutionStatusPending: () => ({
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
lastExecutionDate: '2020-08-20T19:23:38Z',
|
lastExecutionDate: '2020-08-20T19:23:38Z',
|
||||||
error: null,
|
error: null,
|
||||||
|
|
|
@ -6,18 +6,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObject } from 'kibana/server';
|
import { SavedObject } from 'kibana/server';
|
||||||
import { getAlertExecutionStatusPending } from '../lib/alert_execution_status';
|
import { getRuleExecutionStatusPending } from '../lib/rule_execution_status';
|
||||||
import { RawAlert } from '../types';
|
import { RawRule } from '../types';
|
||||||
|
|
||||||
export function transformRulesForExport(rules: SavedObject[]): Array<SavedObject<RawAlert>> {
|
export function transformRulesForExport(rules: SavedObject[]): Array<SavedObject<RawRule>> {
|
||||||
const exportDate = new Date().toISOString();
|
const exportDate = new Date().toISOString();
|
||||||
return rules.map((rule) => transformRuleForExport(rule as SavedObject<RawAlert>, exportDate));
|
return rules.map((rule) => transformRuleForExport(rule as SavedObject<RawRule>, exportDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformRuleForExport(
|
function transformRuleForExport(
|
||||||
rule: SavedObject<RawAlert>,
|
rule: SavedObject<RawRule>,
|
||||||
exportDate: string
|
exportDate: string
|
||||||
): SavedObject<RawAlert> {
|
): SavedObject<RawRule> {
|
||||||
return {
|
return {
|
||||||
...rule,
|
...rule,
|
||||||
attributes: {
|
attributes: {
|
||||||
|
@ -27,7 +27,7 @@ function transformRuleForExport(
|
||||||
apiKey: null,
|
apiKey: null,
|
||||||
apiKeyOwner: null,
|
apiKeyOwner: null,
|
||||||
scheduledTaskId: null,
|
scheduledTaskId: null,
|
||||||
executionStatus: getAlertExecutionStatusPending(exportDate),
|
executionStatus: getRuleExecutionStatusPending(exportDate),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,16 @@ import { fold } from 'fp-ts/lib/Either';
|
||||||
import { ConcreteTaskInstance } from '../../../task_manager/server';
|
import { ConcreteTaskInstance } from '../../../task_manager/server';
|
||||||
import {
|
import {
|
||||||
SanitizedAlert,
|
SanitizedAlert,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
alertParamsSchema,
|
ruleParamsSchema,
|
||||||
alertStateSchema,
|
ruleStateSchema,
|
||||||
AlertTaskParams,
|
RuleTaskParams,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
} from '../../common';
|
} from '../../common';
|
||||||
|
|
||||||
export interface AlertTaskInstance extends ConcreteTaskInstance {
|
export interface AlertTaskInstance extends ConcreteTaskInstance {
|
||||||
state: AlertTaskState;
|
state: RuleTaskState;
|
||||||
params: AlertTaskParams;
|
params: RuleTaskParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
const enumerateErrorFields = (e: t.Errors) =>
|
const enumerateErrorFields = (e: t.Errors) =>
|
||||||
|
@ -33,7 +33,7 @@ export function taskInstanceToAlertTaskInstance<Params extends AlertTypeParams>(
|
||||||
return {
|
return {
|
||||||
...taskInstance,
|
...taskInstance,
|
||||||
params: pipe(
|
params: pipe(
|
||||||
alertParamsSchema.decode(taskInstance.params),
|
ruleParamsSchema.decode(taskInstance.params),
|
||||||
fold((e: t.Errors) => {
|
fold((e: t.Errors) => {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Task "${taskInstance.id}" ${
|
`Task "${taskInstance.id}" ${
|
||||||
|
@ -43,7 +43,7 @@ export function taskInstanceToAlertTaskInstance<Params extends AlertTypeParams>(
|
||||||
}, t.identity)
|
}, t.identity)
|
||||||
),
|
),
|
||||||
state: pipe(
|
state: pipe(
|
||||||
alertStateSchema.decode(taskInstance.state),
|
ruleStateSchema.decode(taskInstance.state),
|
||||||
fold((e: t.Errors) => {
|
fold((e: t.Errors) => {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Task "${taskInstance.id}" ${
|
`Task "${taskInstance.id}" ${
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { eventLoggerMock } from '../../../event_log/server/event_logger.mock';
|
||||||
import { KibanaRequest } from 'kibana/server';
|
import { KibanaRequest } from 'kibana/server';
|
||||||
import { asSavedObjectExecutionSource } from '../../../actions/server';
|
import { asSavedObjectExecutionSource } from '../../../actions/server';
|
||||||
import { InjectActionParamsOpts } from './inject_action_params';
|
import { InjectActionParamsOpts } from './inject_action_params';
|
||||||
import { NormalizedAlertType } from '../rule_type_registry';
|
import { NormalizedRuleType } from '../rule_type_registry';
|
||||||
import {
|
import {
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -28,7 +28,7 @@ jest.mock('./inject_action_params', () => ({
|
||||||
injectActionParams: jest.fn(),
|
injectActionParams: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const alertType: NormalizedAlertType<
|
const ruleType: NormalizedRuleType<
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -71,12 +71,12 @@ const createExecutionHandlerParams: jest.Mocked<
|
||||||
> = {
|
> = {
|
||||||
actionsPlugin: mockActionsPlugin,
|
actionsPlugin: mockActionsPlugin,
|
||||||
spaceId: 'test1',
|
spaceId: 'test1',
|
||||||
alertId: '1',
|
ruleId: '1',
|
||||||
alertName: 'name-of-alert',
|
ruleName: 'name-of-alert',
|
||||||
tags: ['tag-A', 'tag-B'],
|
tags: ['tag-A', 'tag-B'],
|
||||||
apiKey: 'MTIzOmFiYw==',
|
apiKey: 'MTIzOmFiYw==',
|
||||||
kibanaBaseUrl: 'http://localhost:5601',
|
kibanaBaseUrl: 'http://localhost:5601',
|
||||||
alertType,
|
ruleType,
|
||||||
logger: loggingSystemMock.create().get(),
|
logger: loggingSystemMock.create().get(),
|
||||||
eventLogger: mockEventLogger,
|
eventLogger: mockEventLogger,
|
||||||
actions: [
|
actions: [
|
||||||
|
@ -93,13 +93,13 @@ const createExecutionHandlerParams: jest.Mocked<
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
request: {} as KibanaRequest,
|
request: {} as KibanaRequest,
|
||||||
alertParams: {
|
ruleParams: {
|
||||||
foo: true,
|
foo: true,
|
||||||
contextVal: 'My other {{context.value}} goes here',
|
contextVal: 'My other {{context.value}} goes here',
|
||||||
stateVal: 'My other {{state.value}} goes here',
|
stateVal: 'My other {{state.value}} goes here',
|
||||||
},
|
},
|
||||||
supportsEphemeralTasks: false,
|
supportsEphemeralTasks: false,
|
||||||
maxEphemeralActionsPerAlert: 10,
|
maxEphemeralActionsPerRule: 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -123,7 +123,7 @@ test('enqueues execution per selected action', async () => {
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
state: {},
|
state: {},
|
||||||
context: {},
|
context: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(mockActionsPlugin.getActionsClientWithRequest).toHaveBeenCalledWith(
|
expect(mockActionsPlugin.getActionsClientWithRequest).toHaveBeenCalledWith(
|
||||||
createExecutionHandlerParams.request
|
createExecutionHandlerParams.request
|
||||||
|
@ -244,7 +244,7 @@ test(`doesn't call actionsPlugin.execute for disabled actionTypes`, async () =>
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
state: {},
|
state: {},
|
||||||
context: {},
|
context: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledWith({
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledWith({
|
||||||
|
@ -296,7 +296,7 @@ test('trow error error message when action type is disabled', async () => {
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
state: {},
|
state: {},
|
||||||
context: {},
|
context: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(0);
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(0);
|
||||||
|
@ -310,7 +310,7 @@ test('trow error error message when action type is disabled', async () => {
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
state: {},
|
state: {},
|
||||||
context: {},
|
context: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
@ -321,7 +321,7 @@ test('limits actionsPlugin.execute per action group', async () => {
|
||||||
actionGroup: 'other-group',
|
actionGroup: 'other-group',
|
||||||
state: {},
|
state: {},
|
||||||
context: {},
|
context: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(actionsClient.enqueueExecution).not.toHaveBeenCalled();
|
expect(actionsClient.enqueueExecution).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
@ -332,7 +332,7 @@ test('context attribute gets parameterized', async () => {
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
context: { value: 'context-val' },
|
context: { value: 'context-val' },
|
||||||
state: {},
|
state: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
||||||
expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(`
|
expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(`
|
||||||
|
@ -373,7 +373,7 @@ test('state attribute gets parameterized', async () => {
|
||||||
actionGroup: 'default',
|
actionGroup: 'default',
|
||||||
context: {},
|
context: {},
|
||||||
state: { value: 'state-val' },
|
state: { value: 'state-val' },
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1);
|
||||||
expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(`
|
expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(`
|
||||||
|
@ -408,7 +408,7 @@ test('state attribute gets parameterized', async () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test(`logs an error when action group isn't part of actionGroups available for the alertType`, async () => {
|
test(`logs an error when action group isn't part of actionGroups available for the ruleType`, async () => {
|
||||||
const executionHandler = createExecutionHandler(createExecutionHandlerParams);
|
const executionHandler = createExecutionHandler(createExecutionHandlerParams);
|
||||||
const result = await executionHandler({
|
const result = await executionHandler({
|
||||||
// we have to trick the compiler as this is an invalid type and this test checks whether we
|
// we have to trick the compiler as this is an invalid type and this test checks whether we
|
||||||
|
@ -416,10 +416,10 @@ test(`logs an error when action group isn't part of actionGroups available for t
|
||||||
actionGroup: 'invalid-group' as 'default' | 'other-group',
|
actionGroup: 'invalid-group' as 'default' | 'other-group',
|
||||||
context: {},
|
context: {},
|
||||||
state: {},
|
state: {},
|
||||||
alertInstanceId: '2',
|
alertId: '2',
|
||||||
});
|
});
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
expect(createExecutionHandlerParams.logger.error).toHaveBeenCalledWith(
|
expect(createExecutionHandlerParams.logger.error).toHaveBeenCalledWith(
|
||||||
'Invalid action group "invalid-group" for alert "test".'
|
'Invalid action group "invalid-group" for rule "test".'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,9 +19,9 @@ import {
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
RawAlert,
|
RawRule,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { NormalizedAlertType, UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { NormalizedRuleType, UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
import { isEphemeralTaskRejectedDueToCapacityError } from '../../../task_manager/server';
|
import { isEphemeralTaskRejectedDueToCapacityError } from '../../../task_manager/server';
|
||||||
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
import { createAlertEventLogRecordObject } from '../lib/create_alert_event_log_record_object';
|
||||||
|
|
||||||
|
@ -34,15 +34,15 @@ export interface CreateExecutionHandlerOptions<
|
||||||
ActionGroupIds extends string,
|
ActionGroupIds extends string,
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
> {
|
> {
|
||||||
alertId: string;
|
ruleId: string;
|
||||||
alertName: string;
|
ruleName: string;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
actionsPlugin: ActionsPluginStartContract;
|
actionsPlugin: ActionsPluginStartContract;
|
||||||
actions: AlertAction[];
|
actions: AlertAction[];
|
||||||
spaceId: string;
|
spaceId: string;
|
||||||
apiKey: RawAlert['apiKey'];
|
apiKey: RawRule['apiKey'];
|
||||||
kibanaBaseUrl: string | undefined;
|
kibanaBaseUrl: string | undefined;
|
||||||
alertType: NormalizedAlertType<
|
ruleType: NormalizedRuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -54,15 +54,15 @@ export interface CreateExecutionHandlerOptions<
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
eventLogger: IEventLogger;
|
eventLogger: IEventLogger;
|
||||||
request: KibanaRequest;
|
request: KibanaRequest;
|
||||||
alertParams: AlertTypeParams;
|
ruleParams: AlertTypeParams;
|
||||||
supportsEphemeralTasks: boolean;
|
supportsEphemeralTasks: boolean;
|
||||||
maxEphemeralActionsPerAlert: number;
|
maxEphemeralActionsPerRule: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExecutionHandlerOptions<ActionGroupIds extends string> {
|
interface ExecutionHandlerOptions<ActionGroupIds extends string> {
|
||||||
actionGroup: ActionGroupIds;
|
actionGroup: ActionGroupIds;
|
||||||
actionSubgroup?: string;
|
actionSubgroup?: string;
|
||||||
alertInstanceId: string;
|
alertId: string;
|
||||||
context: AlertInstanceContext;
|
context: AlertInstanceContext;
|
||||||
state: AlertInstanceState;
|
state: AlertInstanceState;
|
||||||
}
|
}
|
||||||
|
@ -81,20 +81,20 @@ export function createExecutionHandler<
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
>({
|
>({
|
||||||
logger,
|
logger,
|
||||||
alertId,
|
ruleId,
|
||||||
alertName,
|
ruleName,
|
||||||
tags,
|
tags,
|
||||||
actionsPlugin,
|
actionsPlugin,
|
||||||
actions: alertActions,
|
actions: ruleActions,
|
||||||
spaceId,
|
spaceId,
|
||||||
apiKey,
|
apiKey,
|
||||||
alertType,
|
ruleType,
|
||||||
kibanaBaseUrl,
|
kibanaBaseUrl,
|
||||||
eventLogger,
|
eventLogger,
|
||||||
request,
|
request,
|
||||||
alertParams,
|
ruleParams,
|
||||||
supportsEphemeralTasks,
|
supportsEphemeralTasks,
|
||||||
maxEphemeralActionsPerAlert,
|
maxEphemeralActionsPerRule,
|
||||||
}: CreateExecutionHandlerOptions<
|
}: CreateExecutionHandlerOptions<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
|
@ -104,66 +104,66 @@ export function createExecutionHandler<
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>): ExecutionHandler<ActionGroupIds | RecoveryActionGroupId> {
|
>): ExecutionHandler<ActionGroupIds | RecoveryActionGroupId> {
|
||||||
const alertTypeActionGroups = new Map(
|
const ruleTypeActionGroups = new Map(
|
||||||
alertType.actionGroups.map((actionGroup) => [actionGroup.id, actionGroup.name])
|
ruleType.actionGroups.map((actionGroup) => [actionGroup.id, actionGroup.name])
|
||||||
);
|
);
|
||||||
return async ({
|
return async ({
|
||||||
actionGroup,
|
actionGroup,
|
||||||
actionSubgroup,
|
actionSubgroup,
|
||||||
context,
|
context,
|
||||||
state,
|
state,
|
||||||
alertInstanceId,
|
alertId,
|
||||||
}: ExecutionHandlerOptions<ActionGroupIds | RecoveryActionGroupId>) => {
|
}: ExecutionHandlerOptions<ActionGroupIds | RecoveryActionGroupId>) => {
|
||||||
if (!alertTypeActionGroups.has(actionGroup)) {
|
if (!ruleTypeActionGroups.has(actionGroup)) {
|
||||||
logger.error(`Invalid action group "${actionGroup}" for alert "${alertType.id}".`);
|
logger.error(`Invalid action group "${actionGroup}" for rule "${ruleType.id}".`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const actions = alertActions
|
const actions = ruleActions
|
||||||
.filter(({ group }) => group === actionGroup)
|
.filter(({ group }) => group === actionGroup)
|
||||||
.map((action) => {
|
.map((action) => {
|
||||||
return {
|
return {
|
||||||
...action,
|
...action,
|
||||||
params: transformActionParams({
|
params: transformActionParams({
|
||||||
actionsPlugin,
|
actionsPlugin,
|
||||||
alertId,
|
alertId: ruleId,
|
||||||
alertType: alertType.id,
|
alertType: ruleType.id,
|
||||||
actionTypeId: action.actionTypeId,
|
actionTypeId: action.actionTypeId,
|
||||||
alertName,
|
alertName: ruleName,
|
||||||
spaceId,
|
spaceId,
|
||||||
tags,
|
tags,
|
||||||
alertInstanceId,
|
alertInstanceId: alertId,
|
||||||
alertActionGroup: actionGroup,
|
alertActionGroup: actionGroup,
|
||||||
alertActionGroupName: alertTypeActionGroups.get(actionGroup)!,
|
alertActionGroupName: ruleTypeActionGroups.get(actionGroup)!,
|
||||||
alertActionSubgroup: actionSubgroup,
|
alertActionSubgroup: actionSubgroup,
|
||||||
context,
|
context,
|
||||||
actionParams: action.params,
|
actionParams: action.params,
|
||||||
actionId: action.id,
|
actionId: action.id,
|
||||||
state,
|
state,
|
||||||
kibanaBaseUrl,
|
kibanaBaseUrl,
|
||||||
alertParams,
|
alertParams: ruleParams,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.map((action) => ({
|
.map((action) => ({
|
||||||
...action,
|
...action,
|
||||||
params: injectActionParams({
|
params: injectActionParams({
|
||||||
ruleId: alertId,
|
ruleId,
|
||||||
spaceId,
|
spaceId,
|
||||||
actionParams: action.params,
|
actionParams: action.params,
|
||||||
actionTypeId: action.actionTypeId,
|
actionTypeId: action.actionTypeId,
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const alertLabel = `${alertType.id}:${alertId}: '${alertName}'`;
|
const ruleLabel = `${ruleType.id}:${ruleId}: '${ruleName}'`;
|
||||||
|
|
||||||
const actionsClient = await actionsPlugin.getActionsClientWithRequest(request);
|
const actionsClient = await actionsPlugin.getActionsClientWithRequest(request);
|
||||||
let ephemeralActionsToSchedule = maxEphemeralActionsPerAlert;
|
let ephemeralActionsToSchedule = maxEphemeralActionsPerRule;
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (
|
if (
|
||||||
!actionsPlugin.isActionExecutable(action.id, action.actionTypeId, { notifyUsage: true })
|
!actionsPlugin.isActionExecutable(action.id, action.actionTypeId, { notifyUsage: true })
|
||||||
) {
|
) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Alert "${alertId}" skipped scheduling action "${action.id}" because it is disabled`
|
`Rule "${ruleId}" skipped scheduling action "${action.id}" because it is disabled`
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -176,15 +176,15 @@ export function createExecutionHandler<
|
||||||
spaceId,
|
spaceId,
|
||||||
apiKey: apiKey ?? null,
|
apiKey: apiKey ?? null,
|
||||||
source: asSavedObjectExecutionSource({
|
source: asSavedObjectExecutionSource({
|
||||||
id: alertId,
|
id: ruleId,
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
}),
|
}),
|
||||||
relatedSavedObjects: [
|
relatedSavedObjects: [
|
||||||
{
|
{
|
||||||
id: alertId,
|
id: ruleId,
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
namespace: namespace.namespace,
|
namespace: namespace.namespace,
|
||||||
typeId: alertType.id,
|
typeId: ruleType.id,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -203,18 +203,18 @@ export function createExecutionHandler<
|
||||||
}
|
}
|
||||||
|
|
||||||
const event = createAlertEventLogRecordObject({
|
const event = createAlertEventLogRecordObject({
|
||||||
ruleId: alertId,
|
ruleId,
|
||||||
ruleType: alertType as UntypedNormalizedAlertType,
|
ruleType: ruleType as UntypedNormalizedRuleType,
|
||||||
action: EVENT_LOG_ACTIONS.executeAction,
|
action: EVENT_LOG_ACTIONS.executeAction,
|
||||||
instanceId: alertInstanceId,
|
instanceId: alertId,
|
||||||
group: actionGroup,
|
group: actionGroup,
|
||||||
subgroup: actionSubgroup,
|
subgroup: actionSubgroup,
|
||||||
ruleName: alertName,
|
ruleName,
|
||||||
savedObjects: [
|
savedObjects: [
|
||||||
{
|
{
|
||||||
type: 'alert',
|
type: 'alert',
|
||||||
id: alertId,
|
id: ruleId,
|
||||||
typeId: alertType.id,
|
typeId: ruleType.id,
|
||||||
relation: SAVED_OBJECT_REL_PRIMARY,
|
relation: SAVED_OBJECT_REL_PRIMARY,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -224,7 +224,7 @@ export function createExecutionHandler<
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
...namespace,
|
...namespace,
|
||||||
message: `alert: ${alertLabel} instanceId: '${alertInstanceId}' scheduled ${
|
message: `alert: ${ruleLabel} instanceId: '${alertId}' scheduled ${
|
||||||
actionSubgroup
|
actionSubgroup
|
||||||
? `actionGroup(subgroup): '${actionGroup}(${actionSubgroup})'`
|
? `actionGroup(subgroup): '${actionGroup}(${actionSubgroup})'`
|
||||||
: `actionGroup: '${actionGroup}'`
|
: `actionGroup: '${actionGroup}'`
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -29,10 +29,10 @@ import { alertsMock, rulesClientMock } from '../mocks';
|
||||||
import { eventLoggerMock } from '../../../event_log/server/event_logger.mock';
|
import { eventLoggerMock } from '../../../event_log/server/event_logger.mock';
|
||||||
import { IEventLogger } from '../../../event_log/server';
|
import { IEventLogger } from '../../../event_log/server';
|
||||||
import { Alert, RecoveredActionGroup } from '../../common';
|
import { Alert, RecoveredActionGroup } from '../../common';
|
||||||
import { UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
||||||
|
|
||||||
const ruleType: jest.Mocked<UntypedNormalizedAlertType> = {
|
const ruleType: jest.Mocked<UntypedNormalizedRuleType> = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'My test rule',
|
name: 'My test rule',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup],
|
actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup],
|
||||||
|
@ -100,7 +100,7 @@ describe('Task Runner Cancel', () => {
|
||||||
ruleTypeRegistry,
|
ruleTypeRegistry,
|
||||||
kibanaBaseUrl: 'https://localhost:5601',
|
kibanaBaseUrl: 'https://localhost:5601',
|
||||||
supportsEphemeralTasks: false,
|
supportsEphemeralTasks: false,
|
||||||
maxEphemeralActionsPerAlert: 10,
|
maxEphemeralActionsPerRule: 10,
|
||||||
cancelAlertsOnRuleTimeout: true,
|
cancelAlertsOnRuleTimeout: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ describe('Task Runner Cancel', () => {
|
||||||
scheduled: '1970-01-01T00:00:00.000Z',
|
scheduled: '1970-01-01T00:00:00.000Z',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
message: 'alert execution start: "1"',
|
message: 'rule execution start: "1"',
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -271,7 +271,7 @@ describe('Task Runner Cancel', () => {
|
||||||
scheduled: '1970-01-01T00:00:00.000Z',
|
scheduled: '1970-01-01T00:00:00.000Z',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
message: `alert executed: test:1: 'rule-name'`,
|
message: `rule executed: test:1: 'rule-name'`,
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -395,7 +395,7 @@ describe('Task Runner Cancel', () => {
|
||||||
|
|
||||||
const logger = taskRunnerFactoryInitializerParams.logger;
|
const logger = taskRunnerFactoryInitializerParams.logger;
|
||||||
expect(logger.debug).toHaveBeenCalledTimes(6);
|
expect(logger.debug).toHaveBeenCalledTimes(6);
|
||||||
expect(logger.debug).nthCalledWith(1, 'executing alert test:1 at 1970-01-01T00:00:00.000Z');
|
expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z');
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
2,
|
2,
|
||||||
`Cancelling rule type test with id 1 - execution exceeded rule type timeout of 5m`
|
`Cancelling rule type test with id 1 - execution exceeded rule type timeout of 5m`
|
||||||
|
@ -406,15 +406,15 @@ describe('Task Runner Cancel', () => {
|
||||||
);
|
);
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
4,
|
4,
|
||||||
`alert test:1: 'rule-name' has 1 active alert instances: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`
|
`rule test:1: 'rule-name' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`
|
||||||
);
|
);
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
5,
|
5,
|
||||||
`no scheduling of actions for alert test:1: 'rule-name': alert execution has been cancelled.`
|
`no scheduling of actions for rule test:1: 'rule-name': rule execution has been cancelled.`
|
||||||
);
|
);
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
6,
|
6,
|
||||||
'alertExecutionStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}'
|
'ruleExecutionStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}'
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventLogger = taskRunnerFactoryInitializerParams.eventLogger;
|
const eventLogger = taskRunnerFactoryInitializerParams.eventLogger;
|
||||||
|
@ -440,7 +440,7 @@ describe('Task Runner Cancel', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: `alert execution start: \"1\"`,
|
message: `rule execution start: \"1\"`,
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -498,7 +498,7 @@ describe('Task Runner Cancel', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: "alert executed: test:1: 'rule-name'",
|
message: "rule executed: test:1: 'rule-name'",
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -512,7 +512,7 @@ describe('Task Runner Cancel', () => {
|
||||||
function testActionsExecute() {
|
function testActionsExecute() {
|
||||||
const logger = taskRunnerFactoryInitializerParams.logger;
|
const logger = taskRunnerFactoryInitializerParams.logger;
|
||||||
expect(logger.debug).toHaveBeenCalledTimes(5);
|
expect(logger.debug).toHaveBeenCalledTimes(5);
|
||||||
expect(logger.debug).nthCalledWith(1, 'executing alert test:1 at 1970-01-01T00:00:00.000Z');
|
expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z');
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
2,
|
2,
|
||||||
`Cancelling rule type test with id 1 - execution exceeded rule type timeout of 5m`
|
`Cancelling rule type test with id 1 - execution exceeded rule type timeout of 5m`
|
||||||
|
@ -523,11 +523,11 @@ describe('Task Runner Cancel', () => {
|
||||||
);
|
);
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
4,
|
4,
|
||||||
`alert test:1: 'rule-name' has 1 active alert instances: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`
|
`rule test:1: 'rule-name' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`
|
||||||
);
|
);
|
||||||
expect(logger.debug).nthCalledWith(
|
expect(logger.debug).nthCalledWith(
|
||||||
5,
|
5,
|
||||||
'alertExecutionStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}'
|
'ruleExecutionStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}'
|
||||||
);
|
);
|
||||||
|
|
||||||
const eventLogger = taskRunnerFactoryInitializerParams.eventLogger;
|
const eventLogger = taskRunnerFactoryInitializerParams.eventLogger;
|
||||||
|
@ -553,7 +553,7 @@ describe('Task Runner Cancel', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: `alert execution start: "1"`,
|
message: `rule execution start: "1"`,
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -609,7 +609,7 @@ describe('Task Runner Cancel', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: "test:1: 'rule-name' created new instance: '1'",
|
message: "test:1: 'rule-name' created new alert: '1'",
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -636,7 +636,7 @@ describe('Task Runner Cancel', () => {
|
||||||
{ id: '1', namespace: undefined, rel: 'primary', type: 'alert', type_id: 'test' },
|
{ id: '1', namespace: undefined, rel: 'primary', type: 'alert', type_id: 'test' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: "test:1: 'rule-name' active instance: '1' in actionGroup: 'default'",
|
message: "test:1: 'rule-name' active alert: '1' in actionGroup: 'default'",
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -700,7 +700,7 @@ describe('Task Runner Cancel', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
message: "alert executed: test:1: 'rule-name'",
|
message: "rule executed: test:1: 'rule-name'",
|
||||||
rule: {
|
rule: {
|
||||||
category: 'test',
|
category: 'test',
|
||||||
id: '1',
|
id: '1',
|
||||||
|
|
|
@ -17,13 +17,13 @@ import {
|
||||||
import { actionsMock } from '../../../actions/server/mocks';
|
import { actionsMock } from '../../../actions/server/mocks';
|
||||||
import { alertsMock, rulesClientMock } from '../mocks';
|
import { alertsMock, rulesClientMock } from '../mocks';
|
||||||
import { eventLoggerMock } from '../../../event_log/server/event_logger.mock';
|
import { eventLoggerMock } from '../../../event_log/server/event_logger.mock';
|
||||||
import { UntypedNormalizedAlertType } from '../rule_type_registry';
|
import { UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||||
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
||||||
import { executionContextServiceMock } from '../../../../../src/core/server/mocks';
|
import { executionContextServiceMock } from '../../../../../src/core/server/mocks';
|
||||||
|
|
||||||
const executionContext = executionContextServiceMock.createSetupContract();
|
const executionContext = executionContextServiceMock.createSetupContract();
|
||||||
|
|
||||||
const alertType: UntypedNormalizedAlertType = {
|
const ruleType: UntypedNormalizedRuleType = {
|
||||||
id: 'test',
|
id: 'test',
|
||||||
name: 'My test alert',
|
name: 'My test alert',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -83,7 +83,7 @@ describe('Task Runner Factory', () => {
|
||||||
ruleTypeRegistry: ruleTypeRegistryMock.create(),
|
ruleTypeRegistry: ruleTypeRegistryMock.create(),
|
||||||
kibanaBaseUrl: 'https://localhost:5601',
|
kibanaBaseUrl: 'https://localhost:5601',
|
||||||
supportsEphemeralTasks: true,
|
supportsEphemeralTasks: true,
|
||||||
maxEphemeralActionsPerAlert: 10,
|
maxEphemeralActionsPerRule: 10,
|
||||||
cancelAlertsOnRuleTimeout: true,
|
cancelAlertsOnRuleTimeout: true,
|
||||||
executionContext,
|
executionContext,
|
||||||
};
|
};
|
||||||
|
@ -96,7 +96,7 @@ describe('Task Runner Factory', () => {
|
||||||
test(`throws an error if factory isn't initialized`, () => {
|
test(`throws an error if factory isn't initialized`, () => {
|
||||||
const factory = new TaskRunnerFactory();
|
const factory = new TaskRunnerFactory();
|
||||||
expect(() =>
|
expect(() =>
|
||||||
factory.create(alertType, { taskInstance: mockedTaskInstance })
|
factory.create(ruleType, { taskInstance: mockedTaskInstance })
|
||||||
).toThrowErrorMatchingInlineSnapshot(`"TaskRunnerFactory not initialized"`);
|
).toThrowErrorMatchingInlineSnapshot(`"TaskRunnerFactory not initialized"`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
import { TaskRunner } from './task_runner';
|
import { TaskRunner } from './task_runner';
|
||||||
import { IEventLogger } from '../../../event_log/server';
|
import { IEventLogger } from '../../../event_log/server';
|
||||||
import { RulesClient } from '../rules_client';
|
import { RulesClient } from '../rules_client';
|
||||||
import { NormalizedAlertType } from '../rule_type_registry';
|
import { NormalizedRuleType } from '../rule_type_registry';
|
||||||
|
|
||||||
export interface TaskRunnerContext {
|
export interface TaskRunnerContext {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
|
@ -44,7 +44,7 @@ export interface TaskRunnerContext {
|
||||||
ruleTypeRegistry: RuleTypeRegistry;
|
ruleTypeRegistry: RuleTypeRegistry;
|
||||||
kibanaBaseUrl: string | undefined;
|
kibanaBaseUrl: string | undefined;
|
||||||
supportsEphemeralTasks: boolean;
|
supportsEphemeralTasks: boolean;
|
||||||
maxEphemeralActionsPerAlert: number;
|
maxEphemeralActionsPerRule: number;
|
||||||
cancelAlertsOnRuleTimeout: boolean;
|
cancelAlertsOnRuleTimeout: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ export class TaskRunnerFactory {
|
||||||
ActionGroupIds extends string,
|
ActionGroupIds extends string,
|
||||||
RecoveryActionGroupId extends string
|
RecoveryActionGroupId extends string
|
||||||
>(
|
>(
|
||||||
alertType: NormalizedAlertType<
|
ruleType: NormalizedRuleType<
|
||||||
Params,
|
Params,
|
||||||
ExtractedParams,
|
ExtractedParams,
|
||||||
State,
|
State,
|
||||||
|
@ -92,6 +92,6 @@ export class TaskRunnerFactory {
|
||||||
InstanceContext,
|
InstanceContext,
|
||||||
ActionGroupIds,
|
ActionGroupIds,
|
||||||
RecoveryActionGroupId
|
RecoveryActionGroupId
|
||||||
>(alertType, taskInstance, this.taskRunnerContext!);
|
>(ruleType, taskInstance, this.taskRunnerContext!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ export type ExecutorType<
|
||||||
export interface AlertTypeParamsValidator<Params extends AlertTypeParams> {
|
export interface AlertTypeParamsValidator<Params extends AlertTypeParams> {
|
||||||
validate: (object: unknown) => Params;
|
validate: (object: unknown) => Params;
|
||||||
}
|
}
|
||||||
export interface AlertType<
|
export interface RuleType<
|
||||||
Params extends AlertTypeParams = never,
|
Params extends AlertTypeParams = never,
|
||||||
ExtractedParams extends AlertTypeParams = never,
|
ExtractedParams extends AlertTypeParams = never,
|
||||||
State extends AlertTypeState = never,
|
State extends AlertTypeState = never,
|
||||||
|
@ -163,7 +163,7 @@ export interface AlertType<
|
||||||
ruleTaskTimeout?: string;
|
ruleTaskTimeout?: string;
|
||||||
cancelAlertsOnRuleTimeout?: boolean;
|
cancelAlertsOnRuleTimeout?: boolean;
|
||||||
}
|
}
|
||||||
export type UntypedAlertType = AlertType<
|
export type UntypedRuleType = RuleType<
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
|
@ -184,7 +184,7 @@ export interface AlertMeta extends SavedObjectAttributes {
|
||||||
// note that the `error` property is "null-able", as we're doing a partial
|
// note that the `error` property is "null-able", as we're doing a partial
|
||||||
// update on the alert when we update this data, but need to ensure we
|
// update on the alert when we update this data, but need to ensure we
|
||||||
// delete any previous error if the current status has no error
|
// delete any previous error if the current status has no error
|
||||||
export interface RawAlertExecutionStatus extends SavedObjectAttributes {
|
export interface RawRuleExecutionStatus extends SavedObjectAttributes {
|
||||||
status: AlertExecutionStatuses;
|
status: AlertExecutionStatuses;
|
||||||
lastExecutionDate: string;
|
lastExecutionDate: string;
|
||||||
lastDuration?: number;
|
lastDuration?: number;
|
||||||
|
@ -201,7 +201,7 @@ export interface AlertWithLegacyId<Params extends AlertTypeParams = never> exten
|
||||||
legacyId: string | null;
|
legacyId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SanitizedAlertWithLegacyId<Params extends AlertTypeParams = never> = Omit<
|
export type SanitizedRuleWithLegacyId<Params extends AlertTypeParams = never> = Omit<
|
||||||
AlertWithLegacyId<Params>,
|
AlertWithLegacyId<Params>,
|
||||||
'apiKey'
|
'apiKey'
|
||||||
>;
|
>;
|
||||||
|
@ -212,11 +212,11 @@ export type PartialAlertWithLegacyId<Params extends AlertTypeParams = never> = P
|
||||||
> &
|
> &
|
||||||
Partial<Omit<AlertWithLegacyId<Params>, 'id'>>;
|
Partial<Omit<AlertWithLegacyId<Params>, 'id'>>;
|
||||||
|
|
||||||
export interface RawAlert extends SavedObjectAttributes {
|
export interface RawRule extends SavedObjectAttributes {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
alertTypeId: string;
|
alertTypeId: string; // this cannot be renamed since it is in the saved object
|
||||||
consumer: string;
|
consumer: string;
|
||||||
legacyId: string | null;
|
legacyId: string | null;
|
||||||
schedule: SavedObjectAttributes;
|
schedule: SavedObjectAttributes;
|
||||||
|
@ -234,11 +234,11 @@ export interface RawAlert extends SavedObjectAttributes {
|
||||||
muteAll: boolean;
|
muteAll: boolean;
|
||||||
mutedInstanceIds: string[];
|
mutedInstanceIds: string[];
|
||||||
meta?: AlertMeta;
|
meta?: AlertMeta;
|
||||||
executionStatus: RawAlertExecutionStatus;
|
executionStatus: RawRuleExecutionStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AlertInfoParams = Pick<
|
export type AlertInfoParams = Pick<
|
||||||
RawAlert,
|
RawRule,
|
||||||
| 'params'
|
| 'params'
|
||||||
| 'throttle'
|
| 'throttle'
|
||||||
| 'notifyWhen'
|
| 'notifyWhen'
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { MlPluginSetup } from '../../../../../ml/server';
|
import { MlPluginSetup } from '../../../../../ml/server';
|
||||||
import {
|
import {
|
||||||
AlertType as RuleType,
|
RuleType,
|
||||||
AlertInstanceState as AlertState,
|
AlertInstanceState as AlertState,
|
||||||
AlertInstanceContext as AlertContext,
|
AlertInstanceContext as AlertContext,
|
||||||
} from '../../../../../alerting/server';
|
} from '../../../../../alerting/server';
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { ActionGroupIdsOf } from '../../../../../alerting/common';
|
import { ActionGroupIdsOf } from '../../../../../alerting/common';
|
||||||
import { AlertType, PluginSetupContract } from '../../../../../alerting/server';
|
import { RuleType, PluginSetupContract } from '../../../../../alerting/server';
|
||||||
import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api';
|
import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api';
|
||||||
import {
|
import {
|
||||||
createMetricThresholdExecutor,
|
createMetricThresholdExecutor,
|
||||||
|
@ -31,7 +31,7 @@ import {
|
||||||
type MetricThresholdAllowedActionGroups = ActionGroupIdsOf<
|
type MetricThresholdAllowedActionGroups = ActionGroupIdsOf<
|
||||||
typeof FIRED_ACTIONS | typeof WARNING_ACTIONS
|
typeof FIRED_ACTIONS | typeof WARNING_ACTIONS
|
||||||
>;
|
>;
|
||||||
export type MetricThresholdAlertType = Omit<AlertType, 'ActionGroupIdsOf'> & {
|
export type MetricThresholdAlertType = Omit<RuleType, 'ActionGroupIdsOf'> & {
|
||||||
ActionGroupIdsOf: MetricThresholdAllowedActionGroups;
|
ActionGroupIdsOf: MetricThresholdAllowedActionGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { Logger, ElasticsearchClient } from 'kibana/server';
|
import { Logger, ElasticsearchClient } from 'kibana/server';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertExecutorOptions,
|
AlertExecutorOptions,
|
||||||
AlertInstance,
|
AlertInstance,
|
||||||
RulesClient,
|
RulesClient,
|
||||||
|
@ -80,7 +80,7 @@ export class BaseRule {
|
||||||
this.scopedLogger = Globals.app.getLogger(ruleOptions.id);
|
this.scopedLogger = Globals.app.getLogger(ruleOptions.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRuleType(): AlertType<never, never, never, never, never, 'default'> {
|
public getRuleType(): RuleType<never, never, never, never, never, 'default'> {
|
||||||
const { id, name, actionVariables } = this.ruleOptions;
|
const { id, name, actionVariables } = this.ruleOptions;
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -12,14 +12,14 @@ import {
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
} from '../../alerting/common';
|
} from '../../alerting/common';
|
||||||
import { AlertExecutorOptions, AlertServices, AlertType } from '../../alerting/server';
|
import { AlertExecutorOptions, AlertServices, RuleType } from '../../alerting/server';
|
||||||
import { AlertsClient } from './alert_data_client/alerts_client';
|
import { AlertsClient } from './alert_data_client/alerts_client';
|
||||||
|
|
||||||
type SimpleAlertType<
|
type SimpleAlertType<
|
||||||
TState extends AlertTypeState,
|
TState extends AlertTypeState,
|
||||||
TParams extends AlertTypeParams = {},
|
TParams extends AlertTypeParams = {},
|
||||||
TAlertInstanceContext extends AlertInstanceContext = {}
|
TAlertInstanceContext extends AlertInstanceContext = {}
|
||||||
> = AlertType<TParams, TParams, TState, AlertInstanceState, TAlertInstanceContext, string, string>;
|
> = RuleType<TParams, TParams, TState, AlertInstanceState, TAlertInstanceContext, string, string>;
|
||||||
|
|
||||||
export type AlertTypeExecutor<
|
export type AlertTypeExecutor<
|
||||||
TState extends AlertTypeState,
|
TState extends AlertTypeState,
|
||||||
|
@ -38,7 +38,7 @@ export type AlertTypeWithExecutor<
|
||||||
TAlertInstanceContext extends AlertInstanceContext = {},
|
TAlertInstanceContext extends AlertInstanceContext = {},
|
||||||
TServices extends Record<string, any> = {}
|
TServices extends Record<string, any> = {}
|
||||||
> = Omit<
|
> = Omit<
|
||||||
AlertType<TParams, TParams, TState, AlertInstanceState, TAlertInstanceContext, string, string>,
|
RuleType<TParams, TParams, TState, AlertInstanceState, TAlertInstanceContext, string, string>,
|
||||||
'executor'
|
'executor'
|
||||||
> & {
|
> & {
|
||||||
executor: AlertTypeExecutor<TState, TParams, TAlertInstanceContext, TServices>;
|
executor: AlertTypeExecutor<TState, TParams, TAlertInstanceContext, TServices>;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
AlertExecutorOptions,
|
AlertExecutorOptions,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
} from '../../../alerting/server';
|
} from '../../../alerting/server';
|
||||||
|
@ -39,7 +39,7 @@ export type PersistenceAlertType<
|
||||||
TInstanceContext extends AlertInstanceContext = {},
|
TInstanceContext extends AlertInstanceContext = {},
|
||||||
TActionGroupIds extends string = never
|
TActionGroupIds extends string = never
|
||||||
> = Omit<
|
> = Omit<
|
||||||
AlertType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>,
|
RuleType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>,
|
||||||
'executor'
|
'executor'
|
||||||
> & {
|
> & {
|
||||||
executor: (
|
executor: (
|
||||||
|
@ -65,4 +65,4 @@ export type CreatePersistenceRuleTypeWrapper = (options: {
|
||||||
TActionGroupIds extends string = never
|
TActionGroupIds extends string = never
|
||||||
>(
|
>(
|
||||||
type: PersistenceAlertType<TParams, TState, TInstanceContext, TActionGroupIds>
|
type: PersistenceAlertType<TParams, TState, TInstanceContext, TActionGroupIds>
|
||||||
) => AlertType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>;
|
) => RuleType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { schema, TypeOf } from '@kbn/config-schema';
|
||||||
import {
|
import {
|
||||||
RulesClient,
|
RulesClient,
|
||||||
PartialAlert,
|
PartialAlert,
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
|
@ -103,7 +103,7 @@ export type LegacyNotificationExecutorOptions = AlertExecutorOptions<
|
||||||
*/
|
*/
|
||||||
export const legacyIsNotificationAlertExecutor = (
|
export const legacyIsNotificationAlertExecutor = (
|
||||||
obj: LegacyNotificationAlertTypeDefinition
|
obj: LegacyNotificationAlertTypeDefinition
|
||||||
): obj is AlertType<
|
): obj is RuleType<
|
||||||
LegacyRuleNotificationAlertTypeParams,
|
LegacyRuleNotificationAlertTypeParams,
|
||||||
LegacyRuleNotificationAlertTypeParams,
|
LegacyRuleNotificationAlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -117,7 +117,7 @@ export const legacyIsNotificationAlertExecutor = (
|
||||||
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
* @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function
|
||||||
*/
|
*/
|
||||||
export type LegacyNotificationAlertTypeDefinition = Omit<
|
export type LegacyNotificationAlertTypeDefinition = Omit<
|
||||||
AlertType<
|
RuleType<
|
||||||
LegacyRuleNotificationAlertTypeParams,
|
LegacyRuleNotificationAlertTypeParams,
|
||||||
LegacyRuleNotificationAlertTypeParams,
|
LegacyRuleNotificationAlertTypeParams,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { SearchHit } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||||
import { Logger } from '@kbn/logging';
|
import { Logger } from '@kbn/logging';
|
||||||
import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
|
import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
|
||||||
|
|
||||||
import { AlertExecutorOptions, AlertType } from '../../../../../alerting/server';
|
import { AlertExecutorOptions, RuleType } from '../../../../../alerting/server';
|
||||||
import {
|
import {
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
|
@ -73,7 +73,7 @@ export type SecurityAlertType<
|
||||||
TInstanceContext extends AlertInstanceContext = {},
|
TInstanceContext extends AlertInstanceContext = {},
|
||||||
TActionGroupIds extends string = never
|
TActionGroupIds extends string = never
|
||||||
> = Omit<
|
> = Omit<
|
||||||
AlertType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>,
|
RuleType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, TActionGroupIds>,
|
||||||
'executor'
|
'executor'
|
||||||
> & {
|
> & {
|
||||||
executor: (
|
executor: (
|
||||||
|
@ -107,7 +107,7 @@ export type CreateSecurityRuleTypeWrapper = (
|
||||||
TInstanceContext extends AlertInstanceContext = {}
|
TInstanceContext extends AlertInstanceContext = {}
|
||||||
>(
|
>(
|
||||||
type: SecurityAlertType<TParams, TState, TInstanceContext, 'default'>
|
type: SecurityAlertType<TParams, TState, TInstanceContext, 'default'>
|
||||||
) => AlertType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, 'default'>;
|
) => RuleType<TParams, TParams, TState, AlertInstanceState, TInstanceContext, 'default'>;
|
||||||
|
|
||||||
export type RACAlertSignal = TypeOfFieldMap<AlertsFieldMap> & TypeOfFieldMap<RulesFieldMap>;
|
export type RACAlertSignal = TypeOfFieldMap<AlertsFieldMap> & TypeOfFieldMap<RulesFieldMap>;
|
||||||
export type RACAlert = Exclude<
|
export type RACAlert = Exclude<
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t
|
||||||
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
import { Status } from '../../../../common/detection_engine/schemas/common/schemas';
|
||||||
import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema';
|
import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
|
@ -196,7 +196,7 @@ export type RuleExecutorOptions = AlertExecutorOptions<
|
||||||
// since we are only increasing the strictness of params.
|
// since we are only increasing the strictness of params.
|
||||||
export const isAlertExecutor = (
|
export const isAlertExecutor = (
|
||||||
obj: SignalRuleAlertTypeDefinition
|
obj: SignalRuleAlertTypeDefinition
|
||||||
): obj is AlertType<
|
): obj is RuleType<
|
||||||
RuleParams,
|
RuleParams,
|
||||||
RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values.
|
RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values.
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -207,7 +207,7 @@ export const isAlertExecutor = (
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SignalRuleAlertTypeDefinition = AlertType<
|
export type SignalRuleAlertTypeDefinition = RuleType<
|
||||||
RuleParams,
|
RuleParams,
|
||||||
RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values.
|
RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values.
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||||
import { Logger } from 'src/core/server';
|
import { Logger } from 'src/core/server';
|
||||||
import { AlertType, AlertExecutorOptions } from '../../types';
|
import { RuleType, AlertExecutorOptions } from '../../types';
|
||||||
import { ActionContext, EsQueryAlertActionContext, addMessages } from './action_context';
|
import { ActionContext, EsQueryAlertActionContext, addMessages } from './action_context';
|
||||||
import {
|
import {
|
||||||
EsQueryAlertParams,
|
EsQueryAlertParams,
|
||||||
|
@ -25,7 +25,7 @@ export const ES_QUERY_ID = '.es-query';
|
||||||
export const ActionGroupId = 'query matched';
|
export const ActionGroupId = 'query matched';
|
||||||
export const ConditionMetAlertInstanceId = 'query matched';
|
export const ConditionMetAlertInstanceId = 'query matched';
|
||||||
|
|
||||||
export function getAlertType(logger: Logger): AlertType<
|
export function getAlertType(logger: Logger): RuleType<
|
||||||
EsQueryAlertParams,
|
EsQueryAlertParams,
|
||||||
never, // Only use if defining useSavedObjectReferences hook
|
never, // Only use if defining useSavedObjectReferences hook
|
||||||
EsQueryAlertState,
|
EsQueryAlertState,
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Logger, SavedObjectReference } from 'src/core/server';
|
||||||
import { STACK_ALERTS_FEATURE_ID } from '../../../common';
|
import { STACK_ALERTS_FEATURE_ID } from '../../../common';
|
||||||
import { getGeoContainmentExecutor } from './geo_containment';
|
import { getGeoContainmentExecutor } from './geo_containment';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
|
@ -147,7 +147,7 @@ export interface GeoContainmentInstanceContext extends AlertInstanceContext {
|
||||||
containingBoundaryName: unknown;
|
containingBoundaryName: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GeoContainmentAlertType = AlertType<
|
export type GeoContainmentAlertType = RuleType<
|
||||||
GeoContainmentParams,
|
GeoContainmentParams,
|
||||||
GeoContainmentExtractedParams,
|
GeoContainmentExtractedParams,
|
||||||
GeoContainmentState,
|
GeoContainmentState,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { Logger } from 'src/core/server';
|
import { Logger } from 'src/core/server';
|
||||||
import { AlertType, AlertExecutorOptions, StackAlertsStartDeps } from '../../types';
|
import { RuleType, AlertExecutorOptions, StackAlertsStartDeps } from '../../types';
|
||||||
import { Params, ParamsSchema } from './alert_type_params';
|
import { Params, ParamsSchema } from './alert_type_params';
|
||||||
import { ActionContext, BaseActionContext, addMessages } from './action_context';
|
import { ActionContext, BaseActionContext, addMessages } from './action_context';
|
||||||
import { STACK_ALERTS_FEATURE_ID } from '../../../common';
|
import { STACK_ALERTS_FEATURE_ID } from '../../../common';
|
||||||
|
@ -23,7 +23,7 @@ export const ActionGroupId = 'threshold met';
|
||||||
export function getAlertType(
|
export function getAlertType(
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
data: Promise<StackAlertsStartDeps['triggersActionsUi']['data']>
|
data: Promise<StackAlertsStartDeps['triggersActionsUi']['data']>
|
||||||
): AlertType<Params, never, {}, {}, ActionContext, typeof ActionGroupId> {
|
): RuleType<Params, never, {}, {}, ActionContext, typeof ActionGroupId> {
|
||||||
const alertTypeName = i18n.translate('xpack.stackAlerts.indexThreshold.alertTypeTitle', {
|
const alertTypeName = i18n.translate('xpack.stackAlerts.indexThreshold.alertTypeTitle', {
|
||||||
defaultMessage: 'Index threshold',
|
defaultMessage: 'Index threshold',
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { PluginSetupContract as AlertingSetup } from '../../alerting/server';
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
PluginSetupContract as AlertingSetup,
|
PluginSetupContract as AlertingSetup,
|
||||||
AlertType,
|
RuleType,
|
||||||
RuleParamsAndRefs,
|
RuleParamsAndRefs,
|
||||||
AlertExecutorOptions,
|
AlertExecutorOptions,
|
||||||
} from '../../alerting/server';
|
} from '../../alerting/server';
|
||||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
||||||
} from '../../../../../alerting/common';
|
} from '../../../../../alerting/common';
|
||||||
import { PLUGIN, TRANSFORM_RULE_TYPE } from '../../../../common/constants';
|
import { PLUGIN, TRANSFORM_RULE_TYPE } from '../../../../common/constants';
|
||||||
import { transformHealthRuleParams, TransformHealthRuleParams } from './schema';
|
import { transformHealthRuleParams, TransformHealthRuleParams } from './schema';
|
||||||
import { AlertType } from '../../../../../alerting/server';
|
import { RuleType } from '../../../../../alerting/server';
|
||||||
import { transformHealthServiceProvider } from './transform_health_service';
|
import { transformHealthServiceProvider } from './transform_health_service';
|
||||||
import type { PluginSetupContract as AlertingSetup } from '../../../../../alerting/server';
|
import type { PluginSetupContract as AlertingSetup } from '../../../../../alerting/server';
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ export function registerTransformHealthRuleType(params: RegisterParams) {
|
||||||
alerting.registerType(getTransformHealthRuleType());
|
alerting.registerType(getTransformHealthRuleType());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTransformHealthRuleType(): AlertType<
|
export function getTransformHealthRuleType(): RuleType<
|
||||||
TransformHealthRuleParams,
|
TransformHealthRuleParams,
|
||||||
never,
|
never,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
|
|
@ -5343,16 +5343,16 @@
|
||||||
"xpack.alerting.rulesClient.invalidDate": "パラメーター{field}の無効な日付:「{dateValue}」",
|
"xpack.alerting.rulesClient.invalidDate": "パラメーター{field}の無効な日付:「{dateValue}」",
|
||||||
"xpack.alerting.rulesClient.validateActions.invalidGroups": "無効なアクショングループ:{groups}",
|
"xpack.alerting.rulesClient.validateActions.invalidGroups": "無効なアクショングループ:{groups}",
|
||||||
"xpack.alerting.rulesClient.validateActions.misconfiguredConnector": "無効なコネクター:{groups}",
|
"xpack.alerting.rulesClient.validateActions.misconfiguredConnector": "無効なコネクター:{groups}",
|
||||||
"xpack.alerting.ruleTypeRegistry.get.missingAlertTypeError": "ルールタイプ「{id}」は登録されていません。",
|
"xpack.alerting.ruleTypeRegistry.get.missingRuleTypeError": "ルールタイプ「{id}」は登録されていません。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.customRecoveryActionGroupUsageError": "ルールタイプ[id=\"{id}\"]を登録できません。アクショングループ [{actionGroup}] は、復元とアクティブなアクショングループの両方として使用できません。",
|
"xpack.alerting.ruleTypeRegistry.register.customRecoveryActionGroupUsageError": "ルールタイプ[id=\"{id}\"]を登録できません。アクショングループ [{actionGroup}] は、復元とアクティブなアクショングループの両方として使用できません。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.duplicateAlertTypeError": "ルールタイプ\"{id}\"はすでに登録されています。",
|
"xpack.alerting.ruleTypeRegistry.register.duplicateRuleTypeError": "ルールタイプ\"{id}\"はすでに登録されています。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutAlertTypeError": "ルールタイプ\"{id}\"のデフォルト間隔が無効です:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutRuleTypeError": "ルールタイプ\"{id}\"のデフォルト間隔が無効です:{errorMessage}。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutAlertTypeError": "ルールタイプ\"{id}\"の最低間隔が無効です:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutRuleTypeError": "ルールタイプ\"{id}\"の最低間隔が無効です:{errorMessage}。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidTimeoutAlertTypeError": "ルールタイプ\"{id}\"のタイムアウトが無効です:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidTimeoutRuleTypeError": "ルールタイプ\"{id}\"のタイムアウトが無効です:{errorMessage}。",
|
||||||
"xpack.alerting.savedObjects.goToRulesButtonText": "ルールに移動",
|
"xpack.alerting.savedObjects.goToRulesButtonText": "ルールに移動",
|
||||||
"xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage": "{licenseType} ライセンスの期限が切れたのでアラートタイプ {alertTypeId} は無効です。",
|
"xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage": "{licenseType} ライセンスの期限が切れたのでアラートタイプ {ruleTypeId} は無効です。",
|
||||||
"xpack.alerting.serverSideErrors.invalidLicenseErrorMessage": "アラート{alertTypeId}は無効です。{licenseType}ライセンスが必要です。アップグレードオプションを表示するには、[ライセンス管理]に移動してください。",
|
"xpack.alerting.serverSideErrors.invalidLicenseErrorMessage": "アラート{ruleTypeId}は無効です。{licenseType}ライセンスが必要です。アップグレードオプションを表示するには、[ライセンス管理]に移動してください。",
|
||||||
"xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage": "現時点でライセンス情報を入手できないため、アラートタイプ {alertTypeId} は無効です。",
|
"xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage": "現時点でライセンス情報を入手できないため、アラートタイプ {ruleTypeId} は無効です。",
|
||||||
"xpack.alerting.serverSideErrors.unavailableLicenseInformationErrorMessage": "アラートを利用できません。現在ライセンス情報が利用できません。",
|
"xpack.alerting.serverSideErrors.unavailableLicenseInformationErrorMessage": "アラートを利用できません。現在ライセンス情報が利用できません。",
|
||||||
"xpack.apm.a.thresholdMet": "しきい値一致",
|
"xpack.apm.a.thresholdMet": "しきい値一致",
|
||||||
"xpack.apm.addDataButtonLabel": "データの追加",
|
"xpack.apm.addDataButtonLabel": "データの追加",
|
||||||
|
|
|
@ -5378,18 +5378,18 @@
|
||||||
"xpack.alerting.rulesClient.invalidDate": "参数 {field} 的日期无效:“{dateValue}”",
|
"xpack.alerting.rulesClient.invalidDate": "参数 {field} 的日期无效:“{dateValue}”",
|
||||||
"xpack.alerting.rulesClient.validateActions.invalidGroups": "无效操作组:{groups}",
|
"xpack.alerting.rulesClient.validateActions.invalidGroups": "无效操作组:{groups}",
|
||||||
"xpack.alerting.rulesClient.validateActions.misconfiguredConnector": "无效的连接器:{groups}",
|
"xpack.alerting.rulesClient.validateActions.misconfiguredConnector": "无效的连接器:{groups}",
|
||||||
"xpack.alerting.ruleTypeRegistry.get.missingAlertTypeError": "未注册规则类型“{id}”。",
|
"xpack.alerting.ruleTypeRegistry.get.missingRuleTypeError": "未注册规则类型“{id}”。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.customRecoveryActionGroupUsageError": "无法注册规则类型 [id=\"{id}\"]。操作组 [{actionGroup}] 无法同时用作恢复和活动操作组。",
|
"xpack.alerting.ruleTypeRegistry.register.customRecoveryActionGroupUsageError": "无法注册规则类型 [id=\"{id}\"]。操作组 [{actionGroup}] 无法同时用作恢复和活动操作组。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.duplicateAlertTypeError": "已注册规则类型“{id}”。",
|
"xpack.alerting.ruleTypeRegistry.register.duplicateRuleTypeError": "已注册规则类型“{id}”。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutAlertTypeError": "规则类型“{id}”的默认时间间隔无效:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutRuleTypeError": "规则类型“{id}”的默认时间间隔无效:{errorMessage}。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutAlertTypeError": "规则类型“{id}”的最小时间间隔无效:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutRuleTypeError": "规则类型“{id}”的最小时间间隔无效:{errorMessage}。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.invalidTimeoutAlertTypeError": "规则类型“{id}”的超时无效:{errorMessage}。",
|
"xpack.alerting.ruleTypeRegistry.register.invalidTimeoutRuleTypeError": "规则类型“{id}”的超时无效:{errorMessage}。",
|
||||||
"xpack.alerting.ruleTypeRegistry.register.reservedActionGroupUsageError": "无法注册规则类型 [id=\"{id}\"]。操作组 [{actionGroups}] 由框架保留。",
|
"xpack.alerting.ruleTypeRegistry.register.reservedActionGroupUsageError": "无法注册规则类型 [id=\"{id}\"]。操作组 [{actionGroups}] 由框架保留。",
|
||||||
"xpack.alerting.savedObjects.goToRulesButtonText": "前往规则",
|
"xpack.alerting.savedObjects.goToRulesButtonText": "前往规则",
|
||||||
"xpack.alerting.savedObjects.onImportText": "导入后必须启用 {rulesSavedObjectsLength} 个{rulesSavedObjectsLength, plural,other {规则}}。",
|
"xpack.alerting.savedObjects.onImportText": "导入后必须启用 {rulesSavedObjectsLength} 个{rulesSavedObjectsLength, plural,other {规则}}。",
|
||||||
"xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage": "告警类型 {alertTypeId} 已禁用,因为您的{licenseType}许可证已过期。",
|
"xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage": "告警类型 {ruleTypeId} 已禁用,因为您的{licenseType}许可证已过期。",
|
||||||
"xpack.alerting.serverSideErrors.invalidLicenseErrorMessage": "告警 {alertTypeId} 已禁用,因为它需要{licenseType}许可证。前往“许可证管理”以查看升级选项。",
|
"xpack.alerting.serverSideErrors.invalidLicenseErrorMessage": "告警 {ruleTypeId} 已禁用,因为它需要{licenseType}许可证。前往“许可证管理”以查看升级选项。",
|
||||||
"xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage": "告警类型 {alertTypeId} 已禁用,因为许可证信息当前不可用。",
|
"xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage": "告警类型 {ruleTypeId} 已禁用,因为许可证信息当前不可用。",
|
||||||
"xpack.alerting.serverSideErrors.unavailableLicenseInformationErrorMessage": "告警不可用 - 许可信息当前不可用。",
|
"xpack.alerting.serverSideErrors.unavailableLicenseInformationErrorMessage": "告警不可用 - 许可信息当前不可用。",
|
||||||
"xpack.apm.a.thresholdMet": "已达到阈值",
|
"xpack.apm.a.thresholdMet": "已达到阈值",
|
||||||
"xpack.apm.addDataButtonLabel": "添加数据",
|
"xpack.apm.addDataButtonLabel": "添加数据",
|
||||||
|
|
|
@ -8,12 +8,12 @@ import { HttpSetup } from 'kibana/public';
|
||||||
import { pipe } from 'fp-ts/lib/pipeable';
|
import { pipe } from 'fp-ts/lib/pipeable';
|
||||||
import { fold } from 'fp-ts/lib/Either';
|
import { fold } from 'fp-ts/lib/Either';
|
||||||
import { Errors, identity } from 'io-ts';
|
import { Errors, identity } from 'io-ts';
|
||||||
import { AlertTaskState } from '../../../types';
|
import { RuleTaskState } from '../../../types';
|
||||||
import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants';
|
import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants';
|
||||||
import { alertStateSchema } from '../../../../../alerting/common';
|
import { ruleStateSchema } from '../../../../../alerting/common';
|
||||||
import { AsApiContract, RewriteRequestCase } from '../../../../../actions/common';
|
import { AsApiContract, RewriteRequestCase } from '../../../../../actions/common';
|
||||||
|
|
||||||
const rewriteBodyRes: RewriteRequestCase<AlertTaskState> = ({
|
const rewriteBodyRes: RewriteRequestCase<RuleTaskState> = ({
|
||||||
rule_type_state: alertTypeState,
|
rule_type_state: alertTypeState,
|
||||||
alerts: alertInstances,
|
alerts: alertInstances,
|
||||||
previous_started_at: previousStartedAt,
|
previous_started_at: previousStartedAt,
|
||||||
|
@ -32,17 +32,17 @@ export async function loadAlertState({
|
||||||
}: {
|
}: {
|
||||||
http: HttpSetup;
|
http: HttpSetup;
|
||||||
alertId: string;
|
alertId: string;
|
||||||
}): Promise<AlertTaskState> {
|
}): Promise<RuleTaskState> {
|
||||||
return await http
|
return await http
|
||||||
.get<AsApiContract<AlertTaskState> | EmptyHttpResponse>(
|
.get<AsApiContract<RuleTaskState> | EmptyHttpResponse>(
|
||||||
`${INTERNAL_BASE_ALERTING_API_PATH}/rule/${alertId}/state`
|
`${INTERNAL_BASE_ALERTING_API_PATH}/rule/${alertId}/state`
|
||||||
)
|
)
|
||||||
.then((state) => (state ? rewriteBodyRes(state) : {}))
|
.then((state) => (state ? rewriteBodyRes(state) : {}))
|
||||||
.then((state: AlertTaskState) => {
|
.then((state: RuleTaskState) => {
|
||||||
return pipe(
|
return pipe(
|
||||||
alertStateSchema.decode(state),
|
ruleStateSchema.decode(state),
|
||||||
fold((e: Errors) => {
|
fold((e: Errors) => {
|
||||||
throw new Error(`Alert "${alertId}" has invalid state`);
|
throw new Error(`Rule "${alertId}" has invalid state`);
|
||||||
}, identity)
|
}, identity)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertType,
|
AlertType,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
AlertSummary,
|
AlertSummary,
|
||||||
AlertingFrameworkHealth,
|
AlertingFrameworkHealth,
|
||||||
ResolvedRule,
|
ResolvedRule,
|
||||||
|
@ -56,7 +56,7 @@ export interface ComponentOpts {
|
||||||
errors: string[];
|
errors: string[];
|
||||||
}>;
|
}>;
|
||||||
loadAlert: (id: Alert['id']) => Promise<Alert>;
|
loadAlert: (id: Alert['id']) => Promise<Alert>;
|
||||||
loadAlertState: (id: Alert['id']) => Promise<AlertTaskState>;
|
loadAlertState: (id: Alert['id']) => Promise<RuleTaskState>;
|
||||||
loadAlertSummary: (id: Alert['id']) => Promise<AlertSummary>;
|
loadAlertSummary: (id: Alert['id']) => Promise<AlertSummary>;
|
||||||
loadAlertTypes: () => Promise<AlertType[]>;
|
loadAlertTypes: () => Promise<AlertType[]>;
|
||||||
getHealth: () => Promise<AlertingFrameworkHealth>;
|
getHealth: () => Promise<AlertingFrameworkHealth>;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import {
|
||||||
ResolvedSanitizedRule,
|
ResolvedSanitizedRule,
|
||||||
AlertAction,
|
AlertAction,
|
||||||
AlertAggregations,
|
AlertAggregations,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
AlertSummary,
|
AlertSummary,
|
||||||
ExecutionDuration,
|
ExecutionDuration,
|
||||||
AlertStatus,
|
AlertStatus,
|
||||||
|
@ -36,7 +36,7 @@ import {
|
||||||
AlertNotifyWhenType,
|
AlertNotifyWhenType,
|
||||||
AlertTypeParams,
|
AlertTypeParams,
|
||||||
ActionVariable,
|
ActionVariable,
|
||||||
AlertType as CommonAlertType,
|
RuleType as CommonRuleType,
|
||||||
} from '../../alerting/common';
|
} from '../../alerting/common';
|
||||||
|
|
||||||
// In Triggers and Actions we treat all `Alert`s as `SanitizedAlert<AlertTypeParams>`
|
// In Triggers and Actions we treat all `Alert`s as `SanitizedAlert<AlertTypeParams>`
|
||||||
|
@ -48,7 +48,7 @@ export type {
|
||||||
Alert,
|
Alert,
|
||||||
AlertAction,
|
AlertAction,
|
||||||
AlertAggregations,
|
AlertAggregations,
|
||||||
AlertTaskState,
|
RuleTaskState,
|
||||||
AlertSummary,
|
AlertSummary,
|
||||||
ExecutionDuration,
|
ExecutionDuration,
|
||||||
AlertStatus,
|
AlertStatus,
|
||||||
|
@ -208,7 +208,7 @@ export interface AlertType<
|
||||||
ActionGroupIds extends string = string,
|
ActionGroupIds extends string = string,
|
||||||
RecoveryActionGroupId extends string = string
|
RecoveryActionGroupId extends string = string
|
||||||
> extends Pick<
|
> extends Pick<
|
||||||
CommonAlertType<ActionGroupIds, RecoveryActionGroupId>,
|
CommonRuleType<ActionGroupIds, RecoveryActionGroupId>,
|
||||||
| 'id'
|
| 'id'
|
||||||
| 'name'
|
| 'name'
|
||||||
| 'actionGroups'
|
| 'actionGroups'
|
||||||
|
|
|
@ -22,7 +22,7 @@ export default function emailTest({ getService }: FtrProviderContext) {
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
error: 'Forbidden',
|
error: 'Forbidden',
|
||||||
message:
|
message:
|
||||||
'Alert test.gold.noop is disabled because it requires a Gold license. Go to License Management to view upgrade options.',
|
'Rule test.gold.noop is disabled because it requires a Gold license. Go to License Management to view upgrade options.',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { curry, times } from 'lodash';
|
||||||
import { ES_TEST_INDEX_NAME } from '../../../../lib';
|
import { ES_TEST_INDEX_NAME } from '../../../../lib';
|
||||||
import { FixtureStartDeps, FixtureSetupDeps } from './plugin';
|
import { FixtureStartDeps, FixtureSetupDeps } from './plugin';
|
||||||
import {
|
import {
|
||||||
AlertType,
|
RuleType,
|
||||||
AlertInstanceState,
|
AlertInstanceState,
|
||||||
AlertInstanceContext,
|
AlertInstanceContext,
|
||||||
AlertTypeState,
|
AlertTypeState,
|
||||||
|
@ -62,7 +62,7 @@ function getAlwaysFiringAlertType() {
|
||||||
interface InstanceContext extends AlertInstanceContext {
|
interface InstanceContext extends AlertInstanceContext {
|
||||||
instanceContextValue: boolean;
|
instanceContextValue: boolean;
|
||||||
}
|
}
|
||||||
const result: AlertType<
|
const result: RuleType<
|
||||||
ParamsType & AlertTypeParams,
|
ParamsType & AlertTypeParams,
|
||||||
never, // Only use if defining useSavedObjectReferences hook
|
never, // Only use if defining useSavedObjectReferences hook
|
||||||
State,
|
State,
|
||||||
|
@ -159,7 +159,7 @@ function getCumulativeFiringAlertType() {
|
||||||
interface InstanceState extends AlertInstanceState {
|
interface InstanceState extends AlertInstanceState {
|
||||||
instanceStateValue: boolean;
|
instanceStateValue: boolean;
|
||||||
}
|
}
|
||||||
const result: AlertType<{}, {}, State, InstanceState, {}, 'default' | 'other'> = {
|
const result: RuleType<{}, {}, State, InstanceState, {}, 'default' | 'other'> = {
|
||||||
id: 'test.cumulative-firing',
|
id: 'test.cumulative-firing',
|
||||||
name: 'Test: Cumulative Firing',
|
name: 'Test: Cumulative Firing',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -200,7 +200,7 @@ function getNeverFiringAlertType() {
|
||||||
interface State extends AlertTypeState {
|
interface State extends AlertTypeState {
|
||||||
globalStateValue: boolean;
|
globalStateValue: boolean;
|
||||||
}
|
}
|
||||||
const result: AlertType<ParamsType, never, State, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, State, {}, {}, 'default'> = {
|
||||||
id: 'test.never-firing',
|
id: 'test.never-firing',
|
||||||
name: 'Test: Never firing',
|
name: 'Test: Never firing',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -241,7 +241,7 @@ function getFailingAlertType() {
|
||||||
reference: schema.string(),
|
reference: schema.string(),
|
||||||
});
|
});
|
||||||
type ParamsType = TypeOf<typeof paramsSchema>;
|
type ParamsType = TypeOf<typeof paramsSchema>;
|
||||||
const result: AlertType<ParamsType, never, {}, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.failing',
|
id: 'test.failing',
|
||||||
name: 'Test: Failing',
|
name: 'Test: Failing',
|
||||||
validate: {
|
validate: {
|
||||||
|
@ -283,7 +283,7 @@ function getAuthorizationAlertType(core: CoreSetup<FixtureStartDeps>) {
|
||||||
reference: schema.string(),
|
reference: schema.string(),
|
||||||
});
|
});
|
||||||
type ParamsType = TypeOf<typeof paramsSchema>;
|
type ParamsType = TypeOf<typeof paramsSchema>;
|
||||||
const result: AlertType<ParamsType, never, {}, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.authorization',
|
id: 'test.authorization',
|
||||||
name: 'Test: Authorization',
|
name: 'Test: Authorization',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -371,7 +371,7 @@ function getValidationAlertType() {
|
||||||
param1: schema.string(),
|
param1: schema.string(),
|
||||||
});
|
});
|
||||||
type ParamsType = TypeOf<typeof paramsSchema>;
|
type ParamsType = TypeOf<typeof paramsSchema>;
|
||||||
const result: AlertType<ParamsType, never, {}, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.validation',
|
id: 'test.validation',
|
||||||
name: 'Test: Validation',
|
name: 'Test: Validation',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -404,7 +404,7 @@ function getPatternFiringAlertType() {
|
||||||
interface State extends AlertTypeState {
|
interface State extends AlertTypeState {
|
||||||
patternIndex?: number;
|
patternIndex?: number;
|
||||||
}
|
}
|
||||||
const result: AlertType<ParamsType, never, State, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, State, {}, {}, 'default'> = {
|
||||||
id: 'test.patternFiring',
|
id: 'test.patternFiring',
|
||||||
name: 'Test: Firing on a Pattern',
|
name: 'Test: Firing on a Pattern',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -473,7 +473,7 @@ function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true
|
||||||
interface State extends AlertTypeState {
|
interface State extends AlertTypeState {
|
||||||
patternIndex?: number;
|
patternIndex?: number;
|
||||||
}
|
}
|
||||||
const result: AlertType<ParamsType, never, State, {}, {}, 'default'> = {
|
const result: RuleType<ParamsType, never, State, {}, {}, 'default'> = {
|
||||||
id: `test.patternLongRunning${
|
id: `test.patternLongRunning${
|
||||||
cancelAlertsOnRuleTimeout === true ? '.cancelAlertsOnRuleTimeout' : ''
|
cancelAlertsOnRuleTimeout === true ? '.cancelAlertsOnRuleTimeout' : ''
|
||||||
}`,
|
}`,
|
||||||
|
@ -519,7 +519,7 @@ export function defineAlertTypes(
|
||||||
core: CoreSetup<FixtureStartDeps>,
|
core: CoreSetup<FixtureStartDeps>,
|
||||||
{ alerting }: Pick<FixtureSetupDeps, 'alerting'>
|
{ alerting }: Pick<FixtureSetupDeps, 'alerting'>
|
||||||
) {
|
) {
|
||||||
const noopAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const noopAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.noop',
|
id: 'test.noop',
|
||||||
name: 'Test: Noop',
|
name: 'Test: Noop',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -529,7 +529,7 @@ export function defineAlertTypes(
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
async executor() {},
|
async executor() {},
|
||||||
};
|
};
|
||||||
const goldNoopAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const goldNoopAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.gold.noop',
|
id: 'test.gold.noop',
|
||||||
name: 'Test: Noop',
|
name: 'Test: Noop',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -539,7 +539,7 @@ export function defineAlertTypes(
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
async executor() {},
|
async executor() {},
|
||||||
};
|
};
|
||||||
const onlyContextVariablesAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const onlyContextVariablesAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.onlyContextVariables',
|
id: 'test.onlyContextVariables',
|
||||||
name: 'Test: Only Context Variables',
|
name: 'Test: Only Context Variables',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -552,7 +552,7 @@ export function defineAlertTypes(
|
||||||
},
|
},
|
||||||
async executor() {},
|
async executor() {},
|
||||||
};
|
};
|
||||||
const onlyStateVariablesAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const onlyStateVariablesAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.onlyStateVariables',
|
id: 'test.onlyStateVariables',
|
||||||
name: 'Test: Only State Variables',
|
name: 'Test: Only State Variables',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -565,7 +565,7 @@ export function defineAlertTypes(
|
||||||
isExportable: true,
|
isExportable: true,
|
||||||
async executor() {},
|
async executor() {},
|
||||||
};
|
};
|
||||||
const throwAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const throwAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.throw',
|
id: 'test.throw',
|
||||||
name: 'Test: Throw',
|
name: 'Test: Throw',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -582,7 +582,7 @@ export function defineAlertTypes(
|
||||||
throw new Error('this alert is intended to fail');
|
throw new Error('this alert is intended to fail');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const longRunningAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const longRunningAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.longRunning',
|
id: 'test.longRunning',
|
||||||
name: 'Test: Long Running',
|
name: 'Test: Long Running',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
@ -599,21 +599,20 @@ export function defineAlertTypes(
|
||||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const exampleAlwaysFiringAlertType: AlertType<{}, {}, {}, {}, {}, 'small' | 'medium' | 'large'> =
|
const exampleAlwaysFiringAlertType: RuleType<{}, {}, {}, {}, {}, 'small' | 'medium' | 'large'> = {
|
||||||
{
|
id: 'example.always-firing',
|
||||||
id: 'example.always-firing',
|
name: 'Always firing',
|
||||||
name: 'Always firing',
|
actionGroups: [
|
||||||
actionGroups: [
|
{ id: 'small', name: 'Small t-shirt' },
|
||||||
{ id: 'small', name: 'Small t-shirt' },
|
{ id: 'medium', name: 'Medium t-shirt' },
|
||||||
{ id: 'medium', name: 'Medium t-shirt' },
|
{ id: 'large', name: 'Large t-shirt' },
|
||||||
{ id: 'large', name: 'Large t-shirt' },
|
],
|
||||||
],
|
defaultActionGroupId: 'small',
|
||||||
defaultActionGroupId: 'small',
|
minimumLicenseRequired: 'basic',
|
||||||
minimumLicenseRequired: 'basic',
|
isExportable: true,
|
||||||
isExportable: true,
|
async executor() {},
|
||||||
async executor() {},
|
producer: 'alertsFixture',
|
||||||
producer: 'alertsFixture',
|
};
|
||||||
};
|
|
||||||
|
|
||||||
alerting.registerType(getAlwaysFiringAlertType());
|
alerting.registerType(getAlwaysFiringAlertType());
|
||||||
alerting.registerType(getCumulativeFiringAlertType());
|
alerting.registerType(getCumulativeFiringAlertType());
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
} from 'kibana/server';
|
} from 'kibana/server';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
import { InvalidatePendingApiKey } from '../../../../../../../plugins/alerting/server/types';
|
import { InvalidatePendingApiKey } from '../../../../../../../plugins/alerting/server/types';
|
||||||
import { RawAlert } from '../../../../../../../plugins/alerting/server/types';
|
import { RawRule } from '../../../../../../../plugins/alerting/server/types';
|
||||||
import {
|
import {
|
||||||
ConcreteTaskInstance,
|
ConcreteTaskInstance,
|
||||||
TaskInstance,
|
TaskInstance,
|
||||||
|
@ -89,12 +89,12 @@ export function defineRoutes(core: CoreSetup<FixtureStartDeps>, { logger }: { lo
|
||||||
logger,
|
logger,
|
||||||
`/api/alerts_fixture/${id}/replace_api_key`,
|
`/api/alerts_fixture/${id}/replace_api_key`,
|
||||||
async () => {
|
async () => {
|
||||||
return await savedObjectsWithAlerts.update<RawAlert>(
|
return await savedObjectsWithAlerts.update<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
...(
|
...(
|
||||||
await encryptedSavedObjectsWithAlerts.getDecryptedAsInternalUser<RawAlert>(
|
await encryptedSavedObjectsWithAlerts.getDecryptedAsInternalUser<RawRule>(
|
||||||
'alert',
|
'alert',
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
|
@ -154,7 +154,7 @@ export function defineRoutes(core: CoreSetup<FixtureStartDeps>, { logger }: { lo
|
||||||
const savedObjectsWithAlerts = await savedObjects.getScopedClient(req, {
|
const savedObjectsWithAlerts = await savedObjects.getScopedClient(req, {
|
||||||
includedHiddenTypes: ['alert'],
|
includedHiddenTypes: ['alert'],
|
||||||
});
|
});
|
||||||
const savedAlert = await savedObjectsWithAlerts.get<RawAlert>(type, id);
|
const savedAlert = await savedObjectsWithAlerts.get<RawRule>(type, id);
|
||||||
const result = await retryIfConflicts(
|
const result = await retryIfConflicts(
|
||||||
logger,
|
logger,
|
||||||
`/api/alerts_fixture/saved_object/${type}/${id}`,
|
`/api/alerts_fixture/saved_object/${type}/${id}`,
|
||||||
|
@ -232,7 +232,7 @@ export function defineRoutes(core: CoreSetup<FixtureStartDeps>, { logger }: { lo
|
||||||
const savedObjectsWithTasksAndAlerts = await savedObjects.getScopedClient(req, {
|
const savedObjectsWithTasksAndAlerts = await savedObjects.getScopedClient(req, {
|
||||||
includedHiddenTypes: ['task', 'alert'],
|
includedHiddenTypes: ['task', 'alert'],
|
||||||
});
|
});
|
||||||
const alert = await savedObjectsWithTasksAndAlerts.get<RawAlert>('alert', id);
|
const alert = await savedObjectsWithTasksAndAlerts.get<RawRule>('alert', id);
|
||||||
const result = await retryIfConflicts(
|
const result = await retryIfConflicts(
|
||||||
logger,
|
logger,
|
||||||
`/api/alerts_fixture/{id}/reset_task_status`,
|
`/api/alerts_fixture/{id}/reset_task_status`,
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
|
|
||||||
import { CoreSetup } from 'src/core/server';
|
import { CoreSetup } from 'src/core/server';
|
||||||
import { FixtureStartDeps, FixtureSetupDeps } from './plugin';
|
import { FixtureStartDeps, FixtureSetupDeps } from './plugin';
|
||||||
import { AlertType } from '../../../../../../../plugins/alerting/server';
|
import { RuleType } from '../../../../../../../plugins/alerting/server';
|
||||||
|
|
||||||
export function defineAlertTypes(
|
export function defineAlertTypes(
|
||||||
core: CoreSetup<FixtureStartDeps>,
|
core: CoreSetup<FixtureStartDeps>,
|
||||||
{ alerting }: Pick<FixtureSetupDeps, 'alerting'>
|
{ alerting }: Pick<FixtureSetupDeps, 'alerting'>
|
||||||
) {
|
) {
|
||||||
const noopRestrictedAlertType: AlertType<{}, {}, {}, {}, {}, 'default', 'restrictedRecovered'> = {
|
const noopRestrictedAlertType: RuleType<{}, {}, {}, {}, {}, 'default', 'restrictedRecovered'> = {
|
||||||
id: 'test.restricted-noop',
|
id: 'test.restricted-noop',
|
||||||
name: 'Test: Restricted Noop',
|
name: 'Test: Restricted Noop',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -24,7 +24,7 @@ export function defineAlertTypes(
|
||||||
recoveryActionGroup: { id: 'restrictedRecovered', name: 'Restricted Recovery' },
|
recoveryActionGroup: { id: 'restrictedRecovered', name: 'Restricted Recovery' },
|
||||||
async executor() {},
|
async executor() {},
|
||||||
};
|
};
|
||||||
const noopUnrestrictedAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
const noopUnrestrictedAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.unrestricted-noop',
|
id: 'test.unrestricted-noop',
|
||||||
name: 'Test: Unrestricted Noop',
|
name: 'Test: Unrestricted Noop',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
|
|
@ -227,7 +227,7 @@ instanceStateValue: true
|
||||||
alertId,
|
alertId,
|
||||||
ruleTypeId: 'test.always-firing',
|
ruleTypeId: 'test.always-firing',
|
||||||
outcome: 'success',
|
outcome: 'success',
|
||||||
message: `alert executed: test.always-firing:${alertId}: 'abc'`,
|
message: `rule executed: test.always-firing:${alertId}: 'abc'`,
|
||||||
ruleObject: alertSearchResultWithoutDates,
|
ruleObject: alertSearchResultWithoutDates,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
TaskManagerDoc,
|
TaskManagerDoc,
|
||||||
} from '../../../common/lib';
|
} from '../../../common/lib';
|
||||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||||
import { RawAlert } from '../../../../../plugins/alerting/server/types';
|
import { RawRule } from '../../../../../plugins/alerting/server/types';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default function createAlertTests({ getService }: FtrProviderContext) {
|
export default function createAlertTests({ getService }: FtrProviderContext) {
|
||||||
|
@ -190,7 +190,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) {
|
||||||
execution_status: response.body.execution_status,
|
execution_status: response.body.execution_status,
|
||||||
});
|
});
|
||||||
|
|
||||||
const esResponse = await es.get<SavedObject<RawAlert>>(
|
const esResponse = await es.get<SavedObject<RawRule>>(
|
||||||
{
|
{
|
||||||
index: '.kibana',
|
index: '.kibana',
|
||||||
id: `alert:${response.body.id}`,
|
id: `alert:${response.body.id}`,
|
||||||
|
|
|
@ -133,7 +133,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
savedObjects: [
|
savedObjects: [
|
||||||
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
||||||
],
|
],
|
||||||
message: `alert execution start: "${alertId}"`,
|
message: `rule execution start: "${alertId}"`,
|
||||||
shouldHaveTask: true,
|
shouldHaveTask: true,
|
||||||
rule: {
|
rule: {
|
||||||
id: alertId,
|
id: alertId,
|
||||||
|
@ -150,7 +150,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
||||||
],
|
],
|
||||||
outcome: 'success',
|
outcome: 'success',
|
||||||
message: `alert executed: test.patternFiring:${alertId}: 'abc'`,
|
message: `rule executed: test.patternFiring:${alertId}: 'abc'`,
|
||||||
status: executeStatuses[executeCount++],
|
status: executeStatuses[executeCount++],
|
||||||
shouldHaveTask: true,
|
shouldHaveTask: true,
|
||||||
rule: {
|
rule: {
|
||||||
|
@ -182,15 +182,15 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'new-instance':
|
case 'new-instance':
|
||||||
validateInstanceEvent(event, `created new instance: 'instance'`, false);
|
validateInstanceEvent(event, `created new alert: 'instance'`, false);
|
||||||
break;
|
break;
|
||||||
case 'recovered-instance':
|
case 'recovered-instance':
|
||||||
validateInstanceEvent(event, `instance 'instance' has recovered`, true);
|
validateInstanceEvent(event, `alert 'instance' has recovered`, true);
|
||||||
break;
|
break;
|
||||||
case 'active-instance':
|
case 'active-instance':
|
||||||
validateInstanceEvent(
|
validateInstanceEvent(
|
||||||
event,
|
event,
|
||||||
`active instance: 'instance' in actionGroup: 'default'`,
|
`active alert: 'instance' in actionGroup: 'default'`,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -344,7 +344,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
savedObjects: [
|
savedObjects: [
|
||||||
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
||||||
],
|
],
|
||||||
message: `alert execution start: "${alertId}"`,
|
message: `rule execution start: "${alertId}"`,
|
||||||
shouldHaveTask: true,
|
shouldHaveTask: true,
|
||||||
rule: {
|
rule: {
|
||||||
id: alertId,
|
id: alertId,
|
||||||
|
@ -361,7 +361,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
||||||
],
|
],
|
||||||
outcome: 'success',
|
outcome: 'success',
|
||||||
message: `alert executed: test.patternFiring:${alertId}: 'abc'`,
|
message: `rule executed: test.patternFiring:${alertId}: 'abc'`,
|
||||||
status: executeStatuses[executeCount++],
|
status: executeStatuses[executeCount++],
|
||||||
shouldHaveTask: true,
|
shouldHaveTask: true,
|
||||||
rule: {
|
rule: {
|
||||||
|
@ -398,10 +398,10 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'new-instance':
|
case 'new-instance':
|
||||||
validateInstanceEvent(event, `created new instance: 'instance'`, false);
|
validateInstanceEvent(event, `created new alert: 'instance'`, false);
|
||||||
break;
|
break;
|
||||||
case 'recovered-instance':
|
case 'recovered-instance':
|
||||||
validateInstanceEvent(event, `instance 'instance' has recovered`, true);
|
validateInstanceEvent(event, `alert 'instance' has recovered`, true);
|
||||||
break;
|
break;
|
||||||
case 'active-instance':
|
case 'active-instance':
|
||||||
expect(
|
expect(
|
||||||
|
@ -411,7 +411,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
).to.be(true);
|
).to.be(true);
|
||||||
validateInstanceEvent(
|
validateInstanceEvent(
|
||||||
event,
|
event,
|
||||||
`active instance: 'instance' in actionGroup(subgroup): 'default(${event?.kibana?.alerting?.action_subgroup})'`,
|
`active alert: 'instance' in actionGroup(subgroup): 'default(${event?.kibana?.alerting?.action_subgroup})'`,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -490,7 +490,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
savedObjects: [
|
savedObjects: [
|
||||||
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' },
|
||||||
],
|
],
|
||||||
message: `alert execution start: "${alertId}"`,
|
message: `rule execution start: "${alertId}"`,
|
||||||
shouldHaveTask: true,
|
shouldHaveTask: true,
|
||||||
rule: {
|
rule: {
|
||||||
id: alertId,
|
id: alertId,
|
||||||
|
@ -504,7 +504,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
||||||
spaceId: space.id,
|
spaceId: space.id,
|
||||||
savedObjects: [{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.throw' }],
|
savedObjects: [{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.throw' }],
|
||||||
outcome: 'failure',
|
outcome: 'failure',
|
||||||
message: `alert execution failure: test.throw:${alertId}: 'abc'`,
|
message: `rule execution failure: test.throw:${alertId}: 'abc'`,
|
||||||
errorMessage: 'this alert is intended to fail',
|
errorMessage: 'this alert is intended to fail',
|
||||||
status: 'error',
|
status: 'error',
|
||||||
reason: 'execute',
|
reason: 'execute',
|
||||||
|
|
|
@ -9,7 +9,7 @@ import expect from '@kbn/expect';
|
||||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||||
import { getUrlPrefix } from '../../../common/lib';
|
import { getUrlPrefix } from '../../../common/lib';
|
||||||
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
import { FtrProviderContext } from '../../../common/ftr_provider_context';
|
||||||
import type { RawAlert, RawAlertAction } from '../../../../../plugins/alerting/server/types';
|
import type { RawRule, RawAlertAction } from '../../../../../plugins/alerting/server/types';
|
||||||
import { FILEBEAT_7X_INDICATOR_PATH } from '../../../../../plugins/alerting/server/saved_objects/migrations';
|
import { FILEBEAT_7X_INDICATOR_PATH } from '../../../../../plugins/alerting/server/saved_objects/migrations';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
@ -205,7 +205,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('7.16.0 migrates existing alerts to contain legacyId field', async () => {
|
it('7.16.0 migrates existing alerts to contain legacyId field', async () => {
|
||||||
const searchResult = await es.search<RawAlert>(
|
const searchResult = await es.search<RawRule>(
|
||||||
{
|
{
|
||||||
index: '.kibana',
|
index: '.kibana',
|
||||||
body: {
|
body: {
|
||||||
|
@ -221,13 +221,13 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
||||||
expect(searchResult.statusCode).to.equal(200);
|
expect(searchResult.statusCode).to.equal(200);
|
||||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
||||||
const hit = searchResult.body.hits.hits[0];
|
const hit = searchResult.body.hits.hits[0];
|
||||||
expect((hit!._source!.alert! as RawAlert).legacyId).to.equal(
|
expect((hit!._source!.alert! as RawRule).legacyId).to.equal(
|
||||||
'74f3e6d7-b7bb-477d-ac28-92ee22728e6e'
|
'74f3e6d7-b7bb-477d-ac28-92ee22728e6e'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('7.16.0 migrates existing rules so predefined connectors are not stored in references', async () => {
|
it('7.16.0 migrates existing rules so predefined connectors are not stored in references', async () => {
|
||||||
const searchResult = await es.search<RawAlert>(
|
const searchResult = await es.search<RawRule>(
|
||||||
{
|
{
|
||||||
index: '.kibana',
|
index: '.kibana',
|
||||||
body: {
|
body: {
|
||||||
|
@ -243,7 +243,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
||||||
expect(searchResult.statusCode).to.equal(200);
|
expect(searchResult.statusCode).to.equal(200);
|
||||||
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1);
|
||||||
const hit = searchResult.body.hits.hits[0];
|
const hit = searchResult.body.hits.hits[0];
|
||||||
expect((hit!._source!.alert! as RawAlert).actions! as RawAlertAction[]).to.eql([
|
expect((hit!._source!.alert! as RawRule).actions! as RawAlertAction[]).to.eql([
|
||||||
{
|
{
|
||||||
actionRef: 'action_0',
|
actionRef: 'action_0',
|
||||||
actionTypeId: 'test.noop',
|
actionTypeId: 'test.noop',
|
||||||
|
@ -348,7 +348,7 @@ export default function createGetTests({ getService }: FtrProviderContext) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('8.0 migrates incorrect action group spellings on the Metrics Inventory Threshold rule type', async () => {
|
it('8.0 migrates incorrect action group spellings on the Metrics Inventory Threshold rule type', async () => {
|
||||||
const response = await es.get<{ alert: RawAlert }>(
|
const response = await es.get<{ alert: RawRule }>(
|
||||||
{
|
{
|
||||||
index: '.kibana',
|
index: '.kibana',
|
||||||
id: 'alert:92237b30-4e03-11ec-9ab9-d980518a2d28',
|
id: 'alert:92237b30-4e03-11ec-9ab9-d980518a2d28',
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { Plugin, CoreSetup } from 'kibana/server';
|
import { Plugin, CoreSetup } from 'kibana/server';
|
||||||
import {
|
import {
|
||||||
PluginSetupContract as AlertingSetup,
|
PluginSetupContract as AlertingSetup,
|
||||||
AlertType,
|
RuleType,
|
||||||
} from '../../../../../../plugins/alerting/server';
|
} from '../../../../../../plugins/alerting/server';
|
||||||
import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../plugins/features/server';
|
import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../plugins/features/server';
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export interface AlertingExampleDeps {
|
||||||
features: FeaturesPluginSetup;
|
features: FeaturesPluginSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const noopAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
export const noopAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
id: 'test.noop',
|
id: 'test.noop',
|
||||||
name: 'Test: Noop',
|
name: 'Test: Noop',
|
||||||
actionGroups: [{ id: 'default', name: 'Default' }],
|
actionGroups: [{ id: 'default', name: 'Default' }],
|
||||||
|
@ -29,7 +29,7 @@ export const noopAlertType: AlertType<{}, {}, {}, {}, {}, 'default'> = {
|
||||||
producer: 'alerts',
|
producer: 'alerts',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const alwaysFiringAlertType: AlertType<
|
export const alwaysFiringAlertType: RuleType<
|
||||||
{ instances: Array<{ id: string; state: any }> },
|
{ instances: Array<{ id: string; state: any }> },
|
||||||
never, // Only use if defining useSavedObjectReferences hook
|
never, // Only use if defining useSavedObjectReferences hook
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ export const alwaysFiringAlertType: AlertType<
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const failingAlertType: AlertType<never, never, never, never, never, 'default' | 'other'> = {
|
export const failingAlertType: RuleType<never, never, never, never, never, 'default' | 'other'> = {
|
||||||
id: 'test.failing',
|
id: 'test.failing',
|
||||||
name: 'Test: Failing',
|
name: 'Test: Failing',
|
||||||
actionGroups: [
|
actionGroups: [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue