Skip to content

Commit

Permalink
[INFRA] Enable anomaly detection in hosts view (elastic#177555)
Browse files Browse the repository at this point in the history
Closes elastic#176522

### What was done

- Anomaly Detection top menu item appears in the Hosts View and Asset
Details

<img width="1288" alt="image"
src="https://github.com/elastic/kibana/assets/31922082/51a94d4e-35dd-497a-ada1-1ecbfe3f56e6">
<img width="1288" alt="image"
src="https://github.com/elastic/kibana/assets/31922082/6ba62f99-96f9-4df0-82cc-e6a4e23a14c3">


- Within the Hosts View and Asset Details page the Anomaly Detection
flyout will present to users only with the Hosts option, hiding the
Kubernetes option

<img width="1292" alt="image"
src="https://github.com/elastic/kibana/assets/31922082/fc98d490-cc9b-4e48-a965-e8f870d4536f">

- In the Anomaly tab, when the flyout is opened within the Hosts View
and Asset details, it will only show hosts anomalies, and won't show the
infra type dropdown

<img width="1292" alt="image"
src="https://github.com/elastic/kibana/assets/31922082/432d14b3-678f-4e57-a8eb-9224a8c905bf">

- Fixed the tab items margin
  • Loading branch information
MiriamAparicio authored Mar 4, 2024
1 parent ebbd6e9 commit 47fc709
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import React, { useMemo, useRef } from 'react';
import { AnomaliesTable } from '../../../../pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table';
import { AnomaliesTable } from '../../../ml/anomaly_detection/anomalies_table/anomalies_table';
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
import { useDatePickerContext } from '../../hooks/use_date_picker';
import { useIntersectingState } from '../../hooks/use_intersecting_state';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import { EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { MetricsHostsAnomaly } from '../../../../../../../../common/http_api/infra_ml/results';
import { formatOneDecimalPlace } from '../../../../../../../../common/log_analysis';
import { MetricsHostsAnomaly } from '../../../../../common/http_api/infra_ml/results';
import { formatOneDecimalPlace } from '../../../../../common/log_analysis';

export const AnomalySummary = ({ anomaly }: { anomaly: MetricsHostsAnomaly }) => {
const { actual, typical } = anomaly;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,24 @@ import type { TimeRange } from '@kbn/es-query';
import { css } from '@emotion/react';
import type { SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common';
import { BehaviorSubject } from 'rxjs';
import { datemathToEpochMillis } from '../../../../../../../utils/datemath';
import { useSorting } from '../../../../../../../hooks/use_sorting';
import { useMetricsK8sAnomaliesResults } from '../../../../hooks/use_metrics_k8s_anomalies';
import { useMetricsHostsAnomaliesResults } from '../../../../hooks/use_metrics_hosts_anomalies';
import { datemathToEpochMillis } from '../../../../utils/datemath';
import { useSorting } from '../../../../hooks/use_sorting';
import { useMetricsK8sAnomaliesResults } from '../../../../pages/metrics/inventory_view/hooks/use_metrics_k8s_anomalies';
import { useMetricsHostsAnomaliesResults } from '../../../../pages/metrics/inventory_view/hooks/use_metrics_hosts_anomalies';
import type {
Metric,
MetricsHostsAnomaly,
Sort,
} from '../../../../../../../../common/http_api/infra_ml/results';
} from '../../../../../common/http_api/infra_ml/results';
import { PaginationControls } from './pagination';
import { AnomalySummary } from './annomaly_summary';
import { AnomalySeverityIndicator } from '../../../../../../../components/logging/log_analysis_results/anomaly_severity_indicator';
import { useSourceContext } from '../../../../../../../containers/metrics_source';
import { AnomalySeverityIndicator } from '../../../logging/log_analysis_results/anomaly_severity_indicator';
import { useSourceContext } from '../../../../containers/metrics_source';
import { createResultsUrl } from '../flyout_home';
import { useWaffleViewState, WaffleViewState } from '../../../../hooks/use_waffle_view_state';
import {
useWaffleViewState,
WaffleViewState,
} from '../../../../pages/metrics/inventory_view/hooks/use_waffle_view_state';

type JobType = 'k8s' | 'hosts';
type SortField = 'anomalyScore' | 'startTime';
Expand Down Expand Up @@ -200,6 +203,7 @@ interface Props {
hideDatePicker?: boolean;
// subject to watch the completition of the request
request$?: BehaviorSubject<(() => Promise<unknown>) | undefined>;
hideSelectGroup?: boolean;
}

const DEFAULT_DATE_RANGE: TimeRange = {
Expand All @@ -213,6 +217,7 @@ export const AnomaliesTable = ({
dateRange = DEFAULT_DATE_RANGE,
hideDatePicker = false,
request$,
hideSelectGroup,
}: Props) => {
const [search, setSearch] = useState('');
const trackMetric = useUiTracker({ app: 'infra_metrics' });
Expand Down Expand Up @@ -501,20 +506,22 @@ export const AnomaliesTable = ({
isClearable={true}
/>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<EuiComboBox
placeholder={i18n.translate('xpack.infra.ml.anomalyFlyout.jobTypeSelect', {
defaultMessage: 'Select group',
})}
singleSelection={{ asPlainText: true }}
options={jobOptions}
selectedOptions={selectedJobType}
onChange={changeJobType}
fullWidth
isClearable={false}
data-test-subj="anomaliesComboBoxType"
/>
</EuiFlexItem>
{!hideSelectGroup && (
<EuiFlexItem grow={1}>
<EuiComboBox
placeholder={i18n.translate('xpack.infra.ml.anomalyFlyout.jobTypeSelect', {
defaultMessage: 'Select group',
})}
singleSelection={{ asPlainText: true }}
options={jobOptions}
selectedOptions={selectedJobType}
onChange={changeJobType}
fullWidth
isClearable={false}
data-test-subj="anomaliesComboBoxType"
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
)}
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@
import React, { useState, useCallback } from 'react';
import { EuiHeaderLink, EuiFlyout } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useSourceContext } from '../../../../../../containers/metrics_source';
import { useSourceContext } from '../../../containers/metrics_source';
import { FlyoutHome } from './flyout_home';
import { JobSetupScreen } from './job_setup_screen';
import { useInfraMLCapabilities } from '../../../../../../containers/ml/infra_ml_capabilities';
import { MetricHostsModuleProvider } from '../../../../../../containers/ml/modules/metrics_hosts/module';
import { MetricK8sModuleProvider } from '../../../../../../containers/ml/modules/metrics_k8s/module';
import { useActiveKibanaSpace } from '../../../../../../hooks/use_kibana_space';
import { useInfraMLCapabilities } from '../../../containers/ml/infra_ml_capabilities';
import { MetricHostsModuleProvider } from '../../../containers/ml/modules/metrics_hosts/module';
import { MetricK8sModuleProvider } from '../../../containers/ml/modules/metrics_k8s/module';
import { useActiveKibanaSpace } from '../../../hooks/use_kibana_space';

export const AnomalyDetectionFlyout = () => {
export const AnomalyDetectionFlyout = ({
hideJobType,
hideSelectGroup,
}: {
hideJobType?: boolean;
hideSelectGroup?: boolean;
}) => {
const { hasInfraMLSetupCapabilities } = useInfraMLCapabilities();
const [showFlyout, setShowFlyout] = useState(false);
const [screenName, setScreenName] = useState<'home' | 'setup'>('home');
Expand Down Expand Up @@ -77,6 +83,8 @@ export const AnomalyDetectionFlyout = () => {
hasSetupCapabilities={hasInfraMLSetupCapabilities}
goToSetup={openJobSetup}
closeFlyout={closeFlyout}
hideJobType={hideJobType}
hideSelectGroup={hideSelectGroup}
/>
)}
{screenName === 'setup' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,24 @@ import moment from 'moment';
import { MLJobsAwaitingNodeWarning } from '@kbn/ml-plugin/public';
import { FeatureFeedbackButton, useLinkProps } from '@kbn/observability-shared-plugin/public';
import { css } from '@emotion/react';
import { KibanaEnvironmentContext } from '../../../../../../hooks/use_kibana';
import { SubscriptionSplashPrompt } from '../../../../../../components/subscription_splash_content';
import { useInfraMLCapabilitiesContext } from '../../../../../../containers/ml/infra_ml_capabilities';
import {
MissingResultsPrivilegesPrompt,
MissingSetupPrivilegesPrompt,
} from '../../../../../../components/logging/log_analysis_setup';
import { useMetricHostsModuleContext } from '../../../../../../containers/ml/modules/metrics_hosts/module';
import { useMetricK8sModuleContext } from '../../../../../../containers/ml/modules/metrics_k8s/module';
import { LoadingPrompt } from '../../../../../../components/loading_page';
} from '../../logging/log_analysis_setup';
import { useMetricHostsModuleContext } from '../../../containers/ml/modules/metrics_hosts/module';
import { useMetricK8sModuleContext } from '../../../containers/ml/modules/metrics_k8s/module';
import { LoadingPrompt } from '../../loading_page';
import { AnomaliesTable } from './anomalies_table/anomalies_table';
import { SubscriptionSplashPrompt } from '../../subscription_splash_content';
import { useInfraMLCapabilitiesContext } from '../../../containers/ml/infra_ml_capabilities';
import { KibanaEnvironmentContext } from '../../../hooks/use_kibana';

interface Props {
hasSetupCapabilities: boolean;
goToSetup(type: 'hosts' | 'kubernetes'): void;
closeFlyout(): void;
hideJobType?: boolean;
hideSelectGroup?: boolean;
}

type Tab = 'jobs' | 'anomalies';
Expand Down Expand Up @@ -124,7 +126,7 @@ export const FlyoutHome = (props: Props) => {
<EuiFlyoutHeader hasBorder>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiTitle size="m">
<EuiTitle size="s">
<h2>
<FormattedMessage
defaultMessage="Machine Learning anomaly detection"
Expand Down Expand Up @@ -236,11 +238,14 @@ export const FlyoutHome = (props: Props) => {
hasSetupCapabilities={props.hasSetupCapabilities}
createHosts={createHosts}
createK8s={createK8s}
hideJobType={props.hideJobType}
/>
</>
)}

{tab === 'anomalies' && <AnomaliesTable closeFlyout={closeFlyout} />}
{tab === 'anomalies' && (
<AnomaliesTable closeFlyout={closeFlyout} hideSelectGroup={props.hideSelectGroup} />
)}
</EuiFlyoutBody>
</>
);
Expand Down Expand Up @@ -294,18 +299,18 @@ interface CreateJobTab {
hasK8sJobs: boolean;
createHosts(): void;
createK8s(): void;
hideJobType?: boolean;
}

const CreateJobTab = (props: CreateJobTab) => {
return (
<>
{/* <EuiSpacer size="l" /> */}
<EuiFlexGroup gutterSize={'m'}>
<EuiFlexItem>
<EuiCard
data-test-subj="infraHostsJobCard"
isDisabled={!props.hasSetupCapabilities}
icon={<EuiIcon type={'storage'} size="xl" />}
// title="Hosts"
title={
<FormattedMessage
defaultMessage="Hosts"
Expand Down Expand Up @@ -346,50 +351,53 @@ const CreateJobTab = (props: CreateJobTab) => {
}
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiCard
isDisabled={!props.hasSetupCapabilities}
icon={<EuiIcon type={'logoKubernetes'} size="xl" />}
title={
<FormattedMessage
defaultMessage="Kubernetes Pods"
id="xpack.infra.ml.anomalyFlyout.create.k8sTitle"
/>
}
description={
<FormattedMessage
defaultMessage="Detect anomalies for memory usage and network traffic on Kubernetes Pods."
id="xpack.infra.ml.anomalyFlyout.create.k8sDescription"
/>
}
footer={
<>
{props.hasK8sJobs && (
<EuiButtonEmpty
data-test-subj="infraCreateJobTabRecreateJobsButton"
onClick={props.createK8s}
>
<FormattedMessage
defaultMessage="Recreate jobs"
id="xpack.infra.ml.anomalyFlyout.create.recreateButton"
/>
</EuiButtonEmpty>
)}
{!props.hasK8sJobs && (
<EuiButton
data-test-subj="infraCreateJobTabEnableButton"
onClick={props.createK8s}
>
<FormattedMessage
defaultMessage="Enable"
id="xpack.infra.ml.anomalyFlyout.create.createButton"
/>
</EuiButton>
)}
</>
}
/>
</EuiFlexItem>
{!props.hideJobType && (
<EuiFlexItem>
<EuiCard
data-test-subj="infraK8sJobCard"
isDisabled={!props.hasSetupCapabilities}
icon={<EuiIcon type="logoKubernetes" size="xl" />}
title={
<FormattedMessage
defaultMessage="Kubernetes Pods"
id="xpack.infra.ml.anomalyFlyout.create.k8sTitle"
/>
}
description={
<FormattedMessage
defaultMessage="Detect anomalies for memory usage and network traffic on Kubernetes Pods."
id="xpack.infra.ml.anomalyFlyout.create.k8sDescription"
/>
}
footer={
<>
{props.hasK8sJobs && (
<EuiButtonEmpty
data-test-subj="infraCreateJobTabRecreateJobsButton"
onClick={props.createK8s}
>
<FormattedMessage
defaultMessage="Recreate jobs"
id="xpack.infra.ml.anomalyFlyout.create.recreateButton"
/>
</EuiButtonEmpty>
)}
{!props.hasK8sJobs && (
<EuiButton
data-test-subj="infraCreateJobTabEnableButton"
onClick={props.createK8s}
>
<FormattedMessage
defaultMessage="Enable"
id="xpack.infra.ml.anomalyFlyout.create.createButton"
/>
</EuiButton>
)}
</>
}
/>
</EuiFlexItem>
)}
</EuiFlexGroup>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ import moment, { Moment } from 'moment';
import { i18n } from '@kbn/i18n';
import { FeatureFeedbackButton, useUiTracker } from '@kbn/observability-shared-plugin/public';
import { css } from '@emotion/react';
import { KibanaEnvironmentContext } from '../../../../../../hooks/use_kibana';
import { useSourceContext } from '../../../../../../containers/metrics_source';
import { useMetricK8sModuleContext } from '../../../../../../containers/ml/modules/metrics_k8s/module';
import { useMetricHostsModuleContext } from '../../../../../../containers/ml/modules/metrics_hosts/module';
import { FixedDatePicker } from '../../../../../../components/fixed_datepicker';
import { DEFAULT_K8S_PARTITION_FIELD } from '../../../../../../containers/ml/modules/metrics_k8s/module_descriptor';
import { MetricsExplorerKueryBar } from '../../../../metrics_explorer/components/kuery_bar';
import { convertKueryToElasticSearchQuery } from '../../../../../../utils/kuery';
import { useSourceContext } from '../../../containers/metrics_source';
import { useMetricHostsModuleContext } from '../../../containers/ml/modules/metrics_hosts/module';
import { useMetricK8sModuleContext } from '../../../containers/ml/modules/metrics_k8s/module';
import { FixedDatePicker } from '../../fixed_datepicker';
import { DEFAULT_K8S_PARTITION_FIELD } from '../../../containers/ml/modules/metrics_k8s/module_descriptor';
import { convertKueryToElasticSearchQuery } from '../../../utils/kuery';
import { INFRA_ML_FLYOUT_FEEDBACK_LINK } from './flyout_home';
import { KibanaEnvironmentContext } from '../../../hooks/use_kibana';
import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar';

interface Props {
jobType: 'hosts' | 'kubernetes';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { SourceLoadingPage } from '../../components/source_loading_page';
import { MetricsAlertDropdown } from '../../alerting/common/components/metrics_alert_dropdown';
import { AlertPrefillProvider } from '../../alerting/use_alert_prefill';
import { InfraMLCapabilitiesProvider } from '../../containers/ml/infra_ml_capabilities';
import { AnomalyDetectionFlyout } from './inventory_view/components/ml/anomaly_detection/anomaly_detection_flyout';
import { AnomalyDetectionFlyout } from '../../components/ml/anomaly_detection/anomaly_detection_flyout';
import { HeaderActionMenuContext } from '../../utils/header_action_menu_provider';
import { CreateDerivedIndexPattern, useSourceContext } from '../../containers/metrics_source';
import { NotFoundPage } from '../404';
Expand Down Expand Up @@ -91,6 +91,18 @@ export const InfrastructurePage = () => {
{settingsTabTitle}
</EuiHeaderLink>
<Route path={'/inventory'} component={AnomalyDetectionFlyout} />
<Route
path={'/hosts'}
render={() => {
return <AnomalyDetectionFlyout hideJobType hideSelectGroup />;
}}
/>
<Route
path={'/detail/host'}
render={() => {
return <AnomalyDetectionFlyout hideJobType hideSelectGroup />;
}}
/>
{config.featureFlags.alertsAndRulesDropdownEnabled && (
<MetricsAlertDropdown />
)}
Expand Down
Loading

0 comments on commit 47fc709

Please sign in to comment.