Add pendingRecoveredCount field to AAD (#212162)

This PR adds pendingRecoveredCount field to AAD as a step to make ADD
source of truth.
In the next step we can build alerts in the alerting task runner from
AAD rather than task state.
This commit is contained in:
Ersin Erdal 2025-03-06 18:50:03 +01:00 committed by GitHub
parent 9b729b3a6c
commit 2bf0827fc6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 185 additions and 2 deletions

View file

@ -16,6 +16,7 @@ import {
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
ALERT_PREVIOUS_ACTION_GROUP,
@ -93,6 +94,11 @@ export const alertFieldMap = {
array: false,
required: false,
},
[ALERT_PENDING_RECOVERED_COUNT]: {
type: 'long',
array: false,
required: false,
},
[ALERT_INSTANCE_ID]: {
type: 'keyword',
array: false,

View file

@ -96,6 +96,7 @@ const AlertOptional = rt.partial({
'kibana.alert.intended_timestamp': schemaDate,
'kibana.alert.last_detected': schemaDate,
'kibana.alert.maintenance_window_ids': schemaStringArray,
'kibana.alert.pending_recovered_count': schemaStringOrNumber,
'kibana.alert.previous_action_group': schemaString,
'kibana.alert.reason': schemaString,
'kibana.alert.rule.execution.timestamp': schemaDate,

View file

@ -154,6 +154,7 @@ const SecurityAlertOptional = rt.partial({
'kibana.alert.original_event.start': schemaDate,
'kibana.alert.original_event.timezone': schemaString,
'kibana.alert.original_event.url': schemaString,
'kibana.alert.pending_recovered_count': schemaStringOrNumber,
'kibana.alert.previous_action_group': schemaString,
'kibana.alert.reason': schemaString,
'kibana.alert.risk_score': schemaNumber,

View file

@ -53,6 +53,9 @@ const ALERT_MAINTENANCE_WINDOW_IDS = `${ALERT_NAMESPACE}.maintenance_window_ids`
// kibana.alert.consecutive_matches - count of consecutive times the alert has been active
const ALERT_CONSECUTIVE_MATCHES = `${ALERT_NAMESPACE}.consecutive_matches` as const;
// kibana.alert.pending_recovered_count - count of consecutive times the alert has been recovered
const ALERT_PENDING_RECOVERED_COUNT = `${ALERT_NAMESPACE}.pending_recovered_count` as const;
// kibana.alert.instance.id - alert ID, also known as alert instance ID
const ALERT_INSTANCE_ID = `${ALERT_NAMESPACE}.instance.id` as const;
@ -139,6 +142,7 @@ const fields = {
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_CONSECUTIVE_MATCHES,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
@ -186,6 +190,7 @@ export {
ALERT_FLAPPING_HISTORY,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_INSTANCE_ID,
ALERT_LAST_DETECTED,
ALERT_PREVIOUS_ACTION_GROUP,

View file

@ -249,6 +249,9 @@ describe('mappingFromFieldMap', () => {
last_detected: {
type: 'date',
},
pending_recovered_count: {
type: 'long',
},
previous_action_group: {
type: 'keyword',
},

View file

@ -24,6 +24,7 @@ import {
ALERT_FLAPPING_HISTORY,
ALERT_INSTANCE_ID,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_RULE_CATEGORY,
ALERT_RULE_CONSUMER,
@ -172,6 +173,7 @@ const fetchedAlert1 = {
[ALERT_FLAPPING_HISTORY]: [true],
[ALERT_INSTANCE_ID]: '1',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
[ALERT_RULE_EXECUTION_UUID]: '5f6aa57d-3e22-484e-bae8-cbed868f4d28',
@ -203,6 +205,7 @@ const fetchedAlert2 = {
[ALERT_FLAPPING_HISTORY]: [true, false],
[ALERT_INSTANCE_ID]: '2',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
[ALERT_RULE_EXECUTION_UUID]: '5f6aa57d-3e22-484e-bae8-cbed868f4d28',
@ -234,6 +237,7 @@ const getNewIndexedAlertDoc = (overrides = {}) => ({
[ALERT_FLAPPING_HISTORY]: [true],
[ALERT_INSTANCE_ID]: '1',
[ALERT_MAINTENANCE_WINDOW_IDS]: ['test-id1', 'test-id2'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
[ALERT_RULE_EXECUTION_UUID]: '5f6aa57d-3e22-484e-bae8-cbed868f4d28',
@ -267,6 +271,7 @@ const getOngoingIndexedAlertDoc = (overrides = {}) => ({
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_SEVERITY_IMPROVING]: undefined,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
...overrides,
});
@ -284,6 +289,7 @@ const getRecoveredIndexedAlertDoc = (overrides = {}) => ({
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
...overrides,
});
@ -808,6 +814,7 @@ describe('Alerts Client', () => {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
@ -1115,6 +1122,7 @@ describe('Alerts Client', () => {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, false, false, false],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
@ -1167,6 +1175,7 @@ describe('Alerts Client', () => {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [true, true],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_START]: '2023-03-28T12:27:28.159Z',

View file

@ -28,6 +28,7 @@ import {
ALERT_CONSECUTIVE_MATCHES,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_SEVERITY_IMPROVING,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { alertRule } from './test_fixtures';
@ -54,6 +55,7 @@ describe('buildNewAlert', () => {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_EXECUTION_TIMESTAMP]: '2023-03-28T12:27:28.159Z',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_STATUS]: 'active',
@ -90,6 +92,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'open',
@ -128,6 +131,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'open',
@ -171,6 +175,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'open',
@ -204,6 +209,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_EXECUTION_TIMESTAMP]: '2030-12-15T02:44:13.124Z',
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
@ -253,6 +259,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'custom_workflow',
@ -306,6 +313,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'open',
@ -361,6 +369,7 @@ describe('buildNewAlert', () => {
[ALERT_INSTANCE_ID]: 'alert-A',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_WORKFLOW_STATUS]: 'open',

View file

@ -15,6 +15,7 @@ import {
ALERT_INSTANCE_ID,
ALERT_MAINTENANCE_WINDOW_IDS,
ALERT_CONSECUTIVE_MATCHES,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_RULE_TAGS,
ALERT_START,
ALERT_STATUS,
@ -93,6 +94,7 @@ export const buildNewAlert = <
[ALERT_INSTANCE_ID]: legacyAlert.getId(),
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
[ALERT_PENDING_RECOVERED_COUNT]: legacyAlert.getPendingRecoveredCount(),
[ALERT_STATUS]: 'active',
[ALERT_UUID]: legacyAlert.getUuid(),
[ALERT_SEVERITY_IMPROVING]: false,

View file

@ -30,6 +30,7 @@ import {
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_SEVERITY_IMPROVING,
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { alertRule, existingFlattenedNewAlert, existingExpandedNewAlert } from './test_fixtures';
@ -66,6 +67,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_DURATION]: 36000,
[ALERT_STATUS]: 'active',
@ -130,6 +132,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -210,6 +213,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [false, false, true, true],
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-xyz'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -286,6 +290,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -381,6 +386,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -441,6 +447,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_DURATION]: 36000,
[ALERT_STATUS]: 'active',
@ -541,6 +548,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -646,6 +654,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -731,6 +740,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'open',
@ -833,6 +843,7 @@ for (const flattened of [true, false]) {
[ALERT_FLAPPING]: false,
[ALERT_FLAPPING_HISTORY]: [],
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_PREVIOUS_ACTION_GROUP]: 'error',
[ALERT_STATUS]: 'active',
[ALERT_WORKFLOW_STATUS]: 'custom_status',

View file

@ -10,6 +10,7 @@ import type { Alert } from '@kbn/alerts-as-data-utils';
import {
ALERT_ACTION_GROUP,
ALERT_CONSECUTIVE_MATCHES,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_DURATION,
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
@ -108,6 +109,7 @@ export const buildOngoingAlert = <
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
// Set latest match count
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
[ALERT_PENDING_RECOVERED_COUNT]: legacyAlert.getPendingRecoveredCount(),
// Set the time range
...(legacyAlert.getState().start
? {

View file

@ -32,6 +32,7 @@ import {
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_SEVERITY_IMPROVING,
ALERT_RULE_EXECUTION_UUID,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import {
alertRule,
@ -78,6 +79,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -150,6 +152,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -252,6 +255,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -318,6 +322,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -428,6 +433,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -536,6 +542,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: ['maint-1', 'maint-321'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'open',
[ALERT_DURATION]: 36000,
@ -643,6 +650,7 @@ for (const flattened of [true, false]) {
[ALERT_SEVERITY_IMPROVING]: true,
[ALERT_PREVIOUS_ACTION_GROUP]: 'default',
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_STATUS]: 'recovered',
[ALERT_WORKFLOW_STATUS]: 'custom_status',
[ALERT_DURATION]: 36000,

View file

@ -23,6 +23,7 @@ import {
ALERT_TIME_RANGE,
ALERT_START,
ALERT_CONSECUTIVE_MATCHES,
ALERT_PENDING_RECOVERED_COUNT,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_SEVERITY_IMPROVING,
@ -105,6 +106,7 @@ export const buildRecoveredAlert = <
[ALERT_MAINTENANCE_WINDOW_IDS]: legacyAlert.getMaintenanceWindowIds(),
// Set latest match count, should be 0
[ALERT_CONSECUTIVE_MATCHES]: legacyAlert.getActiveCount(),
[ALERT_PENDING_RECOVERED_COUNT]: legacyAlert.getPendingRecoveredCount(),
// Set status to 'recovered'
[ALERT_STATUS]: 'recovered',
// Set latest duration as recovered alerts should have updated duration

View file

@ -1010,6 +1010,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -2128,6 +2133,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -3246,6 +3256,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -4364,6 +4379,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -5482,6 +5502,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -6606,6 +6631,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -7724,6 +7754,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,
@ -8842,6 +8877,11 @@ Object {
"required": true,
"type": "date",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,

View file

@ -86,6 +86,7 @@ import {
VERSION,
ALERT_CONSECUTIVE_MATCHES,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { validateRuleTypeParams } from '../lib/validate_rule_type_params';
import { ruleRunMetricsStoreMock } from '../lib/rule_run_metrics_store.mock';
@ -503,6 +504,7 @@ describe('Ad Hoc Task Runner', () => {
[ALERT_INSTANCE_ID]: '1',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_CONSECUTIVE_MATCHES]: 1,
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: mockedAdHocRunSO.attributes.rule.consumer,

View file

@ -102,6 +102,7 @@ import {
ALERT_CONSECUTIVE_MATCHES,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_SEVERITY_IMPROVING,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { backfillClientMock } from '../backfill_client/backfill_client.mock';
import { ConnectorAdapterRegistry } from '../connector_adapters/connector_adapter_registry';
@ -617,6 +618,7 @@ describe('Task Runner', () => {
[ALERT_INSTANCE_ID]: '1',
[ALERT_SEVERITY_IMPROVING]: false,
[ALERT_MAINTENANCE_WINDOW_IDS]: ['test-id1', 'test-id2'],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
[ALERT_RULE_CATEGORY]: 'My test rule',
[ALERT_RULE_CONSUMER]: 'bar',
[ALERT_RULE_EXECUTION_UUID]: '5f6aa57d-3e22-484e-bae8-cbed868f4d28',

View file

@ -95,6 +95,11 @@ it('matches snapshot', () => {
"required": false,
"type": "keyword",
},
"kibana.alert.pending_recovered_count": Object {
"array": false,
"required": false,
"type": "long",
},
"kibana.alert.previous_action_group": Object {
"array": false,
"required": false,

View file

@ -1498,6 +1498,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
severity_improving: false,
rule: {
parameters: {
@ -1542,6 +1543,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
severity_improving: false,
rule: {
parameters: {
@ -1602,6 +1604,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
previous_action_group: 'default',
rule: {
parameters: {
@ -1646,6 +1649,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
previous_action_group: 'default',
rule: {
parameters: {
@ -1754,6 +1758,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
severity_improving: false,
rule: {
parameters: {
@ -1798,6 +1803,7 @@ instanceStateValue: true
action_group: 'default',
flapping_history: expectExpect.any(Array),
maintenance_window_ids: [],
pending_recovered_count: 0,
severity_improving: false,
rule: {
parameters: {

View file

@ -10,7 +10,12 @@ import { SearchHit } from '@elastic/elasticsearch/lib/api/types';
import type { Alert } from '@kbn/alerts-as-data-utils';
import { RuleNotifyWhen } from '@kbn/alerting-plugin/common';
import { setTimeout as setTimeoutAsync } from 'timers/promises';
import { ALERT_FLAPPING, ALERT_FLAPPING_HISTORY, ALERT_RULE_UUID } from '@kbn/rule-data-utils';
import {
ALERT_FLAPPING,
ALERT_FLAPPING_HISTORY,
ALERT_RULE_UUID,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
import { Spaces } from '../../../../scenarios';
import {
@ -316,6 +321,64 @@ export default function createAlertsAsDataFlappingTest({ getService }: FtrProvid
expect(state.alertRecoveredInstances.alertA.meta.flapping).to.equal(true);
});
it('should increase and persist pendingRecoveredCount in the alert doc', async () => {
await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`)
.set('kbn-xsrf', 'foo')
.auth('superuser', 'superuser')
.send({
enabled: true,
look_back_window: 6,
status_change_threshold: 4,
})
.expect(200);
// wait so cache expires
await setTimeoutAsync(TEST_CACHE_EXPIRATION_TIME);
const pattern = {
alertA: [true, false, true, false, true, true, false, false, false],
};
const createdRule = await supertestWithoutAuth
.post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`)
.set('kbn-xsrf', 'foo')
.send(
// notify_when is not RuleNotifyWhen.CHANGE, so it's not added to activeCurrent
getTestRuleData({
rule_type_id: 'test.patternFiringAad',
// set the schedule long so we can use "runSoon" to specify rule runs
schedule: { interval: '1d' },
throttle: null,
params: { pattern },
actions: [],
})
);
expect(createdRule.status).to.eql(200);
const ruleId = createdRule.body.id;
objectRemover.add(Spaces.space1.id, ruleId, 'rule', 'alerting');
// Wait for the rule to run once
let run = 1;
await waitForEventLogDocs(ruleId, new Map([['execute', { equal: 1 }]]));
// Run the rule 8 more times
for (let i = 0; i < 8; i++) {
const response = await supertestWithoutAuth
.post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ruleId}/_run_soon`)
.set('kbn-xsrf', 'foo');
expect(response.status).to.eql(204);
await waitForEventLogDocs(ruleId, new Map([['execute', { equal: ++run }]]));
}
const alertDocs = await queryForAlertDocs<PatternFiringAlert>(ruleId);
expect(alertDocs.length).to.equal(3);
// Alert is recovered and flapping
expect(alertDocs[0]._source![ALERT_FLAPPING]).to.equal(true);
expect(alertDocs[0]._source![ALERT_PENDING_RECOVERED_COUNT]).to.equal(3);
});
it('Should not fail when an alert is flapping and recovered for a rule with notify_when: onThrottleInterval', async () => {
await supertest
.post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/settings/_flapping`)
@ -357,7 +420,7 @@ export default function createAlertsAsDataFlappingTest({ getService }: FtrProvid
// Wait for the rule to run once
let run = 1;
await waitForEventLogDocs(ruleId, new Map([['execute', { equal: 1 }]]));
// Run the rule 10 more times
// Run the rule 5 more times
for (let i = 0; i < 5; i++) {
const response = await supertestWithoutAuth
.post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ruleId}/_run_soon`)

View file

@ -40,6 +40,7 @@ import {
ALERT_CONSECUTIVE_MATCHES,
ALERT_RULE_EXECUTION_TIMESTAMP,
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { ObjectRemover } from '../../../../shared/lib';
@ -191,6 +192,7 @@ export default function ({ getService }: FtrProviderContext) {
[ALERT_RULE_TYPE_ID]: '.es-query',
[ALERT_RULE_TAGS]: [],
[ALERT_RULE_UUID]: ruleId,
[ALERT_PENDING_RECOVERED_COUNT]: 0,
};
expect(hits1).to.eql(expected);

View file

@ -26,6 +26,7 @@ import {
SPACE_IDS,
TAGS,
ALERT_PREVIOUS_ACTION_GROUP,
ALERT_PENDING_RECOVERED_COUNT,
} from '@kbn/rule-data-utils';
import { omit, padStart } from 'lodash';
import { FtrProviderContext } from '../../../ftr_provider_context';
@ -216,6 +217,7 @@ export default function ({ getService }: FtrProviderContext) {
[ALERT_RULE_UUID]: ruleId,
[SPACE_IDS]: ['default'],
[TAGS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
});
});
@ -350,6 +352,7 @@ export default function ({ getService }: FtrProviderContext) {
[ALERT_RULE_UUID]: ruleId,
[SPACE_IDS]: ['default'],
[TAGS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
});
});
@ -573,6 +576,7 @@ export default function ({ getService }: FtrProviderContext) {
[ALERT_RULE_UUID]: ruleId,
[SPACE_IDS]: ['default'],
[TAGS]: [],
[ALERT_PENDING_RECOVERED_COUNT]: 0,
});
});
});