From 305a821fed368a8a164484ad37e89aea31ac7e18 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 5 May 2020 15:53:12 -0700 Subject: [PATCH] Revert "[7.x] [Metrics UI] Add inventory metric threshold alerts (#64292) (#65287)" This reverts commit d6b19b70474c66019adfd0a0b32d108bcc4e69c1. --- .../formatters/snapshot_metric_formats.ts | 73 --- .../plugins/infra/common/formatters/types.ts | 11 - .../aws_ec2/toolbar_items.tsx | 32 +- .../aws_rds/toolbar_items.tsx | 30 +- .../inventory_models/aws_s3/toolbar_items.tsx | 22 +- .../aws_sqs/toolbar_items.tsx | 21 +- .../container/toolbar_items.tsx | 23 +- .../inventory_models/host/toolbar_items.tsx | 27 +- .../inventory_models/pod/toolbar_items.tsx | 9 +- .../components/alert_dropdown.tsx | 2 +- .../components/expression.tsx | 37 +- .../alerting/inventory/alert_dropdown.tsx | 62 --- .../alerting/inventory/alert_flyout.tsx | 52 -- .../alerting/inventory/expression.tsx | 498 ------------------ .../components/alerting/inventory/metric.tsx | 150 ------ .../metric_inventory_threshold_alert_type.ts | 34 -- .../alerting/inventory/node_type.tsx | 115 ---- .../alerting/inventory/validation.tsx | 80 --- .../log_text_stream/column_headers.tsx | 2 +- .../logging/log_text_stream/log_date_row.tsx | 2 +- .../containers/source/use_source_via_http.ts | 17 +- x-pack/plugins/infra/public/index.ts | 2 +- x-pack/plugins/infra/public/lib/lib.ts | 6 + .../infra/public/pages/metrics/index.tsx | 7 +- .../components/waffle/node_context_menu.tsx | 315 +++++------ .../lib/create_inventory_metric_formatter.ts | 2 +- .../components/gauges_section_vis.tsx | 2 +- .../metric_detail/components/helpers.ts | 2 +- .../helpers/create_formatter_for_metric.ts | 2 +- .../metrics_explorer/components/kuery_bar.tsx | 5 - x-pack/plugins/infra/public/plugin.ts | 2 - .../utils}/formatters/bytes.test.ts | 4 +- .../utils}/formatters/bytes.ts | 3 +- .../utils}/formatters/datetime.ts | 0 .../utils}/formatters/high_precision.ts | 0 .../utils}/formatters/index.ts | 4 +- .../utils}/formatters/number.ts | 0 .../utils}/formatters/percent.ts | 0 .../infra/server/graphql/sources/resolvers.ts | 10 +- .../metrics/kibana_metrics_adapter.ts | 10 +- .../inventory_metric_threshold_executor.ts | 214 -------- ...r_inventory_metric_threshold_alert_type.ts | 92 ---- .../inventory_metric_threshold/types.ts | 35 -- .../metric_threshold_executor.test.ts | 192 +++---- .../metric_threshold_executor.ts | 63 ++- .../register_metric_threshold_alert_type.ts | 39 +- .../lib/alerting/register_alert_types.ts | 5 +- .../infra/server/lib/compose/kibana.ts | 2 +- .../create_timerange_with_interval.ts | 21 +- .../infra/server/lib/snapshot/snapshot.ts | 52 +- .../infra/server/lib/sources/sources.ts | 33 +- x-pack/plugins/infra/server/plugin.ts | 2 +- .../routes/log_sources/configuration.ts | 4 +- .../lib/get_dataset_for_field.ts | 13 +- .../lib/populate_series_with_tsvb_data.ts | 16 +- .../infra/server/routes/snapshot/index.ts | 9 +- .../server/utils/calculate_metric_interval.ts | 14 +- .../apis/infra/metrics_alerting.ts | 11 +- 58 files changed, 497 insertions(+), 1995 deletions(-) delete mode 100644 x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts delete mode 100644 x-pack/plugins/infra/common/formatters/types.ts delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx delete mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx rename x-pack/plugins/infra/{common => public/utils}/formatters/bytes.test.ts (93%) rename x-pack/plugins/infra/{common => public/utils}/formatters/bytes.ts (96%) rename x-pack/plugins/infra/{common => public/utils}/formatters/datetime.ts (100%) rename x-pack/plugins/infra/{common => public/utils}/formatters/high_precision.ts (100%) rename x-pack/plugins/infra/{common => public/utils}/formatters/index.ts (90%) rename x-pack/plugins/infra/{common => public/utils}/formatters/number.ts (100%) rename x-pack/plugins/infra/{common => public/utils}/formatters/percent.ts (100%) delete mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts delete mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts diff --git a/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts b/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts deleted file mode 100644 index 8b4ae27cb30614..00000000000000 --- a/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts +++ /dev/null @@ -1,73 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -enum InfraFormatterType { - number = 'number', - abbreviatedNumber = 'abbreviatedNumber', - bytes = 'bytes', - bits = 'bits', - percent = 'percent', -} - -interface MetricFormatter { - formatter: InfraFormatterType; - template: string; - bounds?: { min: number; max: number }; -} - -interface MetricFormatters { - [key: string]: MetricFormatter; -} - -export const METRIC_FORMATTERS: MetricFormatters = { - ['count']: { formatter: InfraFormatterType.number, template: '{{value}}' }, - ['cpu']: { - formatter: InfraFormatterType.percent, - template: '{{value}}', - }, - ['memory']: { - formatter: InfraFormatterType.percent, - template: '{{value}}', - }, - ['rx']: { formatter: InfraFormatterType.bits, template: '{{value}}/s' }, - ['tx']: { formatter: InfraFormatterType.bits, template: '{{value}}/s' }, - ['logRate']: { - formatter: InfraFormatterType.abbreviatedNumber, - template: '{{value}}/s', - }, - ['diskIOReadBytes']: { - formatter: InfraFormatterType.bytes, - template: '{{value}}/s', - }, - ['diskIOWriteBytes']: { - formatter: InfraFormatterType.bytes, - template: '{{value}}/s', - }, - ['s3BucketSize']: { - formatter: InfraFormatterType.bytes, - template: '{{value}}', - }, - ['s3TotalRequests']: { - formatter: InfraFormatterType.abbreviatedNumber, - template: '{{value}}', - }, - ['s3NumberOfObjects']: { - formatter: InfraFormatterType.abbreviatedNumber, - template: '{{value}}', - }, - ['s3UploadBytes']: { - formatter: InfraFormatterType.bytes, - template: '{{value}}', - }, - ['s3DownloadBytes']: { - formatter: InfraFormatterType.bytes, - template: '{{value}}', - }, - ['sqsOldestMessage']: { - formatter: InfraFormatterType.number, - template: '{{value}} seconds', - }, -}; diff --git a/x-pack/plugins/infra/common/formatters/types.ts b/x-pack/plugins/infra/common/formatters/types.ts deleted file mode 100644 index c438ec2d4205d1..00000000000000 --- a/x-pack/plugins/infra/common/formatters/types.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export enum InfraWaffleMapDataFormat { - bytesDecimal = 'bytesDecimal', - bitsDecimal = 'bitsDecimal', - abbreviatedNumber = 'abbreviatedNumber', -} diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx index 764db2164b7118..b2da7dec3f2e08 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx @@ -11,29 +11,27 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const ec2MetricTypes: SnapshotMetricType[] = [ - 'cpu', - 'rx', - 'tx', - 'diskIOReadBytes', - 'diskIOWriteBytes', -]; - -export const ec2groupByFields = [ - 'cloud.availability_zone', - 'cloud.machine.type', - 'aws.ec2.instance.image.id', - 'aws.ec2.instance.state.name', -]; - export const AwsEC2ToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = [ + 'cpu', + 'rx', + 'tx', + 'diskIOReadBytes', + 'diskIOWriteBytes', + ]; + const groupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'aws.ec2.instance.image.id', + 'aws.ec2.instance.state.name', + ]; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx index 3eebdee22b2c30..2a8394b9dd3a41 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx @@ -11,28 +11,26 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const rdsMetricTypes: SnapshotMetricType[] = [ - 'cpu', - 'rdsConnections', - 'rdsQueriesExecuted', - 'rdsActiveTransactions', - 'rdsLatency', -]; - -export const rdsGroupByFields = [ - 'cloud.availability_zone', - 'aws.rds.db_instance.class', - 'aws.rds.db_instance.status', -]; - export const AwsRDSToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = [ + 'cpu', + 'rdsConnections', + 'rdsQueriesExecuted', + 'rdsActiveTransactions', + 'rdsLatency', + ]; + const groupByFields = [ + 'cloud.availability_zone', + 'aws.rds.db_instance.class', + 'aws.rds.db_instance.status', + ]; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx index ede618b1bf19d0..324bdd05860290 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx @@ -11,24 +11,22 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const s3MetricTypes: SnapshotMetricType[] = [ - 's3BucketSize', - 's3NumberOfObjects', - 's3TotalRequests', - 's3DownloadBytes', - 's3UploadBytes', -]; - -export const s3GroupByFields = ['cloud.region']; - export const AwsS3ToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = [ + 's3BucketSize', + 's3NumberOfObjects', + 's3TotalRequests', + 's3DownloadBytes', + 's3UploadBytes', + ]; + const groupByFields = ['cloud.region']; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx index e77f3af5781970..3229c07034772c 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx @@ -11,23 +11,22 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const sqsMetricTypes: SnapshotMetricType[] = [ - 'sqsMessagesVisible', - 'sqsMessagesDelayed', - 'sqsMessagesSent', - 'sqsMessagesEmpty', - 'sqsOldestMessage', -]; -export const sqsGroupByFields = ['cloud.region']; - export const AwsSQSToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = [ + 'sqsMessagesVisible', + 'sqsMessagesDelayed', + 'sqsMessagesSent', + 'sqsMessagesEmpty', + 'sqsOldestMessage', + ]; + const groupByFields = ['cloud.region']; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx index f193adbf6aadc4..f6c707726d9ca1 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx @@ -10,22 +10,21 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const containerMetricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; -export const containerGroupByFields = [ - 'host.name', - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', -]; - export const ContainerToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; + const groupByFields = [ + 'host.name', + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', + ]; return ( ); }; diff --git a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx index 8ed684b3885de2..136264c0e26f4d 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx @@ -10,27 +10,20 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const hostMetricTypes: SnapshotMetricType[] = [ - 'cpu', - 'memory', - 'load', - 'rx', - 'tx', - 'logRate', -]; -export const hostGroupByFields = [ - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', -]; export const HostToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'load', 'rx', 'tx', 'logRate']; + const groupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', + ]; return ( ); }; diff --git a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx index 54a32e3e0180a1..c1cd375ff47bf9 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx @@ -10,15 +10,14 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; -export const podMetricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; -export const podGroupByFields = ['kubernetes.namespace', 'kubernetes.node.name', 'service.type']; - export const PodToolbarItems = (props: ToolbarProps) => { + const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; + const groupByFields = ['kubernetes.namespace', 'kubernetes.node.name', 'service.type']; return ( ); }; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx index 8bcf0e9ed5be5d..bb664f40676625 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { AlertFlyout } from './alert_flyout'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -export const MetricsAlertDropdown = () => { +export const AlertDropdown = () => { const [popoverOpen, setPopoverOpen] = useState(false); const [flyoutVisible, setFlyoutVisible] = useState(false); const kibana = useKibana(); diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index 5e14babddcb07a..352ac1927479ea 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -34,8 +34,6 @@ import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; import { MetricsExplorerGroupBy } from '../../../pages/metrics/metrics_explorer/components/group_by'; import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; -import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; - import { ExpressionRow } from './expression_row'; import { AlertContextMeta, TimeUnit, MetricExpression } from '../types'; import { ExpressionChart } from './expression_chart'; @@ -47,7 +45,6 @@ interface Props { groupBy?: string; filterQuery?: string; sourceId?: string; - filterQueryText?: string; alertOnNoData?: boolean; }; alertsContext: AlertsContextValue; @@ -114,15 +111,11 @@ export const Expressions: React.FC = props => { [setAlertParams, alertParams.criteria] ); - const onFilterChange = useCallback( + const onFilterQuerySubmit = useCallback( (filter: any) => { - setAlertParams('filterQueryText', filter); - setAlertParams( - 'filterQuery', - convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' - ); + setAlertParams('filterQuery', filter); }, - [setAlertParams, derivedIndexPattern] + [setAlertParams] ); const onGroupByChange = useCallback( @@ -187,19 +180,10 @@ export const Expressions: React.FC = props => { if (md.currentOptions) { if (md.currentOptions.filterQuery) { - setAlertParams('filterQueryText', md.currentOptions.filterQuery); - setAlertParams( - 'filterQuery', - convertKueryToElasticSearchQuery(md.currentOptions.filterQuery, derivedIndexPattern) || - '' - ); + setAlertParams('filterQuery', md.currentOptions.filterQuery); } else if (md.currentOptions.groupBy && md.series) { const filter = `${md.currentOptions.groupBy}: "${md.series.id}"`; - setAlertParams('filterQueryText', filter); - setAlertParams( - 'filterQuery', - convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' - ); + setAlertParams('filterQuery', filter); } setAlertParams('groupBy', md.currentOptions.groupBy); @@ -216,8 +200,8 @@ export const Expressions: React.FC = props => { }, [alertsContext.metadata, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps const handleFieldSearchChange = useCallback( - (e: ChangeEvent) => onFilterChange(e.target.value), - [onFilterChange] + (e: ChangeEvent) => onFilterQuerySubmit(e.target.value), + [onFilterQuerySubmit] ); return ( @@ -320,14 +304,13 @@ export const Expressions: React.FC = props => { {(alertsContext.metadata && ( )) || ( )} diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx deleted file mode 100644 index d2904206875c79..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx +++ /dev/null @@ -1,62 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useState, useCallback, useMemo } from 'react'; -import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { AlertFlyout } from './alert_flyout'; -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; - -export const InventoryAlertDropdown = () => { - const [popoverOpen, setPopoverOpen] = useState(false); - const [flyoutVisible, setFlyoutVisible] = useState(false); - const kibana = useKibana(); - - const closePopover = useCallback(() => { - setPopoverOpen(false); - }, [setPopoverOpen]); - - const openPopover = useCallback(() => { - setPopoverOpen(true); - }, [setPopoverOpen]); - - const menuItems = useMemo(() => { - return [ - setFlyoutVisible(true)}> - - , - - - , - ]; - }, [kibana.services]); - - return ( - <> - - - - } - isOpen={popoverOpen} - closePopover={closePopover} - > - - - - - ); -}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx deleted file mode 100644 index 83298afd4fc5a5..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx +++ /dev/null @@ -1,52 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useContext } from 'react'; -import { AlertsContextProvider, AlertAdd } from '../../../../../triggers_actions_ui/public'; -import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; -import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; -import { InfraWaffleMapOptions } from '../../../lib/lib'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; - -interface Props { - visible?: boolean; - options?: Partial; - nodeType?: InventoryItemType; - filter?: string; - setVisible: React.Dispatch>; -} - -export const AlertFlyout = (props: Props) => { - const { triggersActionsUI } = useContext(TriggerActionsContext); - const { services } = useKibana(); - - return ( - <> - {triggersActionsUI && ( - - - - )} - - ); -}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx deleted file mode 100644 index 15cad770836bda..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx +++ /dev/null @@ -1,498 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useCallback, useMemo, useEffect, useState, ChangeEvent } from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiButtonIcon, - EuiSpacer, - EuiText, - EuiFormRow, - EuiButtonEmpty, - EuiFieldSearch, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; -import { - Comparator, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../server/lib/alerting/metric_threshold/types'; -import { euiStyled } from '../../../../../observability/public'; -import { - ThresholdExpression, - ForLastExpression, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../triggers_actions_ui/public/common'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; -import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; -import { toMetricOpt } from '../../../pages/metrics/inventory_view/components/toolbars/toolbar_wrapper'; -import { sqsMetricTypes } from '../../../../common/inventory_models/aws_sqs/toolbar_items'; -import { ec2MetricTypes } from '../../../../common/inventory_models/aws_ec2/toolbar_items'; -import { s3MetricTypes } from '../../../../common/inventory_models/aws_s3/toolbar_items'; -import { rdsMetricTypes } from '../../../../common/inventory_models/aws_rds/toolbar_items'; -import { hostMetricTypes } from '../../../../common/inventory_models/host/toolbar_items'; -import { containerMetricTypes } from '../../../../common/inventory_models/container/toolbar_items'; -import { podMetricTypes } from '../../../../common/inventory_models/pod/toolbar_items'; -import { findInventoryModel } from '../../../../common/inventory_models'; -import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { InventoryMetricConditions } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; -import { MetricExpression } from './metric'; -import { NodeTypeExpression } from './node_type'; -import { InfraWaffleMapOptions } from '../../../lib/lib'; -import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; - -interface AlertContextMeta { - options?: Partial; - nodeType?: InventoryItemType; - filter?: string; -} - -interface Props { - errors: IErrorObject[]; - alertParams: { - criteria: InventoryMetricConditions[]; - nodeType: InventoryItemType; - groupBy?: string; - filterQuery?: string; - filterQueryText?: string; - sourceId?: string; - }; - alertsContext: AlertsContextValue; - setAlertParams(key: string, value: any): void; - setAlertProperty(key: string, value: any): void; -} - -type TimeUnit = 's' | 'm' | 'h' | 'd'; - -const defaultExpression = { - metric: 'cpu' as SnapshotMetricType, - comparator: Comparator.GT, - threshold: [], - timeSize: 1, - timeUnit: 'm', -} as InventoryMetricConditions; - -export const Expressions: React.FC = props => { - const { setAlertParams, alertParams, errors, alertsContext } = props; - const { source, createDerivedIndexPattern } = useSourceViaHttp({ - sourceId: 'default', - type: 'metrics', - fetch: alertsContext.http.fetch, - toastWarning: alertsContext.toastNotifications.addWarning, - }); - const [timeSize, setTimeSize] = useState(1); - const [timeUnit, setTimeUnit] = useState('m'); - - const derivedIndexPattern = useMemo(() => createDerivedIndexPattern('metrics'), [ - createDerivedIndexPattern, - ]); - - const updateParams = useCallback( - (id, e: InventoryMetricConditions) => { - const exp = alertParams.criteria ? alertParams.criteria.slice() : []; - exp[id] = { ...exp[id], ...e }; - setAlertParams('criteria', exp); - }, - [setAlertParams, alertParams.criteria] - ); - - const addExpression = useCallback(() => { - const exp = alertParams.criteria.slice(); - exp.push(defaultExpression); - setAlertParams('criteria', exp); - }, [setAlertParams, alertParams.criteria]); - - const removeExpression = useCallback( - (id: number) => { - const exp = alertParams.criteria.slice(); - if (exp.length > 1) { - exp.splice(id, 1); - setAlertParams('criteria', exp); - } - }, - [setAlertParams, alertParams.criteria] - ); - - const onFilterChange = useCallback( - (filter: any) => { - setAlertParams('filterQueryText', filter || ''); - setAlertParams( - 'filterQuery', - convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' - ); - }, - [derivedIndexPattern, setAlertParams] - ); - - const emptyError = useMemo(() => { - return { - aggField: [], - timeSizeUnit: [], - timeWindowSize: [], - }; - }, []); - - const updateTimeSize = useCallback( - (ts: number | undefined) => { - const criteria = alertParams.criteria.map(c => ({ - ...c, - timeSize: ts, - })); - setTimeSize(ts || undefined); - setAlertParams('criteria', criteria); - }, - [alertParams.criteria, setAlertParams] - ); - - const updateTimeUnit = useCallback( - (tu: string) => { - const criteria = alertParams.criteria.map(c => ({ - ...c, - timeUnit: tu, - })); - setTimeUnit(tu as TimeUnit); - setAlertParams('criteria', criteria); - }, - [alertParams.criteria, setAlertParams] - ); - - const updateNodeType = useCallback( - (nt: any) => { - setAlertParams('nodeType', nt); - }, - [setAlertParams] - ); - - const handleFieldSearchChange = useCallback( - (e: ChangeEvent) => onFilterChange(e.target.value), - [onFilterChange] - ); - - useEffect(() => { - const md = alertsContext.metadata; - if (!alertParams.nodeType) { - if (md && md.nodeType) { - setAlertParams('nodeType', md.nodeType); - } else { - setAlertParams('nodeType', 'host'); - } - } - - if (!alertParams.criteria) { - if (md && md.options) { - setAlertParams('criteria', [ - { - ...defaultExpression, - metric: md.options.metric!.type, - } as InventoryMetricConditions, - ]); - } else { - setAlertParams('criteria', [defaultExpression]); - } - } - - if (!alertParams.filterQuery) { - if (md && md.filter) { - setAlertParams('filterQueryText', md.filter); - setAlertParams( - 'filterQuery', - convertKueryToElasticSearchQuery(md.filter, derivedIndexPattern) || '' - ); - } - } - - if (!alertParams.sourceId) { - setAlertParams('sourceId', source?.id); - } - }, [alertsContext.metadata, derivedIndexPattern, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps - - return ( - <> - - -

- -

-
- - - - - {alertParams.criteria && - alertParams.criteria.map((e, idx) => { - return ( - 1} - remove={removeExpression} - addExpression={addExpression} - key={idx} // idx's don't usually make good key's but here the index has semantic meaning - expressionId={idx} - setAlertParams={updateParams} - errors={errors[idx] || emptyError} - expression={e || {}} - /> - ); - })} - - - -
- - - -
- - - - - {(alertsContext.metadata && ( - - )) || ( - - )} - - - - - ); -}; - -interface ExpressionRowProps { - nodeType: InventoryItemType; - expressionId: number; - expression: Omit & { - metric?: SnapshotMetricType; - }; - errors: IErrorObject; - canDelete: boolean; - addExpression(): void; - remove(id: number): void; - setAlertParams(id: number, params: Partial): void; -} - -const StyledExpressionRow = euiStyled(EuiFlexGroup)` - display: flex; - flex-wrap: wrap; - margin: 0 -4px; -`; - -const StyledExpression = euiStyled.div` - padding: 0 4px; -`; - -export const ExpressionRow: React.FC = props => { - const { setAlertParams, expression, errors, expressionId, remove, canDelete } = props; - const { metric, comparator = Comparator.GT, threshold = [] } = expression; - - const updateMetric = useCallback( - (m?: SnapshotMetricType) => { - setAlertParams(expressionId, { ...expression, metric: m }); - }, - [expressionId, expression, setAlertParams] - ); - - const updateComparator = useCallback( - (c?: string) => { - setAlertParams(expressionId, { ...expression, comparator: c as Comparator | undefined }); - }, - [expressionId, expression, setAlertParams] - ); - - const updateThreshold = useCallback( - t => { - if (t.join() !== expression.threshold.join()) { - setAlertParams(expressionId, { ...expression, threshold: t }); - } - }, - [expressionId, expression, setAlertParams] - ); - - const ofFields = useMemo(() => { - let myMetrics = hostMetricTypes; - - switch (props.nodeType) { - case 'awsEC2': - myMetrics = ec2MetricTypes; - break; - case 'awsRDS': - myMetrics = rdsMetricTypes; - break; - case 'awsS3': - myMetrics = s3MetricTypes; - break; - case 'awsSQS': - myMetrics = sqsMetricTypes; - break; - case 'host': - myMetrics = hostMetricTypes; - break; - case 'pod': - myMetrics = podMetricTypes; - break; - case 'container': - myMetrics = containerMetricTypes; - break; - } - return myMetrics.map(toMetricOpt); - }, [props.nodeType]); - - return ( - <> - - - - - v?.value === metric)?.text || '', - }} - metrics={ - ofFields.filter(m => m !== undefined && m.value !== undefined) as Array<{ - value: SnapshotMetricType; - text: string; - }> - } - onChange={updateMetric} - errors={errors} - /> - - - - - {metric && ( - -
-
{metricUnit[metric]?.label || ''}
-
-
- )} -
-
- {canDelete && ( - - remove(expressionId)} - /> - - )} -
- - - ); -}; - -const getDisplayNameForType = (type: InventoryItemType) => { - const inventoryModel = findInventoryModel(type); - return inventoryModel.displayName; -}; - -export const nodeTypes: { [key: string]: any } = { - host: { - text: getDisplayNameForType('host'), - value: 'host', - }, - pod: { - text: getDisplayNameForType('pod'), - value: 'pod', - }, - container: { - text: getDisplayNameForType('container'), - value: 'container', - }, - awsEC2: { - text: getDisplayNameForType('awsEC2'), - value: 'awsEC2', - }, - awsS3: { - text: getDisplayNameForType('awsS3'), - value: 'awsS3', - }, - awsRDS: { - text: getDisplayNameForType('awsRDS'), - value: 'awsRDS', - }, - awsSQS: { - text: getDisplayNameForType('awsSQS'), - value: 'awsSQS', - }, -}; - -const metricUnit: Record = { - count: { label: '' }, - cpu: { label: '%' }, - memory: { label: '%' }, - rx: { label: 'bits/s' }, - tx: { label: 'bits/s' }, - logRate: { label: '/s' }, - diskIOReadBytes: { label: 'bytes/s' }, - diskIOWriteBytes: { label: 'bytes/s' }, - s3BucketSize: { label: 'bytes' }, - s3TotalRequests: { label: '' }, - s3NumberOfObjects: { label: '' }, - s3UploadBytes: { label: 'bytes' }, - s3DownloadBytes: { label: 'bytes' }, - sqsOldestMessage: { label: 'seconds' }, -}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx deleted file mode 100644 index faafdf1b81eeda..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx +++ /dev/null @@ -1,150 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiExpression, - EuiPopover, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiComboBox, -} from '@elastic/eui'; -import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; -import { SnapshotMetricType } from '../../../../common/inventory_models/types'; - -interface Props { - metric?: { value: SnapshotMetricType; text: string }; - metrics: Array<{ value: string; text: string }>; - errors: IErrorObject; - onChange: (metric: SnapshotMetricType) => void; - popupPosition?: - | 'upCenter' - | 'upLeft' - | 'upRight' - | 'downCenter' - | 'downLeft' - | 'downRight' - | 'leftCenter' - | 'leftUp' - | 'leftDown' - | 'rightCenter' - | 'rightUp' - | 'rightDown'; -} - -export const MetricExpression = ({ metric, metrics, errors, onChange, popupPosition }: Props) => { - const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); - const firstFieldOption = { - text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.metric.selectFieldLabel', { - defaultMessage: 'Select a metric', - }), - value: '', - }; - - const availablefieldsOptions = metrics.map(m => { - return { label: m.text, value: m.value }; - }, []); - - return ( - { - setAggFieldPopoverOpen(true); - }} - color={metric ? 'secondary' : 'danger'} - /> - } - isOpen={aggFieldPopoverOpen} - closePopover={() => { - setAggFieldPopoverOpen(false); - }} - withTitle - anchorPosition={popupPosition ?? 'downRight'} - zIndex={8000} - > -
- setAggFieldPopoverOpen(false)}> - - - - - 0 && metric !== undefined} - error={errors.metric} - > - 0 && metric !== undefined} - placeholder={firstFieldOption.text} - options={availablefieldsOptions} - noSuggestions={!availablefieldsOptions.length} - selectedOptions={ - metric ? availablefieldsOptions.filter(a => a.value === metric.value) : [] - } - renderOption={(o: any) => o.label} - onChange={selectedOptions => { - if (selectedOptions.length > 0) { - onChange(selectedOptions[0].value as SnapshotMetricType); - setAggFieldPopoverOpen(false); - } - }} - /> - - - -
-
- ); -}; - -interface ClosablePopoverTitleProps { - children: JSX.Element; - onClose: () => void; -} - -export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { - return ( - - - {children} - - onClose()} - /> - - - - ); -}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts b/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts deleted file mode 100644 index b7abaf5b363737..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts +++ /dev/null @@ -1,34 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { i18n } from '@kbn/i18n'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AlertTypeModel } from '../../../../../triggers_actions_ui/public/types'; -import { Expressions } from './expression'; -import { validateMetricThreshold } from './validation'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; - -export function getInventoryMetricAlertType(): AlertTypeModel { - return { - id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - name: i18n.translate('xpack.infra.metrics.inventory.alertFlyout.alertName', { - defaultMessage: 'Inventory', - }), - iconClass: 'bell', - alertParamsExpression: Expressions, - validate: validateMetricThreshold, - defaultActionMessage: i18n.translate( - 'xpack.infra.metrics.alerting.inventory.threshold.defaultActionMessage', - { - defaultMessage: `\\{\\{alertName\\}\\} - \\{\\{context.group\\}\\} - -\\{\\{context.metricOf.condition0\\}\\} has crossed a threshold of \\{\\{context.thresholdOf.condition0\\}\\} -Current value is \\{\\{context.valueOf.condition0\\}\\} -`, - } - ), - }; -} diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx deleted file mode 100644 index 1623fc4e24dcb7..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx +++ /dev/null @@ -1,115 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; -import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; -import { InventoryItemType } from '../../../../common/inventory_models/types'; - -interface WhenExpressionProps { - value: InventoryItemType; - options: { [key: string]: { text: string; value: InventoryItemType } }; - onChange: (value: InventoryItemType) => void; - popupPosition?: - | 'upCenter' - | 'upLeft' - | 'upRight' - | 'downCenter' - | 'downLeft' - | 'downRight' - | 'leftCenter' - | 'leftUp' - | 'leftDown' - | 'rightCenter' - | 'rightUp' - | 'rightDown'; -} - -export const NodeTypeExpression = ({ - value, - options, - onChange, - popupPosition, -}: WhenExpressionProps) => { - const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); - - return ( - { - setAggTypePopoverOpen(true); - }} - /> - } - isOpen={aggTypePopoverOpen} - closePopover={() => { - setAggTypePopoverOpen(false); - }} - ownFocus - withTitle - anchorPosition={popupPosition ?? 'downLeft'} - > -
- setAggTypePopoverOpen(false)}> - - - { - onChange(e.target.value as InventoryItemType); - setAggTypePopoverOpen(false); - }} - options={Object.values(options).map(o => o)} - /> -
-
- ); -}; - -interface ClosablePopoverTitleProps { - children: JSX.Element; - onClose: () => void; -} - -export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { - return ( - - - {children} - - onClose()} - /> - - - - ); -}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx deleted file mode 100644 index 803893dd5a323f..00000000000000 --- a/x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx +++ /dev/null @@ -1,80 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetricExpressionParams } from '../../../../server/lib/alerting/metric_threshold/types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ValidationResult } from '../../../../../triggers_actions_ui/public/types'; - -export function validateMetricThreshold({ - criteria, -}: { - criteria: MetricExpressionParams[]; -}): ValidationResult { - const validationResult = { errors: {} }; - const errors: { - [id: string]: { - timeSizeUnit: string[]; - timeWindowSize: string[]; - threshold0: string[]; - threshold1: string[]; - metric: string[]; - }; - } = {}; - validationResult.errors = errors; - - if (!criteria || !criteria.length) { - return validationResult; - } - - criteria.forEach((c, idx) => { - // Create an id for each criteria, so we can map errors to specific criteria. - const id = idx.toString(); - - errors[id] = errors[id] || { - timeSizeUnit: [], - timeWindowSize: [], - threshold0: [], - threshold1: [], - metric: [], - }; - - if (!c.threshold || !c.threshold.length) { - errors[id].threshold0.push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { - defaultMessage: 'Threshold is required.', - }) - ); - } - - if (c.comparator === 'between' && (!c.threshold || c.threshold.length < 2)) { - errors[id].threshold1.push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { - defaultMessage: 'Threshold is required.', - }) - ); - } - - if (!c.timeSize) { - errors[id].timeWindowSize.push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.timeRequred', { - defaultMessage: 'Time size is Required.', - }) - ); - } - - if (!c.metric && c.aggType !== 'count') { - errors[id].metric.push( - i18n.translate('xpack.infra.metrics.alertFlyout.error.metricRequired', { - defaultMessage: 'Metric is required.', - }) - ); - } - }); - - return validationResult; -} diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx index c713839a1bba89..72d6aea5ecfc6a 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx @@ -22,7 +22,7 @@ import { } from './log_entry_column'; import { ASSUMED_SCROLLBAR_WIDTH } from './vertical_scroll_panel'; import { LogPositionState } from '../../../containers/logs/log_position'; -import { localizedDate } from '../../../../common/formatters/datetime'; +import { localizedDate } from '../../../utils/formatters/datetime'; export const LogColumnHeaders: React.FunctionComponent<{ columnConfigurations: LogColumnConfiguration[]; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx index 144caed744bab8..fbc450950b8283 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiTitle } from '@elastic/eui'; -import { localizedDate } from '../../../../common/formatters/datetime'; +import { localizedDate } from '../../../utils/formatters/datetime'; interface LogDateRowProps { timestamp: number; diff --git a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts index aad54bd2222b77..bc6374a6538e37 100644 --- a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts +++ b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { useEffect, useMemo, useCallback } from 'react'; +import { useEffect, useMemo } from 'react'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -69,15 +69,12 @@ export const useSourceViaHttp = ({ })(); }, [makeRequest]); - const createDerivedIndexPattern = useCallback( - (indexType: 'logs' | 'metrics' | 'both' = type) => { - return { - fields: response?.source ? response.status.indexFields : [], - title: pickIndexPattern(response?.source, indexType), - }; - }, - [response, type] - ); + const createDerivedIndexPattern = (indexType: 'logs' | 'metrics' | 'both' = type) => { + return { + fields: response?.source ? response.status.indexFields : [], + title: pickIndexPattern(response?.source, indexType), + }; + }; const source = useMemo(() => { return response ? { ...response.source, status: response.status } : null; diff --git a/x-pack/plugins/infra/public/index.ts b/x-pack/plugins/infra/public/index.ts index 1dfdf827f203b5..4465bde377c124 100644 --- a/x-pack/plugins/infra/public/index.ts +++ b/x-pack/plugins/infra/public/index.ts @@ -16,7 +16,7 @@ export const plugin: PluginInitializer< return new Plugin(context); }; -export { FORMATTERS } from '../common/formatters'; +export { FORMATTERS } from './utils/formatters'; export { InfraFormatterType } from './lib/lib'; export type InfraAppId = 'logs' | 'metrics'; diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts index 9043b4d9f69796..e4de0caf9bb8ba 100644 --- a/x-pack/plugins/infra/public/lib/lib.ts +++ b/x-pack/plugins/infra/public/lib/lib.ts @@ -186,6 +186,12 @@ export enum InfraFormatterType { percent = 'percent', } +export enum InfraWaffleMapDataFormat { + bytesDecimal = 'bytesDecimal', + bitsDecimal = 'bitsDecimal', + abbreviatedNumber = 'abbreviatedNumber', +} + export interface InfraGroupByOptions { text: string; field: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index dbf71665ea869a..5dc9802fefd254 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -28,9 +28,7 @@ import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { WaffleOptionsProvider } from './inventory_view/hooks/use_waffle_options'; import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time'; import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters'; - -import { InventoryAlertDropdown } from '../../components/alerting/inventory/alert_dropdown'; -import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; +import { AlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; export const InfrastructurePage = ({ match }: RouteComponentProps) => { const uiCapabilities = useKibana().services.application?.capabilities; @@ -98,8 +96,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { /> - - + diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx index d576f08108649f..c528aa885346e4 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo, useState } from 'react'; -import { AlertFlyout } from '../../../../../components/alerting/inventory/alert_flyout'; +import { AlertFlyout } from '../../../../../alerting/metric_threshold/components/alert_flyout'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; import { getNodeDetailUrl, getNodeLogsUrl } from '../../../../link_to'; import { createUptimeLink } from '../../lib/create_uptime_link'; @@ -24,8 +24,6 @@ import { SectionSubtitle, SectionLinks, SectionLink, - withTheme, - EuiTheme, } from '../../../../../../../observability/public'; import { useLinkProps } from '../../../../../hooks/use_link_props'; @@ -39,178 +37,157 @@ interface Props { popoverPosition: EuiPopoverProps['anchorPosition']; } -export const NodeContextMenu: React.FC = withTheme( - ({ - options, - currentTime, - children, - node, - isPopoverOpen, - closePopover, - nodeType, - popoverPosition, - theme, - }) => { - const [flyoutVisible, setFlyoutVisible] = useState(false); - const inventoryModel = findInventoryModel(nodeType); - const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; - const uiCapabilities = useKibana().services.application?.capabilities; - // Due to the changing nature of the fields between APM and this UI, - // We need to have some exceptions until 7.0 & ECS is finalized. Reference - // #26620 for the details for these fields. - // TODO: This is tech debt, remove it after 7.0 & ECS migration. - const apmField = nodeType === 'host' ? 'host.hostname' : inventoryModel.fields.id; +export const NodeContextMenu: React.FC = ({ + options, + currentTime, + children, + node, + isPopoverOpen, + closePopover, + nodeType, + popoverPosition, +}) => { + const [flyoutVisible, setFlyoutVisible] = useState(false); + const inventoryModel = findInventoryModel(nodeType); + const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; + const uiCapabilities = useKibana().services.application?.capabilities; + // Due to the changing nature of the fields between APM and this UI, + // We need to have some exceptions until 7.0 & ECS is finalized. Reference + // #26620 for the details for these fields. + // TODO: This is tech debt, remove it after 7.0 & ECS migration. + const apmField = nodeType === 'host' ? 'host.hostname' : inventoryModel.fields.id; - const showDetail = inventoryModel.crosslinkSupport.details; - const showLogsLink = - inventoryModel.crosslinkSupport.logs && node.id && uiCapabilities?.logs?.show; - const showAPMTraceLink = - inventoryModel.crosslinkSupport.apm && uiCapabilities?.apm && uiCapabilities?.apm.show; - const showUptimeLink = - inventoryModel.crosslinkSupport.uptime && - (['pod', 'container'].includes(nodeType) || node.ip); + const showDetail = inventoryModel.crosslinkSupport.details; + const showLogsLink = + inventoryModel.crosslinkSupport.logs && node.id && uiCapabilities?.logs?.show; + const showAPMTraceLink = + inventoryModel.crosslinkSupport.apm && uiCapabilities?.apm && uiCapabilities?.apm.show; + const showUptimeLink = + inventoryModel.crosslinkSupport.uptime && (['pod', 'container'].includes(nodeType) || node.ip); - const inventoryId = useMemo(() => { - if (nodeType === 'host') { - if (node.ip) { - return { label: host.ip, value: node.ip }; - } - } else { - if (options.fields) { - const { id } = findInventoryFields(nodeType, options.fields); - return { - label: {id}, - value: node.id, - }; - } + const inventoryId = useMemo(() => { + if (nodeType === 'host') { + if (node.ip) { + return { label: host.ip, value: node.ip }; } - return { label: '', value: '' }; - }, [nodeType, node.ip, node.id, options.fields]); - - const nodeLogsMenuItemLinkProps = useLinkProps({ - app: 'logs', - ...getNodeLogsUrl({ - nodeType, - nodeId: node.id, - time: currentTime, - }), - }); - const nodeDetailMenuItemLinkProps = useLinkProps({ - ...getNodeDetailUrl({ - nodeType, - nodeId: node.id, - from: nodeDetailFrom, - to: currentTime, - }), - }); - const apmTracesMenuItemLinkProps = useLinkProps({ - app: 'apm', - hash: 'traces', - search: { - kuery: `${apmField}:"${node.id}"`, - }, - }); - const uptimeMenuItemLinkProps = useLinkProps(createUptimeLink(options, nodeType, node)); + } else { + if (options.fields) { + const { id } = findInventoryFields(nodeType, options.fields); + return { + label: {id}, + value: node.id, + }; + } + } + return { label: '', value: '' }; + }, [nodeType, node.ip, node.id, options.fields]); - const nodeLogsMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewLogsName', { - defaultMessage: '{inventoryName} logs', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...nodeLogsMenuItemLinkProps, - 'data-test-subj': 'viewLogsContextMenuItem', - isDisabled: !showLogsLink, - }; + const nodeLogsMenuItemLinkProps = useLinkProps({ + app: 'logs', + ...getNodeLogsUrl({ + nodeType, + nodeId: node.id, + time: currentTime, + }), + }); + const nodeDetailMenuItemLinkProps = useLinkProps({ + ...getNodeDetailUrl({ + nodeType, + nodeId: node.id, + from: nodeDetailFrom, + to: currentTime, + }), + }); + const apmTracesMenuItemLinkProps = useLinkProps({ + app: 'apm', + hash: 'traces', + search: { + kuery: `${apmField}:"${node.id}"`, + }, + }); + const uptimeMenuItemLinkProps = useLinkProps(createUptimeLink(options, nodeType, node)); - const nodeDetailMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewMetricsName', { - defaultMessage: '{inventoryName} metrics', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...nodeDetailMenuItemLinkProps, - isDisabled: !showDetail, - }; + const nodeLogsMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewLogsName', { + defaultMessage: '{inventoryName} logs', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...nodeLogsMenuItemLinkProps, + 'data-test-subj': 'viewLogsContextMenuItem', + isDisabled: !showLogsLink, + }; - const apmTracesMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewAPMTraces', { - defaultMessage: '{inventoryName} APM traces', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...apmTracesMenuItemLinkProps, - 'data-test-subj': 'viewApmTracesContextMenuItem', - isDisabled: !showAPMTraceLink, - }; + const nodeDetailMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewMetricsName', { + defaultMessage: '{inventoryName} metrics', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...nodeDetailMenuItemLinkProps, + isDisabled: !showDetail, + }; - const uptimeMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewUptimeLink', { - defaultMessage: '{inventoryName} in Uptime', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...uptimeMenuItemLinkProps, - isDisabled: !showUptimeLink, - }; + const apmTracesMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewAPMTraces', { + defaultMessage: '{inventoryName} APM traces', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...apmTracesMenuItemLinkProps, + 'data-test-subj': 'viewApmTracesContextMenuItem', + isDisabled: !showAPMTraceLink, + }; - const createAlertMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.createAlertLink', { - defaultMessage: 'Create alert', - }), - style: { color: theme?.eui.euiLinkColor || '#006BB4', fontWeight: 500, padding: 0 }, - onClick: () => { - setFlyoutVisible(true); - }, - }; + const uptimeMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewUptimeLink', { + defaultMessage: '{inventoryName} in Uptime', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...uptimeMenuItemLinkProps, + isDisabled: !showUptimeLink, + }; - return ( - <> - -
-
- - - - {inventoryId.label && ( - -
- -
-
- )} - - - - - - - -
-
-
- - - ); - } -); + return ( + <> + +
+
+ + + + {inventoryId.label && ( + +
+ +
+
+ )} + + + + + + +
+
+
+ + + ); +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts index f8c7a10f12831d..acd71e51376948 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts @@ -5,13 +5,13 @@ */ import { get } from 'lodash'; +import { createFormatter } from '../../../../utils/formatters'; import { InfraFormatterType } from '../../../../lib/lib'; import { SnapshotMetricInput, SnapshotCustomMetricInputRT, } from '../../../../../common/http_api/snapshot_api'; import { createFormatterForMetric } from '../../metrics_explorer/components/helpers/create_formatter_for_metric'; -import { createFormatter } from '../../../../../common/formatters'; interface MetricFormatter { formatter: InfraFormatterType; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx index 0f53ced80888b5..0aab676b7d6c54 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx @@ -17,7 +17,7 @@ import { get, last, max } from 'lodash'; import React, { ReactText } from 'react'; import { euiStyled } from '../../../../../../observability/public'; -import { createFormatter } from '../../../../../common/formatters'; +import { createFormatter } from '../../../../utils/formatters'; import { InventoryFormatterType } from '../../../../../common/inventory_models/types'; import { SeriesOverrides, VisSectionProps } from '../types'; import { getChartName } from './helpers'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts index 0b8773db2dddf0..bb4ad326609520 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts @@ -7,7 +7,7 @@ import { ReactText } from 'react'; import Color from 'color'; import { get, first, last, min, max } from 'lodash'; -import { createFormatter } from '../../../../../common/formatters'; +import { createFormatter } from '../../../../utils/formatters'; import { InfraDataSeries } from '../../../../graphql/types'; import { InventoryVisTypeRT, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts index 46bd7b006446af..d07a6b45f02bef 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts @@ -5,7 +5,7 @@ */ import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; -import { createFormatter } from '../../../../../../common/formatters'; +import { createFormatter } from '../../../../../utils/formatters'; import { InfraFormatterType } from '../../../../../lib/lib'; import { metricToFormat } from './metric_to_format'; export const createFormatterForMetric = (metric?: MetricsExplorerMetric) => { diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index 04661bbc377025..e9826e1ff39552 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -14,7 +14,6 @@ import { esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data interface Props { derivedIndexPattern: IIndexPattern; onSubmit: (query: string) => void; - onChange?: (query: string) => void; value?: string | null; placeholder?: string; } @@ -31,7 +30,6 @@ function validateQuery(query: string) { export const MetricsExplorerKueryBar = ({ derivedIndexPattern, onSubmit, - onChange, value, placeholder, }: Props) => { @@ -48,9 +46,6 @@ export const MetricsExplorerKueryBar = ({ const handleChange = (query: string) => { setValidation(validateQuery(query)); setDraftQuery(query); - if (onChange) { - onChange(query); - } }; const filteredDerivedIndexPattern = { diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index d61ef7fc4a631c..8cdfc4f381f436 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -22,7 +22,6 @@ import { DataEnhancedSetup, DataEnhancedStart } from '../../data_enhanced/public import { TriggersAndActionsUIPublicPluginSetup } from '../../../plugins/triggers_actions_ui/public'; import { getAlertType as getLogsAlertType } from './components/alerting/logs/log_threshold_alert_type'; -import { getInventoryMetricAlertType } from './components/alerting/inventory/metric_inventory_threshold_alert_type'; import { createMetricThresholdAlertType } from './alerting/metric_threshold'; export type ClientSetup = void; @@ -54,7 +53,6 @@ export class Plugin setup(core: CoreSetup, pluginsSetup: ClientPluginsSetup) { registerFeatures(pluginsSetup.home); - pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getInventoryMetricAlertType()); pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getLogsAlertType()); pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(createMetricThresholdAlertType()); diff --git a/x-pack/plugins/infra/common/formatters/bytes.test.ts b/x-pack/plugins/infra/public/utils/formatters/bytes.test.ts similarity index 93% rename from x-pack/plugins/infra/common/formatters/bytes.test.ts rename to x-pack/plugins/infra/public/utils/formatters/bytes.test.ts index ccdeed120acca1..4c872bcee057d7 100644 --- a/x-pack/plugins/infra/common/formatters/bytes.test.ts +++ b/x-pack/plugins/infra/public/utils/formatters/bytes.test.ts @@ -3,9 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { InfraWaffleMapDataFormat } from './types'; -import { createBytesFormatter } from './bytes'; +import { InfraWaffleMapDataFormat } from '../../lib/lib'; +import { createBytesFormatter } from './bytes'; describe('createDataFormatter', () => { it('should format bytes as bytesDecimal', () => { const formatter = createBytesFormatter(InfraWaffleMapDataFormat.bytesDecimal); diff --git a/x-pack/plugins/infra/common/formatters/bytes.ts b/x-pack/plugins/infra/public/utils/formatters/bytes.ts similarity index 96% rename from x-pack/plugins/infra/common/formatters/bytes.ts rename to x-pack/plugins/infra/public/utils/formatters/bytes.ts index 3a45caa8b5e150..80a5603ed6994b 100644 --- a/x-pack/plugins/infra/common/formatters/bytes.ts +++ b/x-pack/plugins/infra/public/utils/formatters/bytes.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import { InfraWaffleMapDataFormat } from '../../lib/lib'; import { formatNumber } from './number'; -import { InfraWaffleMapDataFormat } from './types'; /** * The labels are derived from these two Wikipedia articles. diff --git a/x-pack/plugins/infra/common/formatters/datetime.ts b/x-pack/plugins/infra/public/utils/formatters/datetime.ts similarity index 100% rename from x-pack/plugins/infra/common/formatters/datetime.ts rename to x-pack/plugins/infra/public/utils/formatters/datetime.ts diff --git a/x-pack/plugins/infra/common/formatters/high_precision.ts b/x-pack/plugins/infra/public/utils/formatters/high_precision.ts similarity index 100% rename from x-pack/plugins/infra/common/formatters/high_precision.ts rename to x-pack/plugins/infra/public/utils/formatters/high_precision.ts diff --git a/x-pack/plugins/infra/common/formatters/index.ts b/x-pack/plugins/infra/public/utils/formatters/index.ts similarity index 90% rename from x-pack/plugins/infra/common/formatters/index.ts rename to x-pack/plugins/infra/public/utils/formatters/index.ts index 096085696bd6bf..3c60dba7478257 100644 --- a/x-pack/plugins/infra/common/formatters/index.ts +++ b/x-pack/plugins/infra/public/utils/formatters/index.ts @@ -5,12 +5,12 @@ */ import Mustache from 'mustache'; +import { InfraWaffleMapDataFormat } from '../../lib/lib'; import { createBytesFormatter } from './bytes'; import { formatNumber } from './number'; import { formatPercent } from './percent'; -import { InventoryFormatterType } from '../inventory_models/types'; +import { InventoryFormatterType } from '../../../common/inventory_models/types'; import { formatHighPercision } from './high_precision'; -import { InfraWaffleMapDataFormat } from './types'; export const FORMATTERS = { number: formatNumber, diff --git a/x-pack/plugins/infra/common/formatters/number.ts b/x-pack/plugins/infra/public/utils/formatters/number.ts similarity index 100% rename from x-pack/plugins/infra/common/formatters/number.ts rename to x-pack/plugins/infra/public/utils/formatters/number.ts diff --git a/x-pack/plugins/infra/common/formatters/percent.ts b/x-pack/plugins/infra/public/utils/formatters/percent.ts similarity index 100% rename from x-pack/plugins/infra/common/formatters/percent.ts rename to x-pack/plugins/infra/public/utils/formatters/percent.ts diff --git a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts index cffab4ba4f6f00..f880eca933241c 100644 --- a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts +++ b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts @@ -101,9 +101,7 @@ export const createSourcesResolvers = ( return requestedSourceConfiguration; }, async allSources(root, args, { req }) { - const sourceConfigurations = await libs.sources.getAllSourceConfigurations( - req.core.savedObjects.client - ); + const sourceConfigurations = await libs.sources.getAllSourceConfigurations(req); return sourceConfigurations; }, @@ -133,7 +131,7 @@ export const createSourcesResolvers = ( Mutation: { async createSource(root, args, { req }) { const sourceConfiguration = await libs.sources.createSourceConfiguration( - req.core.savedObjects.client, + req, args.id, compactObject({ ...args.sourceProperties, @@ -149,7 +147,7 @@ export const createSourcesResolvers = ( }; }, async deleteSource(root, args, { req }) { - await libs.sources.deleteSourceConfiguration(req.core.savedObjects.client, args.id); + await libs.sources.deleteSourceConfiguration(req, args.id); return { id: args.id, @@ -157,7 +155,7 @@ export const createSourcesResolvers = ( }, async updateSource(root, args, { req }) { const updatedSourceConfiguration = await libs.sources.updateSourceConfiguration( - req.core.savedObjects.client, + req, args.id, compactObject({ ...args.sourceProperties, diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index 62f324e01f8d99..5a5f9d0f8f5293 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -18,7 +18,6 @@ import { InventoryMetricRT, } from '../../../../common/inventory_models/types'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; -import { CallWithRequestParams, InfraDatabaseSearchResponse } from '../framework'; export class KibanaMetricsAdapter implements InfraMetricsAdapter { private framework: KibanaFramework; @@ -121,14 +120,9 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { indexPattern, options.timerange.interval ); - - const client = ( - opts: CallWithRequestParams - ): Promise> => - this.framework.callWithRequest(requestContext, 'search', opts); - const calculatedInterval = await calculateMetricInterval( - client, + this.framework, + requestContext, { indexPattern: `${options.sourceConfiguration.logAlias},${options.sourceConfiguration.metricAlias}`, timestampField: options.sourceConfiguration.fields.timestamp, diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts deleted file mode 100644 index cc8a35f6e47a15..00000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts +++ /dev/null @@ -1,214 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { mapValues, last, get } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import moment from 'moment'; -import { - InfraDatabaseSearchResponse, - CallWithRequestParams, -} from '../../adapters/framework/adapter_types'; -import { Comparator, AlertStates, InventoryMetricConditions } from './types'; -import { AlertServices, AlertExecutorOptions } from '../../../../../alerting/server'; -import { InfraSnapshot } from '../../snapshot'; -import { parseFilterQuery } from '../../../utils/serialized_query'; -import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; -import { InfraTimerangeInput } from '../../../../common/http_api/snapshot_api'; -import { InfraSourceConfiguration } from '../../sources'; -import { InfraBackendLibs } from '../../infra_types'; -import { METRIC_FORMATTERS } from '../../../../common/formatters/snapshot_metric_formats'; -import { createFormatter } from '../../../../common/formatters'; - -interface InventoryMetricThresholdParams { - criteria: InventoryMetricConditions[]; - groupBy: string | undefined; - filterQuery: string | undefined; - nodeType: InventoryItemType; - sourceId?: string; -} - -export const createInventoryMetricThresholdExecutor = ( - libs: InfraBackendLibs, - alertId: string -) => async ({ services, params }: AlertExecutorOptions) => { - const { criteria, filterQuery, sourceId, nodeType } = params as InventoryMetricThresholdParams; - - const source = await libs.sources.getSourceConfiguration( - services.savedObjectsClient, - sourceId || 'default' - ); - - const results = await Promise.all( - criteria.map(c => evaluateCondtion(c, nodeType, source.configuration, services, filterQuery)) - ); - - const invenotryItems = Object.keys(results[0]); - for (const item of invenotryItems) { - const alertInstance = services.alertInstanceFactory(`${alertId}-${item}`); - // AND logic; all criteria must be across the threshold - const shouldAlertFire = results.every(result => result[item].shouldFire); - - // AND logic; because we need to evaluate all criteria, if one of them reports no data then the - // whole alert is in a No Data/Error state - const isNoData = results.some(result => result[item].isNoData); - const isError = results.some(result => result[item].isError); - - if (shouldAlertFire) { - alertInstance.scheduleActions(FIRED_ACTIONS.id, { - group: item, - item, - valueOf: mapToConditionsLookup(results, result => - formatMetric(result[item].metric, result[item].currentValue) - ), - thresholdOf: mapToConditionsLookup(criteria, c => c.threshold), - metricOf: mapToConditionsLookup(criteria, c => c.metric), - }); - } - - alertInstance.replaceState({ - alertState: isError - ? AlertStates.ERROR - : isNoData - ? AlertStates.NO_DATA - : shouldAlertFire - ? AlertStates.ALERT - : AlertStates.OK, - }); - } -}; - -interface ConditionResult { - shouldFire: boolean; - currentValue?: number | null; - isNoData: boolean; - isError: boolean; -} - -const evaluateCondtion = async ( - condition: InventoryMetricConditions, - nodeType: InventoryItemType, - sourceConfiguration: InfraSourceConfiguration, - services: AlertServices, - filterQuery?: string -): Promise> => { - const { comparator, metric } = condition; - let { threshold } = condition; - - const currentValues = await getData( - services, - nodeType, - metric, - { - to: Date.now(), - from: moment() - .subtract(condition.timeSize, condition.timeUnit) - .toDate() - .getTime(), - interval: condition.timeUnit, - }, - sourceConfiguration, - filterQuery - ); - - threshold = threshold.map(n => convertMetricValue(metric, n)); - - const comparisonFunction = comparatorMap[comparator]; - - return mapValues(currentValues, value => ({ - shouldFire: value !== undefined && value !== null && comparisonFunction(value, threshold), - metric, - currentValue: value, - isNoData: value === null, - isError: value === undefined, - })); -}; - -const getData = async ( - services: AlertServices, - nodeType: InventoryItemType, - metric: SnapshotMetricType, - timerange: InfraTimerangeInput, - sourceConfiguration: InfraSourceConfiguration, - filterQuery?: string -) => { - const snapshot = new InfraSnapshot(); - const esClient = ( - options: CallWithRequestParams - ): Promise> => - services.callCluster('search', options); - - const options = { - filterQuery: parseFilterQuery(filterQuery), - nodeType, - groupBy: [], - sourceConfiguration, - metric: { type: metric }, - timerange, - }; - - const { nodes } = await snapshot.getNodes(esClient, options); - - return nodes.reduce((acc, n) => { - const nodePathItem = last(n.path); - acc[nodePathItem.label] = n.metric && n.metric.value; - return acc; - }, {} as Record); -}; - -const comparatorMap = { - [Comparator.BETWEEN]: (value: number, [a, b]: number[]) => - value >= Math.min(a, b) && value <= Math.max(a, b), - // `threshold` is always an array of numbers in case the BETWEEN comparator is - // used; all other compartors will just destructure the first value in the array - [Comparator.GT]: (a: number, [b]: number[]) => a > b, - [Comparator.LT]: (a: number, [b]: number[]) => a < b, - [Comparator.OUTSIDE_RANGE]: (value: number, [a, b]: number[]) => value < a || value > b, - [Comparator.GT_OR_EQ]: (a: number, [b]: number[]) => a >= b, - [Comparator.LT_OR_EQ]: (a: number, [b]: number[]) => a <= b, -}; - -const mapToConditionsLookup = ( - list: any[], - mapFn: (value: any, index: number, array: any[]) => unknown -) => - list - .map(mapFn) - .reduce( - (result: Record, value, i) => ({ ...result, [`condition${i}`]: value }), - {} - ); - -export const FIRED_ACTIONS = { - id: 'metrics.invenotry_threshold.fired', - name: i18n.translate('xpack.infra.metrics.alerting.inventory.threshold.fired', { - defaultMessage: 'Fired', - }), -}; - -// Some metrics in the UI are in a different unit that what we store in ES. -const convertMetricValue = (metric: SnapshotMetricType, value: number) => { - if (converters[metric]) { - return converters[metric](value); - } else { - return value; - } -}; -const converters: Record number> = { - cpu: n => Number(n) / 100, - memory: n => Number(n) / 100, -}; - -const formatMetric = (metric: SnapshotMetricType, value: number) => { - // if (SnapshotCustomMetricInputRT.is(metric)) { - // const formatter = createFormatterForMetric(metric); - // return formatter(val); - // } - const metricFormatter = get(METRIC_FORMATTERS, metric, METRIC_FORMATTERS.count); - if (value == null) { - return ''; - } - const formatter = createFormatter(metricFormatter.formatter, metricFormatter.template); - return formatter(value); -}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts deleted file mode 100644 index 3b6a1b5557bc69..00000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts +++ /dev/null @@ -1,92 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { i18n } from '@kbn/i18n'; -import { schema } from '@kbn/config-schema'; -import { curry } from 'lodash'; -import uuid from 'uuid'; -import { - createInventoryMetricThresholdExecutor, - FIRED_ACTIONS, -} from './inventory_metric_threshold_executor'; -import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from './types'; -import { InfraBackendLibs } from '../../infra_types'; - -const condition = schema.object({ - threshold: schema.arrayOf(schema.number()), - comparator: schema.oneOf([ - schema.literal('>'), - schema.literal('<'), - schema.literal('>='), - schema.literal('<='), - schema.literal('between'), - schema.literal('outside'), - ]), - timeUnit: schema.string(), - timeSize: schema.number(), - metric: schema.string(), -}); - -export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs) => ({ - id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - name: 'Inventory', - validate: { - params: schema.object( - { - criteria: schema.arrayOf(condition), - nodeType: schema.string(), - filterQuery: schema.maybe(schema.string()), - sourceId: schema.string(), - }, - { unknowns: 'allow' } - ), - }, - defaultActionGroupId: FIRED_ACTIONS.id, - actionGroups: [FIRED_ACTIONS], - executor: curry(createInventoryMetricThresholdExecutor)(libs, uuid.v4()), - actionVariables: { - context: [ - { - name: 'group', - description: i18n.translate( - 'xpack.infra.metrics.alerting.threshold.alerting.groupActionVariableDescription', - { - defaultMessage: 'Name of the group reporting data', - } - ), - }, - { - name: 'valueOf', - description: i18n.translate( - 'xpack.infra.metrics.alerting.threshold.alerting.valueOfActionVariableDescription', - { - defaultMessage: - 'Record of the current value of the watched metric; grouped by condition, i.e valueOf.condition0, valueOf.condition1, etc.', - } - ), - }, - { - name: 'thresholdOf', - description: i18n.translate( - 'xpack.infra.metrics.alerting.threshold.alerting.thresholdOfActionVariableDescription', - { - defaultMessage: - 'Record of the alerting threshold; grouped by condition, i.e thresholdOf.condition0, thresholdOf.condition1, etc.', - } - ), - }, - { - name: 'metricOf', - description: i18n.translate( - 'xpack.infra.metrics.alerting.threshold.alerting.metricOfActionVariableDescription', - { - defaultMessage: - 'Record of the watched metric; grouped by condition, i.e metricOf.condition0, metricOf.condition1, etc.', - } - ), - }, - ], - }, -}); diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts deleted file mode 100644 index 73ee1ab6b76159..00000000000000 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts +++ /dev/null @@ -1,35 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { SnapshotMetricType } from '../../../../common/inventory_models/types'; - -export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; - -export enum Comparator { - GT = '>', - LT = '<', - GT_OR_EQ = '>=', - LT_OR_EQ = '<=', - BETWEEN = 'between', - OUTSIDE_RANGE = 'outside', -} - -export enum AlertStates { - OK, - ALERT, - NO_DATA, - ERROR, -} - -export type TimeUnit = 's' | 'm' | 'h' | 'd'; - -export interface InventoryMetricConditions { - metric: SnapshotMetricType; - timeSize: number; - timeUnit: TimeUnit; - sourceId?: string; - threshold: number[]; - comparator: Comparator; -} diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 2531e939792af2..0007b8bd719f44 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; import { Comparator, AlertStates } from './types'; import * as mocks from './test_mocks'; @@ -12,14 +13,81 @@ import { AlertServicesMock, AlertInstanceMock, } from '../../../../../alerting/server/mocks'; -import { InfraSources } from '../../sources'; + +const executor = createMetricThresholdExecutor('test') as (opts: { + params: AlertExecutorOptions['params']; + services: { callCluster: AlertExecutorOptions['params']['callCluster'] }; +}) => Promise; + +const services: AlertServicesMock = alertsMock.createAlertServices(); +services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { + if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; + const metric = body.query.bool.filter[1]?.exists.field; + if (body.aggs.groupings) { + if (body.aggs.groupings.composite.after) { + return mocks.compositeEndResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateCompositeResponse; + } + return mocks.basicCompositeResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateMetricResponse; + } else if (metric === 'test.metric.3') { + return mocks.emptyMetricResponse; + } + return mocks.basicMetricResponse; +}); +services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { + if (sourceId === 'alternate') + return { + id: 'alternate', + attributes: { metricAlias: 'alternatebeat-*' }, + type, + references: [], + }; + return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; +}); interface AlertTestInstance { instance: AlertInstanceMock; actionQueue: any[]; state: any; } +const alertInstances = new Map(); +services.alertInstanceFactory.mockImplementation((instanceID: string) => { + const alertInstance: AlertTestInstance = { + instance: alertsMock.createAlertInstanceFactory(), + actionQueue: [], + state: {}, + }; + alertInstances.set(instanceID, alertInstance); + alertInstance.instance.replaceState.mockImplementation((newState: any) => { + alertInstance.state = newState; + return alertInstance.instance; + }); + alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => { + alertInstance.actionQueue.push({ id, action }); + return alertInstance.instance; + }); + return alertInstance.instance; +}); + +function mostRecentAction(id: string) { + return alertInstances.get(id)!.actionQueue.pop(); +} +function getState(id: string) { + return alertInstances.get(id)!.state; +} + +const baseCriterion = { + aggType: 'avg', + metric: 'test.metric.1', + timeSize: 1, + timeUnit: 'm', +}; describe('The metric threshold alert type', () => { describe('querying the entire infrastructure', () => { const instanceID = 'test-*'; @@ -99,6 +167,14 @@ describe('The metric threshold alert type', () => { expect(action.reason).toContain('threshold of 0.75'); expect(action.reason).toContain('test.metric.1'); }); + test('fetches the index pattern dynamically', async () => { + await execute(Comparator.LT, [17], 'alternate'); + expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id); + expect(getState(instanceID).alertState).toBe(AlertStates.ALERT); + await execute(Comparator.LT, [1.5], 'alternate'); + expect(mostRecentAction(instanceID)).toBe(undefined); + expect(getState(instanceID).alertState).toBe(AlertStates.OK); + }); }); describe('querying with a groupBy parameter', () => { @@ -262,117 +338,3 @@ describe('The metric threshold alert type', () => { }); }); }); - -const createMockStaticConfiguration = (sources: any) => ({ - enabled: true, - query: { - partitionSize: 1, - partitionFactor: 1, - }, - sources, -}); - -const mockLibs: any = { - sources: new InfraSources({ - config: createMockStaticConfiguration({}), - }), - configuration: createMockStaticConfiguration({}), -}; - -const executor = createMetricThresholdExecutor(mockLibs, 'test') as (opts: { - params: AlertExecutorOptions['params']; - services: { callCluster: AlertExecutorOptions['params']['callCluster'] }; -}) => Promise; - -const services: AlertServicesMock = alertsMock.createAlertServices(); -services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { - if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; - const metric = body.query.bool.filter[1]?.exists.field; - if (body.aggs.groupings) { - if (body.aggs.groupings.composite.after) { - return mocks.compositeEndResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateCompositeResponse; - } - return mocks.basicCompositeResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateMetricResponse; - } - return mocks.basicMetricResponse; -}); -services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { - if (sourceId === 'alternate') - return { - id: 'alternate', - attributes: { metricAlias: 'alternatebeat-*' }, - type, - references: [], - }; - return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; -}); - -services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { - if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; - const metric = body.query.bool.filter[1]?.exists.field; - if (body.aggs.groupings) { - if (body.aggs.groupings.composite.after) { - return mocks.compositeEndResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateCompositeResponse; - } - return mocks.basicCompositeResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateMetricResponse; - } else if (metric === 'test.metric.3') { - return mocks.emptyMetricResponse; - } - return mocks.basicMetricResponse; -}); -services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { - if (sourceId === 'alternate') - return { - id: 'alternate', - attributes: { metricAlias: 'alternatebeat-*' }, - type, - references: [], - }; - return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; -}); - -const alertInstances = new Map(); -services.alertInstanceFactory.mockImplementation((instanceID: string) => { - const alertInstance: AlertTestInstance = { - instance: alertsMock.createAlertInstanceFactory(), - actionQueue: [], - state: {}, - }; - alertInstances.set(instanceID, alertInstance); - alertInstance.instance.replaceState.mockImplementation((newState: any) => { - alertInstance.state = newState; - return alertInstance.instance; - }); - alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => { - alertInstance.actionQueue.push({ id, action }); - return alertInstance.instance; - }); - return alertInstance.instance; -}); - -function mostRecentAction(id: string) { - return alertInstances.get(id)!.actionQueue.pop(); -} - -function getState(id: string) { - return alertInstances.get(id)!.state; -} - -const baseCriterion = { - aggType: 'avg', - metric: 'test.metric.1', - timeSize: 1, - timeUnit: 'm', -}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 5c34a058577a1f..bd77e5e2daf42b 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -5,6 +5,8 @@ */ import { mapValues } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { convertSavedObjectToSavedSourceConfiguration } from '../../sources/sources'; +import { infraSourceConfigurationSavedObjectType } from '../../sources/saved_object_mappings'; import { InfraDatabaseSearchResponse } from '../../adapters/framework/adapter_types'; import { createAfterKeyHandler } from '../../../utils/create_afterkey_handler'; import { getAllCompositeData } from '../../../utils/get_all_composite_data'; @@ -20,9 +22,9 @@ import { import { AlertServices, AlertExecutorOptions } from '../../../../../alerting/server'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { getDateHistogramOffset } from '../../snapshot/query_helpers'; -import { InfraBackendLibs } from '../../infra_types'; const TOTAL_BUCKETS = 5; +const DEFAULT_INDEX_PATTERN = 'metricbeat-*'; interface Aggregation { aggregatedIntervals: { @@ -74,7 +76,6 @@ const getParsedFilterQuery: ( export const getElasticsearchMetricQuery = ( { metric, aggType, timeUnit, timeSize }: MetricExpressionParams, - timefield: string, groupBy?: string, filterQuery?: string ) => { @@ -108,7 +109,7 @@ export const getElasticsearchMetricQuery = ( const baseAggs = { aggregatedIntervals: { date_histogram: { - field: timefield, + field: '@timestamp', fixed_interval: interval, offset, extended_bounds: { @@ -180,23 +181,43 @@ export const getElasticsearchMetricQuery = ( }; }; +const getIndexPattern: ( + services: AlertServices, + sourceId?: string +) => Promise = async function({ savedObjectsClient }, sourceId = 'default') { + try { + const sourceConfiguration = await savedObjectsClient.get( + infraSourceConfigurationSavedObjectType, + sourceId + ); + const { metricAlias } = convertSavedObjectToSavedSourceConfiguration( + sourceConfiguration + ).configuration; + return metricAlias || DEFAULT_INDEX_PATTERN; + } catch (e) { + if (e.output.statusCode === 404) { + return DEFAULT_INDEX_PATTERN; + } else { + throw e; + } + } +}; + const getMetric: ( services: AlertServices, params: MetricExpressionParams, index: string, - timefield: string, groupBy: string | undefined, filterQuery: string | undefined ) => Promise> = async function( - { callCluster }, + { savedObjectsClient, callCluster }, params, index, - timefield, groupBy, filterQuery ) { const { aggType } = params; - const searchBody = getElasticsearchMetricQuery(params, timefield, groupBy, filterQuery); + const searchBody = getElasticsearchMetricQuery(params, groupBy, filterQuery); try { if (groupBy) { @@ -244,7 +265,7 @@ const comparatorMap = { [Comparator.LT_OR_EQ]: (a: number, [b]: number[]) => a <= b, }; -export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: string) => +export const createMetricThresholdExecutor = (alertUUID: string) => async function({ services, params }: AlertExecutorOptions) { const { criteria, groupBy, filterQuery, sourceId, alertOnNoData } = params as { criteria: MetricExpressionParams[]; @@ -254,22 +275,11 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: s alertOnNoData: boolean; }; - const source = await libs.sources.getSourceConfiguration( - services.savedObjectsClient, - sourceId || 'default' - ); - const config = source.configuration; const alertResults = await Promise.all( - criteria.map(criterion => { - return (async () => { - const currentValues = await getMetric( - services, - criterion, - config.fields.timestamp, - config.metricAlias, - groupBy, - filterQuery - ); + criteria.map(criterion => + (async () => { + const index = await getIndexPattern(services, sourceId); + const currentValues = await getMetric(services, criterion, index, groupBy, filterQuery); const { threshold, comparator } = criterion; const comparisonFunction = comparatorMap[comparator]; return mapValues(currentValues, value => ({ @@ -281,14 +291,13 @@ export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: s isNoData: value === null, isError: value === undefined, })); - })(); - }) + })() + ) ); - // Because each alert result has the same group definitions, just grap the groups from the first one. const groups = Object.keys(alertResults[0]); for (const group of groups) { - const alertInstance = services.alertInstanceFactory(`${alertId}-${group}`); + const alertInstance = services.alertInstanceFactory(`${alertUUID}-${group}`); // AND logic; all criteria must be across the threshold const shouldAlertFire = alertResults.every(result => result[group].shouldFire); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts index 23611559a184f5..029491c1168cfb 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts @@ -6,11 +6,11 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid'; import { schema } from '@kbn/config-schema'; -import { curry } from 'lodash'; +import { PluginSetupContract } from '../../../../../alerting/server'; import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metrics_explorer'; import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; -import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; import { InfraBackendLibs } from '../../infra_types'; +import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; const oneOfLiterals = (arrayOfLiterals: Readonly) => schema.string({ @@ -18,7 +18,17 @@ const oneOfLiterals = (arrayOfLiterals: Readonly) => arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`, }); -export function registerMetricThresholdAlertType(libs: InfraBackendLibs) { +export async function registerMetricThresholdAlertType( + alertingPlugin: PluginSetupContract, + libs: InfraBackendLibs +) { + if (!alertingPlugin) { + throw new Error( + 'Cannot register metric threshold alert type. Both the actions and alerting plugins need to be enabled.' + ); + } + const alertUUID = uuid.v4(); + const baseCriterion = { threshold: schema.arrayOf(schema.number()), comparator: oneOfLiterals(Object.values(Comparator)), @@ -60,24 +70,21 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs) { } ); - return { + alertingPlugin.registerType({ id: METRIC_THRESHOLD_ALERT_TYPE_ID, name: 'Metric threshold', validate: { - params: schema.object( - { - criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])), - groupBy: schema.maybe(schema.string()), - filterQuery: schema.maybe(schema.string()), - sourceId: schema.string(), - alertOnNoData: schema.maybe(schema.boolean()), - }, - { unknowns: 'allow' } - ), + params: schema.object({ + criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])), + groupBy: schema.maybe(schema.string()), + filterQuery: schema.maybe(schema.string()), + sourceId: schema.string(), + alertOnNoData: schema.maybe(schema.boolean()), + }), }, defaultActionGroupId: FIRED_ACTIONS.id, actionGroups: [FIRED_ACTIONS], - executor: curry(createMetricThresholdExecutor)(libs, uuid.v4()), + executor: createMetricThresholdExecutor(alertUUID), actionVariables: { context: [ { name: 'group', description: groupActionVariableDescription }, @@ -85,5 +92,5 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs) { { name: 'reason', description: reasonActionVariableDescription }, ], }, - }; + }); } diff --git a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts index 44d30d7281f20d..9760873ff74781 100644 --- a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts @@ -6,16 +6,13 @@ import { PluginSetupContract } from '../../../../alerting/server'; import { registerMetricThresholdAlertType } from './metric_threshold/register_metric_threshold_alert_type'; -import { registerMetricInventoryThresholdAlertType } from './inventory_metric_threshold/register_inventory_metric_threshold_alert_type'; import { registerLogThresholdAlertType } from './log_threshold/register_log_threshold_alert_type'; import { InfraBackendLibs } from '../infra_types'; const registerAlertTypes = (alertingPlugin: PluginSetupContract, libs: InfraBackendLibs) => { if (alertingPlugin) { - alertingPlugin.registerType(registerMetricThresholdAlertType(libs)); - alertingPlugin.registerType(registerMetricInventoryThresholdAlertType(libs)); + const registerFns = [registerMetricThresholdAlertType, registerLogThresholdAlertType]; - const registerFns = [registerLogThresholdAlertType]; registerFns.forEach(fn => { fn(alertingPlugin, libs); }); diff --git a/x-pack/plugins/infra/server/lib/compose/kibana.ts b/x-pack/plugins/infra/server/lib/compose/kibana.ts index 626b9d46bbde30..fc4732b8ca4746 100644 --- a/x-pack/plugins/infra/server/lib/compose/kibana.ts +++ b/x-pack/plugins/infra/server/lib/compose/kibana.ts @@ -28,7 +28,7 @@ export function compose(core: CoreSetup, config: InfraConfig, plugins: InfraServ const sourceStatus = new InfraSourceStatus(new InfraElasticsearchSourceStatusAdapter(framework), { sources, }); - const snapshot = new InfraSnapshot(); + const snapshot = new InfraSnapshot({ sources, framework }); const logEntryCategoriesAnalysis = new LogEntryCategoriesAnalysis({ framework }); const logEntryRateAnalysis = new LogEntryRateAnalysis({ framework }); diff --git a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts index c75ee6d6440442..cf2b1e59b2a225 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts @@ -5,23 +5,26 @@ */ import { uniq } from 'lodash'; +import { RequestHandlerContext } from 'kibana/server'; import { InfraSnapshotRequestOptions } from './types'; import { getMetricsAggregations } from './query_helpers'; import { calculateMetricInterval } from '../../utils/calculate_metric_interval'; import { SnapshotModel, SnapshotModelMetricAggRT } from '../../../common/inventory_models/types'; +import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; import { getDatasetForField } from '../../routes/metrics_explorer/lib/get_dataset_for_field'; import { InfraTimerangeInput } from '../../../common/http_api/snapshot_api'; -import { ESSearchClient } from '.'; export const createTimeRangeWithInterval = async ( - client: ESSearchClient, + framework: KibanaFramework, + requestContext: RequestHandlerContext, options: InfraSnapshotRequestOptions ): Promise => { const aggregations = getMetricsAggregations(options); - const modules = await aggregationsToModules(client, aggregations, options); + const modules = await aggregationsToModules(framework, requestContext, aggregations, options); const interval = Math.max( (await calculateMetricInterval( - client, + framework, + requestContext, { indexPattern: options.sourceConfiguration.metricAlias, timestampField: options.sourceConfiguration.fields.timestamp, @@ -40,7 +43,8 @@ export const createTimeRangeWithInterval = async ( }; const aggregationsToModules = async ( - client: ESSearchClient, + framework: KibanaFramework, + requestContext: RequestHandlerContext, aggregations: SnapshotModel, options: InfraSnapshotRequestOptions ): Promise => { @@ -55,7 +59,12 @@ const aggregationsToModules = async ( const fields = await Promise.all( uniqueFields.map( async field => - await getDatasetForField(client, field as string, options.sourceConfiguration.metricAlias) + await getDatasetForField( + framework, + requestContext, + field as string, + options.sourceConfiguration.metricAlias + ) ) ); return fields.filter(f => f) as string[]; diff --git a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts b/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts index 4057ed246ccaf0..07abfa5fd474a9 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts @@ -3,7 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { InfraDatabaseSearchResponse, CallWithRequestParams } from '../adapters/framework'; + +import { RequestHandlerContext } from 'src/core/server'; +import { InfraDatabaseSearchResponse } from '../adapters/framework'; +import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; +import { InfraSources } from '../sources'; import { JsonObject } from '../../../common/typed_json'; import { SNAPSHOT_COMPOSITE_REQUEST_SIZE } from './constants'; @@ -27,26 +31,36 @@ import { InfraSnapshotRequestOptions } from './types'; import { createTimeRangeWithInterval } from './create_timerange_with_interval'; import { SnapshotNode } from '../../../common/http_api/snapshot_api'; -export type ESSearchClient = ( - options: CallWithRequestParams -) => Promise>; export class InfraSnapshot { + constructor(private readonly libs: { sources: InfraSources; framework: KibanaFramework }) {} + public async getNodes( - client: ESSearchClient, + requestContext: RequestHandlerContext, options: InfraSnapshotRequestOptions ): Promise<{ nodes: SnapshotNode[]; interval: string }> { // Both requestGroupedNodes and requestNodeMetrics may send several requests to elasticsearch // in order to page through the results of their respective composite aggregations. // Both chains of requests are supposed to run in parallel, and their results be merged // when they have both been completed. - const timeRangeWithIntervalApplied = await createTimeRangeWithInterval(client, options); + const timeRangeWithIntervalApplied = await createTimeRangeWithInterval( + this.libs.framework, + requestContext, + options + ); const optionsWithTimerange = { ...options, timerange: timeRangeWithIntervalApplied }; - const groupedNodesPromise = requestGroupedNodes(client, optionsWithTimerange); - const nodeMetricsPromise = requestNodeMetrics(client, optionsWithTimerange); + const groupedNodesPromise = requestGroupedNodes( + requestContext, + optionsWithTimerange, + this.libs.framework + ); + const nodeMetricsPromise = requestNodeMetrics( + requestContext, + optionsWithTimerange, + this.libs.framework + ); const groupedNodeBuckets = await groupedNodesPromise; const nodeMetricBuckets = await nodeMetricsPromise; - return { nodes: mergeNodeBuckets(groupedNodeBuckets, nodeMetricBuckets, options), interval: timeRangeWithIntervalApplied.interval, @@ -63,12 +77,15 @@ const handleAfterKey = createAfterKeyHandler( input => input?.aggregations?.nodes?.after_key ); -const callClusterFactory = (search: ESSearchClient) => (opts: any) => - search<{}, InfraSnapshotAggregationResponse>(opts); +const callClusterFactory = (framework: KibanaFramework, requestContext: RequestHandlerContext) => ( + opts: any +) => + framework.callWithRequest<{}, InfraSnapshotAggregationResponse>(requestContext, 'search', opts); const requestGroupedNodes = async ( - client: ESSearchClient, - options: InfraSnapshotRequestOptions + requestContext: RequestHandlerContext, + options: InfraSnapshotRequestOptions, + framework: KibanaFramework ): Promise => { const inventoryModel = findInventoryModel(options.nodeType); const query = { @@ -107,12 +124,13 @@ const requestGroupedNodes = async ( return await getAllCompositeData< InfraSnapshotAggregationResponse, InfraSnapshotNodeGroupByBucket - >(callClusterFactory(client), query, bucketSelector, handleAfterKey); + >(callClusterFactory(framework, requestContext), query, bucketSelector, handleAfterKey); }; const requestNodeMetrics = async ( - client: ESSearchClient, - options: InfraSnapshotRequestOptions + requestContext: RequestHandlerContext, + options: InfraSnapshotRequestOptions, + framework: KibanaFramework ): Promise => { const index = options.metric.type === 'logRate' @@ -157,7 +175,7 @@ const requestNodeMetrics = async ( return await getAllCompositeData< InfraSnapshotAggregationResponse, InfraSnapshotNodeMetricsBucket - >(callClusterFactory(client), query, bucketSelector, handleAfterKey); + >(callClusterFactory(framework, requestContext), query, bucketSelector, handleAfterKey); }; // buckets can be InfraSnapshotNodeGroupByBucket[] or InfraSnapshotNodeMetricsBucket[] diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index 71682c9e798a6f..0368c7bfd6db81 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -9,7 +9,7 @@ import { failure } from 'io-ts/lib/PathReporter'; import { identity, constant } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; -import { SavedObjectsClientContract } from 'src/core/server'; +import { RequestHandlerContext, SavedObjectsClientContract } from 'src/core/server'; import { defaultSourceConfiguration } from './defaults'; import { NotFoundError } from './errors'; import { infraSourceConfigurationSavedObjectType } from './saved_object_mappings'; @@ -41,6 +41,7 @@ export class InfraSources { sourceId: string ): Promise { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); + const savedSourceConfiguration = await this.getInternalSourceConfiguration(sourceId) .then(internalSourceConfiguration => ({ id: sourceId, @@ -78,12 +79,10 @@ export class InfraSources { return savedSourceConfiguration; } - public async getAllSourceConfigurations(savedObjectsClient: SavedObjectsClientContract) { + public async getAllSourceConfigurations(requestContext: RequestHandlerContext) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); - const savedSourceConfigurations = await this.getAllSavedSourceConfigurations( - savedObjectsClient - ); + const savedSourceConfigurations = await this.getAllSavedSourceConfigurations(requestContext); return savedSourceConfigurations.map(savedSourceConfiguration => ({ ...savedSourceConfiguration, @@ -95,7 +94,7 @@ export class InfraSources { } public async createSourceConfiguration( - savedObjectsClient: SavedObjectsClientContract, + requestContext: RequestHandlerContext, sourceId: string, source: InfraSavedSourceConfiguration ) { @@ -107,7 +106,7 @@ export class InfraSources { ); const createdSourceConfiguration = convertSavedObjectToSavedSourceConfiguration( - await savedObjectsClient.create( + await requestContext.core.savedObjects.client.create( infraSourceConfigurationSavedObjectType, pickSavedSourceConfiguration(newSourceConfiguration) as any, { id: sourceId } @@ -123,22 +122,22 @@ export class InfraSources { }; } - public async deleteSourceConfiguration( - savedObjectsClient: SavedObjectsClientContract, - sourceId: string - ) { - await savedObjectsClient.delete(infraSourceConfigurationSavedObjectType, sourceId); + public async deleteSourceConfiguration(requestContext: RequestHandlerContext, sourceId: string) { + await requestContext.core.savedObjects.client.delete( + infraSourceConfigurationSavedObjectType, + sourceId + ); } public async updateSourceConfiguration( - savedObjectsClient: SavedObjectsClientContract, + requestContext: RequestHandlerContext, sourceId: string, sourceProperties: InfraSavedSourceConfiguration ) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); const { configuration, version } = await this.getSourceConfiguration( - savedObjectsClient, + requestContext.core.savedObjects.client, sourceId ); @@ -148,7 +147,7 @@ export class InfraSources { ); const updatedSourceConfiguration = convertSavedObjectToSavedSourceConfiguration( - await savedObjectsClient.update( + await requestContext.core.savedObjects.client.update( infraSourceConfigurationSavedObjectType, sourceId, pickSavedSourceConfiguration(updatedSourceConfigurationAttributes) as any, @@ -214,8 +213,8 @@ export class InfraSources { return convertSavedObjectToSavedSourceConfiguration(savedObject); } - private async getAllSavedSourceConfigurations(savedObjectsClient: SavedObjectsClientContract) { - const savedObjects = await savedObjectsClient.find({ + private async getAllSavedSourceConfigurations(requestContext: RequestHandlerContext) { + const savedObjects = await requestContext.core.savedObjects.client.find({ type: infraSourceConfigurationSavedObjectType, }); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 13446594ab114e..2dbc93668fdf82 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -109,7 +109,7 @@ export class InfraServerPlugin { sources, } ); - const snapshot = new InfraSnapshot(); + const snapshot = new InfraSnapshot({ sources, framework }); const logEntryCategoriesAnalysis = new LogEntryCategoriesAnalysis({ framework }); const logEntryRateAnalysis = new LogEntryRateAnalysis({ framework }); diff --git a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts index 46929954431f51..0ce594675773c2 100644 --- a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts +++ b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts @@ -82,12 +82,12 @@ export const initLogSourceConfigurationRoutes = ({ framework, sources }: InfraBa const sourceConfigurationExists = sourceConfiguration.origin === 'stored'; const patchedSourceConfiguration = await (sourceConfigurationExists ? sources.updateSourceConfiguration( - requestContext.core.savedObjects.client, + requestContext, sourceId, patchedSourceConfigurationProperties ) : sources.createSourceConfiguration( - requestContext.core.savedObjects.client, + requestContext, sourceId, patchedSourceConfigurationProperties )); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts index 94e91d32b14bb5..66f0ca8fc706a3 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchClient } from '../../../lib/snapshot'; +import { RequestHandlerContext } from 'kibana/server'; +import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; interface EventDatasetHit { _source: { @@ -15,7 +16,8 @@ interface EventDatasetHit { } export const getDatasetForField = async ( - client: ESSearchClient, + framework: KibanaFramework, + requestContext: RequestHandlerContext, field: string, indexPattern: string ) => { @@ -31,8 +33,11 @@ export const getDatasetForField = async ( }, }; - const response = await client(params); - + const response = await framework.callWithRequest( + requestContext, + 'search', + params + ); if (response.hits.total.value === 0) { return null; } diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts index a709cbdeeb680f..e735a26d96a91d 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts @@ -17,10 +17,6 @@ import { createMetricModel } from './create_metrics_model'; import { JsonObject } from '../../../../common/typed_json'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; import { getDatasetForField } from './get_dataset_for_field'; -import { - CallWithRequestParams, - InfraDatabaseSearchResponse, -} from '../../../lib/adapters/framework'; export const populateSeriesWithTSVBData = ( request: KibanaRequest, @@ -56,21 +52,17 @@ export const populateSeriesWithTSVBData = ( } const timerange = { min: options.timerange.from, max: options.timerange.to }; - const client = ( - opts: CallWithRequestParams - ): Promise> => - framework.callWithRequest(requestContext, 'search', opts); - // Create the TSVB model based on the request options const model = createMetricModel(options); const modules = await Promise.all( uniq(options.metrics.filter(m => m.field)).map( - async m => await getDatasetForField(client, m.field as string, options.indexPattern) + async m => + await getDatasetForField(framework, requestContext, m.field as string, options.indexPattern) ) ); - const calculatedInterval = await calculateMetricInterval( - client, + framework, + requestContext, { indexPattern: options.indexPattern, timestampField: options.timerange.field, diff --git a/x-pack/plugins/infra/server/routes/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/index.ts index 2d951d426b03a0..d1dc03893a0d9b 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/index.ts @@ -13,7 +13,6 @@ import { UsageCollector } from '../../usage/usage_collector'; import { parseFilterQuery } from '../../utils/serialized_query'; import { SnapshotRequestRT, SnapshotNodeResponseRT } from '../../../common/http_api/snapshot_api'; import { throwErrors } from '../../../common/runtime_types'; -import { CallWithRequestParams, InfraDatabaseSearchResponse } from '../../lib/adapters/framework'; const escapeHatch = schema.object({}, { unknowns: 'allow' }); @@ -58,13 +57,7 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => { metric, timerange, }; - - const searchES = ( - opts: CallWithRequestParams - ): Promise> => - framework.callWithRequest(requestContext, 'search', opts); - - const nodesWithInterval = await libs.snapshot.getNodes(searchES, options); + const nodesWithInterval = await libs.snapshot.getNodes(requestContext, options); return response.ok({ body: SnapshotNodeResponseRT.encode(nodesWithInterval), }); diff --git a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts index 43e109b009f48e..7cbbdc0f2145be 100644 --- a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts +++ b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts @@ -4,11 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -// import { RequestHandlerContext } from 'src/core/server'; +import { RequestHandlerContext } from 'src/core/server'; import { findInventoryModel } from '../../common/inventory_models'; -// import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; +import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; import { InventoryItemType } from '../../common/inventory_models/types'; -import { ESSearchClient } from '../lib/snapshot'; interface Options { indexPattern: string; @@ -24,7 +23,8 @@ interface Options { * This is useful for visualizing metric modules like s3 that only send metrics once per day. */ export const calculateMetricInterval = async ( - client: ESSearchClient, + framework: KibanaFramework, + requestContext: RequestHandlerContext, options: Options, modules?: string[], nodeType?: InventoryItemType // TODO: check that this type still makes sense @@ -73,7 +73,11 @@ export const calculateMetricInterval = async ( }, }; - const resp = await client<{}, PeriodAggregationData>(query); + const resp = await framework.callWithRequest<{}, PeriodAggregationData>( + requestContext, + 'search', + query + ); // if ES doesn't return an aggregations key, something went seriously wrong. if (!resp.aggregations) { diff --git a/x-pack/test/api_integration/apis/infra/metrics_alerting.ts b/x-pack/test/api_integration/apis/infra/metrics_alerting.ts index 5c43e8938a8c12..19879f5761ab2c 100644 --- a/x-pack/test/api_integration/apis/infra/metrics_alerting.ts +++ b/x-pack/test/api_integration/apis/infra/metrics_alerting.ts @@ -32,7 +32,7 @@ export default function({ getService }: FtrProviderContext) { describe('querying the entire infrastructure', () => { for (const aggType of aggs) { it(`should work with the ${aggType} aggregator`, async () => { - const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), '@timestamp'); + const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType)); const result = await client.search({ index, body: searchBody, @@ -45,7 +45,6 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), - '@timestamp', undefined, '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' ); @@ -60,7 +59,6 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery in KQL format', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), - '@timestamp', undefined, '"agent.hostname":"foo"' ); @@ -76,11 +74,7 @@ export default function({ getService }: FtrProviderContext) { describe('querying with a groupBy parameter', () => { for (const aggType of aggs) { it(`should work with the ${aggType} aggregator`, async () => { - const searchBody = getElasticsearchMetricQuery( - getSearchParams(aggType), - '@timestamp', - 'agent.id' - ); + const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), 'agent.id'); const result = await client.search({ index, body: searchBody, @@ -93,7 +87,6 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), - '@timestamp', 'agent.id', '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' );