mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
Add flapping state object and interface in AAD index and Event Log (#143920)
* move flapping to kibana.alerting in event log * move flapping back to under kibana.alert. Add integration tests * add default flapping state to alert logs
This commit is contained in:
parent
5e7989844d
commit
c5bcfd6762
25 changed files with 192 additions and 30 deletions
|
@ -30,6 +30,7 @@ const ALERT_DURATION = `${ALERT_NAMESPACE}.duration.us` as const;
|
|||
const ALERT_END = `${ALERT_NAMESPACE}.end` as const;
|
||||
const ALERT_EVALUATION_THRESHOLD = `${ALERT_NAMESPACE}.evaluation.threshold` as const;
|
||||
const ALERT_EVALUATION_VALUE = `${ALERT_NAMESPACE}.evaluation.value` as const;
|
||||
const ALERT_FLAPPING = `${ALERT_NAMESPACE}.flapping` as const;
|
||||
const ALERT_INSTANCE_ID = `${ALERT_NAMESPACE}.instance.id` as const;
|
||||
const ALERT_REASON = `${ALERT_NAMESPACE}.reason` as const;
|
||||
const ALERT_RISK_SCORE = `${ALERT_NAMESPACE}.risk_score` as const;
|
||||
|
@ -115,6 +116,7 @@ const fields = {
|
|||
ALERT_END,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
ALERT_EVALUATION_VALUE,
|
||||
ALERT_FLAPPING,
|
||||
ALERT_INSTANCE_ID,
|
||||
ALERT_RULE_CONSUMER,
|
||||
ALERT_RULE_PRODUCER,
|
||||
|
@ -176,6 +178,7 @@ export {
|
|||
ALERT_END,
|
||||
ALERT_EVALUATION_THRESHOLD,
|
||||
ALERT_EVALUATION_VALUE,
|
||||
ALERT_FLAPPING,
|
||||
ALERT_INSTANCE_ID,
|
||||
ALERT_NAMESPACE,
|
||||
ALERT_RULE_NAMESPACE,
|
||||
|
|
|
@ -36,4 +36,5 @@ export interface AlertStatus {
|
|||
muted: boolean;
|
||||
actionGroupId?: string;
|
||||
activeStartDate?: string;
|
||||
flapping: boolean;
|
||||
}
|
||||
|
|
|
@ -122,12 +122,14 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": true,
|
||||
"status": "OK",
|
||||
},
|
||||
"alert-2": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": true,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -232,6 +234,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -272,6 +275,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -311,6 +315,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -351,6 +356,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": "action group A",
|
||||
"activeStartDate": "2020-06-18T00:00:00.000Z",
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
|
@ -391,6 +397,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": "2020-06-18T00:00:00.000Z",
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
|
@ -431,6 +438,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": "action group B",
|
||||
"activeStartDate": "2020-06-18T00:00:00.000Z",
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
|
@ -469,6 +477,7 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": "action group A",
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
|
@ -511,12 +520,14 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": "action group A",
|
||||
"activeStartDate": "2020-06-18T00:00:00.000Z",
|
||||
"flapping": false,
|
||||
"muted": true,
|
||||
"status": "Active",
|
||||
},
|
||||
"alert-2": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": true,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -566,12 +577,14 @@ describe('alertSummaryFromEventLog', () => {
|
|||
"alert-1": Object {
|
||||
"actionGroupId": "action group B",
|
||||
"activeStartDate": "2020-06-18T00:00:00.000Z",
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
"alert-2": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "OK",
|
||||
},
|
||||
|
@ -584,6 +597,43 @@ describe('alertSummaryFromEventLog', () => {
|
|||
testExecutionDurations(eventsFactory.getExecutionDurations(), executionDuration);
|
||||
});
|
||||
|
||||
test('rule with currently active alert, flapping', async () => {
|
||||
const rule = createRule({});
|
||||
const eventsFactory = new EventsFactory();
|
||||
const events = eventsFactory
|
||||
.addExecute()
|
||||
.addActiveAlert('alert-1', 'action group A', true)
|
||||
.getEvents();
|
||||
|
||||
const executionEvents = eventsFactory.getEvents();
|
||||
|
||||
const summary: AlertSummary = alertSummaryFromEventLog({
|
||||
rule,
|
||||
events,
|
||||
executionEvents,
|
||||
dateStart,
|
||||
dateEnd,
|
||||
});
|
||||
const { lastRun, status, alerts, executionDuration } = summary;
|
||||
expect({ lastRun, status, alerts }).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"alerts": Object {
|
||||
"alert-1": Object {
|
||||
"actionGroupId": "action group A",
|
||||
"activeStartDate": undefined,
|
||||
"flapping": true,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
},
|
||||
"lastRun": "2020-06-18T00:00:00.000Z",
|
||||
"status": "Active",
|
||||
}
|
||||
`);
|
||||
|
||||
testExecutionDurations(eventsFactory.getExecutionDurations(), executionDuration);
|
||||
});
|
||||
|
||||
const testExecutionDurations = (
|
||||
actualDurations: Record<string, number>,
|
||||
executionDuration?: {
|
||||
|
@ -642,7 +692,11 @@ export class EventsFactory {
|
|||
return this;
|
||||
}
|
||||
|
||||
addActiveAlert(alertId: string, actionGroupId: string | undefined): EventsFactory {
|
||||
addActiveAlert(
|
||||
alertId: string,
|
||||
actionGroupId: string | undefined,
|
||||
flapping = false
|
||||
): EventsFactory {
|
||||
const kibanaAlerting = actionGroupId
|
||||
? { instance_id: alertId, action_group_id: actionGroupId }
|
||||
: { instance_id: alertId };
|
||||
|
@ -652,7 +706,7 @@ export class EventsFactory {
|
|||
provider: EVENT_LOG_PROVIDER,
|
||||
action: EVENT_LOG_ACTIONS.activeInstance,
|
||||
},
|
||||
kibana: { alerting: kibanaAlerting },
|
||||
kibana: { alerting: kibanaAlerting, alert: { flapping } },
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,11 @@ export function alertSummaryFromEventLog(params: AlertSummaryFromEventLogParams)
|
|||
if (alertId === undefined) continue;
|
||||
|
||||
const status = getAlertStatus(alerts, alertId);
|
||||
|
||||
if (event?.kibana?.alert?.flapping) {
|
||||
status.flapping = true;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case EVENT_LOG_ACTIONS.newInstance:
|
||||
status.activeStartDate = timeStamp;
|
||||
|
@ -152,6 +157,7 @@ function getAlertStatus(alerts: Map<string, AlertStatus>, alertId: string): Aler
|
|||
muted: false,
|
||||
actionGroupId: undefined,
|
||||
activeStartDate: undefined,
|
||||
flapping: false,
|
||||
};
|
||||
alerts.set(alertId, status);
|
||||
return status;
|
||||
|
|
|
@ -66,6 +66,7 @@ const alert = {
|
|||
end: '2020-01-01T03:00:00.000Z',
|
||||
duration: '2343252346',
|
||||
},
|
||||
flapping: false,
|
||||
};
|
||||
|
||||
const action = {
|
||||
|
|
|
@ -48,6 +48,7 @@ interface AlertOpts {
|
|||
message: string;
|
||||
group?: string;
|
||||
state?: AlertInstanceState;
|
||||
flapping: boolean;
|
||||
}
|
||||
|
||||
interface ActionOpts {
|
||||
|
@ -247,6 +248,7 @@ export function createAlertRecord(context: RuleContextOpts, alert: AlertOpts) {
|
|||
},
|
||||
],
|
||||
ruleName: context.ruleName,
|
||||
flapping: alert.flapping,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ interface CreateAlertEventLogRecordParams {
|
|||
typeId: string;
|
||||
relation?: string;
|
||||
}>;
|
||||
flapping?: boolean;
|
||||
}
|
||||
|
||||
export function createAlertEventLogRecordObject(params: CreateAlertEventLogRecordParams): Event {
|
||||
|
@ -50,6 +51,7 @@ export function createAlertEventLogRecordObject(params: CreateAlertEventLogRecor
|
|||
namespace,
|
||||
consumer,
|
||||
spaceId,
|
||||
flapping,
|
||||
} = params;
|
||||
const alerting =
|
||||
params.instanceId || group
|
||||
|
@ -72,6 +74,7 @@ export function createAlertEventLogRecordObject(params: CreateAlertEventLogRecor
|
|||
},
|
||||
kibana: {
|
||||
alert: {
|
||||
...(flapping !== undefined ? { flapping } : {}),
|
||||
rule: {
|
||||
rule_type_id: ruleType.id,
|
||||
...(consumer ? { consumer } : {}),
|
||||
|
|
|
@ -128,7 +128,7 @@ describe('getAlertSummary()', () => {
|
|||
.advanceTime(10000)
|
||||
.addExecute()
|
||||
.addRecoveredAlert('alert-previously-active')
|
||||
.addActiveAlert('alert-currently-active', 'action group A')
|
||||
.addActiveAlert('alert-currently-active', 'action group A', true)
|
||||
.getEvents();
|
||||
const eventsResult = {
|
||||
...AlertSummaryFindEventsResult,
|
||||
|
@ -157,18 +157,21 @@ describe('getAlertSummary()', () => {
|
|||
"alert-currently-active": Object {
|
||||
"actionGroupId": "action group A",
|
||||
"activeStartDate": "2019-02-12T21:01:22.479Z",
|
||||
"flapping": true,
|
||||
"muted": false,
|
||||
"status": "Active",
|
||||
},
|
||||
"alert-muted-no-activity": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": true,
|
||||
"status": "OK",
|
||||
},
|
||||
"alert-previously-active": Object {
|
||||
"actionGroupId": undefined,
|
||||
"activeStartDate": undefined,
|
||||
"flapping": false,
|
||||
"muted": false,
|
||||
"status": "OK",
|
||||
},
|
||||
|
|
|
@ -198,6 +198,7 @@ export const generateAlertOpts = ({ action, group, state, id }: GeneratorParams
|
|||
message,
|
||||
state,
|
||||
...(group ? { group } : {}),
|
||||
flapping: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -158,48 +158,56 @@ describe('logAlerts', () => {
|
|||
id: '7',
|
||||
message: "test-rule-type-id:123: 'test rule' alert '7' has recovered",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(2, {
|
||||
action: 'recovered-instance',
|
||||
id: '8',
|
||||
message: "test-rule-type-id:123: 'test rule' alert '8' has recovered",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(3, {
|
||||
action: 'recovered-instance',
|
||||
id: '9',
|
||||
message: "test-rule-type-id:123: 'test rule' alert '9' has recovered",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(4, {
|
||||
action: 'recovered-instance',
|
||||
id: '10',
|
||||
message: "test-rule-type-id:123: 'test rule' alert '10' has recovered",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(5, {
|
||||
action: 'new-instance',
|
||||
id: '4',
|
||||
message: "test-rule-type-id:123: 'test rule' created new alert: '4'",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(6, {
|
||||
action: 'active-instance',
|
||||
id: '1',
|
||||
message: "test-rule-type-id:123: 'test rule' active alert: '1' in actionGroup: 'undefined'",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(7, {
|
||||
action: 'active-instance',
|
||||
id: '2',
|
||||
message: "test-rule-type-id:123: 'test rule' active alert: '2' in actionGroup: 'undefined'",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith(8, {
|
||||
action: 'active-instance',
|
||||
id: '4',
|
||||
message: "test-rule-type-id:123: 'test rule' active alert: '4' in actionGroup: 'undefined'",
|
||||
state: {},
|
||||
flapping: false,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ export function logAlerts<
|
|||
group: actionGroup,
|
||||
message,
|
||||
state,
|
||||
flapping: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -115,6 +116,7 @@ export function logAlerts<
|
|||
group: actionGroup,
|
||||
message,
|
||||
state,
|
||||
flapping: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -128,6 +130,7 @@ export function logAlerts<
|
|||
group: actionGroup,
|
||||
message,
|
||||
state,
|
||||
flapping: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,6 +276,9 @@
|
|||
},
|
||||
"alert": {
|
||||
"properties": {
|
||||
"flapping": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rule": {
|
||||
"properties": {
|
||||
"consumer": {
|
||||
|
|
|
@ -120,6 +120,7 @@ export const EventSchema = schema.maybe(
|
|||
),
|
||||
alert: schema.maybe(
|
||||
schema.object({
|
||||
flapping: ecsBoolean(),
|
||||
rule: schema.maybe(
|
||||
schema.object({
|
||||
consumer: ecsString(),
|
||||
|
@ -199,6 +200,10 @@ function ecsDate() {
|
|||
return schema.maybe(schema.string({ validate: validateDate }));
|
||||
}
|
||||
|
||||
function ecsBoolean() {
|
||||
return schema.maybe(schema.boolean());
|
||||
}
|
||||
|
||||
const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
||||
|
||||
function validateDate(isoDate: string) {
|
||||
|
|
|
@ -161,6 +161,11 @@ function generateSchemaLines(lineWriter, prop, mappings) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (mappings.type === 'boolean') {
|
||||
lineWriter.addLine(`${propKey}: ecsBoolean(),`);
|
||||
return;
|
||||
}
|
||||
|
||||
// only handling objects for the rest of this function
|
||||
if (mappings.properties == null) {
|
||||
logError(`unknown properties to map: ${prop}: ${JSON.stringify(mappings)}`);
|
||||
|
@ -324,6 +329,10 @@ function ecsDate() {
|
|||
return schema.maybe(schema.string({ validate: validateDate }));
|
||||
}
|
||||
|
||||
function ecsBoolean() {
|
||||
return schema.maybe(schema.boolean());
|
||||
}
|
||||
|
||||
const ISO_DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;
|
||||
|
||||
function validateDate(isoDate: string) {
|
||||
|
|
|
@ -58,6 +58,9 @@ exports.EcsCustomPropertyMappings = {
|
|||
},
|
||||
alert: {
|
||||
properties: {
|
||||
flapping: {
|
||||
type: 'boolean',
|
||||
},
|
||||
rule: {
|
||||
properties: {
|
||||
consumer: {
|
||||
|
|
|
@ -43,6 +43,9 @@ it('matches snapshot', () => {
|
|||
"kibana.alert.end": Object {
|
||||
"type": "date",
|
||||
},
|
||||
"kibana.alert.flapping": Object {
|
||||
"type": "boolean",
|
||||
},
|
||||
"kibana.alert.instance.id": Object {
|
||||
"required": true,
|
||||
"type": "keyword",
|
||||
|
|
|
@ -33,6 +33,7 @@ export const technicalRuleFieldMap = {
|
|||
[Fields.ALERT_DURATION]: { type: 'long' },
|
||||
[Fields.ALERT_SEVERITY]: { type: 'keyword' },
|
||||
[Fields.ALERT_STATUS]: { type: 'keyword', required: true },
|
||||
[Fields.ALERT_FLAPPING]: { type: 'boolean' },
|
||||
[Fields.VERSION]: {
|
||||
type: 'version',
|
||||
array: false,
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
TAGS,
|
||||
TIMESTAMP,
|
||||
VERSION,
|
||||
// ALERT_FLAPPING,
|
||||
} from '../../common/technical_rule_data_field_names';
|
||||
import { CommonAlertFieldNameLatest, CommonAlertIdFieldNameLatest } from '../../common/schemas';
|
||||
import { IRuleDataClient } from '../rule_data_client';
|
||||
|
|
|
@ -14,7 +14,13 @@ const http = httpServiceMock.createStartContract();
|
|||
describe('loadRuleSummary', () => {
|
||||
test('should call rule summary API', async () => {
|
||||
const resolvedValue: RuleSummary = {
|
||||
alerts: {},
|
||||
alerts: {
|
||||
'1': {
|
||||
flapping: true,
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
},
|
||||
},
|
||||
consumer: 'alerts',
|
||||
enabled: true,
|
||||
errorMessages: [],
|
||||
|
@ -35,7 +41,13 @@ describe('loadRuleSummary', () => {
|
|||
};
|
||||
|
||||
http.get.mockResolvedValueOnce({
|
||||
alerts: {},
|
||||
alerts: {
|
||||
'1': {
|
||||
flapping: true,
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
},
|
||||
},
|
||||
consumer: 'alerts',
|
||||
enabled: true,
|
||||
error_messages: [],
|
||||
|
|
|
@ -72,11 +72,13 @@ describe('rules', () => {
|
|||
status: 'OK',
|
||||
muted: false,
|
||||
actionGroupId: 'default',
|
||||
flapping: false,
|
||||
},
|
||||
second_rule: {
|
||||
status: 'Active',
|
||||
muted: false,
|
||||
actionGroupId: 'action group id unknown',
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -134,10 +136,12 @@ describe('rules', () => {
|
|||
['us-central']: {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
['us-east']: {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -169,8 +173,8 @@ describe('rules', () => {
|
|||
mutedInstanceIds: ['us-west', 'us-east'],
|
||||
});
|
||||
const ruleType = mockRuleType();
|
||||
const ruleUsWest: AlertStatus = { status: 'OK', muted: false };
|
||||
const ruleUsEast: AlertStatus = { status: 'OK', muted: false };
|
||||
const ruleUsWest: AlertStatus = { status: 'OK', muted: false, flapping: false };
|
||||
const ruleUsEast: AlertStatus = { status: 'OK', muted: false, flapping: false };
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<RuleComponent
|
||||
|
@ -183,10 +187,12 @@ describe('rules', () => {
|
|||
'us-west': {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
'us-east': {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
})}
|
||||
|
@ -219,6 +225,7 @@ describe('alertToListItem', () => {
|
|||
muted: false,
|
||||
activeStartDate: fake2MinutesAgo.toISOString(),
|
||||
actionGroupId: 'testing',
|
||||
flapping: false,
|
||||
};
|
||||
|
||||
expect(alertToListItem(fakeNow.getTime(), ruleType, 'id', alert)).toEqual({
|
||||
|
@ -238,6 +245,7 @@ describe('alertToListItem', () => {
|
|||
status: 'Active',
|
||||
muted: false,
|
||||
activeStartDate: fake2MinutesAgo.toISOString(),
|
||||
flapping: false,
|
||||
};
|
||||
|
||||
expect(alertToListItem(fakeNow.getTime(), ruleType, 'id', alert)).toEqual({
|
||||
|
@ -258,6 +266,7 @@ describe('alertToListItem', () => {
|
|||
muted: true,
|
||||
activeStartDate: fake2MinutesAgo.toISOString(),
|
||||
actionGroupId: 'default',
|
||||
flapping: false,
|
||||
};
|
||||
|
||||
expect(alertToListItem(fakeNow.getTime(), ruleType, 'id', alert)).toEqual({
|
||||
|
@ -276,6 +285,7 @@ describe('alertToListItem', () => {
|
|||
status: 'Active',
|
||||
muted: false,
|
||||
actionGroupId: 'default',
|
||||
flapping: false,
|
||||
};
|
||||
|
||||
expect(alertToListItem(fakeNow.getTime(), ruleType, 'id', alert)).toEqual({
|
||||
|
@ -294,6 +304,7 @@ describe('alertToListItem', () => {
|
|||
status: 'OK',
|
||||
muted: true,
|
||||
actionGroupId: 'default',
|
||||
flapping: false,
|
||||
};
|
||||
expect(alertToListItem(fakeNow.getTime(), ruleType, 'id', alert)).toEqual({
|
||||
alert: 'id',
|
||||
|
@ -389,11 +400,13 @@ describe('tabbed content', () => {
|
|||
status: 'OK',
|
||||
muted: false,
|
||||
actionGroupId: 'default',
|
||||
flapping: false,
|
||||
},
|
||||
second_rule: {
|
||||
status: 'Active',
|
||||
muted: false,
|
||||
actionGroupId: 'action group id unknown',
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -473,6 +486,7 @@ function mockRuleSummary(overloads: Partial<RuleSummary> = {}): RuleSummary {
|
|||
status: 'OK',
|
||||
muted: false,
|
||||
actionGroupId: 'testActionGroup',
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
executionDuration: {
|
||||
|
|
|
@ -167,6 +167,7 @@ function mockRuleSummary(overloads: Partial<any> = {}): any {
|
|||
foo: {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
executionDuration: {
|
||||
|
|
|
@ -101,6 +101,7 @@ export function mockRuleSummary(overloads: Partial<RuleSummary> = {}): RuleSumma
|
|||
status: 'OK',
|
||||
muted: false,
|
||||
actionGroupId: 'testActionGroup',
|
||||
flapping: false,
|
||||
},
|
||||
},
|
||||
executionDuration: {
|
||||
|
|
|
@ -193,6 +193,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
|||
event,
|
||||
`created new alert: 'instance'`,
|
||||
false,
|
||||
false,
|
||||
currentExecutionId
|
||||
);
|
||||
break;
|
||||
|
@ -202,6 +203,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
|||
event,
|
||||
`alert 'instance' has recovered`,
|
||||
true,
|
||||
false,
|
||||
currentExecutionId
|
||||
);
|
||||
break;
|
||||
|
@ -211,6 +213,7 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
|||
event,
|
||||
`active alert: 'instance' in actionGroup: 'default'`,
|
||||
false,
|
||||
false,
|
||||
currentExecutionId
|
||||
);
|
||||
break;
|
||||
|
@ -259,33 +262,11 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
for (const event of actionEvents) {
|
||||
switch (event?.event?.action) {
|
||||
case 'execute':
|
||||
expect(event?.kibana?.alert?.rule?.execution?.uuid).not.to.be(undefined);
|
||||
expect(
|
||||
executionIds.indexOf(event?.kibana?.alert?.rule?.execution?.uuid)
|
||||
).to.be.greaterThan(-1);
|
||||
validateEvent(event, {
|
||||
spaceId: space.id,
|
||||
savedObjects: [
|
||||
{ type: 'action', id: createdAction.id, rel: 'primary', type_id: 'test.noop' },
|
||||
],
|
||||
message: `action executed: test.noop:${createdAction.id}: MY action`,
|
||||
outcome: 'success',
|
||||
shouldHaveTask: true,
|
||||
ruleTypeId: response.body.rule_type_id,
|
||||
rule: undefined,
|
||||
consumer: 'alertsFixture',
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function validateInstanceEvent(
|
||||
event: IValidatedEvent,
|
||||
subMessage: string,
|
||||
shouldHaveEventEnd: boolean,
|
||||
flapping: boolean,
|
||||
executionId?: string
|
||||
) {
|
||||
validateEvent(event, {
|
||||
|
@ -307,8 +288,32 @@ export default function eventLogTests({ getService }: FtrProviderContext) {
|
|||
name: response.body.name,
|
||||
},
|
||||
consumer: 'alertsFixture',
|
||||
flapping,
|
||||
});
|
||||
}
|
||||
|
||||
for (const event of actionEvents) {
|
||||
switch (event?.event?.action) {
|
||||
case 'execute':
|
||||
expect(event?.kibana?.alert?.rule?.execution?.uuid).not.to.be(undefined);
|
||||
expect(
|
||||
executionIds.indexOf(event?.kibana?.alert?.rule?.execution?.uuid)
|
||||
).to.be.greaterThan(-1);
|
||||
validateEvent(event, {
|
||||
spaceId: space.id,
|
||||
savedObjects: [
|
||||
{ type: 'action', id: createdAction.id, rel: 'primary', type_id: 'test.noop' },
|
||||
],
|
||||
message: `action executed: test.noop:${createdAction.id}: MY action`,
|
||||
outcome: 'success',
|
||||
shouldHaveTask: true,
|
||||
ruleTypeId: response.body.rule_type_id,
|
||||
rule: undefined,
|
||||
consumer: 'alertsFixture',
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should generate expected events for rules with multiple searches', async () => {
|
||||
|
@ -567,6 +572,7 @@ interface ValidateEventLogParams {
|
|||
ruleset?: string;
|
||||
namespace?: string;
|
||||
};
|
||||
flapping?: boolean;
|
||||
}
|
||||
|
||||
export function validateEvent(event: IValidatedEvent, params: ValidateEventLogParams): void {
|
||||
|
@ -585,6 +591,7 @@ export function validateEvent(event: IValidatedEvent, params: ValidateEventLogPa
|
|||
numRecoveredAlerts,
|
||||
consumer,
|
||||
ruleTypeId,
|
||||
flapping,
|
||||
} = params;
|
||||
const { status, actionGroupId, instanceId, reason, shouldHaveEventEnd } = params;
|
||||
|
||||
|
@ -634,6 +641,10 @@ export function validateEvent(event: IValidatedEvent, params: ValidateEventLogPa
|
|||
expect(event?.kibana?.alert?.rule?.execution?.metrics?.alert_counts?.new).to.be(numNewAlerts);
|
||||
}
|
||||
|
||||
if (flapping !== undefined) {
|
||||
expect(event?.kibana?.alert?.flapping).to.be(flapping);
|
||||
}
|
||||
|
||||
expect(event?.kibana?.alert?.rule?.rule_type_id).to.be(ruleTypeId);
|
||||
expect(event?.kibana?.space_ids?.[0]).to.equal(spaceId);
|
||||
|
||||
|
|
|
@ -93,10 +93,12 @@ export default function eventLogAlertTests({ getService }: FtrProviderContext) {
|
|||
start?: string;
|
||||
durationToDate?: string;
|
||||
} = {};
|
||||
|
||||
for (let i = 0; i < instanceEvents.length; ++i) {
|
||||
switch (instanceEvents[i]?.event?.action) {
|
||||
case 'new-instance':
|
||||
expect(instanceEvents[i]?.kibana?.alerting?.instance_id).to.equal('instance');
|
||||
expect(instanceEvents[i]?.kibana?.alert?.flapping).to.equal(false);
|
||||
// a new alert should generate a unique UUID for the duration of its activeness
|
||||
expect(instanceEvents[i]?.event?.end).to.be(undefined);
|
||||
|
||||
|
@ -107,6 +109,7 @@ export default function eventLogAlertTests({ getService }: FtrProviderContext) {
|
|||
|
||||
case 'active-instance':
|
||||
expect(instanceEvents[i]?.kibana?.alerting?.instance_id).to.equal('instance');
|
||||
expect(instanceEvents[i]?.kibana?.alert?.flapping).to.equal(false);
|
||||
expect(instanceEvents[i]?.event?.start).to.equal(currentAlertSpan.start);
|
||||
expect(instanceEvents[i]?.event?.end).to.be(undefined);
|
||||
|
||||
|
@ -121,6 +124,7 @@ export default function eventLogAlertTests({ getService }: FtrProviderContext) {
|
|||
|
||||
case 'recovered-instance':
|
||||
expect(instanceEvents[i]?.kibana?.alerting?.instance_id).to.equal('instance');
|
||||
expect(instanceEvents[i]?.kibana?.alert?.flapping).to.equal(false);
|
||||
expect(instanceEvents[i]?.event?.start).to.equal(currentAlertSpan.start);
|
||||
expect(instanceEvents[i]?.event?.end).not.to.be(undefined);
|
||||
expect(
|
||||
|
|
|
@ -180,6 +180,7 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo
|
|||
'1': {
|
||||
status: 'OK',
|
||||
muted: true,
|
||||
flapping: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -239,20 +240,24 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo
|
|||
muted: false,
|
||||
actionGroupId: 'default',
|
||||
activeStartDate: actualAlerts.alertA.activeStartDate,
|
||||
flapping: false,
|
||||
},
|
||||
alertB: {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
alertC: {
|
||||
status: 'Active',
|
||||
muted: true,
|
||||
actionGroupId: 'default',
|
||||
activeStartDate: actualAlerts.alertC.activeStartDate,
|
||||
flapping: false,
|
||||
},
|
||||
alertD: {
|
||||
status: 'OK',
|
||||
muted: true,
|
||||
flapping: false,
|
||||
},
|
||||
};
|
||||
expect(actualAlerts).to.eql(expectedAlerts);
|
||||
|
@ -294,20 +299,24 @@ export default function createGetAlertSummaryTests({ getService }: FtrProviderCo
|
|||
muted: false,
|
||||
actionGroupId: 'default',
|
||||
activeStartDate: actualAlerts.alertA.activeStartDate,
|
||||
flapping: false,
|
||||
},
|
||||
alertB: {
|
||||
status: 'OK',
|
||||
muted: false,
|
||||
flapping: false,
|
||||
},
|
||||
alertC: {
|
||||
status: 'Active',
|
||||
muted: true,
|
||||
actionGroupId: 'default',
|
||||
activeStartDate: actualAlerts.alertC.activeStartDate,
|
||||
flapping: false,
|
||||
},
|
||||
alertD: {
|
||||
status: 'OK',
|
||||
muted: true,
|
||||
flapping: false,
|
||||
},
|
||||
};
|
||||
expect(actualAlerts).to.eql(expectedAlerts);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue