From 93dd0e75cf3d835de456eb49039a37b352496418 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 1 Mar 2023 14:48:04 +0100 Subject: [PATCH 1/7] getUnhealthyTransformsReport --- .../register_transform_health_rule_type.ts | 17 ++++-- .../transform_health_service.ts | 52 ++++++++++++++++--- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts index 7698a11927fc1..a591ae350e3d5 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts @@ -19,17 +19,28 @@ import { PLUGIN, TRANSFORM_RULE_TYPE } from '../../../../common/constants'; import { transformHealthRuleParams, TransformHealthRuleParams } from './schema'; import { transformHealthServiceProvider } from './transform_health_service'; -export interface BaseResponse { +export interface TransformHealth { + status: 'green' | 'unknown' | 'yellow' | 'red'; + issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: string }>; +} + +export interface BaseTransformAlertResponse { transform_id: string; description?: string; + health: TransformHealth; +} + +export interface NotStartedTransformResponse extends BaseTransformAlertResponse { + transform_state: string; + node_name?: string; } -export interface NotStartedTransformResponse extends BaseResponse { +export interface UnhealthyTransformResponse extends BaseTransformAlertResponse { transform_state: string; node_name?: string; } -export interface ErrorMessagesTransformResponse extends BaseResponse { +export interface ErrorMessagesTransformResponse extends BaseTransformAlertResponse { error_messages: Array<{ message: string; timestamp: number; node_name?: string }>; } diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts index 435e30cf8c84a..bdb2d6f1a68df 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts @@ -8,8 +8,9 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { keyBy, partition } from 'lodash'; +import { keyBy, memoize, partition } from 'lodash'; import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { type TransformGetTransformStatsTransformStats } from '@elastic/elasticsearch/lib/api/types'; import { TransformHealthRuleParams } from './schema'; import { ALL_TRANSFORMS_SELECTION, @@ -18,10 +19,12 @@ import { TRANSFORM_STATE, } from '../../../../common/constants'; import { getResultTestConfig } from '../../../../common/utils/alerts'; -import { +import type { ErrorMessagesTransformResponse, NotStartedTransformResponse, + TransformHealth, TransformHealthAlertContext, + UnhealthyTransformResponse, } from './register_transform_health_rule_type'; import type { TransformHealthAlertRule } from '../../../../common/types/alerting'; import { isContinuousTransform } from '../../../../common/types/transform'; @@ -41,6 +44,13 @@ type Transform = estypes.TransformGetTransformTransformSummary & { type TransformWithAlertingRules = Transform & { alerting_rules: TransformHealthAlertRule[] }; +/** + * TODO update types in the es client + */ +type TransformGetTransformStats = TransformGetTransformStatsTransformStats & { + health: TransformHealth; +}; + export function transformHealthServiceProvider( esClient: ElasticsearchClient, rulesClient?: RulesClient @@ -90,6 +100,16 @@ export function transformHealthServiceProvider( return resultTransformIds; }; + const getTransformStats = memoize( + async (transformIds: string[]): Promise => { + return ( + await esClient.transform.getTransformStats({ + transform_id: transformIds.join(','), + }) + ).transforms as TransformGetTransformStats[]; + } + ); + return { /** * Returns report about not started transforms @@ -100,11 +120,7 @@ export function transformHealthServiceProvider( async getTransformsStateReport( transformIds: string[] ): Promise<[NotStartedTransformResponse[], NotStartedTransformResponse[]]> { - const transformsStats = ( - await esClient.transform.getTransformStats({ - transform_id: transformIds.join(','), - }) - ).transforms; + const transformsStats = await getTransformStats(transformIds); return partition( transformsStats.map((t) => ({ @@ -112,6 +128,7 @@ export function transformHealthServiceProvider( description: transformsDict.get(t.id)?.description, transform_state: t.state, node_name: t.node?.name, + health: t.health, })), (t) => t.transform_state !== TRANSFORM_STATE.STARTED && @@ -192,6 +209,27 @@ export function transformHealthServiceProvider( }) .filter((v) => failedTransforms.has(v.transform_id)); }, + /** + * Returns report about unhealthy transforms + * @param transformIds + */ + async getUnhealthyTransformsReport( + transformIds: string[] + ): Promise { + const transformsStats = await getTransformStats(transformIds); + + return transformsStats + .filter((t) => t.health.status !== 'green') + .map((t) => { + return { + transform_id: t.id, + transform_state: t.state, + node_name: t.node?.name, + description: transformsDict.get(t.id)?.description, + health: t.health, + }; + }); + }, /** * Returns results of the transform health checks * @param params From 18bb3d5962f19ae0fd7815a6fa80b10802428cf7 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 1 Mar 2023 16:09:55 +0100 Subject: [PATCH 2/7] disable errorMessages check --- x-pack/plugins/transform/common/constants.ts | 11 +++ .../transform/common/types/alerting.ts | 6 ++ .../plugins/transform/common/utils/alerts.ts | 5 +- .../register_transform_health_rule.ts | 4 +- .../tests_selection_control.tsx | 71 +++++++++++-------- .../transform_health_rule_type/schema.ts | 5 ++ .../transform_health_service.ts | 28 ++++++++ 7 files changed, 97 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 3bf8d5c97cc07..0e8eb21c063bf 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -190,6 +190,17 @@ export const TRANSFORM_HEALTH_CHECK_NAMES: Record< } ), }, + healthCheck: { + name: i18n.translate('xpack.transform.alertTypes.transformHealth.healthCheckName', { + defaultMessage: 'Unhealthy transforms', + }), + description: i18n.translate( + 'xpack.transform.alertTypes.transformHealth.healthCheckDescription', + { + defaultMessage: 'Get alerts if a transform health status is not green.', + } + ), + }, }; // Transform API default values https://www.elastic.co/guide/en/elasticsearch/reference/current/put-transform.html diff --git a/x-pack/plugins/transform/common/types/alerting.ts b/x-pack/plugins/transform/common/types/alerting.ts index aa08db9a8ce13..4e4d5a7407c5f 100644 --- a/x-pack/plugins/transform/common/types/alerting.ts +++ b/x-pack/plugins/transform/common/types/alerting.ts @@ -14,9 +14,15 @@ export type TransformHealthRuleParams = { notStarted?: { enabled: boolean; } | null; + /** + * @deprecated replaced in favor of healthCheck in 8.8 + */ errorMessages?: { enabled: boolean; } | null; + healthCheck?: { + enabled: boolean; + } | null; } | null; } & RuleTypeParams; diff --git a/x-pack/plugins/transform/common/utils/alerts.ts b/x-pack/plugins/transform/common/utils/alerts.ts index 88c6fc64a35b2..1a4947db6ae2e 100644 --- a/x-pack/plugins/transform/common/utils/alerts.ts +++ b/x-pack/plugins/transform/common/utils/alerts.ts @@ -13,7 +13,10 @@ export function getResultTestConfig(config: TransformHealthRuleTestsConfig) { enabled: config?.notStarted?.enabled ?? true, }, errorMessages: { - enabled: config?.errorMessages?.enabled ?? true, + enabled: config?.errorMessages?.enabled ?? false, + }, + healthCheck: { + enabled: config?.healthCheck?.enabled ?? true, }, }; } diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts index dfbe7e3154bf1..47428c070cda6 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts @@ -67,13 +67,13 @@ export function getTransformHealthRuleType(): RuleTypeModel>([ + 'errorMessages', +]); + export const TestsSelectionControl: FC = React.memo( ({ config, onChange, errors }) => { const uiConfig = getResultTestConfig(config); + const initConfig = useMemo(() => { + return uiConfig; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const updateCallback = useCallback( (update: Partial>) => { onChange({ @@ -43,35 +52,37 @@ export const TestsSelectionControl: FC = React.memo( Object.entries(uiConfig) as Array< [TransformHealthTests, typeof uiConfig[TransformHealthTests]] > - ).map(([name, conf], i) => { - return ( - {TRANSFORM_HEALTH_CHECK_NAMES[name]?.name}} - description={TRANSFORM_HEALTH_CHECK_NAMES[name]?.description} - fullWidth - gutterSize={'s'} - > - - - } - onChange={updateCallback.bind(null, { - [name]: { - ...uiConfig[name], - enabled: !uiConfig[name].enabled, - }, - })} - checked={uiConfig[name].enabled} - /> - - - ); - })} + ) + .filter(([name]) => !disabledChecks.has(name) || initConfig[name].enabled) + .map(([name, conf], i) => { + return ( + {TRANSFORM_HEALTH_CHECK_NAMES[name]?.name}} + description={TRANSFORM_HEALTH_CHECK_NAMES[name]?.description} + fullWidth + gutterSize={'s'} + > + + + } + onChange={updateCallback.bind(null, { + [name]: { + ...uiConfig[name], + enabled: !uiConfig[name].enabled, + }, + })} + checked={uiConfig[name].enabled} + /> + + + ); + })} diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/schema.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/schema.ts index e98d6edd294ac..5c487927c8461 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/schema.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/schema.ts @@ -18,6 +18,11 @@ export const transformHealthRuleParams = schema.object({ }) ), errorMessages: schema.nullable( + schema.object({ + enabled: schema.boolean({ defaultValue: false }), + }) + ), + healthCheck: schema.nullable( schema.object({ enabled: schema.boolean({ defaultValue: true }), }) diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts index bdb2d6f1a68df..56963d717f164 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts @@ -309,6 +309,34 @@ export function transformHealthServiceProvider( }); } + if (testsConfig.healthCheck.enabled) { + const response = await this.getUnhealthyTransformsReport(transformIds); + const isHealthy = response.length === 0; + const count = response.length; + const transformsString = response.map((t) => t.transform_id).join(', '); + result.push({ + isHealthy, + name: TRANSFORM_HEALTH_CHECK_NAMES.healthCheck.name, + context: { + results: isHealthy ? [] : response, + message: isHealthy + ? i18n.translate( + 'xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage', + { + defaultMessage: + '{count, plural, one {Transform} other {Transforms}} {transformsString} {count, plural, one {is} other {are}} healthy.', + values: { count, transformsString }, + } + ) + : i18n.translate('xpack.transform.alertTypes.transformHealth.healthCheckMessage', { + defaultMessage: + '{count, plural, one {Transform} other {Transforms}} {transformsString} {count, plural, one {is} other {are}} unhealthy.', + values: { count, transformsString }, + }), + }, + }); + } + return result; }, From e5ade235040f7154c06b38f4da7ff3fa04096671 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 2 Mar 2023 09:44:50 +0100 Subject: [PATCH 3/7] update context, update default template --- .../register_transform_health_rule.ts | 9 +++++++-- .../register_transform_health_rule_type.ts | 3 ++- .../transform_health_service.ts | 6 ++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts index 47428c070cda6..f6e0946299fed 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts @@ -67,8 +67,13 @@ export function getTransformHealthRuleType(): RuleTypeModel t.transform_state !== TRANSFORM_STATE.STARTED && @@ -226,7 +227,8 @@ export function transformHealthServiceProvider( transform_state: t.state, node_name: t.node?.name, description: transformsDict.get(t.id)?.description, - health: t.health, + health_status: t.health.status, + issues: t.health.issues, }; }); }, From f5fc49453738a331a220382eb6c506be8af2e857 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Thu, 2 Mar 2023 13:08:39 +0100 Subject: [PATCH 4/7] use fields format --- .../register_transform_health_rule.ts | 3 +- .../register_transform_health_rule_type.ts | 32 +++++---- .../transform_health_service.ts | 69 ++++++++++++------- x-pack/plugins/transform/server/plugin.ts | 12 +++- .../transform/server/routes/api/transforms.ts | 8 +-- x-pack/plugins/transform/server/types.ts | 3 + 6 files changed, 79 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts index f6e0946299fed..39075710b8c51 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/register_transform_health_rule.ts @@ -77,8 +77,7 @@ export function getTransformHealthRuleType(): RuleTypeModel; + issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: number }>; } export interface BaseTransformAlertResponse { transform_id: string; description?: string; health_status: TransformHealth['status']; - issues?: TransformHealth['issues']; -} - -export interface NotStartedTransformResponse extends BaseTransformAlertResponse { - transform_state: string; - node_name?: string; + issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: string }>; } -export interface UnhealthyTransformResponse extends BaseTransformAlertResponse { +export interface TransformStateReportResponse extends BaseTransformAlertResponse { transform_state: string; node_name?: string; } @@ -45,7 +41,7 @@ export interface ErrorMessagesTransformResponse extends BaseTransformAlertRespon error_messages: Array<{ message: string; timestamp: number; node_name?: string }>; } -export type TransformHealthResult = NotStartedTransformResponse | ErrorMessagesTransformResponse; +export type TransformHealthResult = TransformStateReportResponse | ErrorMessagesTransformResponse; export type TransformHealthAlertContext = { results: TransformHealthResult[]; @@ -66,14 +62,17 @@ export const TRANSFORM_ISSUE_DETECTED: ActionGroup = { interface RegisterParams { logger: Logger; alerting: AlertingSetup; + getFieldFormatsStart: () => FieldFormatsStart; } export function registerTransformHealthRuleType(params: RegisterParams) { const { alerting } = params; - alerting.registerType(getTransformHealthRuleType()); + alerting.registerType(getTransformHealthRuleType(params.getFieldFormatsStart)); } -export function getTransformHealthRuleType(): RuleType< +export function getTransformHealthRuleType( + getFieldFormatsStart: () => FieldFormatsStart +): RuleType< TransformHealthRuleParams, never, RuleTypeState, @@ -117,14 +116,19 @@ export function getTransformHealthRuleType(): RuleType< doesSetRecoveryContext: true, async executor(options) { const { - services: { scopedClusterClient, alertFactory }, + services: { scopedClusterClient, alertFactory, uiSettingsClient }, params, } = options; - const transformHealthService = transformHealthServiceProvider( - scopedClusterClient.asCurrentUser + const fieldFormatsRegistry = await getFieldFormatsStart().fieldFormatServiceFactory( + uiSettingsClient ); + const transformHealthService = transformHealthServiceProvider({ + esClient: scopedClusterClient.asCurrentUser, + fieldFormatsRegistry, + }); + const executionResult = await transformHealthService.getHealthChecksResults(params); const unhealthyTests = executionResult.filter(({ isHealthy }) => !isHealthy); diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts index f5b06a2b81453..72eb8981aadd6 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts @@ -11,6 +11,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { keyBy, memoize, partition } from 'lodash'; import type { RulesClient } from '@kbn/alerting-plugin/server'; import { type TransformGetTransformStatsTransformStats } from '@elastic/elasticsearch/lib/api/types'; +import { FIELD_FORMAT_IDS, FieldFormatsRegistry } from '@kbn/field-formats-plugin/common'; import { TransformHealthRuleParams } from './schema'; import { ALL_TRANSFORMS_SELECTION, @@ -21,10 +22,9 @@ import { import { getResultTestConfig } from '../../../../common/utils/alerts'; import type { ErrorMessagesTransformResponse, - NotStartedTransformResponse, + TransformStateReportResponse, TransformHealth, TransformHealthAlertContext, - UnhealthyTransformResponse, } from './register_transform_health_rule_type'; import type { TransformHealthAlertRule } from '../../../../common/types/alerting'; import { isContinuousTransform } from '../../../../common/types/transform'; @@ -51,10 +51,15 @@ type TransformGetTransformStats = TransformGetTransformStatsTransformStats & { health: TransformHealth; }; -export function transformHealthServiceProvider( - esClient: ElasticsearchClient, - rulesClient?: RulesClient -) { +export function transformHealthServiceProvider({ + esClient, + rulesClient, + fieldFormatsRegistry, +}: { + esClient: ElasticsearchClient; + rulesClient?: RulesClient; + fieldFormatsRegistry?: FieldFormatsRegistry; +}) { const transformsDict = new Map(); /** @@ -110,6 +115,34 @@ export function transformHealthServiceProvider( } ); + function baseTransformAlertResponseFormatter( + transformStats: TransformGetTransformStats + ): TransformStateReportResponse { + const dateFormatter = fieldFormatsRegistry!.deserialize({ id: FIELD_FORMAT_IDS.DATE }); + + return { + transform_id: transformStats.id, + description: transformsDict.get(transformStats.id)?.description, + transform_state: transformStats.state, + node_name: transformStats.node?.name, + health_status: transformStats.health.status, + ...(transformStats.health.issues + ? { + issues: transformStats.health.issues.map((issue) => { + return { + issue: issue.issue, + details: issue.details, + count: issue.count, + ...(issue.first_occurrence + ? { first_occurrence: dateFormatter.convert(issue.first_occurrence) } + : {}), + }; + }), + } + : {}), + }; + } + return { /** * Returns report about not started transforms @@ -119,18 +152,11 @@ export function transformHealthServiceProvider( */ async getTransformsStateReport( transformIds: string[] - ): Promise<[NotStartedTransformResponse[], NotStartedTransformResponse[]]> { + ): Promise<[TransformStateReportResponse[], TransformStateReportResponse[]]> { const transformsStats = await getTransformStats(transformIds); return partition( - transformsStats.map((t) => ({ - transform_id: t.id, - description: transformsDict.get(t.id)?.description, - transform_state: t.state, - node_name: t.node?.name, - health_status: t.health.status, - issues: t.health.issues, - })), + transformsStats.map(baseTransformAlertResponseFormatter), (t) => t.transform_state !== TRANSFORM_STATE.STARTED && t.transform_state !== TRANSFORM_STATE.INDEXING @@ -216,21 +242,12 @@ export function transformHealthServiceProvider( */ async getUnhealthyTransformsReport( transformIds: string[] - ): Promise { + ): Promise { const transformsStats = await getTransformStats(transformIds); return transformsStats .filter((t) => t.health.status !== 'green') - .map((t) => { - return { - transform_id: t.id, - transform_state: t.state, - node_name: t.node?.name, - description: transformsDict.get(t.id)?.description, - health_status: t.health.status, - issues: t.health.issues, - }; - }); + .map(baseTransformAlertResponseFormatter); }, /** * Returns results of the transform health checks diff --git a/x-pack/plugins/transform/server/plugin.ts b/x-pack/plugins/transform/server/plugin.ts index 3eab84ca0b5fc..fdcc4d606a25e 100644 --- a/x-pack/plugins/transform/server/plugin.ts +++ b/x-pack/plugins/transform/server/plugin.ts @@ -31,6 +31,8 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { private readonly license: License; private readonly logger: Logger; + private fieldFormatsStart: PluginStartDependencies['fieldFormats'] | null = null; + constructor(initContext: PluginInitializerContext) { this.logger = initContext.logger.get(); this.apiRoutes = new ApiRoutes(); @@ -78,13 +80,19 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> { }); if (alerting) { - registerTransformHealthRuleType({ alerting, logger: this.logger }); + registerTransformHealthRuleType({ + alerting, + logger: this.logger, + getFieldFormatsStart: () => this.fieldFormatsStart!, + }); } return {}; } - start(core: CoreStart, plugins: PluginStartDependencies) {} + start(core: CoreStart, plugins: PluginStartDependencies) { + this.fieldFormatsStart = plugins.fieldFormats; + } stop() {} } diff --git a/x-pack/plugins/transform/server/routes/api/transforms.ts b/x-pack/plugins/transform/server/routes/api/transforms.ts index 580f0f54aabf7..36db7b9a03e3a 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms.ts @@ -97,10 +97,10 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) { const alerting = await ctx.alerting; if (alerting) { - const transformHealthService = transformHealthServiceProvider( - esClient.asCurrentUser, - alerting.getRulesClient() - ); + const transformHealthService = transformHealthServiceProvider({ + esClient: esClient.asCurrentUser, + rulesClient: alerting.getRulesClient(), + }); // @ts-ignore await transformHealthService.populateTransformsWithAssignedRules(body.transforms); diff --git a/x-pack/plugins/transform/server/types.ts b/x-pack/plugins/transform/server/types.ts index 26bdf02acb5c0..3a748314521a7 100644 --- a/x-pack/plugins/transform/server/types.ts +++ b/x-pack/plugins/transform/server/types.ts @@ -10,16 +10,19 @@ import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugi import { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { AlertingPlugin } from '@kbn/alerting-plugin/server'; +import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import { License } from './services'; export interface PluginSetupDependencies { licensing: LicensingPluginSetup; features: FeaturesPluginSetup; alerting?: AlertingPlugin['setup']; + fieldFormats: FieldFormatsSetup; } export interface PluginStartDependencies { dataViews: DataViewsServerPluginStart; + fieldFormats: FieldFormatsStart; } export interface RouteDependencies { From e5afe623dad12c254ad3e85e1dba6dcd2febb737 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Mon, 6 Mar 2023 16:55:29 +0100 Subject: [PATCH 5/7] fix message --- x-pack/plugins/transform/common/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 0e8eb21c063bf..7c1077126c6ef 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -192,7 +192,7 @@ export const TRANSFORM_HEALTH_CHECK_NAMES: Record< }, healthCheck: { name: i18n.translate('xpack.transform.alertTypes.transformHealth.healthCheckName', { - defaultMessage: 'Unhealthy transforms', + defaultMessage: 'Unhealthy transform', }), description: i18n.translate( 'xpack.transform.alertTypes.transformHealth.healthCheckDescription', From d1b6e8be1f37ba4c271c0a49c904ba7b2c143223 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 7 Mar 2023 11:46:05 +0100 Subject: [PATCH 6/7] refactor types --- .../register_transform_health_rule_type.ts | 9 ++---- .../transform_health_service.ts | 28 ++++++------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts index db4e03363efbd..9128c91c1f965 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts @@ -16,19 +16,14 @@ import type { import { RuleType } from '@kbn/alerting-plugin/server'; import type { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; -import { PLUGIN, TRANSFORM_RULE_TYPE } from '../../../../common/constants'; +import { PLUGIN, type TransformHealth, TRANSFORM_RULE_TYPE } from '../../../../common/constants'; import { transformHealthRuleParams, TransformHealthRuleParams } from './schema'; import { transformHealthServiceProvider } from './transform_health_service'; -export interface TransformHealth { - status: 'green' | 'unknown' | 'yellow' | 'red'; - issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: number }>; -} - export interface BaseTransformAlertResponse { transform_id: string; description?: string; - health_status: TransformHealth['status']; + health_status: TransformHealth; issues?: Array<{ issue: string; details?: string; count: number; first_occurrence?: string }>; } diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts index 72eb8981aadd6..5c218a40abb45 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/transform_health_service.ts @@ -10,8 +10,8 @@ import { i18n } from '@kbn/i18n'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { keyBy, memoize, partition } from 'lodash'; import type { RulesClient } from '@kbn/alerting-plugin/server'; -import { type TransformGetTransformStatsTransformStats } from '@elastic/elasticsearch/lib/api/types'; import { FIELD_FORMAT_IDS, FieldFormatsRegistry } from '@kbn/field-formats-plugin/common'; +import { TransformStats } from '../../../../common/types/transform_stats'; import { TransformHealthRuleParams } from './schema'; import { ALL_TRANSFORMS_SELECTION, @@ -23,7 +23,6 @@ import { getResultTestConfig } from '../../../../common/utils/alerts'; import type { ErrorMessagesTransformResponse, TransformStateReportResponse, - TransformHealth, TransformHealthAlertContext, } from './register_transform_health_rule_type'; import type { TransformHealthAlertRule } from '../../../../common/types/alerting'; @@ -44,13 +43,6 @@ type Transform = estypes.TransformGetTransformTransformSummary & { type TransformWithAlertingRules = Transform & { alerting_rules: TransformHealthAlertRule[] }; -/** - * TODO update types in the es client - */ -type TransformGetTransformStats = TransformGetTransformStatsTransformStats & { - health: TransformHealth; -}; - export function transformHealthServiceProvider({ esClient, rulesClient, @@ -105,18 +97,16 @@ export function transformHealthServiceProvider({ return resultTransformIds; }; - const getTransformStats = memoize( - async (transformIds: string[]): Promise => { - return ( - await esClient.transform.getTransformStats({ - transform_id: transformIds.join(','), - }) - ).transforms as TransformGetTransformStats[]; - } - ); + const getTransformStats = memoize(async (transformIds: string[]): Promise => { + return ( + await esClient.transform.getTransformStats({ + transform_id: transformIds.join(','), + }) + ).transforms as TransformStats[]; + }); function baseTransformAlertResponseFormatter( - transformStats: TransformGetTransformStats + transformStats: TransformStats ): TransformStateReportResponse { const dateFormatter = fieldFormatsRegistry!.deserialize({ id: FIELD_FORMAT_IDS.DATE }); From 798f2367373bf8f36a2c8399735279a1564bc939 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Tue, 7 Mar 2023 14:27:53 +0100 Subject: [PATCH 7/7] sets healthCheck based on the errorMessages --- .../transform/common/utils/alerts.test.ts | 108 ++++++++++++++++++ .../plugins/transform/common/utils/alerts.ts | 12 +- 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/transform/common/utils/alerts.test.ts diff --git a/x-pack/plugins/transform/common/utils/alerts.test.ts b/x-pack/plugins/transform/common/utils/alerts.test.ts new file mode 100644 index 0000000000000..ae4cc5815f38c --- /dev/null +++ b/x-pack/plugins/transform/common/utils/alerts.test.ts @@ -0,0 +1,108 @@ +/* + * 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 { getResultTestConfig } from './alerts'; + +describe('getResultTestConfig', () => { + test('provides default config for new rule', () => { + expect(getResultTestConfig(undefined)).toEqual({ + healthCheck: { + enabled: true, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: false, + }, + }); + }); + + test('provides config for rule created with default settings', () => { + expect(getResultTestConfig(null)).toEqual({ + healthCheck: { + enabled: true, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: false, + }, + }); + }); + + test('completes already defined config', () => { + expect( + getResultTestConfig({ + healthCheck: null, + notStarted: null, + errorMessages: { + enabled: false, + }, + }) + ).toEqual({ + healthCheck: { + enabled: false, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: false, + }, + }); + }); + + test('sets healthCheck based on the errorMessages', () => { + expect( + getResultTestConfig({ + healthCheck: null, + notStarted: null, + errorMessages: { + enabled: true, + }, + }) + ).toEqual({ + healthCheck: { + enabled: false, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: true, + }, + }); + }); + + test('preserves complete config', () => { + expect( + getResultTestConfig({ + healthCheck: { + enabled: false, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: true, + }, + }) + ).toEqual({ + healthCheck: { + enabled: false, + }, + notStarted: { + enabled: true, + }, + errorMessages: { + enabled: true, + }, + }); + }); +}); diff --git a/x-pack/plugins/transform/common/utils/alerts.ts b/x-pack/plugins/transform/common/utils/alerts.ts index 1a4947db6ae2e..c02626f0d3f46 100644 --- a/x-pack/plugins/transform/common/utils/alerts.ts +++ b/x-pack/plugins/transform/common/utils/alerts.ts @@ -8,6 +8,16 @@ import type { TransformHealthRuleTestsConfig } from '../types/alerting'; export function getResultTestConfig(config: TransformHealthRuleTestsConfig) { + let healthCheckEnabled = true; + + if (typeof config?.healthCheck?.enabled === 'boolean') { + healthCheckEnabled = config?.healthCheck?.enabled; + } else if (typeof config?.errorMessages?.enabled === 'boolean') { + // if errorMessages test has been explicitly enabled / disabled, + // also disabled the healthCheck test + healthCheckEnabled = false; + } + return { notStarted: { enabled: config?.notStarted?.enabled ?? true, @@ -16,7 +26,7 @@ export function getResultTestConfig(config: TransformHealthRuleTestsConfig) { enabled: config?.errorMessages?.enabled ?? false, }, healthCheck: { - enabled: config?.healthCheck?.enabled ?? true, + enabled: healthCheckEnabled, }, }; }