From a3ee8a8cfb284ba9c652e78bf0bb9477bc5e39b0 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 24 Jul 2023 13:09:23 -0400 Subject: [PATCH 01/20] Initial commit --- .../kbn-alerting-state-types/index.ts | 2 - .../src/alert_instance.ts | 5 +- .../src/date_from_string.test.ts | 29 ----- .../src/date_from_string.ts | 27 ---- .../src/rule_task_instance.ts | 3 +- x-pack/plugins/alerting/common/index.ts | 1 - .../alerting/server/alert/alert.test.ts | 54 ++++---- x-pack/plugins/alerting/server/alert/alert.ts | 8 +- .../server/alert/create_alert_factory.test.ts | 12 +- .../alerts_client/alerts_client.test.ts | 30 ++--- .../legacy_alerts_client.test.ts | 2 +- .../plugins/alerting/server/lib/types.test.ts | 29 ----- x-pack/plugins/alerting/server/lib/types.ts | 20 --- .../server/routes/get_rule_state.test.ts | 2 +- .../routes/legacy/get_alert_state.test.ts | 2 +- .../server/rule_type_registry.test.ts | 16 +-- .../alerting/server/rule_type_registry.ts | 115 ++++++++++++++++-- .../task_runner/alert_task_instance.test.ts | 4 +- .../task_runner/execution_handler.test.ts | 8 +- .../server/task_runner/execution_handler.ts | 2 +- .../alerting/server/task_runner/fixtures.ts | 4 +- .../task_runner/rule_action_helper.test.ts | 16 +-- .../server/task_runner/rule_action_helper.ts | 2 +- .../server/task_runner/task_runner.test.ts | 12 +- .../server/task_runner/task_runner.ts | 2 +- .../tests/alerting/group1/event_log.ts | 9 +- 26 files changed, 202 insertions(+), 214 deletions(-) delete mode 100644 x-pack/packages/kbn-alerting-state-types/src/date_from_string.test.ts delete mode 100644 x-pack/packages/kbn-alerting-state-types/src/date_from_string.ts delete mode 100644 x-pack/plugins/alerting/server/lib/types.test.ts diff --git a/x-pack/packages/kbn-alerting-state-types/index.ts b/x-pack/packages/kbn-alerting-state-types/index.ts index c30ea9fb35f2ae..99c421e09d92f2 100644 --- a/x-pack/packages/kbn-alerting-state-types/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/index.ts @@ -15,8 +15,6 @@ export type { } from './src/alert_instance'; export { rawAlertInstance } from './src/alert_instance'; -export { DateFromString } from './src/date_from_string'; - export type { TrackedLifecycleAlertState, WrappedLifecycleRuleState } from './src/lifecycle_state'; export { wrappedStateRt } from './src/lifecycle_state'; diff --git a/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts b/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts index 9685cdb656993b..fe8e09dc7a5c1c 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts @@ -6,10 +6,9 @@ */ import * as t from 'io-ts'; -import { DateFromString } from './date_from_string'; const actionSchema = t.type({ - date: DateFromString, + date: t.string, }); export const throttledActionSchema = t.record(t.string, actionSchema); @@ -21,7 +20,7 @@ const lastScheduledActionsSchema = t.intersection([ }), t.type({ group: t.string, - date: DateFromString, + date: t.string, }), t.partial({ actions: throttledActionSchema }), ]); diff --git a/x-pack/packages/kbn-alerting-state-types/src/date_from_string.test.ts b/x-pack/packages/kbn-alerting-state-types/src/date_from_string.test.ts deleted file mode 100644 index eb635076304324..00000000000000 --- a/x-pack/packages/kbn-alerting-state-types/src/date_from_string.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DateFromString } from './date_from_string'; -import { right, isLeft } from 'fp-ts/lib/Either'; - -describe('DateFromString', () => { - test('validated and parses a string into a Date', () => { - const date = new Date(1973, 10, 30); - expect(DateFromString.decode(date.toISOString())).toEqual(right(date)); - }); - - test('validated and returns a failure for an actual Date', () => { - const date = new Date(1973, 10, 30); - expect(isLeft(DateFromString.decode(date))).toEqual(true); - }); - - test('validated and returns a failure for an invalid Date string', () => { - expect(isLeft(DateFromString.decode('1234-23-45'))).toEqual(true); - }); - - test('validated and returns a failure for a null value', () => { - expect(isLeft(DateFromString.decode(null))).toEqual(true); - }); -}); diff --git a/x-pack/packages/kbn-alerting-state-types/src/date_from_string.ts b/x-pack/packages/kbn-alerting-state-types/src/date_from_string.ts deleted file mode 100644 index 1588334a44d49d..00000000000000 --- a/x-pack/packages/kbn-alerting-state-types/src/date_from_string.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { either } from 'fp-ts/lib/Either'; - -// represents a Date from an ISO string -export const DateFromString = new t.Type( - 'DateFromString', - // detect the type - (value): value is Date => value instanceof Date, - (valueToDecode, context) => - either.chain( - // validate this is a string - t.string.validate(valueToDecode, context), - // decode - (value) => { - const decoded = new Date(value); - return isNaN(decoded.getTime()) ? t.failure(valueToDecode, context) : t.success(decoded); - } - ), - (valueToEncode) => valueToEncode.toISOString() -); diff --git a/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts b/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts index 415b5e665cec50..64ff32ca5b0399 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts @@ -7,7 +7,6 @@ import * as t from 'io-ts'; import { throttledActionSchema, rawAlertInstance } from './alert_instance'; -import { DateFromString } from './date_from_string'; export enum ActionsCompletion { COMPLETE = 'complete', @@ -20,7 +19,7 @@ export const ruleStateSchema = t.partial({ alertInstances: t.record(t.string, rawAlertInstance), // tracks the recovered alerts for flapping purposes alertRecoveredInstances: t.record(t.string, rawAlertInstance), - previousStartedAt: t.union([t.null, DateFromString]), + previousStartedAt: t.union([t.null, t.string]), summaryActions: throttledActionSchema, }); diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index 3134ed5b69fdb2..1abeb94afb16c4 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -27,7 +27,6 @@ export type { } from '@kbn/alerting-state-types'; export { rawAlertInstance, - DateFromString, wrappedStateRt, ActionsCompletion, ruleStateSchema, diff --git a/x-pack/plugins/alerting/server/alert/alert.test.ts b/x-pack/plugins/alerting/server/alert/alert.test.ts index 95894fe4401074..c4db2189e6d262 100644 --- a/x-pack/plugins/alerting/server/alert/alert.test.ts +++ b/x-pack/plugins/alerting/server/alert/alert.test.ts @@ -44,7 +44,7 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -58,10 +58,10 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', actions: { - 'slack:alert:1h': { date: new Date() }, + 'slack:alert:1h': { date: new Date().toISOString() }, }, }, }, @@ -77,7 +77,7 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -91,7 +91,7 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -105,10 +105,10 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', actions: { - '111-111': { date: new Date() }, + '111-111': { date: new Date().toISOString() }, }, }, }, @@ -122,10 +122,10 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date('2020-01-01'), + date: new Date('2020-01-01').toISOString(), group: 'default', actions: { - '111-111': { date: new Date() }, + '111-111': { date: new Date().toISOString() }, }, }, }, @@ -141,10 +141,10 @@ describe('isThrottled', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', actions: { - '111-111': { date: new Date() }, + '111-111': { date: new Date().toISOString() }, }, }, }, @@ -165,7 +165,7 @@ describe('scheduledActionGroupHasChanged()', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -184,7 +184,7 @@ describe('scheduledActionGroupHasChanged()', () => { const alert = new Alert('1', { meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -274,7 +274,7 @@ describe('scheduleActions()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -288,7 +288,7 @@ describe('scheduleActions()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -302,7 +302,7 @@ describe('scheduleActions()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -396,10 +396,10 @@ describe('updateLastScheduledActions()', () => { flappingHistory: [], maintenanceWindowIds: [], lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', actions: { - 'slack:alert:1h': { date: new Date() }, + 'slack:alert:1h': { date: new Date().toISOString() }, }, }, }, @@ -429,7 +429,7 @@ describe('getContext()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -442,7 +442,7 @@ describe('getContext()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -458,7 +458,7 @@ describe('hasContext()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -472,7 +472,7 @@ describe('hasContext()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -486,7 +486,7 @@ describe('hasContext()', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, }, @@ -503,7 +503,7 @@ describe('toJSON', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, flappingHistory: [false, true], @@ -520,7 +520,7 @@ describe('toJSON', () => { }, meta: { lastScheduledActions: { - date: expect.any(Date), + date: expect.any(String), group: 'default', }, uuid: expect.any(String), @@ -538,7 +538,7 @@ describe('toRaw', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, flappingHistory: [false, true, true], @@ -557,7 +557,7 @@ describe('toRaw', () => { state: { foo: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'default', }, flappingHistory: [false, true, true], diff --git a/x-pack/plugins/alerting/server/alert/alert.ts b/x-pack/plugins/alerting/server/alert/alert.ts index 4e08a314bb3a40..2e4cf3d2c5b1e2 100644 --- a/x-pack/plugins/alerting/server/alert/alert.ts +++ b/x-pack/plugins/alerting/server/alert/alert.ts @@ -111,11 +111,13 @@ export class Alert< this.meta.lastScheduledActions.actions[uuid] || this.meta.lastScheduledActions.actions[actionHash]; // actionHash must be removed once all the hash identifiers removed from the task state const lastTriggerDate = actionInState?.date; - return !!(lastTriggerDate && lastTriggerDate.getTime() + throttleMills > Date.now()); + return !!( + lastTriggerDate && new Date(lastTriggerDate).getTime() + throttleMills > Date.now() + ); } return false; } else { - return this.meta.lastScheduledActions.date.getTime() + throttleMills > Date.now(); + return new Date(this.meta.lastScheduledActions.date).getTime() + throttleMills > Date.now(); } } return false; @@ -202,7 +204,7 @@ export class Alert< if (!this.meta.lastScheduledActions) { this.meta.lastScheduledActions = {} as LastScheduledActions; } - const date = new Date(); + const date = new Date().toISOString(); this.meta.lastScheduledActions.group = group; this.meta.lastScheduledActions.date = date; diff --git a/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts b/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts index dc9c09269403a4..c991ed961a89cc 100644 --- a/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts +++ b/x-pack/plugins/alerting/server/alert/create_alert_factory.test.ts @@ -49,7 +49,10 @@ describe('createAlertFactory()', () => { test('reuses existing alerts', () => { const alert = new Alert('1', { state: { foo: true }, - meta: { lastScheduledActions: { group: 'default', date: new Date() }, uuid: 'uuid-previous' }, + meta: { + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, + uuid: 'uuid-previous', + }, }); const alertFactory = createAlertFactory({ alerts: { @@ -65,7 +68,7 @@ describe('createAlertFactory()', () => { uuid: 'uuid-previous', flappingHistory: [], lastScheduledActions: { - date: expect.any(Date), + date: expect.any(String), group: 'default', }, }, @@ -100,7 +103,10 @@ describe('createAlertFactory()', () => { test('gets alert if it exists, returns null if it does not', () => { const alert = new Alert('1', { state: { foo: true }, - meta: { lastScheduledActions: { group: 'default', date: new Date() }, uuid: 'uuid-previous' }, + meta: { + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, + uuid: 'uuid-previous', + }, }); const alertFactory = createAlertFactory({ alerts: { diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 4cc568c3be71d3..c6e1aec9a68b9a 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -144,7 +144,7 @@ describe('Alerts Client', () => { meta: { flapping: false, flappingHistory: [true, false], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }), @@ -153,7 +153,7 @@ describe('Alerts Client', () => { meta: { flapping: false, flappingHistory: [true, false, false], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'def', }, }), @@ -212,7 +212,7 @@ describe('Alerts Client', () => { meta: { flapping: false, flappingHistory: [true, false], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: id, }, }); @@ -252,7 +252,7 @@ describe('Alerts Client', () => { meta: { flapping: false, flappingHistory: [true, false], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }), @@ -507,7 +507,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -767,7 +767,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -777,7 +777,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true, false], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'def', }, }, @@ -1383,7 +1383,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -1393,7 +1393,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true, false], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'def', }, }, @@ -1431,7 +1431,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -1441,7 +1441,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true, false], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'def', }, }, @@ -1654,7 +1654,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -1831,7 +1831,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -2019,7 +2019,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, @@ -2109,7 +2109,7 @@ describe('Alerts Client', () => { flapping: false, flappingHistory: [true], maintenanceWindowIds: [], - lastScheduledActions: { group: 'default', date: new Date() }, + lastScheduledActions: { group: 'default', date: new Date().toISOString() }, uuid: 'abc', }, }, diff --git a/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.test.ts index 89f1a9469c2ea4..f8c341e132e51c 100644 --- a/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/legacy_alerts_client.test.ts @@ -110,7 +110,7 @@ const testAlert2 = { meta: { lastScheduledActions: { group: 'default', - date: new Date(), + date: new Date().toISOString(), }, uuid: 'def', }, diff --git a/x-pack/plugins/alerting/server/lib/types.test.ts b/x-pack/plugins/alerting/server/lib/types.test.ts deleted file mode 100644 index b3f61a0f2172c4..00000000000000 --- a/x-pack/plugins/alerting/server/lib/types.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DateFromString } from './types'; -import { right, isLeft } from 'fp-ts/lib/Either'; - -describe('DateFromString', () => { - test('validated and parses a string into a Date', () => { - const date = new Date(1973, 10, 30); - expect(DateFromString.decode(date.toISOString())).toEqual(right(date)); - }); - - test('validated and returns a failure for an actual Date', () => { - const date = new Date(1973, 10, 30); - expect(isLeft(DateFromString.decode(date))).toEqual(true); - }); - - test('validated and returns a failure for an invalid Date string', () => { - expect(isLeft(DateFromString.decode('1234-23-45'))).toEqual(true); - }); - - test('validated and returns a failure for a null value', () => { - expect(isLeft(DateFromString.decode(null))).toEqual(true); - }); -}); diff --git a/x-pack/plugins/alerting/server/lib/types.ts b/x-pack/plugins/alerting/server/lib/types.ts index 173ba1119a72a0..aa5c13c3fb5643 100644 --- a/x-pack/plugins/alerting/server/lib/types.ts +++ b/x-pack/plugins/alerting/server/lib/types.ts @@ -5,29 +5,9 @@ * 2.0. */ -import * as t from 'io-ts'; -import { either } from 'fp-ts/lib/Either'; import { Rule } from '../types'; import { RuleRunMetrics } from './rule_run_metrics_store'; -// represents a Date from an ISO string -export const DateFromString = new t.Type( - 'DateFromString', - // detect the type - (value): value is Date => value instanceof Date, - (valueToDecode, context) => - either.chain( - // validate this is a string - t.string.validate(valueToDecode, context), - // decode - (value) => { - const decoded = new Date(value); - return isNaN(decoded.getTime()) ? t.failure(valueToDecode, context) : t.success(decoded); - } - ), - (valueToEncode) => valueToEncode.toISOString() -); - export type RuleInfo = Pick & { spaceId: string }; export interface LogSearchMetricsOpts { diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts index 04d3704c88714a..d84c6fe73b616c 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts @@ -32,7 +32,7 @@ describe('getRuleStateRoute', () => { meta: { lastScheduledActions: { group: 'first_group', - date: new Date(), + date: new Date().toISOString(), }, }, }, diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts index 42527256925f7e..67fd50a965ea48 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts @@ -37,7 +37,7 @@ describe('getAlertStateRoute', () => { meta: { lastScheduledActions: { group: 'first_group', - date: new Date(), + date: new Date().toISOString(), }, }, }, diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index 51f14d65bb2c32..3f25a18c7fec96 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -437,17 +437,12 @@ describe('Create Lifecycle', () => { const registry = new RuleTypeRegistry(ruleTypeRegistryParams); registry.register(ruleType); expect(taskManager.registerTaskDefinitions).toHaveBeenCalledTimes(1); - expect(taskManager.registerTaskDefinitions.mock.calls[0]).toEqual([ - { - 'alerting:test': { - createTaskRunner: expect.any(Function), - paramsSchema: expect.any(Object), - indirectParamsSchema: rawRuleSchema, - timeout: '20m', - title: 'Test', - }, + expect(taskManager.registerTaskDefinitions.mock.calls[0][0]).toMatchObject({ + 'alerting:test': { + timeout: '20m', + title: 'Test', }, - ]); + }); }); test('shallow clones the given rule type', () => { @@ -707,7 +702,6 @@ describe('Create Lifecycle', () => { "defaultScheduleInterval": undefined, "doesSetRecoveryContext": false, "enabledInLicense": false, - "hasFieldsForAAD": false, "hasGetSummarizedAlerts": false, "id": "test", "isExportable": true, diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index f703bce729644d..a2d97754b5c980 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -9,11 +9,10 @@ import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; import { schema } from '@kbn/config-schema'; import typeDetect from 'type-detect'; -import { intersection } from 'lodash'; +import { intersection, max } from 'lodash'; import { Logger } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { RunContext, TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; -import { rawRuleSchema } from './raw_rule_schema'; import { TaskRunnerFactory } from './task_runner'; import { RuleType, @@ -62,7 +61,6 @@ export interface RegistryRuleType | 'ruleTaskTimeout' | 'defaultScheduleInterval' | 'doesSetRecoveryContext' - | 'fieldsForAAD' > { id: string; enabledInLicense: boolean; @@ -276,10 +274,112 @@ export class RuleTypeRegistry { /** stripping the typing is required in order to store the RuleTypes in a Map */ normalizedRuleType as unknown as UntypedNormalizedRuleType ); + + let alertStateSchema = schema.maybe(schema.any()); + if (ruleType.alertStateSchemaByVersion) { + const versions = Object.keys(ruleType.alertStateSchemaByVersion).map((key) => + parseInt(key, 10) + ); + const latest = max(versions); + if (latest !== undefined) { + alertStateSchema = ruleType.alertStateSchemaByVersion[latest].extends({ + start: schema.maybe(schema.string()), + duration: schema.maybe(schema.string()), + end: schema.maybe(schema.string()), + }); + } + } + + const rawAlertInstanceSchema = schema.maybe( + schema.recordOf( + schema.string(), + schema.object({ + meta: schema.maybe( + schema.object({ + lastScheduledActions: schema.maybe( + schema.object({ + subgroup: schema.maybe(schema.string()), + group: schema.string(), + date: schema.string(), + actions: schema.maybe( + schema.recordOf(schema.string(), schema.object({ date: schema.string() })) + ), + }) + ), + flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), + flapping: schema.maybe(schema.boolean()), + maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), + pendingRecoveredCount: schema.maybe(schema.number()), + uuid: schema.maybe(schema.string()), + }) + ), + // Places using alert state: + // x-pack/examples/alerting_example/server/alert_types/always_firing.ts + // x-pack/examples/alerting_example/server/alert_types/astros.ts + // x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts + // x-pack/plugins/alerting/server/lib/process_alerts.ts + // x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts + // x-pack/plugins/monitoring/server/alerts/base_rule.ts + // x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts + // x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts + // x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.ts + // x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts + // x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/duration_anomaly.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/status_check.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls_legacy.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls.ts + // x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts + // x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts + state: alertStateSchema, + }) + ) + ); + + let ruleStateSchema = schema.maybe(schema.any()); + if (ruleType.ruleStateSchemaByVersion) { + const versions = Object.keys(ruleType.ruleStateSchemaByVersion).map((key) => + parseInt(key, 10) + ); + const latest = max(versions); + if (latest !== undefined) { + ruleStateSchema = ruleType.ruleStateSchemaByVersion[latest]; + } + } + this.taskManager.registerTaskDefinitions({ [`alerting:${ruleType.id}`]: { title: ruleType.name, timeout: ruleType.ruleTaskTimeout, + stateSchemaByVersion: { + 1: { + up: (state) => state, + schema: schema.object({ + // Places using rule state: + // x-pack/examples/alerting_example/server/alert_types/always_firing.ts + // x-pack/examples/alerting_example/server/alert_types/astros.ts + // x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts + // x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts + // x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts + // x-pack/plugins/stack_alerts/server/rule_types/geo_containment/geo_containment.ts + // x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/duration_anomaly.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/status_check.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls.ts + // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls_legacy.ts + // x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts + // x-pack/test/rule_registry/spaces_only/tests/trial/get_summarized_alerts.ts + // x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts + alertTypeState: ruleStateSchema, + alertInstances: rawAlertInstanceSchema, + alertRecoveredInstances: rawAlertInstanceSchema, + previousStartedAt: schema.maybe(schema.nullable(schema.string())), + summaryActions: schema.maybe( + schema.recordOf(schema.string(), schema.object({ date: schema.string() })) + ), + }), + }, + }, createTaskRunner: (context: RunContext) => this.taskRunnerFactory.create< Params, @@ -291,14 +391,9 @@ export class RuleTypeRegistry { RecoveryActionGroupId | RecoveredActionGroupId, AlertData >(normalizedRuleType, context, this.inMemoryMetrics), - paramsSchema: schema.object({ - alertId: schema.string(), - spaceId: schema.string(), - consumer: schema.maybe(schema.string()), - }), - indirectParamsSchema: rawRuleSchema, }, }); + if (this.alertsService && ruleType.alerts) { this.alertsService.register(ruleType.alerts); } @@ -379,7 +474,6 @@ export class RuleTypeRegistry { doesSetRecoveryContext, alerts, getSummarizedAlerts, - fieldsForAAD, }, ]: [string, UntypedNormalizedRuleType]) => ({ id, @@ -400,7 +494,6 @@ export class RuleTypeRegistry { minimumLicenseRequired ).isValid, hasGetSummarizedAlerts: !!getSummarizedAlerts, - hasFieldsForAAD: Boolean(fieldsForAAD), ...(alerts ? { alerts } : {}), }) ) diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts index 916d9c27a7831e..a1f835b92fc1e0 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts @@ -42,7 +42,7 @@ const alert: SanitizedRule<{ describe('Alert Task Instance', () => { test(`validates that a TaskInstance has valid Alert Task State`, () => { - const lastScheduledActionsDate = new Date(); + const lastScheduledActionsDate = new Date().toISOString(); const taskInstance: ConcreteTaskInstance = { id: uuidv4(), attempts: 0, @@ -62,7 +62,7 @@ describe('Alert Task Instance', () => { meta: { lastScheduledActions: { group: 'first_group', - date: lastScheduledActionsDate.toISOString(), + date: lastScheduledActionsDate, }, }, }, diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts index 4412aee0163d46..a9aca56579a1c7 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts @@ -160,7 +160,7 @@ const generateAlert = ({ meta: { maintenanceWindowIds, lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: lastScheduledActionsGroup, actions: throttledActions, }, @@ -182,7 +182,7 @@ const generateRecoveredAlert = ({ id, state }: { id: number; state?: AlertInstan state: state || { test: true }, meta: { lastScheduledActions: { - date: new Date(), + date: new Date().toISOString(), group: 'recovered', actions: {}, }, @@ -786,7 +786,7 @@ describe('Execution Handler', () => { await executionHandler.run( generateAlert({ id: 1, - throttledActions: { '111-111': { date: new Date(DATE_1970) } }, + throttledActions: { '111-111': { date: new Date(DATE_1970).toISOString() } }, }) ); @@ -1010,7 +1010,7 @@ describe('Execution Handler', () => { expect(result).toEqual({ throttledSummaryActions: { '111-111': { - date: new Date(), + date: new Date().toISOString(), }, }, }); diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts index d91a2ea104c930..4c76a087fa9aa7 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts @@ -246,7 +246,7 @@ export class ExecutionHandler< }); if (isActionOnInterval(action)) { - throttledSummaryActions[action.uuid!] = { date: new Date() }; + throttledSummaryActions[action.uuid!] = { date: new Date().toISOString() }; } logActions.push({ diff --git a/x-pack/plugins/alerting/server/task_runner/fixtures.ts b/x-pack/plugins/alerting/server/task_runner/fixtures.ts index bb7dfaaeddf691..677ecfa15c2d60 100644 --- a/x-pack/plugins/alerting/server/task_runner/fixtures.ts +++ b/x-pack/plugins/alerting/server/task_runner/fixtures.ts @@ -382,7 +382,7 @@ export const generateRunnerResult = ({ ...(state && { alertInstances }), ...(state && { alertRecoveredInstances }), ...(state && { alertTypeState: {} }), - ...(state && { previousStartedAt: new Date('1970-01-01T00:00:00.000Z') }), + ...(state && { previousStartedAt: new Date('1970-01-01T00:00:00.000Z').toISOString() }), ...(state && { summaryActions }), }, hasError, @@ -439,7 +439,7 @@ export const generateAlertInstance = ( meta: { uuid: expect.any(String), lastScheduledActions: { - date: new Date(DATE_1970), + date: new Date(DATE_1970).toISOString(), group: 'default', ...(actions && { actions }), }, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_action_helper.test.ts b/x-pack/plugins/alerting/server/task_runner/rule_action_helper.test.ts index 872672801b52c4..c2ac1ab38a2fad 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_action_helper.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_action_helper.test.ts @@ -146,21 +146,21 @@ describe('rule_action_helper', () => { const result = getSummaryActionsFromTaskState({ actions: [mockSummaryAction], summaryActions: { - '111-111': { date: new Date('01.01.2020') }, - '222-222': { date: new Date('01.01.2020') }, + '111-111': { date: new Date('01.01.2020').toISOString() }, + '222-222': { date: new Date('01.01.2020').toISOString() }, }, }); - expect(result).toEqual({ '111-111': { date: new Date('01.01.2020') } }); + expect(result).toEqual({ '111-111': { date: new Date('01.01.2020').toISOString() } }); }); test('should replace hash with uuid', () => { const result = getSummaryActionsFromTaskState({ actions: [mockSummaryAction], summaryActions: { - 'slack:summary:1d': { date: new Date('01.01.2020') }, + 'slack:summary:1d': { date: new Date('01.01.2020').toISOString() }, }, }); - expect(result).toEqual({ '111-111': { date: new Date('01.01.2020') } }); + expect(result).toEqual({ '111-111': { date: new Date('01.01.2020').toISOString() } }); }); }); @@ -180,7 +180,7 @@ describe('rule_action_helper', () => { jest.useRealTimers(); }); const logger = { debug: jest.fn() } as unknown as Logger; - const throttledSummaryActions = { '111-111': { date: new Date('2020-01-01T00:00:00.000Z') } }; + const throttledSummaryActions = { '111-111': { date: '2020-01-01T00:00:00.000Z' } }; test('should return false if the action does not have throttle filed', () => { const result = isSummaryActionThrottled({ @@ -227,7 +227,7 @@ describe('rule_action_helper', () => { test('should return false if the action is not in the task instance', () => { const result = isSummaryActionThrottled({ action: mockSummaryAction, - throttledSummaryActions: { '123-456': { date: new Date('2020-01-01T00:00:00.000Z') } }, + throttledSummaryActions: { '123-456': { date: '2020-01-01T00:00:00.000Z' } }, logger, }); expect(result).toBe(false); @@ -237,7 +237,7 @@ describe('rule_action_helper', () => { jest.advanceTimersByTime(3600000 * 2); const result = isSummaryActionThrottled({ action: mockSummaryAction, - throttledSummaryActions: { '123-456': { date: new Date('2020-01-01T00:00:00.000Z') } }, + throttledSummaryActions: { '123-456': { date: '2020-01-01T00:00:00.000Z' } }, logger, }); expect(result).toBe(false); diff --git a/x-pack/plugins/alerting/server/task_runner/rule_action_helper.ts b/x-pack/plugins/alerting/server/task_runner/rule_action_helper.ts index 79fe92b0790262..a23323ffee2b7b 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_action_helper.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_action_helper.ts @@ -58,7 +58,7 @@ export const isSummaryActionThrottled = ({ logger.debug(`Action'${action?.actionTypeId}:${action?.id}', has an invalid throttle interval`); } - const throttled = throttledAction.date.getTime() + throttleMills > Date.now(); + const throttled = new Date(throttledAction.date).getTime() + throttleMills > Date.now(); if (throttled) { logger.debug( diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index 63d0b894529bfb..fc075e80e54c07 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -1588,7 +1588,7 @@ describe('Task Runner', () => { generateEnqueueFunctionInput({ isBulk, id: '1', foo: true }) ); expect(result.state.summaryActions).toEqual({ - '111-111': { date: new Date(DATE_1970) }, + '111-111': { date: new Date(DATE_1970).toISOString() }, }); } ); @@ -1858,9 +1858,7 @@ describe('Task Runner', () => { const runnerResult = await taskRunner.run(); - expect(runnerResult.state.previousStartedAt).toEqual( - new Date(originalAlertSate.previousStartedAt) - ); + expect(runnerResult.state.previousStartedAt).toEqual(originalAlertSate.previousStartedAt); expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); }); @@ -2768,7 +2766,7 @@ describe('Task Runner', () => { meta: { uuid: expect.any(String), lastScheduledActions: { - date: new Date(DATE_1970), + date: new Date(DATE_1970).toISOString(), group: 'default', }, flappingHistory: [true], @@ -2938,7 +2936,7 @@ describe('Task Runner', () => { meta: { uuid: expect.any(String), lastScheduledActions: { - date: new Date(DATE_1970), + date: new Date(DATE_1970).toISOString(), group: 'default', }, flappingHistory: [true], @@ -2955,7 +2953,7 @@ describe('Task Runner', () => { meta: { uuid: expect.any(String), lastScheduledActions: { - date: new Date(DATE_1970), + date: new Date(DATE_1970).toISOString(), group: 'default', }, flappingHistory: [true], diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 850e3d2aa7f1fd..93858b412a332b 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -855,7 +855,7 @@ export class TaskRunner< ): RuleTaskState => { return { ...omit(runStateWithMetrics, ['metrics']), - previousStartedAt: startedAt, + previousStartedAt: startedAt?.toISOString(), }; }; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts index 2fe26f2bdb9279..a4ee78fdfbbcb2 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts @@ -1584,8 +1584,13 @@ export function validateEvent(event: IValidatedEvent, params: ValidateEventLogPa const task = event?.kibana?.task; expect(task).to.be.ok(); expect(typeof Date.parse(typeof task?.scheduled)).to.be('number'); - expect(typeof task?.schedule_delay).to.be('number'); - expect(task?.schedule_delay).to.be.greaterThan(-1); + expect(typeof task?.schedule_delay).to.be('string'); + // TypeScript on expect(...) not happy without this check + const scheduleDelay = + typeof task?.schedule_delay === 'string' + ? parseInt(task.schedule_delay, 10) + : task?.schedule_delay; + expect(scheduleDelay).to.be.greaterThan(-1); } else { expect(event?.kibana?.task).to.be(undefined); } From aa829464d06c7fb104c75d5e8d30e548d4c361d0 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 24 Jul 2023 17:17:24 +0000 Subject: [PATCH 02/20] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- x-pack/plugins/alerting/server/rule_type_registry.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index 3f25a18c7fec96..62f12d26abc387 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -17,7 +17,6 @@ import { inMemoryMetricsMock } from './monitoring/in_memory_metrics.mock'; import { alertsServiceMock } from './alerts_service/alerts_service.mock'; import { schema } from '@kbn/config-schema'; import { RecoveredActionGroupId } from '../common'; -import { rawRuleSchema } from './raw_rule_schema'; const logger = loggingSystemMock.create().get(); let mockedLicenseState: jest.Mocked; From c1674dc29a9435c8475b5613246ec28da7f693c3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 24 Jul 2023 13:21:19 -0400 Subject: [PATCH 03/20] Keep hasFieldsForAAD --- x-pack/plugins/alerting/server/rule_type_registry.test.ts | 1 + x-pack/plugins/alerting/server/rule_type_registry.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index 3f25a18c7fec96..a43fec64cba6fb 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -702,6 +702,7 @@ describe('Create Lifecycle', () => { "defaultScheduleInterval": undefined, "doesSetRecoveryContext": false, "enabledInLicense": false, + "hasFieldsForAAD": false, "hasGetSummarizedAlerts": false, "id": "test", "isExportable": true, diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index a2d97754b5c980..be386474e210bb 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -61,6 +61,7 @@ export interface RegistryRuleType | 'ruleTaskTimeout' | 'defaultScheduleInterval' | 'doesSetRecoveryContext' + | 'fieldsForAAD' > { id: string; enabledInLicense: boolean; @@ -474,6 +475,7 @@ export class RuleTypeRegistry { doesSetRecoveryContext, alerts, getSummarizedAlerts, + fieldsForAAD, }, ]: [string, UntypedNormalizedRuleType]) => ({ id, @@ -494,6 +496,7 @@ export class RuleTypeRegistry { minimumLicenseRequired ).isValid, hasGetSummarizedAlerts: !!getSummarizedAlerts, + hasFieldsForAAD: Boolean(fieldsForAAD), ...(alerts ? { alerts } : {}), }) ) From 35c9f166e2ccc6c5bc3e42883ffd88073638d07d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 24 Jul 2023 13:31:57 -0400 Subject: [PATCH 04/20] Fix code merge --- .../alerting/server/rule_type_registry.ts | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index be386474e210bb..8c96a46bea7c1a 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -9,7 +9,7 @@ import Boom from '@hapi/boom'; import { i18n } from '@kbn/i18n'; import { schema } from '@kbn/config-schema'; import typeDetect from 'type-detect'; -import { intersection, max } from 'lodash'; +import { intersection } from 'lodash'; import { Logger } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { RunContext, TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; @@ -276,21 +276,6 @@ export class RuleTypeRegistry { normalizedRuleType as unknown as UntypedNormalizedRuleType ); - let alertStateSchema = schema.maybe(schema.any()); - if (ruleType.alertStateSchemaByVersion) { - const versions = Object.keys(ruleType.alertStateSchemaByVersion).map((key) => - parseInt(key, 10) - ); - const latest = max(versions); - if (latest !== undefined) { - alertStateSchema = ruleType.alertStateSchemaByVersion[latest].extends({ - start: schema.maybe(schema.string()), - duration: schema.maybe(schema.string()), - end: schema.maybe(schema.string()), - }); - } - } - const rawAlertInstanceSchema = schema.maybe( schema.recordOf( schema.string(), @@ -332,22 +317,11 @@ export class RuleTypeRegistry { // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls.ts // x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts // x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts - state: alertStateSchema, + state: schema.maybe(schema.any()), }) ) ); - let ruleStateSchema = schema.maybe(schema.any()); - if (ruleType.ruleStateSchemaByVersion) { - const versions = Object.keys(ruleType.ruleStateSchemaByVersion).map((key) => - parseInt(key, 10) - ); - const latest = max(versions); - if (latest !== undefined) { - ruleStateSchema = ruleType.ruleStateSchemaByVersion[latest]; - } - } - this.taskManager.registerTaskDefinitions({ [`alerting:${ruleType.id}`]: { title: ruleType.name, @@ -371,7 +345,7 @@ export class RuleTypeRegistry { // x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts // x-pack/test/rule_registry/spaces_only/tests/trial/get_summarized_alerts.ts // x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts - alertTypeState: ruleStateSchema, + alertTypeState: schema.maybe(schema.any()), alertInstances: rawAlertInstanceSchema, alertRecoveredInstances: rawAlertInstanceSchema, previousStartedAt: schema.maybe(schema.nullable(schema.string())), From 532a3ddeda08f4bcba102231f7b50a83d77c947e Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 24 Jul 2023 14:12:52 -0400 Subject: [PATCH 05/20] Fix typecheck failures --- .../api/preview_rules/alert_instance_factory_stub.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/alert_instance_factory_stub.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/alert_instance_factory_stub.ts index df087c7d9775b6..61a772ddc44d17 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/alert_instance_factory_stub.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/alert_instance_factory_stub.ts @@ -29,19 +29,19 @@ export const alertInstanceFactoryStub = < replaceState(state: TInstanceState) { return new Alert('', { state: {} as TInstanceState, - meta: { lastScheduledActions: { group: 'default', date: new Date() } }, + meta: { lastScheduledActions: { group: 'default', date: new Date().toISOString() } }, }); }, scheduleActions(actionGroup: TActionGroupIds, alertcontext: TInstanceContext) { return new Alert('', { state: {} as TInstanceState, - meta: { lastScheduledActions: { group: 'default', date: new Date() } }, + meta: { lastScheduledActions: { group: 'default', date: new Date().toISOString() } }, }); }, setContext(alertContext: TInstanceContext) { return new Alert('', { state: {} as TInstanceState, - meta: { lastScheduledActions: { group: 'default', date: new Date() } }, + meta: { lastScheduledActions: { group: 'default', date: new Date().toISOString() } }, }); }, getContext() { From b6f9c7f41ec01add4a9b126f52a9d1a903edab55 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 27 Jul 2023 14:49:38 -0400 Subject: [PATCH 06/20] Undo failing test --- .../spaces_only/tests/alerting/group1/event_log.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts index a4ee78fdfbbcb2..2fe26f2bdb9279 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts @@ -1584,13 +1584,8 @@ export function validateEvent(event: IValidatedEvent, params: ValidateEventLogPa const task = event?.kibana?.task; expect(task).to.be.ok(); expect(typeof Date.parse(typeof task?.scheduled)).to.be('number'); - expect(typeof task?.schedule_delay).to.be('string'); - // TypeScript on expect(...) not happy without this check - const scheduleDelay = - typeof task?.schedule_delay === 'string' - ? parseInt(task.schedule_delay, 10) - : task?.schedule_delay; - expect(scheduleDelay).to.be.greaterThan(-1); + expect(typeof task?.schedule_delay).to.be('number'); + expect(task?.schedule_delay).to.be.greaterThan(-1); } else { expect(event?.kibana?.task).to.be(undefined); } From 7967331530fd0457365c95d59de743b20a285d17 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 27 Jul 2023 14:51:11 -0400 Subject: [PATCH 07/20] Fix test failure --- .../public/application/lib/rule_api/state.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.test.ts index 40047259de4d9f..364697507218bf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.test.ts @@ -82,7 +82,7 @@ describe('loadRuleState', () => { meta: { lastScheduledActions: { group: 'first_group', - date: new Date('2020-02-09T23:15:41.941Z'), + date: '2020-02-09T23:15:41.941Z', }, }, }, From 35bfc3b6293dd68b631d16d30dc9f4a3021fe940 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 28 Jul 2023 10:20:19 -0400 Subject: [PATCH 08/20] Merge types and schemas into a single source --- .../kbn-alerting-state-types/index.ts | 26 ++-- .../src/alert_instance.ts | 43 ------ .../src/rule_task_instance.ts | 14 -- .../src/task_state/index.ts | 40 ++++++ .../src/task_state/v1/index.ts | 47 +++++++ .../kbn-alerting-state-types/tsconfig.json | 2 +- x-pack/plugins/alerting/common/index.ts | 8 +- x-pack/plugins/alerting/server/alert/alert.ts | 6 +- .../alerting/server/rule_type_registry.ts | 77 +---------- .../task_runner/alert_task_instance.test.ts | 127 +----------------- .../server/task_runner/alert_task_instance.ts | 12 +- .../monitoring/server/alerts/base_rule.ts | 5 - .../server/saved_objects/migrations.ts | 3 +- .../saved_objects/migrations_880.test.ts | 3 +- .../public/application/lib/rule_api/state.ts | 16 +-- 15 files changed, 118 insertions(+), 311 deletions(-) create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/index.ts create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts diff --git a/x-pack/packages/kbn-alerting-state-types/index.ts b/x-pack/packages/kbn-alerting-state-types/index.ts index 99c421e09d92f2..80a5c3506eab80 100644 --- a/x-pack/packages/kbn-alerting-state-types/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/index.ts @@ -5,18 +5,22 @@ * 2.0. */ -export type { - ThrottledActions, - LastScheduledActions, - AlertInstanceMeta, - AlertInstanceState, - AlertInstanceContext, - RawAlertInstance, -} from './src/alert_instance'; -export { rawAlertInstance } from './src/alert_instance'; +export type { AlertInstanceContext } from './src/alert_instance'; export type { TrackedLifecycleAlertState, WrappedLifecycleRuleState } from './src/lifecycle_state'; export { wrappedStateRt } from './src/lifecycle_state'; -export type { RuleTaskState, RuleTaskParams } from './src/rule_task_instance'; -export { ActionsCompletion, ruleStateSchema, ruleParamsSchema } from './src/rule_task_instance'; +export type { RuleTaskParams } from './src/rule_task_instance'; +export { ActionsCompletion, ruleParamsSchema } from './src/rule_task_instance'; + +export type { + LatestTaskStateSchema as RuleTaskState, + MutableLatestTaskStateSchema as MutableRuleTaskState, + LatestRawAlertInstanceSchema as RawAlertInstance, + LatestAlertInstanceMetaSchema as AlertInstanceMeta, + MutableLatestAlertInstanceMetaSchema as MutableAlertInstanceMeta, + LatestAlertInstanceStateSchema as AlertInstanceState, + LatestThrottledActionSchema as ThrottledActions, + LatestLastScheduledActionsSchema as LastScheduledActions, +} from './src/task_state'; +export { stateSchemaByVersion, emptyState as emptyTaskState } from './src/task_state'; diff --git a/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts b/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts index fe8e09dc7a5c1c..003fdcda742f97 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/alert_instance.ts @@ -7,48 +7,5 @@ import * as t from 'io-ts'; -const actionSchema = t.type({ - date: t.string, -}); - -export const throttledActionSchema = t.record(t.string, actionSchema); -export type ThrottledActions = t.TypeOf; - -const lastScheduledActionsSchema = t.intersection([ - t.partial({ - subgroup: t.string, - }), - t.type({ - group: t.string, - date: t.string, - }), - t.partial({ actions: throttledActionSchema }), -]); - -export type LastScheduledActions = t.TypeOf; - -const metaSchema = t.partial({ - lastScheduledActions: lastScheduledActionsSchema, - // an array used to track changes in alert state, the order is based on the rule executions (oldest to most recent) - // true - alert has changed from active/recovered - // false - the status has remained either active or recovered - flappingHistory: t.array(t.boolean), - // flapping flag that indicates whether the alert is flapping - flapping: t.boolean, - maintenanceWindowIds: t.array(t.string), - pendingRecoveredCount: t.number, - uuid: t.string, -}); -export type AlertInstanceMeta = t.TypeOf; - -const stateSchema = t.record(t.string, t.unknown); -export type AlertInstanceState = t.TypeOf; - const contextSchema = t.record(t.string, t.unknown); export type AlertInstanceContext = t.TypeOf; - -export const rawAlertInstance = t.partial({ - state: stateSchema, - meta: metaSchema, -}); -export type RawAlertInstance = t.TypeOf; diff --git a/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts b/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts index 64ff32ca5b0399..a5b881f6f124cf 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/rule_task_instance.ts @@ -6,26 +6,12 @@ */ import * as t from 'io-ts'; -import { throttledActionSchema, rawAlertInstance } from './alert_instance'; export enum ActionsCompletion { COMPLETE = 'complete', PARTIAL = 'partial', } -export const ruleStateSchema = t.partial({ - alertTypeState: t.record(t.string, t.unknown), - // tracks the active alerts - alertInstances: t.record(t.string, rawAlertInstance), - // tracks the recovered alerts for flapping purposes - alertRecoveredInstances: t.record(t.string, rawAlertInstance), - previousStartedAt: t.union([t.null, t.string]), - summaryActions: throttledActionSchema, -}); - -// This is serialized in the rule task document -export type RuleTaskState = t.TypeOf; - export const ruleParamsSchema = t.intersection([ t.type({ alertId: t.string, diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/index.ts new file mode 100644 index 00000000000000..dbceac9534ae7e --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/index.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { type TypeOf } from '@kbn/config-schema'; +import * as v1 from './v1'; + +export const stateSchemaByVersion = { + 1: v1.versionDefinition, +}; + +const latest = v1; +/** + * WARNING: Do not modify the code below when doing a new version. + * Update the "latest" variable instead. + */ +const latestTaskStateSchema = latest.versionDefinition.schema; +export type LatestTaskStateSchema = TypeOf; +export type LatestRawAlertInstanceSchema = TypeOf; +export type LatestAlertInstanceMetaSchema = TypeOf; +export type LatestAlertInstanceStateSchema = TypeOf; +export type LatestThrottledActionSchema = TypeOf; +export type LatestLastScheduledActionsSchema = TypeOf; + +export const emptyState: LatestTaskStateSchema = { + alertTypeState: {}, + alertInstances: {}, + alertRecoveredInstances: {}, + previousStartedAt: null, + summaryActions: {}, +}; + +type Mutable = { + -readonly [k in keyof T]: Mutable; +}; +export type MutableLatestTaskStateSchema = Mutable; +export type MutableLatestAlertInstanceMetaSchema = Mutable; diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts new file mode 100644 index 00000000000000..e344aee8bc06b2 --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +const actionSchema = schema.object({ date: schema.string() }); +export const throttledActionSchema = schema.recordOf(schema.string(), actionSchema); +// TODO: Add schema by rule type for alert state +export const alertStateSchema = schema.recordOf(schema.string(), schema.any()); +// TODO: Add schema by rule type for rule state +const ruleStateSchema = schema.recordOf(schema.string(), schema.any()); + +export const lastScheduledActionsSchema = schema.object({ + subgroup: schema.maybe(schema.string()), + group: schema.string(), + date: schema.string(), + actions: schema.maybe(throttledActionSchema), +}); + +export const metaSchema = schema.object({ + lastScheduledActions: schema.maybe(lastScheduledActionsSchema), + flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), + flapping: schema.maybe(schema.boolean()), + maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), + pendingRecoveredCount: schema.maybe(schema.number()), + uuid: schema.maybe(schema.string()), +}); + +export const rawAlertInstanceSchema = schema.object({ + meta: schema.maybe(metaSchema), + state: schema.maybe(alertStateSchema), +}); + +export const versionDefinition = { + up: (state: Record) => state, + schema: schema.object({ + alertTypeState: schema.maybe(ruleStateSchema), + alertInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), + alertRecoveredInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), + previousStartedAt: schema.maybe(schema.nullable(schema.string())), + summaryActions: schema.maybe(throttledActionSchema), + }), +}; diff --git a/x-pack/packages/kbn-alerting-state-types/tsconfig.json b/x-pack/packages/kbn-alerting-state-types/tsconfig.json index 6d27b06d5f8ba8..e1a705d2a1ed8a 100644 --- a/x-pack/packages/kbn-alerting-state-types/tsconfig.json +++ b/x-pack/packages/kbn-alerting-state-types/tsconfig.json @@ -13,5 +13,5 @@ "exclude": [ "target/**/*" ], - "kbn_references": [] + "kbn_references": ["@kbn/config-schema"] } diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index 1abeb94afb16c4..e283a8b278abc2 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -25,13 +25,7 @@ export type { RuleTaskState, RuleTaskParams, } from '@kbn/alerting-state-types'; -export { - rawAlertInstance, - wrappedStateRt, - ActionsCompletion, - ruleStateSchema, - ruleParamsSchema, -} from '@kbn/alerting-state-types'; +export { wrappedStateRt, ActionsCompletion, ruleParamsSchema } from '@kbn/alerting-state-types'; export * from './alert_summary'; export * from './builtin_action_groups'; export * from './bulk_edit'; diff --git a/x-pack/plugins/alerting/server/alert/alert.ts b/x-pack/plugins/alerting/server/alert/alert.ts index 2e4cf3d2c5b1e2..b05c3bea22cc35 100644 --- a/x-pack/plugins/alerting/server/alert/alert.ts +++ b/x-pack/plugins/alerting/server/alert/alert.ts @@ -7,12 +7,12 @@ import { v4 as uuidV4 } from 'uuid'; import { isEmpty } from 'lodash'; +import { MutableAlertInstanceMeta } from '@kbn/alerting-state-types'; import { AlertHit, CombinedSummarizedAlerts } from '../types'; import { AlertInstanceMeta, AlertInstanceState, RawAlertInstance, - rawAlertInstance, AlertInstanceContext, DefaultActionGroupId, LastScheduledActions, @@ -52,7 +52,7 @@ export class Alert< ActionGroupIds extends string = never > { private scheduledExecutionOptions?: ScheduledExecutionOptions; - private meta: AlertInstanceMeta; + private meta: MutableAlertInstanceMeta; private state: State; private context: Context; private readonly id: string; @@ -226,7 +226,7 @@ export class Alert< * Used to serialize alert instance state */ toJSON() { - return rawAlertInstance.encode(this.toRaw()); + return this.toRaw(); } toRaw(recovered: boolean = false): RawAlertInstance { diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 8c96a46bea7c1a..78b61a46a57f7f 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -13,6 +13,7 @@ import { intersection } from 'lodash'; import { Logger } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { RunContext, TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; +import { stateSchemaByVersion } from '@kbn/alerting-state-types'; import { TaskRunnerFactory } from './task_runner'; import { RuleType, @@ -276,85 +277,11 @@ export class RuleTypeRegistry { normalizedRuleType as unknown as UntypedNormalizedRuleType ); - const rawAlertInstanceSchema = schema.maybe( - schema.recordOf( - schema.string(), - schema.object({ - meta: schema.maybe( - schema.object({ - lastScheduledActions: schema.maybe( - schema.object({ - subgroup: schema.maybe(schema.string()), - group: schema.string(), - date: schema.string(), - actions: schema.maybe( - schema.recordOf(schema.string(), schema.object({ date: schema.string() })) - ), - }) - ), - flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), - flapping: schema.maybe(schema.boolean()), - maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), - pendingRecoveredCount: schema.maybe(schema.number()), - uuid: schema.maybe(schema.string()), - }) - ), - // Places using alert state: - // x-pack/examples/alerting_example/server/alert_types/always_firing.ts - // x-pack/examples/alerting_example/server/alert_types/astros.ts - // x-pack/plugins/alerting/server/lib/get_alerts_for_notification.ts - // x-pack/plugins/alerting/server/lib/process_alerts.ts - // x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts - // x-pack/plugins/monitoring/server/alerts/base_rule.ts - // x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts - // x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts - // x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/schedule_notification_actions.ts - // x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts - // x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/duration_anomaly.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/status_check.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls_legacy.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls.ts - // x-pack/test/alerting_api_integration/common/plugins/alerts/server/alert_types.ts - // x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts - state: schema.maybe(schema.any()), - }) - ) - ); - this.taskManager.registerTaskDefinitions({ [`alerting:${ruleType.id}`]: { title: ruleType.name, timeout: ruleType.ruleTaskTimeout, - stateSchemaByVersion: { - 1: { - up: (state) => state, - schema: schema.object({ - // Places using rule state: - // x-pack/examples/alerting_example/server/alert_types/always_firing.ts - // x-pack/examples/alerting_example/server/alert_types/astros.ts - // x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts - // x-pack/plugins/rule_registry/server/utils/create_lifecycle_executor.ts - // x-pack/plugins/stack_alerts/server/rule_types/es_query/executor.ts - // x-pack/plugins/stack_alerts/server/rule_types/geo_containment/geo_containment.ts - // x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/duration_anomaly.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/status_check.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls.ts - // x-pack/plugins/synthetics/server/legacy_uptime/lib/alerts/tls_legacy.ts - // x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts - // x-pack/test/rule_registry/spaces_only/tests/trial/get_summarized_alerts.ts - // x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts - alertTypeState: schema.maybe(schema.any()), - alertInstances: rawAlertInstanceSchema, - alertRecoveredInstances: rawAlertInstanceSchema, - previousStartedAt: schema.maybe(schema.nullable(schema.string())), - summaryActions: schema.maybe( - schema.recordOf(schema.string(), schema.object({ date: schema.string() })) - ), - }), - }, - }, + stateSchemaByVersion, createTaskRunner: (context: RunContext) => this.taskRunnerFactory.create< Params, diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts index a1f835b92fc1e0..93bb08a55c7d05 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts @@ -41,8 +41,7 @@ const alert: SanitizedRule<{ }; describe('Alert Task Instance', () => { - test(`validates that a TaskInstance has valid Alert Task State`, () => { - const lastScheduledActionsDate = new Date().toISOString(); + test(`passes-through the state object`, () => { const taskInstance: ConcreteTaskInstance = { id: uuidv4(), attempts: 0, @@ -52,129 +51,7 @@ describe('Alert Task Instance', () => { scheduledAt: new Date(), startedAt: new Date(), retryAt: new Date(Date.now() + 5 * 60 * 1000), - state: { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: { - state: {}, - meta: { - lastScheduledActions: { - group: 'first_group', - date: lastScheduledActionsDate, - }, - }, - }, - second_instance: {}, - }, - }, - taskType: 'alerting:test', - params: { - alertId: '1', - }, - ownerId: null, - }; - - const alertTaskInsatnce: AlertTaskInstance = taskInstanceToAlertTaskInstance(taskInstance); - - expect(alertTaskInsatnce).toEqual({ - ...taskInstance, - state: { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: { - state: {}, - meta: { - lastScheduledActions: { - group: 'first_group', - date: lastScheduledActionsDate, - }, - }, - }, - second_instance: {}, - }, - }, - }); - }); - - test(`throws if state is invalid`, () => { - const taskInstance: ConcreteTaskInstance = { - id: '215ee69b-1df9-428e-ab1a-ccf274f8fa5b', - attempts: 0, - status: TaskStatus.Running, - version: '123', - runAt: new Date(), - scheduledAt: new Date(), - startedAt: new Date(), - retryAt: new Date(Date.now() + 5 * 60 * 1000), - state: { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: 'invalid', - second_instance: {}, - }, - }, - taskType: 'alerting:test', - params: { - alertId: '1', - }, - ownerId: null, - }; - - expect(() => taskInstanceToAlertTaskInstance(taskInstance)).toThrowErrorMatchingInlineSnapshot( - `"Task \\"215ee69b-1df9-428e-ab1a-ccf274f8fa5b\\" has invalid state at .alertInstances.first_instance"` - ); - }); - - test(`throws with Alert id when alert is present and state is invalid`, () => { - const taskInstance: ConcreteTaskInstance = { - id: '215ee69b-1df9-428e-ab1a-ccf274f8fa5b', - attempts: 0, - status: TaskStatus.Running, - version: '123', - runAt: new Date(), - scheduledAt: new Date(), - startedAt: new Date(), - retryAt: new Date(Date.now() + 5 * 60 * 1000), - state: { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: 'invalid', - second_instance: {}, - }, - }, - taskType: 'alerting:test', - params: { - alertId: '1', - }, - ownerId: null, - }; - - expect(() => - taskInstanceToAlertTaskInstance(taskInstance, alert) - ).toThrowErrorMatchingInlineSnapshot( - `"Task \\"215ee69b-1df9-428e-ab1a-ccf274f8fa5b\\" (underlying Alert \\"alert-123\\") has invalid state at .alertInstances.first_instance"` - ); - }); - - test(`allows an initial empty state`, () => { - const taskInstance: ConcreteTaskInstance = { - id: uuidv4(), - attempts: 0, - status: TaskStatus.Running, - version: '123', - runAt: new Date(), - scheduledAt: new Date(), - startedAt: new Date(), - retryAt: new Date(Date.now() + 5 * 60 * 1000), - state: {}, + state: { foo: true }, taskType: 'alerting:test', params: { alertId: '1', diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts index d831fe8c63b07f..1851c186379907 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts @@ -13,7 +13,6 @@ import { SanitizedRule, RuleTaskState, ruleParamsSchema, - ruleStateSchema, RuleTaskParams, RuleTypeParams, } from '../../common'; @@ -42,15 +41,6 @@ export function taskInstanceToAlertTaskInstance( ); }, t.identity) ), - state: pipe( - ruleStateSchema.decode(taskInstance.state), - fold((e: t.Errors) => { - throw new Error( - `Task "${taskInstance.id}" ${ - alert ? `(underlying Alert "${alert.id}") ` : '' - }has invalid state at ${enumerateErrorFields(e)}` - ); - }, t.identity) - ), + state: taskInstance.state as RuleTaskState, }; } diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.ts b/x-pack/plugins/monitoring/server/alerts/base_rule.ts index 17491ffc760cbd..8a7b70ba8e6f07 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_rule.ts @@ -194,11 +194,6 @@ export class BaseRule { const filteredAlertInstance = this.filterAlertInstance(alertInstance, filters); if (filteredAlertInstance) { accum[instanceId] = filteredAlertInstance as RawAlertInstance; - if (filteredAlertInstance.state) { - accum[instanceId].state = { - alertStates: (filteredAlertInstance.state as AlertInstanceState).alertStates, - }; - } } return accum; }, diff --git a/x-pack/plugins/task_manager/server/saved_objects/migrations.ts b/x-pack/plugins/task_manager/server/saved_objects/migrations.ts index bcbd493f831602..83bd683fdba0f7 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/migrations.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/migrations.ts @@ -16,6 +16,7 @@ import { } from '@kbn/core/server'; import type { RuleTaskState, + MutableRuleTaskState, TrackedLifecycleAlertState, WrappedLifecycleRuleState, } from '@kbn/alerting-state-types'; @@ -253,7 +254,7 @@ function addAlertUUID(doc: SavedObjectUnsanitizedDoc, currentUUIDs: Map ): void { diff --git a/x-pack/plugins/task_manager/server/saved_objects/migrations_880.test.ts b/x-pack/plugins/task_manager/server/saved_objects/migrations_880.test.ts index c8c0d0bf91ed34..1fee82adc4cf5b 100644 --- a/x-pack/plugins/task_manager/server/saved_objects/migrations_880.test.ts +++ b/x-pack/plugins/task_manager/server/saved_objects/migrations_880.test.ts @@ -11,6 +11,7 @@ import { migrationMocks } from '@kbn/core/server/mocks'; import { SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server'; import type { RuleTaskState, + MutableRuleTaskState, WrappedLifecycleRuleState, RawAlertInstance, } from '@kbn/alerting-state-types'; @@ -73,7 +74,7 @@ describe('successful migrations for 8.8.0', () => { }); function checkMetaInRuleTaskState( - actual: RuleTaskState, + actual: MutableRuleTaskState, original: RuleTaskState, wrappedUUIDs?: Map ) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.ts index 3f9fc3d61097e5..cd818689571e12 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/state.ts @@ -5,10 +5,6 @@ * 2.0. */ import { HttpSetup } from '@kbn/core/public'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { Errors, identity } from 'io-ts'; -import { ruleStateSchema } from '@kbn/alerting-plugin/common'; import { AsApiContract, RewriteRequestCase } from '@kbn/actions-plugin/common'; import { RuleTaskState } from '../../../types'; import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants'; @@ -33,17 +29,9 @@ export async function loadRuleState({ http: HttpSetup; ruleId: string; }): Promise { - return await http + return (await http .get | EmptyHttpResponse>( `${INTERNAL_BASE_ALERTING_API_PATH}/rule/${ruleId}/state` ) - .then((state) => (state ? rewriteBodyRes(state) : {})) - .then((state: RuleTaskState) => { - return pipe( - ruleStateSchema.decode(state), - fold((e: Errors) => { - throw new Error(`Rule "${ruleId}" has invalid state`); - }, identity) - ); - }); + .then((state) => (state ? rewriteBodyRes(state) : {}))) as RuleTaskState; } From 8fe518ecfc6a71a2c5d06e7fc15de9a0cc9e2e66 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 28 Jul 2023 11:14:01 -0400 Subject: [PATCH 09/20] Attempt reducing bundle size for alerting plugin --- x-pack/plugins/alerting/common/index.ts | 1 - .../alerting_event_logger/alerting_event_logger.test.ts | 2 +- .../plugins/alerting/server/lib/last_run_status.test.ts | 2 +- x-pack/plugins/alerting/server/lib/last_run_status.ts | 3 ++- .../alerting/server/lib/rule_execution_status.test.ts | 7 ++----- .../plugins/alerting/server/lib/rule_execution_status.ts | 3 ++- .../alerting/server/lib/rule_run_metrics_store.test.ts | 2 +- .../alerting/server/lib/rule_run_metrics_store.ts | 2 +- .../alerting/server/task_runner/alert_task_instance.ts | 9 ++------- .../server/task_runner/execution_handler.test.ts | 2 +- .../alerting/server/task_runner/execution_handler.ts | 2 +- 11 files changed, 14 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index e283a8b278abc2..05b9e84ee2b7a3 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -25,7 +25,6 @@ export type { RuleTaskState, RuleTaskParams, } from '@kbn/alerting-state-types'; -export { wrappedStateRt, ActionsCompletion, ruleParamsSchema } from '@kbn/alerting-state-types'; export * from './alert_summary'; export * from './builtin_action_groups'; export * from './bulk_edit'; diff --git a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts index b5fff8a84c38cc..007cd4481bd7e6 100644 --- a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts +++ b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.test.ts @@ -7,6 +7,7 @@ import { eventLoggerMock } from '@kbn/event-log-plugin/server/event_logger.mock'; import { IEvent, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { AlertingEventLogger, RuleContextOpts, @@ -19,7 +20,6 @@ import { } from './alerting_event_logger'; import { UntypedNormalizedRuleType } from '../../rule_type_registry'; import { - ActionsCompletion, RecoveredActionGroup, RuleExecutionStatusErrorReasons, RuleExecutionStatusWarningReasons, diff --git a/x-pack/plugins/alerting/server/lib/last_run_status.test.ts b/x-pack/plugins/alerting/server/lib/last_run_status.test.ts index d6b6f62b1b60a5..33af749fe1e083 100644 --- a/x-pack/plugins/alerting/server/lib/last_run_status.test.ts +++ b/x-pack/plugins/alerting/server/lib/last_run_status.test.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { lastRunFromState } from './last_run_status'; -import { ActionsCompletion } from '../../common'; import { RuleRunMetrics } from './rule_run_metrics_store'; import { RuleResultServiceResults, RuleResultService } from '../monitoring/rule_result_service'; diff --git a/x-pack/plugins/alerting/server/lib/last_run_status.ts b/x-pack/plugins/alerting/server/lib/last_run_status.ts index a007d8637eac07..56da93f074c274 100644 --- a/x-pack/plugins/alerting/server/lib/last_run_status.ts +++ b/x-pack/plugins/alerting/server/lib/last_run_status.ts @@ -5,10 +5,11 @@ * 2.0. */ +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { RuleTaskStateAndMetrics } from '../task_runner/types'; import { getReasonFromError } from './error_with_reason'; import { getEsErrorMessage } from './errors'; -import { ActionsCompletion, RuleLastRunOutcomeOrderMap, RuleLastRunOutcomes } from '../../common'; +import { RuleLastRunOutcomeOrderMap, RuleLastRunOutcomes } from '../../common'; import { RuleLastRunOutcomeValues, RuleExecutionStatusWarningReasons, diff --git a/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts b/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts index 69c90ed812549a..0210de56a6b0df 100644 --- a/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts +++ b/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts @@ -6,11 +6,8 @@ */ import { loggingSystemMock } from '@kbn/core/server/mocks'; -import { - ActionsCompletion, - RuleExecutionStatusErrorReasons, - RuleExecutionStatusWarningReasons, -} from '../types'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; +import { RuleExecutionStatusErrorReasons, RuleExecutionStatusWarningReasons } from '../types'; import { executionStatusFromState, executionStatusFromError, diff --git a/x-pack/plugins/alerting/server/lib/rule_execution_status.ts b/x-pack/plugins/alerting/server/lib/rule_execution_status.ts index fbcf5d9ec5f2ac..43ab9e2153a94e 100644 --- a/x-pack/plugins/alerting/server/lib/rule_execution_status.ts +++ b/x-pack/plugins/alerting/server/lib/rule_execution_status.ts @@ -6,6 +6,7 @@ */ import { Logger } from '@kbn/core/server'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { RuleExecutionStatus, RuleExecutionStatusValues, @@ -16,7 +17,7 @@ import { } from '../types'; import { getReasonFromError } from './error_with_reason'; import { getEsErrorMessage } from './errors'; -import { ActionsCompletion, RuleExecutionStatuses } from '../../common'; +import { RuleExecutionStatuses } from '../../common'; import { translations } from '../constants/translations'; import { RuleTaskStateAndMetrics } from '../task_runner/types'; import { RuleRunMetrics } from './rule_run_metrics_store'; diff --git a/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.test.ts b/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.test.ts index a042df442b787d..8f2410480cc6f1 100644 --- a/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.test.ts +++ b/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.test.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { RuleRunMetricsStore } from './rule_run_metrics_store'; -import { ActionsCompletion } from '../types'; describe('RuleRunMetricsStore', () => { const ruleRunMetricsStore = new RuleRunMetricsStore(); diff --git a/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.ts b/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.ts index db83aeb7a63d63..14879e1558ba61 100644 --- a/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.ts +++ b/x-pack/plugins/alerting/server/lib/rule_run_metrics_store.ts @@ -6,7 +6,7 @@ */ import { set } from '@kbn/safer-lodash-set'; -import { ActionsCompletion } from '../types'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { ActionsConfigMap } from './get_actions_config_map'; import { SearchMetrics } from './types'; diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts index 1851c186379907..adcf228dde7835 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts @@ -9,13 +9,8 @@ import * as t from 'io-ts'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { ConcreteTaskInstance } from '@kbn/task-manager-plugin/server'; -import { - SanitizedRule, - RuleTaskState, - ruleParamsSchema, - RuleTaskParams, - RuleTypeParams, -} from '../../common'; +import { ruleParamsSchema } from '@kbn/alerting-state-types'; +import { SanitizedRule, RuleTaskState, RuleTaskParams, RuleTypeParams } from '../../common'; export interface AlertTaskInstance extends ConcreteTaskInstance { state: RuleTaskState; diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts index a9aca56579a1c7..77b866cf081124 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts @@ -13,10 +13,10 @@ import { renderActionParameterTemplatesDefault, } from '@kbn/actions-plugin/server/mocks'; import { KibanaRequest } from '@kbn/core/server'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { InjectActionParamsOpts, injectActionParams } from './inject_action_params'; import { NormalizedRuleType } from '../rule_type_registry'; import { - ActionsCompletion, ThrottledActions, RuleTypeParams, RuleTypeState, diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts index 4c76a087fa9aa7..f71173b160e995 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts @@ -11,6 +11,7 @@ import { getRuleDetailsRoute, triggersActionsRoute } from '@kbn/rule-data-utils' import { asSavedObjectExecutionSource } from '@kbn/actions-plugin/server'; import { isEphemeralTaskRejectedDueToCapacityError } from '@kbn/task-manager-plugin/server'; import { ExecuteOptions as EnqueueExecutionOptions } from '@kbn/actions-plugin/server/create_execute_function'; +import { ActionsCompletion } from '@kbn/alerting-state-types'; import { ActionsClient } from '@kbn/actions-plugin/server/actions_client'; import { chunk } from 'lodash'; import { AlertingEventLogger } from '../lib/alerting_event_logger/alerting_event_logger'; @@ -28,7 +29,6 @@ import { transformActionParams, transformSummaryActionParams } from './transform import { Alert } from '../alert'; import { NormalizedRuleType } from '../rule_type_registry'; import { - ActionsCompletion, AlertInstanceContext, AlertInstanceState, RuleAction, From dcdd31e061027bf8039b8974458c89e4466595d8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 28 Jul 2023 14:33:13 -0400 Subject: [PATCH 10/20] allow undefined --- .../kbn-alerting-state-types/src/task_state/v1/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts index e344aee8bc06b2..c3c4877f30b911 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts @@ -10,9 +10,9 @@ import { schema } from '@kbn/config-schema'; const actionSchema = schema.object({ date: schema.string() }); export const throttledActionSchema = schema.recordOf(schema.string(), actionSchema); // TODO: Add schema by rule type for alert state -export const alertStateSchema = schema.recordOf(schema.string(), schema.any()); +export const alertStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); // TODO: Add schema by rule type for rule state -const ruleStateSchema = schema.recordOf(schema.string(), schema.any()); +const ruleStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); export const lastScheduledActionsSchema = schema.object({ subgroup: schema.maybe(schema.string()), From 2d8af0bfc727894e2d47b09a51a71f52dd207178 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 31 Jul 2023 07:59:53 -0400 Subject: [PATCH 11/20] Add migrations --- .../src/task_state/lib/index.ts | 12 ++ .../src/task_state/v1/index.ts | 41 +------ .../src/task_state/v1/migration.ts | 106 ++++++++++++++++++ .../src/task_state/v1/schema.ts | 44 ++++++++ 4 files changed, 166 insertions(+), 37 deletions(-) create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts new file mode 100644 index 00000000000000..40d0f4d61db1c5 --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isPlainObject } from 'lodash'; + +export function isJSONObject(obj: unknown): obj is Record { + return isPlainObject(obj); +} diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts index c3c4877f30b911..4f07799c7f57ed 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts @@ -5,43 +5,10 @@ * 2.0. */ -import { schema } from '@kbn/config-schema'; - -const actionSchema = schema.object({ date: schema.string() }); -export const throttledActionSchema = schema.recordOf(schema.string(), actionSchema); -// TODO: Add schema by rule type for alert state -export const alertStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); -// TODO: Add schema by rule type for rule state -const ruleStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); - -export const lastScheduledActionsSchema = schema.object({ - subgroup: schema.maybe(schema.string()), - group: schema.string(), - date: schema.string(), - actions: schema.maybe(throttledActionSchema), -}); - -export const metaSchema = schema.object({ - lastScheduledActions: schema.maybe(lastScheduledActionsSchema), - flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), - flapping: schema.maybe(schema.boolean()), - maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), - pendingRecoveredCount: schema.maybe(schema.number()), - uuid: schema.maybe(schema.string()), -}); - -export const rawAlertInstanceSchema = schema.object({ - meta: schema.maybe(metaSchema), - state: schema.maybe(alertStateSchema), -}); +import { upMigration } from './migration'; +import { versionSchema } from './schema'; export const versionDefinition = { - up: (state: Record) => state, - schema: schema.object({ - alertTypeState: schema.maybe(ruleStateSchema), - alertInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), - alertRecoveredInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), - previousStartedAt: schema.maybe(schema.nullable(schema.string())), - summaryActions: schema.maybe(throttledActionSchema), - }), + up: upMigration, + schema: versionSchema, }; diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts new file mode 100644 index 00000000000000..93dd50f553c3b5 --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { every } from 'lodash'; +import { type TypeOf } from '@kbn/config-schema'; +import { isJSONObject } from '../lib'; +import { + versionSchema, + throttledActionSchema, + rawAlertInstanceSchema, + metaSchema, + lastScheduledActionsSchema, +} from './schema'; + +type VersionSchema = TypeOf; +type ThrottledActionsSchema = TypeOf; +type LastScheduledActionsSchema = TypeOf; +type RawAlertInstanceSchema = TypeOf; + +function migrateThrottledActions(throttledActions: unknown): ThrottledActionsSchema | undefined { + if (!isJSONObject(throttledActions)) { + return; + } + return Object.keys(throttledActions).reduce((acc, key) => { + const val = throttledActions[key]; + if (isJSONObject(val) && typeof val.date === 'string') { + acc[key] = { + date: val.date, + }; + } + return acc; + }, {} as TypeOf); +} + +function migrateLastScheduledActions( + lastScheduledActions: unknown +): LastScheduledActionsSchema | undefined { + if ( + !isJSONObject(lastScheduledActions) || + typeof lastScheduledActions.group !== 'string' || + typeof lastScheduledActions.date !== 'string' + ) { + return; + } + return { + subgroup: + typeof lastScheduledActions.subgroup === 'string' ? lastScheduledActions.subgroup : undefined, + group: lastScheduledActions.group, + date: lastScheduledActions.date, + actions: migrateThrottledActions(lastScheduledActions.actions), + }; +} + +function migrateMeta(meta: unknown): TypeOf | undefined { + if (!isJSONObject(meta)) { + return; + } + return { + lastScheduledActions: migrateLastScheduledActions(meta.lastScheduledActions), + flappingHistory: + Array.isArray(meta.flappingHistory) && + every(meta.flappingHistory, (item) => typeof item === 'boolean') + ? meta.flappingHistory + : undefined, + flapping: typeof meta.flapping === 'boolean' ? meta.flapping : undefined, + maintenanceWindowIds: + Array.isArray(meta.maintenanceWindowIds) && + every(meta.maintenanceWindowIds, (item) => typeof item === 'string') + ? meta.maintenanceWindowIds + : undefined, + pendingRecoveredCount: + typeof meta.pendingRecoveredCount === 'number' ? meta.pendingRecoveredCount : undefined, + uuid: typeof meta.uuid || undefined, + }; +} + +function migrateAlertInstances( + alertInstances: unknown +): Record | undefined { + if (!isJSONObject(alertInstances)) { + return; + } + return Object.keys(alertInstances).reduce((acc, key) => { + const val = alertInstances[key]; + if (isJSONObject(val)) { + acc[key] = { + meta: migrateMeta(val.meta), + state: isJSONObject(val.state) ? val.state : undefined, + }; + } + return acc; + }, {} as Record); +} + +export const upMigration = (state: Record): VersionSchema => ({ + alertTypeState: isJSONObject(state.alertTypeState) ? state.alertTypeState : undefined, + alertInstances: migrateAlertInstances(state.alertInstances), + alertRecoveredInstances: migrateAlertInstances(state.alertRecoveredInstances), + previousStartedAt: + typeof state.previousStartedAt === 'string' ? state.previousStartedAt : undefined, + summaryActions: migrateThrottledActions(state.summaryActions), +}); diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts new file mode 100644 index 00000000000000..6b038a6becc6e9 --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +const actionSchema = schema.object({ date: schema.string() }); +export const throttledActionSchema = schema.recordOf(schema.string(), actionSchema); +// TODO: Add schema by rule type for alert state +export const alertStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); +// TODO: Add schema by rule type for rule state +const ruleStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); + +export const lastScheduledActionsSchema = schema.object({ + subgroup: schema.maybe(schema.string()), + group: schema.string(), + date: schema.string(), + actions: schema.maybe(throttledActionSchema), +}); + +export const metaSchema = schema.object({ + lastScheduledActions: schema.maybe(lastScheduledActionsSchema), + flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), + flapping: schema.maybe(schema.boolean()), + maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), + pendingRecoveredCount: schema.maybe(schema.number()), + uuid: schema.maybe(schema.string()), +}); + +export const rawAlertInstanceSchema = schema.object({ + meta: schema.maybe(metaSchema), + state: schema.maybe(alertStateSchema), +}); + +export const versionSchema = schema.object({ + alertTypeState: schema.maybe(ruleStateSchema), + alertInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), + alertRecoveredInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), + previousStartedAt: schema.maybe(schema.nullable(schema.string())), + summaryActions: schema.maybe(throttledActionSchema), +}); From 1b38ed894f06f48bcab6a288cba998ec57767659 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 31 Jul 2023 08:32:23 -0400 Subject: [PATCH 12/20] Add unit tests and fix type check --- .../src/task_state/v1/index.ts | 9 + .../src/task_state/v1/migration.test.ts | 225 ++++++++++++++++++ .../src/task_state/v1/migration.ts | 30 ++- 3 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.test.ts diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts index 4f07799c7f57ed..4b28d7e68d0857 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/index.ts @@ -8,6 +8,15 @@ import { upMigration } from './migration'; import { versionSchema } from './schema'; +export { + versionSchema, + throttledActionSchema, + rawAlertInstanceSchema, + metaSchema, + alertStateSchema, + lastScheduledActionsSchema, +} from './schema'; + export const versionDefinition = { up: upMigration, schema: versionSchema, diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.test.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.test.ts new file mode 100644 index 00000000000000..fab82accc9a304 --- /dev/null +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.test.ts @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + migrateThrottledActions, + migrateLastScheduledActions, + migrateMeta, + migrateAlertInstances, + upMigration, +} from './migration'; + +describe('migrateThrottledActions', () => { + it('should return undefined if input is not an object', () => { + const result = migrateThrottledActions(null); + expect(result).toBeUndefined(); + }); + + it('should return the migrated throttledActions object', () => { + const input = { + key1: { date: '2023-07-31T12:00:00Z' }, + key2: { date: '2023-07-30T12:00:00Z' }, + key3: 'notAnObject', + }; + + const expectedOutput = { + key1: { date: '2023-07-31T12:00:00Z' }, + key2: { date: '2023-07-30T12:00:00Z' }, + }; + + const result = migrateThrottledActions(input); + expect(result).toEqual(expectedOutput); + }); +}); + +describe('migrateLastScheduledActions', () => { + it('should return undefined if input is not a valid lastScheduledActions object', () => { + const result = migrateLastScheduledActions({ group: 'group1' }); // Missing 'date' property + expect(result).toBeUndefined(); + }); + + it('should return the migrated lastScheduledActions object', () => { + const input = { + group: 'group1', + subgroup: 'subgroup1', + date: '2023-07-31T12:00:00Z', + actions: { + key1: { date: '2023-07-31T12:00:00Z' }, + key2: { date: '2023-07-30T12:00:00Z' }, + }, + }; + + const expectedOutput = { + group: 'group1', + subgroup: 'subgroup1', + date: '2023-07-31T12:00:00Z', + actions: { + key1: { date: '2023-07-31T12:00:00Z' }, + key2: { date: '2023-07-30T12:00:00Z' }, + }, + }; + + const result = migrateLastScheduledActions(input); + expect(result).toEqual(expectedOutput); + }); +}); + +describe('migrateMeta', () => { + it('should return undefined if input is not an object', () => { + const result = migrateMeta(null); + expect(result).toBeUndefined(); + }); + + it('should return the migrated meta object', () => { + const input = { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }; + + const expectedOutput = { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }; + + const result = migrateMeta(input); + expect(result).toEqual(expectedOutput); + }); +}); + +describe('migrateAlertInstances', () => { + it('should return undefined if input is not an object', () => { + const result = migrateAlertInstances(null); + expect(result).toBeUndefined(); + }); + + it('should return the migrated alertInstances object', () => { + const input = { + instance1: { + meta: { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }, + state: { key: 'value' }, + }, + instance2: { + meta: { + lastScheduledActions: { + group: 'group2', + date: '2023-07-30T12:00:00Z', + }, + }, + }, + instance3: 'notAnObject', + }; + + const expectedOutput = { + instance1: { + meta: { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }, + state: { key: 'value' }, + }, + instance2: { + meta: { + lastScheduledActions: { + group: 'group2', + date: '2023-07-30T12:00:00Z', + }, + }, + }, + }; + + const result = migrateAlertInstances(input); + expect(result).toEqual(expectedOutput); + }); +}); + +describe('upMigration', () => { + it('should return the migrated state object', () => { + const inputState = { + alertTypeState: {}, + alertInstances: { + instance1: { + meta: { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }, + state: { key: 'value' }, + }, + }, + alertRecoveredInstances: {}, + previousStartedAt: '2023-07-30T12:00:00Z', + summaryActions: { + action1: { date: '2023-07-31T12:00:00Z' }, + }, + }; + + const expectedOutput = { + alertTypeState: {}, + alertInstances: { + instance1: { + meta: { + lastScheduledActions: { + group: 'group1', + date: '2023-07-31T12:00:00Z', + }, + flappingHistory: [true, false, true], + flapping: true, + maintenanceWindowIds: ['id1', 'id2'], + pendingRecoveredCount: 3, + uuid: 'abc123', + }, + state: { key: 'value' }, + }, + }, + alertRecoveredInstances: {}, + previousStartedAt: '2023-07-30T12:00:00Z', + summaryActions: { + action1: { date: '2023-07-31T12:00:00Z' }, + }, + }; + + const result = upMigration(inputState); + expect(result).toEqual(expectedOutput); + }); +}); diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts index 93dd50f553c3b5..f5bb8232854ac6 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts @@ -21,7 +21,9 @@ type ThrottledActionsSchema = TypeOf; type LastScheduledActionsSchema = TypeOf; type RawAlertInstanceSchema = TypeOf; -function migrateThrottledActions(throttledActions: unknown): ThrottledActionsSchema | undefined { +export function migrateThrottledActions( + throttledActions: unknown +): ThrottledActionsSchema | undefined { if (!isJSONObject(throttledActions)) { return; } @@ -36,7 +38,7 @@ function migrateThrottledActions(throttledActions: unknown): ThrottledActionsSch }, {} as TypeOf); } -function migrateLastScheduledActions( +export function migrateLastScheduledActions( lastScheduledActions: unknown ): LastScheduledActionsSchema | undefined { if ( @@ -55,7 +57,7 @@ function migrateLastScheduledActions( }; } -function migrateMeta(meta: unknown): TypeOf | undefined { +export function migrateMeta(meta: unknown): TypeOf | undefined { if (!isJSONObject(meta)) { return; } @@ -74,11 +76,11 @@ function migrateMeta(meta: unknown): TypeOf | undefined { : undefined, pendingRecoveredCount: typeof meta.pendingRecoveredCount === 'number' ? meta.pendingRecoveredCount : undefined, - uuid: typeof meta.uuid || undefined, + uuid: typeof meta.uuid === 'string' ? meta.uuid : undefined, }; } -function migrateAlertInstances( +export function migrateAlertInstances( alertInstances: unknown ): Record | undefined { if (!isJSONObject(alertInstances)) { @@ -96,11 +98,13 @@ function migrateAlertInstances( }, {} as Record); } -export const upMigration = (state: Record): VersionSchema => ({ - alertTypeState: isJSONObject(state.alertTypeState) ? state.alertTypeState : undefined, - alertInstances: migrateAlertInstances(state.alertInstances), - alertRecoveredInstances: migrateAlertInstances(state.alertRecoveredInstances), - previousStartedAt: - typeof state.previousStartedAt === 'string' ? state.previousStartedAt : undefined, - summaryActions: migrateThrottledActions(state.summaryActions), -}); +export const upMigration = (state: Record): VersionSchema => { + return { + alertTypeState: isJSONObject(state.alertTypeState) ? state.alertTypeState : undefined, + alertInstances: migrateAlertInstances(state.alertInstances), + alertRecoveredInstances: migrateAlertInstances(state.alertRecoveredInstances), + previousStartedAt: + typeof state.previousStartedAt === 'string' ? state.previousStartedAt : undefined, + summaryActions: migrateThrottledActions(state.summaryActions), + }; +}; From 667e8b17bd49278f86f434f93443785894cf8b48 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 31 Jul 2023 08:53:24 -0400 Subject: [PATCH 13/20] Add back accidentally removed code --- x-pack/plugins/alerting/server/rule_type_registry.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 78b61a46a57f7f..7a17699bd756b9 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -14,6 +14,7 @@ import { Logger } from '@kbn/core/server'; import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { RunContext, TaskManagerSetupContract } from '@kbn/task-manager-plugin/server'; import { stateSchemaByVersion } from '@kbn/alerting-state-types'; +import { rawRuleSchema } from './raw_rule_schema'; import { TaskRunnerFactory } from './task_runner'; import { RuleType, @@ -293,6 +294,12 @@ export class RuleTypeRegistry { RecoveryActionGroupId | RecoveredActionGroupId, AlertData >(normalizedRuleType, context, this.inMemoryMetrics), + paramsSchema: schema.object({ + alertId: schema.string(), + spaceId: schema.string(), + consumer: schema.maybe(schema.string()), + }), + indirectParamsSchema: rawRuleSchema, }, }); From ca0b27a186dcacf0566d4312c051bdb19e301ad8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 31 Jul 2023 13:01:45 -0400 Subject: [PATCH 14/20] Add back the comments --- .../kbn-alerting-state-types/src/task_state/v1/schema.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts index 6b038a6becc6e9..1fdc704d6252d6 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts @@ -23,7 +23,11 @@ export const lastScheduledActionsSchema = schema.object({ export const metaSchema = schema.object({ lastScheduledActions: schema.maybe(lastScheduledActionsSchema), + // an array used to track changes in alert state, the order is based on the rule executions (oldest to most recent) + // true - alert has changed from active/recovered + // false - the status has remained either active or recovered flappingHistory: schema.maybe(schema.arrayOf(schema.boolean())), + // flapping flag that indicates whether the alert is flapping flapping: schema.maybe(schema.boolean()), maintenanceWindowIds: schema.maybe(schema.arrayOf(schema.string())), pendingRecoveredCount: schema.maybe(schema.number()), @@ -37,7 +41,9 @@ export const rawAlertInstanceSchema = schema.object({ export const versionSchema = schema.object({ alertTypeState: schema.maybe(ruleStateSchema), + // tracks the active alerts alertInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), + // tracks the recovered alerts for flapping purposes alertRecoveredInstances: schema.maybe(schema.recordOf(schema.string(), rawAlertInstanceSchema)), previousStartedAt: schema.maybe(schema.nullable(schema.string())), summaryActions: schema.maybe(throttledActionSchema), From eaf3fee459d0efcef1b6869af7d018aa3f11bf32 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 31 Jul 2023 13:24:28 -0400 Subject: [PATCH 15/20] Make code more readable --- .../src/task_state/lib/index.ts | 20 ++++++++++ .../src/task_state/v1/migration.ts | 38 ++++++++----------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts index 40d0f4d61db1c5..219705c1185b44 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/lib/index.ts @@ -10,3 +10,23 @@ import { isPlainObject } from 'lodash'; export function isJSONObject(obj: unknown): obj is Record { return isPlainObject(obj); } + +export function isString(value: unknown): value is string { + return typeof value === 'string'; +} + +export function isBoolean(value: unknown): value is boolean { + return typeof value === 'boolean'; +} + +export function isNumber(value: unknown): value is number { + return typeof value === 'number'; +} + +export function isStringArray(value: unknown): value is string[] { + return Array.isArray(value) && value.every((item) => typeof item === 'string'); +} + +export function isBooleanArray(value: unknown): value is boolean[] { + return Array.isArray(value) && value.every((item) => typeof item === 'boolean'); +} diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts index f5bb8232854ac6..d4e4947bcb0b8a 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/migration.ts @@ -5,9 +5,8 @@ * 2.0. */ -import { every } from 'lodash'; import { type TypeOf } from '@kbn/config-schema'; -import { isJSONObject } from '../lib'; +import { isJSONObject, isString, isBoolean, isNumber, isStringArray, isBooleanArray } from '../lib'; import { versionSchema, throttledActionSchema, @@ -29,7 +28,7 @@ export function migrateThrottledActions( } return Object.keys(throttledActions).reduce((acc, key) => { const val = throttledActions[key]; - if (isJSONObject(val) && typeof val.date === 'string') { + if (isJSONObject(val) && isString(val.date)) { acc[key] = { date: val.date, }; @@ -43,14 +42,13 @@ export function migrateLastScheduledActions( ): LastScheduledActionsSchema | undefined { if ( !isJSONObject(lastScheduledActions) || - typeof lastScheduledActions.group !== 'string' || - typeof lastScheduledActions.date !== 'string' + !isString(lastScheduledActions.group) || + !isString(lastScheduledActions.date) ) { return; } return { - subgroup: - typeof lastScheduledActions.subgroup === 'string' ? lastScheduledActions.subgroup : undefined, + subgroup: isString(lastScheduledActions.subgroup) ? lastScheduledActions.subgroup : undefined, group: lastScheduledActions.group, date: lastScheduledActions.date, actions: migrateThrottledActions(lastScheduledActions.actions), @@ -63,20 +61,15 @@ export function migrateMeta(meta: unknown): TypeOf | undefine } return { lastScheduledActions: migrateLastScheduledActions(meta.lastScheduledActions), - flappingHistory: - Array.isArray(meta.flappingHistory) && - every(meta.flappingHistory, (item) => typeof item === 'boolean') - ? meta.flappingHistory - : undefined, - flapping: typeof meta.flapping === 'boolean' ? meta.flapping : undefined, - maintenanceWindowIds: - Array.isArray(meta.maintenanceWindowIds) && - every(meta.maintenanceWindowIds, (item) => typeof item === 'string') - ? meta.maintenanceWindowIds - : undefined, - pendingRecoveredCount: - typeof meta.pendingRecoveredCount === 'number' ? meta.pendingRecoveredCount : undefined, - uuid: typeof meta.uuid === 'string' ? meta.uuid : undefined, + flappingHistory: isBooleanArray(meta.flappingHistory) ? meta.flappingHistory : undefined, + flapping: isBoolean(meta.flapping) ? meta.flapping : undefined, + maintenanceWindowIds: isStringArray(meta.maintenanceWindowIds) + ? meta.maintenanceWindowIds + : undefined, + pendingRecoveredCount: isNumber(meta.pendingRecoveredCount) + ? meta.pendingRecoveredCount + : undefined, + uuid: isString(meta.uuid) ? meta.uuid : undefined, }; } @@ -103,8 +96,7 @@ export const upMigration = (state: Record): VersionSchema => { alertTypeState: isJSONObject(state.alertTypeState) ? state.alertTypeState : undefined, alertInstances: migrateAlertInstances(state.alertInstances), alertRecoveredInstances: migrateAlertInstances(state.alertRecoveredInstances), - previousStartedAt: - typeof state.previousStartedAt === 'string' ? state.previousStartedAt : undefined, + previousStartedAt: isString(state.previousStartedAt) ? state.previousStartedAt : undefined, summaryActions: migrateThrottledActions(state.summaryActions), }; }; From 26a781efc4ee21bedd1cd91e00bd89df52b9db1c Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:04:48 +0000 Subject: [PATCH 16/20] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- x-pack/performance/journeys/apm_service_inventory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/performance/journeys/apm_service_inventory.ts b/x-pack/performance/journeys/apm_service_inventory.ts index d98b151c000d64..980c193f67bbbc 100644 --- a/x-pack/performance/journeys/apm_service_inventory.ts +++ b/x-pack/performance/journeys/apm_service_inventory.ts @@ -35,7 +35,7 @@ export const journey = new Journey({ ); }, ftrConfigPath: 'x-pack/performance/configs/apm_config.ts', - skipped: true + skipped: true, }) .step('Navigate to Service Inventory Page', async ({ page, kbnUrl }) => { await page.goto(kbnUrl.get(`app/apm/services`)); From 51aa13ca8e2c3ca525f9d2a6fe2610ba0028e682 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Aug 2023 07:33:10 -0400 Subject: [PATCH 17/20] Add comment linking to GitHub issue --- .../kbn-alerting-state-types/src/task_state/v1/schema.ts | 2 ++ x-pack/plugins/monitoring/common/types/alerts.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts index 1fdc704d6252d6..62e802483dcf7e 100644 --- a/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts +++ b/x-pack/packages/kbn-alerting-state-types/src/task_state/v1/schema.ts @@ -10,8 +10,10 @@ import { schema } from '@kbn/config-schema'; const actionSchema = schema.object({ date: schema.string() }); export const throttledActionSchema = schema.recordOf(schema.string(), actionSchema); // TODO: Add schema by rule type for alert state +// https://github.com/elastic/kibana/issues/159344 export const alertStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); // TODO: Add schema by rule type for rule state +// https://github.com/elastic/kibana/issues/159344 const ruleStateSchema = schema.recordOf(schema.string(), schema.maybe(schema.any())); export const lastScheduledActionsSchema = schema.object({ diff --git a/x-pack/plugins/monitoring/common/types/alerts.ts b/x-pack/plugins/monitoring/common/types/alerts.ts index 71943f42dd21ff..eaeb1192ea52cb 100644 --- a/x-pack/plugins/monitoring/common/types/alerts.ts +++ b/x-pack/plugins/monitoring/common/types/alerts.ts @@ -79,6 +79,7 @@ export interface AlertInstanceState { [x: string]: unknown; } +// Gets interesting for making this strict export interface AlertState { cluster: AlertCluster; ccs?: string; @@ -86,6 +87,7 @@ export interface AlertState { [key: string]: unknown; } +// Gets interesting for making this strict export interface AlertNodeState extends AlertState { nodeId: string; nodeName?: string; From 95108cac0ee3cc116ee123cd331dcb91d4c267a7 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 25 Aug 2023 08:32:52 -0400 Subject: [PATCH 18/20] Remove some outdated code comments --- x-pack/plugins/monitoring/common/types/alerts.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/monitoring/common/types/alerts.ts b/x-pack/plugins/monitoring/common/types/alerts.ts index eaeb1192ea52cb..71943f42dd21ff 100644 --- a/x-pack/plugins/monitoring/common/types/alerts.ts +++ b/x-pack/plugins/monitoring/common/types/alerts.ts @@ -79,7 +79,6 @@ export interface AlertInstanceState { [x: string]: unknown; } -// Gets interesting for making this strict export interface AlertState { cluster: AlertCluster; ccs?: string; @@ -87,7 +86,6 @@ export interface AlertState { [key: string]: unknown; } -// Gets interesting for making this strict export interface AlertNodeState extends AlertState { nodeId: string; nodeName?: string; From c05457212ae707326a90321b7da382017bdcd096 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 28 Aug 2023 12:42:11 -0400 Subject: [PATCH 19/20] Add back code that only keeps alertStates in the state --- x-pack/plugins/monitoring/server/alerts/base_rule.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.ts b/x-pack/plugins/monitoring/server/alerts/base_rule.ts index 8a7b70ba8e6f07..271398c270110d 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_rule.ts @@ -193,7 +193,15 @@ export class BaseRule { const alertInstance: RawAlertInstance = states.alertInstances[instanceId]; const filteredAlertInstance = this.filterAlertInstance(alertInstance, filters); if (filteredAlertInstance) { - accum[instanceId] = filteredAlertInstance as RawAlertInstance; + const state = filteredAlertInstance.state + ? { + alertStates: (filteredAlertInstance.state as AlertInstanceState).alertStates, + } + : filteredAlertInstance.state; + accum[instanceId] = { + ...filteredAlertInstance, + state, + } as RawAlertInstance; } return accum; }, From 8259214adfb3dc7279ace2cc85e35589655945a7 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 28 Aug 2023 13:48:37 -0400 Subject: [PATCH 20/20] Modify code to make tests pass --- .../plugins/monitoring/server/alerts/base_rule.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.ts b/x-pack/plugins/monitoring/server/alerts/base_rule.ts index 271398c270110d..7c280801293519 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_rule.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_rule.ts @@ -191,16 +191,15 @@ export class BaseRule { return accum; } const alertInstance: RawAlertInstance = states.alertInstances[instanceId]; - const filteredAlertInstance = this.filterAlertInstance(alertInstance, filters); + const { state, ...filteredAlertInstance } = this.filterAlertInstance( + alertInstance, + filters + ); if (filteredAlertInstance) { - const state = filteredAlertInstance.state - ? { - alertStates: (filteredAlertInstance.state as AlertInstanceState).alertStates, - } - : filteredAlertInstance.state; accum[instanceId] = { ...filteredAlertInstance, - state, + // Only keep "alertStates" within the state + ...(state ? { state: { alertStates: state.alertStates } } : {}), } as RawAlertInstance; } return accum;