mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[ObsUx] [Infra] Change container details view with asset details view (#180436)
Part of https://github.com/elastic/kibana/issues/179844
### In this PR
- From Inventory, open asset details page view for Containers
- Show overview tab with CPU and Memory KPIs and metric charts
- Metadata tab with old fields, more metadata fields will be shown in
follow-up PR
- Added links to container metrics documentation, currently there are no
docs for K8s metrics just for docker containers
#### How to test
- The feature is under a FF, on inventory page go to settings and enable
`Container view`
- In containers inventory, select a container and click on 'Docker
container metrics' link (there's an
[issue](https://github.com/elastic/kibana/issues/180806) to reword this
links as K8s containers are also shown)
- Container details page should be shown with overview and metadata tabs
- On overview tab KPIs for CPU and Memory and Metrics section with CPU
and Memory charts should be displayed
<img width="937" alt="image"
src="d2f25f2a
-ea4f-4516-b216-38464682fd14">
This commit is contained in:
parent
2de84ce4dd
commit
a4579a7e78
81 changed files with 1890 additions and 375 deletions
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { Entity, Fields } from '../entity';
|
||||
import { Serializable } from '../serializable';
|
||||
|
||||
interface DockerContainerDocument extends Fields {
|
||||
'container.id': string;
|
||||
'metricset.name'?: string;
|
||||
}
|
||||
|
||||
export class DockerContainer extends Entity<DockerContainerDocument> {
|
||||
metrics() {
|
||||
return new DockerContainerMetrics({
|
||||
...this.fields,
|
||||
'docker.cpu.total.pct': 25,
|
||||
'docker.memory.usage.pct': 20,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface DockerContainerMetricsDocument extends DockerContainerDocument {
|
||||
'docker.cpu.total.pct': number;
|
||||
'docker.memory.usage.pct': number;
|
||||
}
|
||||
|
||||
class DockerContainerMetrics extends Serializable<DockerContainerMetricsDocument> {}
|
||||
|
||||
export function dockerContainer(id: string): DockerContainer {
|
||||
return new DockerContainer({
|
||||
'container.id': id,
|
||||
});
|
||||
}
|
|
@ -6,14 +6,20 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { container, ContainerMetricsDocument } from './container';
|
||||
import { dockerContainer, DockerContainerMetricsDocument } from './docker_container';
|
||||
import { host, HostMetricsDocument } from './host';
|
||||
import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container';
|
||||
import { pod, PodMetricsDocument } from './pod';
|
||||
|
||||
export type InfraDocument = HostMetricsDocument | PodMetricsDocument | ContainerMetricsDocument;
|
||||
export type InfraDocument =
|
||||
| HostMetricsDocument
|
||||
| PodMetricsDocument
|
||||
| DockerContainerMetricsDocument
|
||||
| K8sContainerMetricsDocument;
|
||||
|
||||
export const infra = {
|
||||
host,
|
||||
pod,
|
||||
container,
|
||||
dockerContainer,
|
||||
k8sContainer,
|
||||
};
|
||||
|
|
|
@ -10,30 +10,32 @@
|
|||
import { Entity, Fields } from '../entity';
|
||||
import { Serializable } from '../serializable';
|
||||
|
||||
interface ContainerDocument extends Fields {
|
||||
interface K8sContainerDocument extends Fields {
|
||||
'container.id': string;
|
||||
'kubernetes.pod.uid': string;
|
||||
'kubernetes.node.name': string;
|
||||
'metricset.name'?: string;
|
||||
}
|
||||
|
||||
export class Container extends Entity<ContainerDocument> {
|
||||
export class K8sContainer extends Entity<K8sContainerDocument> {
|
||||
metrics() {
|
||||
return new ContainerMetrics({
|
||||
return new K8sContainerMetrics({
|
||||
...this.fields,
|
||||
'kubernetes.container.cpu.usage.limit.pct': 46,
|
||||
'kubernetes.container.memory.usage.limit.pct': 30,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface ContainerMetricsDocument extends ContainerDocument {
|
||||
export interface K8sContainerMetricsDocument extends K8sContainerDocument {
|
||||
'kubernetes.container.cpu.usage.limit.pct': number;
|
||||
'kubernetes.container.memory.usage.limit.pct': number;
|
||||
}
|
||||
|
||||
class ContainerMetrics extends Serializable<ContainerMetricsDocument> {}
|
||||
class K8sContainerMetrics extends Serializable<K8sContainerMetricsDocument> {}
|
||||
|
||||
export function container(id: string, uid: string, nodeName: string) {
|
||||
return new Container({
|
||||
export function k8sContainer(id: string, uid: string, nodeName: string): K8sContainer {
|
||||
return new K8sContainer({
|
||||
'container.id': id,
|
||||
'kubernetes.pod.uid': uid,
|
||||
'kubernetes.node.name': nodeName,
|
|
@ -9,7 +9,7 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
import { Entity, Fields } from '../entity';
|
||||
import { Serializable } from '../serializable';
|
||||
import { container } from './container';
|
||||
import { k8sContainer } from './k8s_container';
|
||||
|
||||
interface PodDocument extends Fields {
|
||||
'kubernetes.pod.uid': string;
|
||||
|
@ -26,7 +26,7 @@ export class Pod extends Entity<PodDocument> {
|
|||
}
|
||||
|
||||
container(id: string) {
|
||||
return container(id, this.fields['kubernetes.pod.uid'], this.fields['kubernetes.node.name']);
|
||||
return k8sContainer(id, this.fields['kubernetes.pod.uid'], this.fields['kubernetes.node.name']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { InfraDocument, infra } from '@kbn/apm-synthtrace-client';
|
||||
|
||||
import { Scenario } from '../cli/scenario';
|
||||
import { withClient } from '../lib/utils/with_client';
|
||||
|
||||
const scenario: Scenario<InfraDocument> = async (runOptions) => {
|
||||
return {
|
||||
generate: ({ range, clients: { infraEsClient } }) => {
|
||||
const { numContainers = 5 } = runOptions.scenarioOpts || {};
|
||||
const { logger } = runOptions;
|
||||
|
||||
const CONTAINERS = Array(numContainers)
|
||||
.fill(0)
|
||||
.map((_, idx) => infra.dockerContainer(`container-${idx}`));
|
||||
|
||||
const containers = range
|
||||
.interval('30s')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
CONTAINERS.flatMap((container) => [container.metrics().timestamp(timestamp)])
|
||||
);
|
||||
|
||||
return [
|
||||
withClient(
|
||||
infraEsClient,
|
||||
logger.perf('generating_infra_docker_containers', () => containers)
|
||||
),
|
||||
];
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default scenario;
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { InfraDocument, infra } from '@kbn/apm-synthtrace-client';
|
||||
|
||||
import { Scenario } from '../cli/scenario';
|
||||
import { withClient } from '../lib/utils/with_client';
|
||||
|
||||
const scenario: Scenario<InfraDocument> = async (runOptions) => {
|
||||
return {
|
||||
generate: ({ range, clients: { infraEsClient } }) => {
|
||||
const { numContainers = 5 } = runOptions.scenarioOpts || {};
|
||||
const { logger } = runOptions;
|
||||
|
||||
const CONTAINERS = Array(numContainers)
|
||||
.fill(0)
|
||||
.map((_, idx) => infra.k8sContainer(`container-${idx}`, `pod-${idx}`, `node-${idx}`));
|
||||
|
||||
const containers = range
|
||||
.interval('30s')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
CONTAINERS.flatMap((container) => [container.metrics().timestamp(timestamp)])
|
||||
);
|
||||
|
||||
return [
|
||||
withClient(
|
||||
infraEsClient,
|
||||
logger.perf('generating_infra_containers', () => containers)
|
||||
),
|
||||
];
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default scenario;
|
|
@ -123,6 +123,8 @@ export const OBSERVABILITY_ENABLE_COMPARISON_BY_DEFAULT_ID =
|
|||
'observability:enableComparisonByDefault';
|
||||
export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID =
|
||||
'observability:enableInfrastructureHostsView';
|
||||
export const OBSERVABILITY_ENABLE_CONTAINER_ASSET_VIEW_ID =
|
||||
'observability:enableContainerAssetView';
|
||||
export const OBSERVABILITY_ENABLE_INFRASTRUCTURE_ASSET_CUSTOM_DASHBOARDS_ID =
|
||||
'observability:enableInfrastructureAssetCustomDashboards';
|
||||
export const OBSERVABILITY_ENABLE_INSPECT_ES_QUERIES_ID = 'observability:enableInspectEsQueries';
|
||||
|
|
|
@ -627,6 +627,10 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
|
|||
type: 'boolean',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
},
|
||||
'observability:enableInfrastructureContainerAssetView': {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
},
|
||||
'observability:enableInfrastructureProfilingIntegration': {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
|
|
|
@ -46,6 +46,7 @@ export interface UsageStats {
|
|||
'observability:apmAWSLambdaPriceFactor': string;
|
||||
'observability:apmAWSLambdaRequestCostPerMillion': number;
|
||||
'observability:enableInfrastructureHostsView': boolean;
|
||||
'observability:enableInfrastructureContainerAssetView': boolean;
|
||||
'observability:enableInfrastructureProfilingIntegration': boolean;
|
||||
'observability:enableInfrastructureAssetCustomDashboards': boolean;
|
||||
'observability:apmAgentExplorerView': boolean;
|
||||
|
|
|
@ -10404,6 +10404,12 @@
|
|||
"description": "Non-default value of setting."
|
||||
}
|
||||
},
|
||||
"observability:enableInfrastructureContainerAssetView":{
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "Non-default value of setting."
|
||||
}
|
||||
},
|
||||
"observability:enableInfrastructureProfilingIntegration": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
|
|
|
@ -10,76 +10,107 @@ import { i18n } from '@kbn/i18n';
|
|||
import React from 'react';
|
||||
import { ContentTabIds, type Tab } from '../../components/asset_details/types';
|
||||
|
||||
export const commonFlyoutTabs: Tab[] = [
|
||||
{
|
||||
id: ContentTabIds.OVERVIEW,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.overview', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.METADATA,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.metadata', {
|
||||
defaultMessage: 'Metadata',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.METRICS,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.metrics', {
|
||||
defaultMessage: 'Metrics',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.PROCESSES,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.processes', {
|
||||
defaultMessage: 'Processes',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.PROFILING,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.profiling', {
|
||||
defaultMessage: 'Universal Profiling',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.LOGS,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.logs', {
|
||||
defaultMessage: 'Logs',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.ANOMALIES,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.anomalies', {
|
||||
defaultMessage: 'Anomalies',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.OSQUERY,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.osquery', {
|
||||
defaultMessage: 'Osquery',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: ContentTabIds.DASHBOARDS,
|
||||
name: i18n.translate('xpack.infra.infra.nodeDetails.tabs.dashboards', {
|
||||
defaultMessage: 'Dashboards',
|
||||
}),
|
||||
append: (
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.infra.customDashboards.technicalPreviewBadgeLabel', {
|
||||
defaultMessage: 'Technical preview',
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.infra.customDashboards.technicalPreviewBadgeDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.',
|
||||
}
|
||||
)}
|
||||
iconType="beaker"
|
||||
size="s"
|
||||
style={{ verticalAlign: 'middle' }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
const overviewTab: Tab = {
|
||||
id: ContentTabIds.OVERVIEW,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.overview.title', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
};
|
||||
|
||||
const metadataTab: Tab = {
|
||||
id: ContentTabIds.METADATA,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.metadata.title', {
|
||||
defaultMessage: 'Metadata',
|
||||
}),
|
||||
};
|
||||
|
||||
const metricsTab: Tab = {
|
||||
id: ContentTabIds.METRICS,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.metrics.title', {
|
||||
defaultMessage: 'Metrics',
|
||||
}),
|
||||
};
|
||||
|
||||
const processesTab: Tab = {
|
||||
id: ContentTabIds.PROCESSES,
|
||||
name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.processes', {
|
||||
defaultMessage: 'Processes',
|
||||
}),
|
||||
};
|
||||
|
||||
const profilingTab: Tab = {
|
||||
id: ContentTabIds.PROFILING,
|
||||
name: i18n.translate('xpack.infra.metrics.nodeDetails.tabs.profiling', {
|
||||
defaultMessage: 'Universal Profiling',
|
||||
}),
|
||||
};
|
||||
|
||||
const logsTab: Tab = {
|
||||
id: ContentTabIds.LOGS,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.logs.title', {
|
||||
defaultMessage: 'Logs',
|
||||
}),
|
||||
};
|
||||
|
||||
const anomaliesTab: Tab = {
|
||||
id: ContentTabIds.ANOMALIES,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.anomalies', {
|
||||
defaultMessage: 'Anomalies',
|
||||
}),
|
||||
};
|
||||
|
||||
const osqueryTab: Tab = {
|
||||
id: ContentTabIds.OSQUERY,
|
||||
name: i18n.translate('xpack.infra.nodeDetails.tabs.osquery', {
|
||||
defaultMessage: 'Osquery',
|
||||
}),
|
||||
};
|
||||
|
||||
const dashboardsTab: Tab = {
|
||||
id: ContentTabIds.DASHBOARDS,
|
||||
name: i18n.translate('xpack.infra.infra.nodeDetails.tabs.dashboards', {
|
||||
defaultMessage: 'Dashboards',
|
||||
}),
|
||||
append: (
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate('xpack.infra.customDashboards.technicalPreviewBadgeLabel', {
|
||||
defaultMessage: 'Technical preview',
|
||||
})}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.infra.customDashboards.technicalPreviewBadgeDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.',
|
||||
}
|
||||
)}
|
||||
iconType="beaker"
|
||||
size="s"
|
||||
style={{ verticalAlign: 'middle' }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
export const hostDetailsTabs: Tab[] = [
|
||||
overviewTab,
|
||||
metadataTab,
|
||||
metricsTab,
|
||||
processesTab,
|
||||
profilingTab,
|
||||
logsTab,
|
||||
anomaliesTab,
|
||||
osqueryTab,
|
||||
dashboardsTab,
|
||||
];
|
||||
// Profiling and Logs tab would be added in next iteration
|
||||
export const containerDetailsTabs: Tab[] = [overviewTab, metadataTab];
|
||||
|
||||
export const getAssetDetailsTabs = (type: string): Tab[] => {
|
||||
switch (type) {
|
||||
case 'host':
|
||||
return hostDetailsTabs;
|
||||
case 'container':
|
||||
return containerDetailsTabs;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics';
|
||||
export const HOST_METRICS_DOTTED_LINES_DOC_HREF = 'https://ela.st/docs-infra-why-dotted';
|
||||
export const CONTAINER_METRICS_DOC_HREF = 'https://ela.st/docs-infra-docker-container-metrics';
|
||||
|
||||
export const KPI_CHART_HEIGHT = 150;
|
||||
export const METRIC_CHART_HEIGHT = 300;
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { LensConfig, LensDataviewDataset } from '@kbn/lens-embeddable-utils
|
|||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { useDataView } from '../../../hooks/use_data_view';
|
||||
import { METRIC_CHART_HEIGHT } from '../../../common/visualizations/constants';
|
||||
import { buildCombinedHostsFilter } from '../../../utils/filters/build';
|
||||
import { buildCombinedAssetFilter } from '../../../utils/filters/build';
|
||||
import { type BrushEndArgs, LensChart, type OnFilterEvent, LensChartProps } from '../../lens';
|
||||
import { useDatePickerContext } from '../hooks/use_date_picker';
|
||||
import { extractRangeFromChartFilterEvent } from './chart_utils';
|
||||
|
@ -31,7 +31,7 @@ export const Chart = ({ id, queryField, overrides, dateRange, assetId, ...props
|
|||
|
||||
const filters = useMemo(() => {
|
||||
return [
|
||||
buildCombinedHostsFilter({
|
||||
buildCombinedAssetFilter({
|
||||
field: queryField,
|
||||
values: [assetId],
|
||||
dataView,
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { EuiText, EuiLink } from '@elastic/eui';
|
||||
import { useDockerContainerPageViewMetricsCharts } from '../hooks/use_container_metrics_charts';
|
||||
import { Section } from '../components/section';
|
||||
import { ChartsGrid } from '../charts_grid/charts_grid';
|
||||
import { Chart } from './chart';
|
||||
import { TitleWithTooltip } from '../components/section_title';
|
||||
import { CONTAINER_METRIC_GROUP_TITLES } from '../translations';
|
||||
import { CONTAINER_METRICS_DOC_HREF } from '../../../common/visualizations/constants';
|
||||
import { MetricsChartsFields, ContainerMetricTypes } from './types';
|
||||
|
||||
interface Props extends MetricsChartsFields {
|
||||
metric: ContainerMetricTypes;
|
||||
}
|
||||
|
||||
const FRAGMENT_BASE = 'key-metrics';
|
||||
|
||||
export const DockerCharts = React.forwardRef<HTMLDivElement, Props>(
|
||||
({ assetId, dataView, dateRange, metric }, ref) => {
|
||||
const { charts } = useDockerContainerPageViewMetricsCharts({
|
||||
metric,
|
||||
metricsDataViewId: dataView?.id,
|
||||
});
|
||||
return (
|
||||
<Section
|
||||
title={
|
||||
<TitleWithTooltip
|
||||
title={CONTAINER_METRIC_GROUP_TITLES[metric]}
|
||||
tooltipContent={
|
||||
<EuiText size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.container.toolTip"
|
||||
defaultMessage="See container-related {link} for more information"
|
||||
values={{
|
||||
link: (
|
||||
<EuiLink
|
||||
data-test-subj="infraAssetDetailsViewContainerMetricsDocumentationLink"
|
||||
href={`${CONTAINER_METRICS_DOC_HREF}#${FRAGMENT_BASE}-${metric}`}
|
||||
target="_blank"
|
||||
className={cx({
|
||||
[css`
|
||||
text-transform: lowercase;
|
||||
`]: metric !== 'cpu',
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.container.toolTip.linkText"
|
||||
defaultMessage="{metric} metrics"
|
||||
values={{ metric: CONTAINER_METRIC_GROUP_TITLES[metric] }}
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
}
|
||||
data-test-subj={`infraAssetDetailsDockerChartsSection${metric}`}
|
||||
id="dockerContainerCharts"
|
||||
ref={ref}
|
||||
>
|
||||
<ChartsGrid columns={2}>
|
||||
{charts.map((chart) => (
|
||||
<Chart
|
||||
key={chart.id}
|
||||
{...chart}
|
||||
assetId={assetId}
|
||||
dateRange={dateRange}
|
||||
queryField={findInventoryFields('container').id}
|
||||
/>
|
||||
))}
|
||||
</ChartsGrid>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -5,8 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { EuiText, EuiLink, EuiButtonEmpty } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
|
@ -16,16 +14,12 @@ import { HOST_METRIC_GROUP_TITLES } from '../translations';
|
|||
import { Section } from '../components/section';
|
||||
import { ChartsGrid } from '../charts_grid/charts_grid';
|
||||
import { Chart } from './chart';
|
||||
import { type HostMetricTypes, useHostCharts } from '../hooks/use_metrics_charts';
|
||||
import { useHostCharts } from '../hooks/use_host_metrics_charts';
|
||||
import { TitleWithTooltip } from '../components/section_title';
|
||||
import { MetricsChartsFields, HostMetricTypes } from './types';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
dateRange: TimeRange;
|
||||
dataView?: DataView;
|
||||
overview?: boolean;
|
||||
interface Props extends MetricsChartsFields {
|
||||
metric: Exclude<HostMetricTypes, 'kpi'>;
|
||||
onShowAll?: (metric: string) => void;
|
||||
}
|
||||
|
||||
const FRAGMENT_BASE = 'key-metrics';
|
||||
|
|
|
@ -6,4 +6,5 @@
|
|||
*/
|
||||
|
||||
export { HostCharts } from './host_charts';
|
||||
export { KubernetesCharts } from './kubernetes_charts';
|
||||
export { KubernetesNodeCharts, KubernetesContainerCharts } from './kubernetes_charts';
|
||||
export { DockerCharts } from './docker_charts';
|
||||
|
|
|
@ -5,66 +5,124 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { EuiButtonEmpty } from '@elastic/eui';
|
||||
import { EuiButtonEmpty, EuiText, EuiLink } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { useKubernetesCharts } from '../hooks/use_metrics_charts';
|
||||
import { useKubernetesCharts } from '../hooks/use_host_metrics_charts';
|
||||
import { Section } from '../components/section';
|
||||
import { SectionTitle } from '../components/section_title';
|
||||
import { HOST_METRIC_GROUP_TITLES } from '../translations';
|
||||
import { SectionTitle, TitleWithTooltip } from '../components/section_title';
|
||||
import { CONTAINER_METRIC_GROUP_TITLES, HOST_METRIC_GROUP_TITLES } from '../translations';
|
||||
import { INTEGRATIONS } from '../constants';
|
||||
import { ChartsGrid } from '../charts_grid/charts_grid';
|
||||
import { Chart } from './chart';
|
||||
import { useIntegrationCheck } from '../hooks/use_integration_check';
|
||||
import { useK8sContainerPageViewMetricsCharts } from '../hooks/use_container_metrics_charts';
|
||||
import { CONTAINER_METRICS_DOC_HREF } from '../../../common/visualizations/constants';
|
||||
import { ContainerMetricTypes, MetricsChartsFields } from './types';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
dateRange: TimeRange;
|
||||
dataView?: DataView;
|
||||
overview?: boolean;
|
||||
onShowAll?: (metric: string) => void;
|
||||
}
|
||||
const FRAGMENT_BASE = 'key-metrics';
|
||||
|
||||
export const KubernetesCharts = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
Props & { onShowAll?: (metric: string) => void }
|
||||
>(({ assetId, dataView, dateRange, onShowAll, overview }, ref) => {
|
||||
const { charts } = useKubernetesCharts({
|
||||
dataViewId: dataView?.id,
|
||||
options: { overview },
|
||||
});
|
||||
export const KubernetesNodeCharts = React.forwardRef<HTMLDivElement, MetricsChartsFields>(
|
||||
({ assetId, dataView, dateRange, onShowAll, overview }, ref) => {
|
||||
const { charts } = useKubernetesCharts({
|
||||
dataViewId: dataView?.id,
|
||||
options: { overview },
|
||||
});
|
||||
|
||||
const hasIntegration = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetes });
|
||||
const hasIntegration = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetesNode });
|
||||
|
||||
if (!hasIntegration) {
|
||||
return null;
|
||||
if (!hasIntegration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Section
|
||||
title={<SectionTitle title={HOST_METRIC_GROUP_TITLES.kubernetes} />}
|
||||
data-test-subj="infraAssetDetailsKubernetesChartsSection"
|
||||
id="kubernetes"
|
||||
ref={ref}
|
||||
extraAction={
|
||||
onShowAll ? (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="infraAssetDetailsKubernetesChartsShowAllButton"
|
||||
onClick={() => onShowAll('kubernetes')}
|
||||
size="xs"
|
||||
flush="both"
|
||||
iconSide="right"
|
||||
iconType="sortRight"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.kubernetes.showAllButton"
|
||||
defaultMessage="Show all"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<ChartsGrid columns={2}>
|
||||
{charts.map((chart) => (
|
||||
<Chart
|
||||
key={chart.id}
|
||||
{...chart}
|
||||
assetId={assetId}
|
||||
dateRange={dateRange}
|
||||
queryField={findInventoryFields('host').id}
|
||||
/>
|
||||
))}
|
||||
</ChartsGrid>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const KubernetesContainerCharts = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
MetricsChartsFields & { metric: ContainerMetricTypes }
|
||||
>(({ assetId, dataView, dateRange, metric }, ref) => {
|
||||
const { charts } = useK8sContainerPageViewMetricsCharts({
|
||||
metric,
|
||||
metricsDataViewId: dataView?.id,
|
||||
});
|
||||
return (
|
||||
<Section
|
||||
title={<SectionTitle title={HOST_METRIC_GROUP_TITLES.kubernetes} />}
|
||||
data-test-subj="infraAssetDetailsKubernetesChartsSection"
|
||||
id="kubernetes"
|
||||
ref={ref}
|
||||
extraAction={
|
||||
onShowAll ? (
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="infraAssetDetailsKubernetesChartsShowAllButton"
|
||||
onClick={() => onShowAll('kubernetes')}
|
||||
size="xs"
|
||||
flush="both"
|
||||
iconSide="right"
|
||||
iconType="sortRight"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.kubernetes.showAllButton"
|
||||
defaultMessage="Show all"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
) : null
|
||||
title={
|
||||
<TitleWithTooltip
|
||||
title={CONTAINER_METRIC_GROUP_TITLES[metric]}
|
||||
tooltipContent={
|
||||
<EuiText size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.container.k8s.toolTip"
|
||||
defaultMessage="See container-related {link} for more information"
|
||||
values={{
|
||||
link: (
|
||||
// confirm the link, there's not documentation for k8s container metrics
|
||||
<EuiLink
|
||||
data-test-subj="infraAssetDetailsViewContainerK8sMetricsDocumentationLink"
|
||||
href={`${CONTAINER_METRICS_DOC_HREF}#${FRAGMENT_BASE}-${metric}`}
|
||||
target="_blank"
|
||||
className={cx({
|
||||
[css`
|
||||
text-transform: lowercase;
|
||||
`]: metric !== 'cpu',
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.assetDetails.charts.container.k8s.toolTip.linkText"
|
||||
defaultMessage="{metric} metrics"
|
||||
values={{ metric: CONTAINER_METRIC_GROUP_TITLES[metric] }}
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
}
|
||||
data-test-subj="infraAssetDetailsK8ContainerChartsSection"
|
||||
id="k8sContainerCharts"
|
||||
ref={ref}
|
||||
>
|
||||
<ChartsGrid columns={2}>
|
||||
{charts.map((chart) => (
|
||||
|
@ -73,7 +131,7 @@ export const KubernetesCharts = React.forwardRef<
|
|||
{...chart}
|
||||
assetId={assetId}
|
||||
dateRange={dateRange}
|
||||
queryField={findInventoryFields('host').id}
|
||||
queryField={findInventoryFields('container').id}
|
||||
/>
|
||||
))}
|
||||
</ChartsGrid>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
|
||||
export type HostMetricTypes = 'cpu' | 'memory' | 'network' | 'disk' | 'log' | 'kpi';
|
||||
export type KubernetesContainerMetrics = 'cpu' | 'memory';
|
||||
export type DockerContainerMetrics = 'cpu' | 'memory' | 'network' | 'disk';
|
||||
export type ContainerMetricTypes = KubernetesContainerMetrics | DockerContainerMetrics;
|
||||
|
||||
export interface MetricsChartsFields {
|
||||
assetId: string;
|
||||
dateRange: TimeRange;
|
||||
dataView?: DataView;
|
||||
overview?: boolean;
|
||||
onShowAll?: (metric: string) => void;
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiFlexItem, useEuiTheme } from '@elastic/eui';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { Filter, Query, TimeRange } from '@kbn/es-query';
|
||||
import { Kpi } from './kpi';
|
||||
import {
|
||||
useK8sContainerKpiCharts,
|
||||
useDockerContainerKpiCharts,
|
||||
} from '../../hooks/use_container_metrics_charts';
|
||||
import { useIntegrationCheck } from '../../hooks/use_integration_check';
|
||||
import { INTEGRATIONS } from '../../constants';
|
||||
|
||||
export interface ContainerKpiChartsProps {
|
||||
dataView?: DataView;
|
||||
dateRange: TimeRange;
|
||||
query?: Query;
|
||||
filters?: Filter[];
|
||||
searchSessionId?: string;
|
||||
options?: {
|
||||
getSubtitle?: (formulaValue: string) => string;
|
||||
};
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export const ContainerKpiCharts = ({
|
||||
dateRange,
|
||||
dataView,
|
||||
filters,
|
||||
options,
|
||||
query,
|
||||
searchSessionId,
|
||||
loading = false,
|
||||
}: ContainerKpiChartsProps) => {
|
||||
const isK8Container = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetesContainer });
|
||||
|
||||
return isK8Container ? (
|
||||
<KubernetesKpiCharts
|
||||
dateRange={dateRange}
|
||||
dataView={dataView}
|
||||
filters={filters}
|
||||
options={options}
|
||||
query={query}
|
||||
searchSessionId={searchSessionId}
|
||||
loading={loading}
|
||||
/>
|
||||
) : (
|
||||
<DockerKpiCharts
|
||||
dateRange={dateRange}
|
||||
dataView={dataView}
|
||||
filters={filters}
|
||||
options={options}
|
||||
query={query}
|
||||
searchSessionId={searchSessionId}
|
||||
loading={loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const DockerKpiCharts = ({
|
||||
dateRange,
|
||||
dataView,
|
||||
filters,
|
||||
options,
|
||||
query,
|
||||
searchSessionId,
|
||||
loading = false,
|
||||
}: ContainerKpiChartsProps) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const charts = useDockerContainerKpiCharts({
|
||||
dataViewId: dataView?.id,
|
||||
options: {
|
||||
getSubtitle: options?.getSubtitle,
|
||||
seriesColor: euiTheme.colors.lightestShade,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{charts.map((chartProps, index) => (
|
||||
<EuiFlexItem key={index}>
|
||||
<Kpi
|
||||
{...chartProps}
|
||||
dateRange={dateRange}
|
||||
filters={filters}
|
||||
query={query}
|
||||
searchSessionId={searchSessionId}
|
||||
loading={loading}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const KubernetesKpiCharts = ({
|
||||
dateRange,
|
||||
dataView,
|
||||
filters,
|
||||
options,
|
||||
query,
|
||||
searchSessionId,
|
||||
loading = false,
|
||||
}: ContainerKpiChartsProps) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const charts = useK8sContainerKpiCharts({
|
||||
dataViewId: dataView?.id,
|
||||
options: {
|
||||
getSubtitle: options?.getSubtitle,
|
||||
seriesColor: euiTheme.colors.lightestShade,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{charts.map((chartProps, index) => (
|
||||
<EuiFlexItem key={index}>
|
||||
<Kpi
|
||||
{...chartProps}
|
||||
dateRange={dateRange}
|
||||
filters={filters}
|
||||
query={query}
|
||||
searchSessionId={searchSessionId}
|
||||
loading={loading}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -10,7 +10,7 @@ import { EuiFlexItem, useEuiTheme } from '@elastic/eui';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { Filter, Query, TimeRange } from '@kbn/es-query';
|
||||
import { Kpi } from './kpi';
|
||||
import { useHostKpiCharts } from '../../hooks/use_metrics_charts';
|
||||
import { useHostKpiCharts } from '../../hooks/use_host_metrics_charts';
|
||||
|
||||
export interface HostKpiChartsProps {
|
||||
dataView?: DataView;
|
||||
|
|
|
@ -15,5 +15,7 @@ export const APM_HOST_FILTER_FIELD = 'host.hostname';
|
|||
export const ASSET_DETAILS_URL_STATE_KEY = 'assetDetails';
|
||||
|
||||
export const INTEGRATIONS = {
|
||||
[INTEGRATION_NAME.kubernetes]: 'kubernetes.node',
|
||||
[INTEGRATION_NAME.kubernetesNode]: 'kubernetes.node',
|
||||
[INTEGRATION_NAME.kubernetesContainer]: 'kubernetes.container',
|
||||
[INTEGRATION_NAME.docker]: 'docker',
|
||||
};
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { ContainerMetricTypes } from '../charts/types';
|
||||
import {
|
||||
useK8sContainerPageViewMetricsCharts,
|
||||
useDockerContainerPageViewMetricsCharts,
|
||||
useDockerContainerKpiCharts,
|
||||
useK8sContainerKpiCharts,
|
||||
} from './use_container_metrics_charts';
|
||||
|
||||
const metricsDataViewId = 'metricsDataViewId';
|
||||
const getContainerChartsExpectedOrder = (metric: ContainerMetricTypes): string[] => {
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return ['cpuUsage'];
|
||||
case 'memory':
|
||||
return ['memoryUsage'];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const getK8sContainerChartsExpectedOrder = (metric: ContainerMetricTypes): string[] => {
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return ['k8sCpuUsage'];
|
||||
case 'memory':
|
||||
return ['k8sMemoryUsage'];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
describe('useDockerContainerCharts', () => {
|
||||
describe.each<[ContainerMetricTypes]>([['cpu'], ['memory']])('%s', (item) => {
|
||||
test.each<[ContainerMetricTypes]>([[item]])(
|
||||
'should return an array of charts with correct order for metric "%s"',
|
||||
async (metric) => {
|
||||
const expectedOrder = getContainerChartsExpectedOrder(metric);
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useDockerContainerPageViewMetricsCharts({ metricsDataViewId, metric })
|
||||
);
|
||||
await waitForNextUpdate();
|
||||
|
||||
const { charts } = result.current;
|
||||
|
||||
expect(charts).toHaveLength(expectedOrder.length);
|
||||
|
||||
charts.forEach((chart, index) => {
|
||||
expect(chart).toHaveProperty('id', expectedOrder[index]);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useDockerKPIMetricsCharts', () => {
|
||||
it('should return an array of charts with correct order', async () => {
|
||||
const expectedOrder = ['cpuUsage', 'memoryUsage'];
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useDockerContainerKpiCharts({ dataViewId: metricsDataViewId })
|
||||
);
|
||||
await waitForNextUpdate();
|
||||
expect(result.current).toHaveLength(expectedOrder.length);
|
||||
result.current.forEach((chart, index) => {
|
||||
expect(chart).toHaveProperty('id', expectedOrder[index]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('useK8sContainerCharts', () => {
|
||||
describe.each<[ContainerMetricTypes]>([['cpu'], ['memory']])('%s', (item) => {
|
||||
test.each<[ContainerMetricTypes]>([[item]])(
|
||||
'should return an array of charts with correct order for metric "%s"',
|
||||
async (metric) => {
|
||||
const expectedOrder = getK8sContainerChartsExpectedOrder(metric);
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useK8sContainerPageViewMetricsCharts({ metricsDataViewId, metric })
|
||||
);
|
||||
await waitForNextUpdate();
|
||||
|
||||
const { charts } = result.current;
|
||||
|
||||
expect(charts).toHaveLength(expectedOrder.length);
|
||||
|
||||
charts.forEach((chart, index) => {
|
||||
expect(chart).toHaveProperty('id', expectedOrder[index]);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useK8sContainerKPIMetricsCharts', () => {
|
||||
it('should return an array of charts with correct order', async () => {
|
||||
const expectedOrder = ['k8sCpuUsage', 'k8sMemoryUsage'];
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useK8sContainerKpiCharts({ dataViewId: metricsDataViewId })
|
||||
);
|
||||
await waitForNextUpdate();
|
||||
expect(result.current).toHaveLength(expectedOrder.length);
|
||||
result.current.forEach((chart, index) => {
|
||||
expect(chart).toHaveProperty('id', expectedOrder[index]);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { ContainerMetricTypes } from '../charts/types';
|
||||
|
||||
const getSubtitleFromFormula = (value: string) =>
|
||||
value.startsWith('max')
|
||||
? i18n.translate('xpack.infra.containerViewPage.kpi.subtitle.max', { defaultMessage: 'Max' })
|
||||
: i18n.translate('xpack.infra.assetDetails.kpi.subtitle.average', {
|
||||
defaultMessage: 'Average',
|
||||
});
|
||||
|
||||
export const useDockerContainerPageViewMetricsCharts = ({
|
||||
metric,
|
||||
metricsDataViewId,
|
||||
}: {
|
||||
metric: ContainerMetricTypes;
|
||||
metricsDataViewId?: string;
|
||||
}) => {
|
||||
const { value: charts = [], error } = useAsync(async () => {
|
||||
const containerCharts = await getDockerContainerCharts(metric);
|
||||
|
||||
return containerCharts.map((chart) => {
|
||||
return {
|
||||
...chart,
|
||||
...(metricsDataViewId && {
|
||||
dataset: {
|
||||
index: metricsDataViewId,
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
}, [metricsDataViewId]);
|
||||
|
||||
return { charts, error };
|
||||
};
|
||||
|
||||
const getDockerContainerCharts = async (metric: ContainerMetricTypes) => {
|
||||
const model = findInventoryModel('container');
|
||||
const { cpu, memory } = await model.metrics.getCharts();
|
||||
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return [cpu.xy.dockerContainerCpuUsage];
|
||||
case 'memory':
|
||||
return [memory.xy.dockerContainerMemoryUsage];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const useK8sContainerPageViewMetricsCharts = ({
|
||||
metric,
|
||||
metricsDataViewId,
|
||||
}: {
|
||||
metric: ContainerMetricTypes;
|
||||
metricsDataViewId?: string;
|
||||
}) => {
|
||||
const { value: charts = [], error } = useAsync(async () => {
|
||||
const containerK8sCharts = await getK8sContainerCharts(metric);
|
||||
|
||||
return containerK8sCharts.map((chart) => {
|
||||
return {
|
||||
...chart,
|
||||
...(metricsDataViewId && {
|
||||
dataset: {
|
||||
index: metricsDataViewId,
|
||||
},
|
||||
}),
|
||||
};
|
||||
});
|
||||
}, [metricsDataViewId]);
|
||||
|
||||
return { charts, error };
|
||||
};
|
||||
|
||||
const getK8sContainerCharts = async (metric: ContainerMetricTypes) => {
|
||||
const model = findInventoryModel('container');
|
||||
const { cpu, memory } = await model.metrics.getCharts();
|
||||
|
||||
switch (metric) {
|
||||
case 'cpu':
|
||||
return [cpu.xy.k8sContainerCpuUsage];
|
||||
case 'memory':
|
||||
return [memory.xy.k8sContainerMemoryUsage];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const useDockerContainerKpiCharts = ({
|
||||
dataViewId,
|
||||
options,
|
||||
}: {
|
||||
dataViewId?: string;
|
||||
options?: { seriesColor: string; getSubtitle?: (formulaValue: string) => string };
|
||||
}) => {
|
||||
const { value: charts = [] } = useAsync(async () => {
|
||||
const model = findInventoryModel('container');
|
||||
const { cpu, memory } = await model.metrics.getCharts();
|
||||
|
||||
return [cpu.metric.dockerContainerCpuUsage, memory.metric.dockerContainerMemoryUsage].map(
|
||||
(chart) => ({
|
||||
...chart,
|
||||
seriesColor: options?.seriesColor,
|
||||
decimals: 1,
|
||||
subtitle: getSubtitle(options, chart),
|
||||
...(dataViewId && {
|
||||
dataset: {
|
||||
index: dataViewId,
|
||||
},
|
||||
}),
|
||||
})
|
||||
);
|
||||
}, [dataViewId, options?.seriesColor, options?.getSubtitle]);
|
||||
|
||||
return charts;
|
||||
};
|
||||
|
||||
export const useK8sContainerKpiCharts = ({
|
||||
dataViewId,
|
||||
options,
|
||||
}: {
|
||||
dataViewId?: string;
|
||||
options?: { seriesColor: string; getSubtitle?: (formulaValue: string) => string };
|
||||
}) => {
|
||||
const { value: charts = [] } = useAsync(async () => {
|
||||
const model = findInventoryModel('container');
|
||||
const { cpu, memory } = await model.metrics.getCharts();
|
||||
|
||||
return [cpu.metric.k8sContainerCpuUsage, memory.metric.k8sContainerMemoryUsage].map(
|
||||
(chart) => ({
|
||||
...chart,
|
||||
seriesColor: options?.seriesColor,
|
||||
decimals: 1,
|
||||
subtitle: getSubtitle(options, chart),
|
||||
...(dataViewId && {
|
||||
dataset: {
|
||||
index: dataViewId,
|
||||
},
|
||||
}),
|
||||
})
|
||||
);
|
||||
}, [dataViewId, options?.seriesColor, options?.getSubtitle]);
|
||||
|
||||
return charts;
|
||||
};
|
||||
|
||||
function getSubtitle(
|
||||
options: { getSubtitle?: ((formulaValue: string) => string) | undefined } | undefined,
|
||||
chart: { value: string }
|
||||
) {
|
||||
return options?.getSubtitle
|
||||
? options?.getSubtitle(chart.value)
|
||||
: getSubtitleFromFormula(chart.value);
|
||||
}
|
|
@ -6,12 +6,8 @@
|
|||
*/
|
||||
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import {
|
||||
useHostKpiCharts,
|
||||
useHostCharts,
|
||||
useKubernetesCharts,
|
||||
type HostMetricTypes,
|
||||
} from './use_metrics_charts';
|
||||
import { HostMetricTypes } from '../charts/types';
|
||||
import { useHostKpiCharts, useHostCharts, useKubernetesCharts } from './use_host_metrics_charts';
|
||||
|
||||
const dataViewId = 'metricsDataViewId';
|
||||
const getHostChartsExpectedOrder = (metric: HostMetricTypes, overview: boolean): string[] => {
|
|
@ -8,8 +8,8 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { HostMetricTypes } from '../charts/types';
|
||||
|
||||
export type HostMetricTypes = 'cpu' | 'memory' | 'network' | 'disk' | 'log' | 'kpi';
|
||||
interface UseChartsOptions {
|
||||
overview?: boolean;
|
||||
}
|
||||
|
@ -101,9 +101,7 @@ export const useHostKpiCharts = ({
|
|||
...chart,
|
||||
seriesColor: options?.seriesColor,
|
||||
decimals: 1,
|
||||
subtitle: options?.getSubtitle
|
||||
? options?.getSubtitle(chart.value)
|
||||
: getSubtitleFromFormula(chart.value),
|
||||
subtitle: getSubtitle(options, chart),
|
||||
...(dataViewId && {
|
||||
dataset: {
|
||||
index: dataViewId,
|
||||
|
@ -151,3 +149,12 @@ const getHostsCharts = async ({
|
|||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
function getSubtitle(
|
||||
options: { getSubtitle?: ((formulaValue: string) => string) | undefined } | undefined,
|
||||
chart: { value: string }
|
||||
) {
|
||||
return options?.getSubtitle
|
||||
? options?.getSubtitle(chart.value)
|
||||
: getSubtitleFromFormula(chart.value);
|
||||
}
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
import { HostMetricTypes } from '../../hooks/use_metrics_charts';
|
||||
import { useDatePickerContext } from '../../hooks/use_date_picker';
|
||||
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
|
||||
import { useDataViewsContext } from '../../hooks/use_data_views';
|
||||
import { useIntersectingState } from '../../hooks/use_intersecting_state';
|
||||
import { MetricsTemplate } from './metrics_template';
|
||||
import { HostCharts, KubernetesCharts } from '../../charts';
|
||||
import { HostCharts, KubernetesNodeCharts } from '../../charts';
|
||||
import { HostMetricTypes } from '../../charts/types';
|
||||
|
||||
const METRIC_TYPES: Array<Exclude<HostMetricTypes, 'kpi'>> = [
|
||||
'cpu',
|
||||
|
@ -41,7 +41,7 @@ export const HostMetrics = () => {
|
|||
metric={metric}
|
||||
/>
|
||||
))}
|
||||
<KubernetesCharts
|
||||
<KubernetesNodeCharts
|
||||
assetId={asset.id}
|
||||
dataView={metrics.dataView}
|
||||
dateRange={state.dateRange}
|
||||
|
|
|
@ -9,38 +9,52 @@ import React, { useMemo } from 'react';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
|
||||
import {
|
||||
findInventoryFields,
|
||||
type InventoryItemType,
|
||||
} from '@kbn/metrics-data-access-plugin/common';
|
||||
import { buildCombinedAssetFilter } from '../../../../../utils/filters/build';
|
||||
import { HostKpiCharts } from '../../../components/kpis/host_kpi_charts';
|
||||
import { useLoadingStateContext } from '../../../hooks/use_loading_state';
|
||||
import { ContainerKpiCharts } from '../../../components/kpis/container_kpi_charts';
|
||||
|
||||
interface Props {
|
||||
dataView?: DataView;
|
||||
assetId: string;
|
||||
assetType: InventoryItemType;
|
||||
dateRange: TimeRange;
|
||||
}
|
||||
|
||||
export const KPIGrid = ({ assetId, dataView, dateRange }: Props) => {
|
||||
export const KPIGrid = ({ assetId, assetType, dataView, dateRange }: Props) => {
|
||||
const { searchSessionId } = useLoadingStateContext();
|
||||
|
||||
const filters = useMemo(() => {
|
||||
return [
|
||||
buildCombinedHostsFilter({
|
||||
field: findInventoryFields('host').id,
|
||||
buildCombinedAssetFilter({
|
||||
field: findInventoryFields(assetType).id,
|
||||
values: [assetId],
|
||||
dataView,
|
||||
}),
|
||||
];
|
||||
}, [dataView, assetId]);
|
||||
}, [dataView, assetId, assetType]);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup direction="row" gutterSize="s" data-test-subj="infraAssetDetailsKPIGrid">
|
||||
<HostKpiCharts
|
||||
dataView={dataView}
|
||||
filters={filters}
|
||||
dateRange={dateRange}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
{assetType === 'host' ? (
|
||||
<HostKpiCharts
|
||||
dataView={dataView}
|
||||
filters={filters}
|
||||
dateRange={dateRange}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
) : (
|
||||
<ContainerKpiCharts
|
||||
dataView={dataView}
|
||||
filters={filters}
|
||||
dateRange={dateRange}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexGrid } from '@elastic/eui';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { DockerCharts } from '../../../charts/docker_charts';
|
||||
import { INTEGRATIONS } from '../../../constants';
|
||||
import { useIntegrationCheck } from '../../../hooks/use_integration_check';
|
||||
import { KubernetesContainerCharts } from '../../../charts/kubernetes_charts';
|
||||
|
||||
interface Props {
|
||||
assetId: string;
|
||||
dateRange: TimeRange;
|
||||
dataView?: DataView;
|
||||
}
|
||||
|
||||
export const ContainerMetrics = (props: Props) => {
|
||||
const isK8sContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.kubernetesContainer });
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="m" direction="column">
|
||||
<EuiFlexGrid columns={2} gutterSize="s">
|
||||
{isK8sContainer ? (
|
||||
<>
|
||||
<KubernetesContainerCharts {...props} metric="cpu" />
|
||||
<KubernetesContainerCharts {...props} metric="memory" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DockerCharts {...props} metric="cpu" />
|
||||
<DockerCharts {...props} metric="memory" />
|
||||
</>
|
||||
)}
|
||||
</EuiFlexGrid>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexGrid } from '@elastic/eui';
|
|||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { useTabSwitcherContext } from '../../../hooks/use_tab_switcher';
|
||||
import { HostCharts, KubernetesCharts } from '../../../charts';
|
||||
import { HostCharts, KubernetesNodeCharts } from '../../../charts';
|
||||
import { ContentTabIds } from '../../../types';
|
||||
|
||||
interface Props {
|
||||
|
@ -33,7 +33,7 @@ export const HostMetrics = (props: Props) => {
|
|||
<HostCharts {...props} metric="network" onShowAll={onClick} overview />
|
||||
</EuiFlexGrid>
|
||||
<HostCharts {...props} metric="disk" onShowAll={onClick} overview />
|
||||
<KubernetesCharts {...props} onShowAll={onClick} overview />
|
||||
<KubernetesNodeCharts {...props} onShowAll={onClick} overview />
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import type { TimeRange } from '@kbn/es-query';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { HostMetrics } from './host_metrics';
|
||||
import { ContainerMetrics } from './container_metrics';
|
||||
import { Section } from '../../../components/section';
|
||||
import { MetricsSectionTitle } from '../section_titles';
|
||||
|
||||
|
@ -24,6 +25,8 @@ export const MetricsContent = ({ assetType, ...props }: Props) => {
|
|||
switch (assetType) {
|
||||
case 'host':
|
||||
return <HostMetrics {...props} />;
|
||||
case 'container':
|
||||
return <ContainerMetrics {...props} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -31,7 +34,7 @@ export const MetricsContent = ({ assetType, ...props }: Props) => {
|
|||
|
||||
return (
|
||||
<Section
|
||||
title={<MetricsSectionTitle />}
|
||||
title={<MetricsSectionTitle assetType={assetType} />}
|
||||
data-test-subj="infraAssetDetailsMetricsCollapsible"
|
||||
id="metrics"
|
||||
collapsible
|
||||
|
|
|
@ -48,21 +48,29 @@ export const Overview = () => {
|
|||
return (
|
||||
<EuiFlexGroup direction="column" gutterSize="m" ref={ref}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<KPIGrid assetId={asset.id} dateRange={state.dateRange} dataView={metrics.dataView} />
|
||||
<CpuProfilingPrompt />
|
||||
<KPIGrid
|
||||
assetId={asset.id}
|
||||
assetType={asset.type}
|
||||
dateRange={state.dateRange}
|
||||
dataView={metrics.dataView}
|
||||
/>
|
||||
{asset.type === 'host' ? <CpuProfilingPrompt /> : null}
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
{fetchMetadataError && !metadataLoading ? <MetadataErrorCallout /> : metadataSummarySection}
|
||||
<SectionSeparator />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<AlertsSummaryContent
|
||||
assetId={asset.id}
|
||||
assetType={asset.type}
|
||||
dateRange={state.dateRange}
|
||||
/>
|
||||
<SectionSeparator />
|
||||
</EuiFlexItem>
|
||||
{asset.type === 'host' ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<AlertsSummaryContent
|
||||
assetId={asset.id}
|
||||
assetType={asset.type}
|
||||
dateRange={state.dateRange}
|
||||
/>
|
||||
<SectionSeparator />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
{asset.type === 'host' ? (
|
||||
<EuiFlexItem grow={false}>
|
||||
<ServicesContent hostName={asset.id} dateRange={state.dateRange} />
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { HostMetricsExplanationContent } from '../../../lens';
|
||||
import { TitleWithTooltip } from '../../components/section_title';
|
||||
import { AlertsTooltipContent } from '../../components/alerts_tooltip_content';
|
||||
import { ServicesTooltipContent } from '../../components/services_tooltip_content';
|
||||
import { ContainerMetricsExplanationContent } from '../../../lens/metric_explanation/container_metrics_explanation_content';
|
||||
|
||||
export const MetricsSectionTitle = () => {
|
||||
export const MetricsSectionTitle = ({ assetType }: { assetType: InventoryItemType }) => {
|
||||
return (
|
||||
<TitleWithTooltip
|
||||
title={i18n.translate('xpack.infra.assetDetails.overview.metricsSectionTitle', {
|
||||
|
@ -19,7 +21,7 @@ export const MetricsSectionTitle = () => {
|
|||
})}
|
||||
data-test-subj="infraAssetDetailsMetricsTitle"
|
||||
tooltipTestSubj="infraAssetDetailsMetricsPopoverButton"
|
||||
tooltipContent={<HostMetricsExplanationContent />}
|
||||
tooltipContent={getTooltipContent(assetType)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -47,3 +49,12 @@ export const ServicesSectionTitle = () => (
|
|||
tooltipContent={<ServicesTooltipContent />}
|
||||
/>
|
||||
);
|
||||
|
||||
function getTooltipContent(assetType: InventoryItemType) {
|
||||
switch (assetType) {
|
||||
case 'host':
|
||||
return <HostMetricsExplanationContent />;
|
||||
default:
|
||||
return <ContainerMetricsExplanationContent />;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,3 +31,18 @@ export const HOST_METRIC_GROUP_TITLES = {
|
|||
defaultMessage: 'Kubernetes',
|
||||
}),
|
||||
};
|
||||
|
||||
export const CONTAINER_METRIC_GROUP_TITLES = {
|
||||
cpu: i18n.translate('xpack.infra.metricsGroup.containerCpu', {
|
||||
defaultMessage: 'CPU',
|
||||
}),
|
||||
memory: i18n.translate('xpack.infra.metricsGroup.containerMemory', {
|
||||
defaultMessage: 'Memory',
|
||||
}),
|
||||
network: i18n.translate('xpack.infra.metricsGroup.containerNetwork', {
|
||||
defaultMessage: 'Network',
|
||||
}),
|
||||
disk: i18n.translate('xpack.infra.metricsGroup.containerDisk', {
|
||||
defaultMessage: 'Disk',
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -98,5 +98,7 @@ export interface RouteState {
|
|||
export type DataViewOrigin = 'logs' | 'metrics';
|
||||
|
||||
export enum INTEGRATION_NAME {
|
||||
kubernetes = 'kubernetes',
|
||||
kubernetesNode = 'kubernetesNode',
|
||||
kubernetesContainer = 'kubernetesContainer',
|
||||
docker = 'docker',
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiText, EuiLink } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import {
|
||||
CONTAINER_METRICS_DOC_HREF,
|
||||
HOST_METRICS_DOTTED_LINES_DOC_HREF,
|
||||
} from '../../../common/visualizations/constants';
|
||||
|
||||
export const ContainerMetricsExplanationContent = () => {
|
||||
return (
|
||||
<EuiText size="xs">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.containerViewPage.metricsExplanation"
|
||||
defaultMessage="Showing metrics for your container(s)"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<EuiText size="xs">
|
||||
<EuiLink
|
||||
data-test-subj="containerViewMetricsDocumentationLink"
|
||||
href={CONTAINER_METRICS_DOC_HREF}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate('xpack.infra.containerViewPage.tooltip.whatAreTheseMetricsLink', {
|
||||
defaultMessage: 'What are these metrics?',
|
||||
})}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</p>
|
||||
<p>
|
||||
<EuiText size="xs">
|
||||
<EuiLink
|
||||
data-test-subj="containerViewMetricsDocumentationLink"
|
||||
href={HOST_METRICS_DOTTED_LINES_DOC_HREF}
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate('xpack.infra.hostsViewPage.tooltip.whyAmISeeingDottedLines', {
|
||||
defaultMessage: 'Why am I seeing dotted lines?',
|
||||
})}
|
||||
</EuiLink>
|
||||
</EuiText>
|
||||
</p>
|
||||
</EuiText>
|
||||
);
|
||||
};
|
|
@ -10,7 +10,7 @@ import { useSourceContext } from '../../../../../containers/metrics_source';
|
|||
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
|
||||
import type { HostNodeRow } from '../../hooks/use_hosts_table';
|
||||
import { AssetDetails } from '../../../../../components/asset_details';
|
||||
import { commonFlyoutTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
import { hostDetailsTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
|
||||
export interface Props {
|
||||
node: HostNodeRow;
|
||||
|
@ -32,7 +32,7 @@ export const FlyoutWrapper = ({ node: { name }, closeFlyout }: Props) => {
|
|||
showActionsColumn: true,
|
||||
},
|
||||
}}
|
||||
tabs={commonFlyoutTabs}
|
||||
tabs={hostDetailsTabs}
|
||||
links={['nodeDetails']}
|
||||
renderMode={{
|
||||
mode: 'flyout',
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { HostKpiCharts } from '../../../../../components/asset_details';
|
||||
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
|
||||
import { buildCombinedAssetFilter } from '../../../../../utils/filters/build';
|
||||
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
|
||||
import { useHostsViewContext } from '../../hooks/use_hosts_view';
|
||||
import { useHostCountContext } from '../../hooks/use_host_count';
|
||||
|
@ -26,7 +26,7 @@ export const KpiCharts = () => {
|
|||
const filters = shouldUseSearchCriteria
|
||||
? [...searchCriteria.filters, ...(searchCriteria.panelFilters ?? [])]
|
||||
: [
|
||||
buildCombinedHostsFilter({
|
||||
buildCombinedAssetFilter({
|
||||
field: 'host.name',
|
||||
values: hostNodes.map((p) => p.name),
|
||||
dataView,
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useUnifiedSearchContext } from '../../../hooks/use_unified_search';
|
|||
import { useLogsSearchUrlState } from '../../../hooks/use_logs_search_url_state';
|
||||
import { LogsLinkToStream } from './logs_link_to_stream';
|
||||
import { LogsSearchBar } from './logs_search_bar';
|
||||
import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build';
|
||||
import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build';
|
||||
import { useLogViewReference } from '../../../../../../hooks/use_log_view_reference';
|
||||
|
||||
export const LogsTabContent = () => {
|
||||
|
@ -27,7 +27,7 @@ export const LogsTabContent = () => {
|
|||
|
||||
const hostsFilterQuery = useMemo(
|
||||
() =>
|
||||
buildCombinedHostsFilter({
|
||||
buildCombinedAssetFilter({
|
||||
field: 'host.name',
|
||||
values: hostNodes.map((p) => p.name),
|
||||
}),
|
||||
|
|
|
@ -11,7 +11,7 @@ import { METRIC_CHART_HEIGHT } from '../../../../../../common/visualizations/con
|
|||
import { LensChart } from '../../../../../../components/lens';
|
||||
import { useUnifiedSearchContext } from '../../../hooks/use_unified_search';
|
||||
import { useHostsViewContext } from '../../../hooks/use_hosts_view';
|
||||
import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build';
|
||||
import { buildCombinedAssetFilter } from '../../../../../../utils/filters/build';
|
||||
import { useHostsTableContext } from '../../../hooks/use_hosts_table';
|
||||
import { useAfterLoadedState } from '../../../hooks/use_after_loaded_state';
|
||||
|
||||
|
@ -40,7 +40,7 @@ export const Chart = ({ id, ...chartProps }: ChartProps) => {
|
|||
return shouldUseSearchCriteria
|
||||
? [...searchCriteria.filters, ...(searchCriteria.panelFilters ?? [])]
|
||||
: [
|
||||
buildCombinedHostsFilter({
|
||||
buildCombinedAssetFilter({
|
||||
field: 'host.name',
|
||||
values: currentPage.map((p) => p.name),
|
||||
dataView,
|
||||
|
|
|
@ -29,7 +29,7 @@ import { useMetricsDataViewContext } from './use_metrics_data_view';
|
|||
import { ColumnHeader } from '../components/table/column_header';
|
||||
import { TABLE_COLUMN_LABEL, TABLE_CONTENT_LABEL } from '../translations';
|
||||
import { METRICS_TOOLTIP } from '../../../../common/visualizations';
|
||||
import { buildCombinedHostsFilter } from '../../../../utils/filters/build';
|
||||
import { buildCombinedAssetFilter } from '../../../../utils/filters/build';
|
||||
|
||||
/**
|
||||
* Columns and items types
|
||||
|
@ -151,7 +151,7 @@ export const useHostsTable = () => {
|
|||
return [];
|
||||
}
|
||||
const selectedHostNames = selectedItems.map(({ name }) => name);
|
||||
const newFilter = buildCombinedHostsFilter({
|
||||
const newFilter = buildCombinedAssetFilter({
|
||||
field: 'host.name',
|
||||
values: selectedHostNames,
|
||||
dataView,
|
||||
|
|
|
@ -12,7 +12,7 @@ import type { InfraWaffleMapOptions } from '../../../../../lib/lib';
|
|||
import { ContentTabIds } from '../../../../../components/asset_details/types';
|
||||
import { AssetDetails } from '../../../../../components/asset_details';
|
||||
import { useSourceContext } from '../../../../../containers/metrics_source';
|
||||
import { commonFlyoutTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
import { hostDetailsTabs } from '../../../../../common/asset_details_config/asset_details_tabs';
|
||||
|
||||
interface Props {
|
||||
assetName: string;
|
||||
|
@ -25,7 +25,7 @@ interface Props {
|
|||
}
|
||||
|
||||
const flyoutTabs = [
|
||||
...commonFlyoutTabs,
|
||||
...hostDetailsTabs,
|
||||
{
|
||||
id: ContentTabIds.LINK_TO_APM,
|
||||
name: i18n.translate('xpack.infra.assetDetails.tabs.linkToApm', {
|
||||
|
|
|
@ -57,7 +57,7 @@ export const WaffleInventorySwitcher: React.FC = () => {
|
|||
);
|
||||
const goToHost = useCallback(() => goToNodeType('host'), [goToNodeType]);
|
||||
const goToK8 = useCallback(() => goToNodeType('pod'), [goToNodeType]);
|
||||
const goToDocker = useCallback(() => goToNodeType('container'), [goToNodeType]);
|
||||
const goToContainer = useCallback(() => goToNodeType('container'), [goToNodeType]);
|
||||
const goToAwsEC2 = useCallback(() => goToNodeType('awsEC2'), [goToNodeType]);
|
||||
const goToAwsS3 = useCallback(() => goToNodeType('awsS3'), [goToNodeType]);
|
||||
const goToAwsRDS = useCallback(() => goToNodeType('awsRDS'), [goToNodeType]);
|
||||
|
@ -79,9 +79,9 @@ export const WaffleInventorySwitcher: React.FC = () => {
|
|||
onClick: goToK8,
|
||||
},
|
||||
{
|
||||
'data-test-subj': 'goToDocker',
|
||||
'data-test-subj': 'goToContainer',
|
||||
name: getDisplayNameForType('container'),
|
||||
onClick: goToDocker,
|
||||
onClick: goToContainer,
|
||||
},
|
||||
{
|
||||
name: 'AWS',
|
||||
|
@ -117,7 +117,7 @@ export const WaffleInventorySwitcher: React.FC = () => {
|
|||
],
|
||||
},
|
||||
] as EuiContextMenuPanelDescriptor[],
|
||||
[goToAwsEC2, goToAwsRDS, goToAwsS3, goToAwsSQS, goToDocker, goToHost, goToK8]
|
||||
[goToAwsEC2, goToAwsRDS, goToAwsS3, goToAwsSQS, goToContainer, goToHost, goToK8]
|
||||
);
|
||||
|
||||
const selectedText = useMemo(() => {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { SourceLoadingPage } from '../../../components/source_loading_page';
|
|||
import { useSourceContext } from '../../../containers/metrics_source';
|
||||
import { AssetDetails } from '../../../components/asset_details';
|
||||
import { MetricsPageTemplate } from '../page_template';
|
||||
import { commonFlyoutTabs } from '../../../common/asset_details_config/asset_details_tabs';
|
||||
import { getAssetDetailsTabs } from '../../../common/asset_details_config/asset_details_tabs';
|
||||
|
||||
export const AssetDetailPage = () => {
|
||||
const { isLoading, loadSourceFailureMessage, loadSource, source } = useSourceContext();
|
||||
|
@ -43,7 +43,7 @@ export const AssetDetailPage = () => {
|
|||
<AssetDetails
|
||||
assetId={nodeId}
|
||||
assetType={nodeType}
|
||||
tabs={commonFlyoutTabs}
|
||||
tabs={getAssetDetailsTabs(nodeType)}
|
||||
renderMode={{
|
||||
mode: 'page',
|
||||
}}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
import { EuiErrorBoundary } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { useRouteMatch } from 'react-router-dom';
|
||||
import { useUiSetting } from '@kbn/kibana-react-plugin/public';
|
||||
import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common';
|
||||
import { AssetDetailPage } from './asset_detail_page';
|
||||
import { MetricDetailPage } from './metric_detail_page';
|
||||
import { MetricsTimeProvider } from './hooks/use_metrics_time';
|
||||
|
@ -18,9 +20,12 @@ export const NodeDetail = () => {
|
|||
params: { type: nodeType },
|
||||
} = useRouteMatch<{ type: InventoryItemType; node: string }>();
|
||||
|
||||
const isContainerAssetViewEnabled = useUiSetting(enableInfrastructureContainerAssetView);
|
||||
|
||||
const showContainerAssetDetailPage = nodeType === 'container' && isContainerAssetViewEnabled;
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
{nodeType === 'host' ? (
|
||||
{nodeType === 'host' || showContainerAssetDetailPage ? (
|
||||
<AssetDetailPage />
|
||||
) : (
|
||||
<MetricsTimeProvider>
|
||||
|
|
|
@ -13,6 +13,7 @@ import React from 'react';
|
|||
import {
|
||||
enableInfrastructureHostsView,
|
||||
enableInfrastructureProfilingIntegration,
|
||||
enableInfrastructureContainerAssetView,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
import { useEditableSettings } from '@kbn/observability-shared-plugin/public';
|
||||
import { withSuspense } from '@kbn/shared-ux-utility';
|
||||
|
@ -83,6 +84,12 @@ export function FeaturesConfigurationPanel({
|
|||
unsavedChange={unsavedChanges[enableInfrastructureProfilingIntegration]}
|
||||
/>
|
||||
)}
|
||||
<FieldRow
|
||||
field={fields[enableInfrastructureContainerAssetView]}
|
||||
isSavingEnabled={true}
|
||||
onFieldChange={handleFieldChange}
|
||||
unsavedChange={unsavedChanges[enableInfrastructureContainerAssetView]}
|
||||
/>
|
||||
</FieldRowProvider>
|
||||
</EuiForm>
|
||||
);
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
useEditableSettings,
|
||||
} from '@kbn/observability-shared-plugin/public';
|
||||
import {
|
||||
enableInfrastructureContainerAssetView,
|
||||
enableInfrastructureHostsView,
|
||||
enableInfrastructureProfilingIntegration,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
|
@ -90,6 +91,7 @@ export const SourceConfigurationSettings = ({
|
|||
const infraUiSettings = useEditableSettings([
|
||||
enableInfrastructureHostsView,
|
||||
enableInfrastructureProfilingIntegration,
|
||||
enableInfrastructureContainerAssetView,
|
||||
]);
|
||||
|
||||
const resetAllUnsavedChanges = useCallback(() => {
|
||||
|
|
|
@ -16,7 +16,7 @@ import type { DataView } from '@kbn/data-views-plugin/common';
|
|||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import type { InfraCustomDashboardAssetType } from '../../../common/custom_dashboards';
|
||||
|
||||
export const buildCombinedHostsFilter = ({
|
||||
export const buildCombinedAssetFilter = ({
|
||||
field,
|
||||
values,
|
||||
dataView,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ALERT_TIME_RANGE } from '@kbn/rule-data-utils';
|
|||
import { BoolQuery, buildEsQuery, Filter, type TimeRange } from '@kbn/es-query';
|
||||
import type { AlertStatus } from '@kbn/observability-plugin/common/typings';
|
||||
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
|
||||
import { buildCombinedHostsFilter } from './build';
|
||||
import { buildCombinedAssetFilter } from './build';
|
||||
import { ALERT_STATUS_QUERY } from '../../components/shared/alerts/constants';
|
||||
|
||||
export interface AlertsEsQuery {
|
||||
|
@ -28,7 +28,7 @@ export const createAlertsEsQuery = ({
|
|||
const alertStatusFilter = createAlertStatusFilter(status);
|
||||
|
||||
const dateFilter = createDateFilter(dateRange);
|
||||
const hostsFilter = buildCombinedHostsFilter({
|
||||
const hostsFilter = buildCombinedAssetFilter({
|
||||
field: findInventoryFields('host').id,
|
||||
values: assetIds,
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import { InventoryModel } from '../types';
|
|||
|
||||
export { containerSnapshotMetricTypes } from './metrics';
|
||||
|
||||
export const container: InventoryModel = {
|
||||
export const container: InventoryModel<typeof metrics> = {
|
||||
id: 'container',
|
||||
displayName: i18n.translate('xpack.metricsData.inventoryModel.container.displayName', {
|
||||
defaultMessage: 'Docker Containers',
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
CPU_USAGE_LABEL,
|
||||
DEFAULT_XY_FITTING_FUNCTION,
|
||||
DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
DEFAULT_XY_YBOUNDS,
|
||||
} from '../../../shared/charts/constants';
|
||||
import { LensConfigWithId } from '../../../types';
|
||||
import { formulas } from '../formulas';
|
||||
|
||||
const dockerContainerCpuUsageXY: LensConfigWithId = {
|
||||
id: 'cpuUsage',
|
||||
chartType: 'xy',
|
||||
title: CPU_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'line',
|
||||
type: 'series',
|
||||
xAxis: '@timestamp',
|
||||
yAxis: [formulas.dockerContainerCpuUsage],
|
||||
},
|
||||
],
|
||||
...DEFAULT_XY_FITTING_FUNCTION,
|
||||
...DEFAULT_XY_HIDDEN_LEGEND,
|
||||
...DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
...DEFAULT_XY_YBOUNDS,
|
||||
};
|
||||
|
||||
const k8sContainerCpuUsageXY: LensConfigWithId = {
|
||||
id: 'k8sCpuUsage',
|
||||
chartType: 'xy',
|
||||
title: CPU_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'line',
|
||||
type: 'series',
|
||||
xAxis: '@timestamp',
|
||||
yAxis: [formulas.k8sContainerCpuUsage],
|
||||
},
|
||||
],
|
||||
...DEFAULT_XY_FITTING_FUNCTION,
|
||||
...DEFAULT_XY_HIDDEN_LEGEND,
|
||||
...DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
...DEFAULT_XY_YBOUNDS,
|
||||
};
|
||||
|
||||
const dockerContainerCpuUsageMetric: LensConfigWithId = {
|
||||
id: 'cpuUsage',
|
||||
chartType: 'metric',
|
||||
title: CPU_USAGE_LABEL,
|
||||
trendLine: true,
|
||||
...formulas.dockerContainerCpuUsage,
|
||||
};
|
||||
|
||||
const containerK8sCpuUsageMetric: LensConfigWithId = {
|
||||
id: 'k8sCpuUsage',
|
||||
chartType: 'metric',
|
||||
title: CPU_USAGE_LABEL,
|
||||
trendLine: true,
|
||||
...formulas.k8sContainerCpuUsage,
|
||||
};
|
||||
|
||||
export const cpu = {
|
||||
xy: {
|
||||
dockerContainerCpuUsage: dockerContainerCpuUsageXY,
|
||||
k8sContainerCpuUsage: k8sContainerCpuUsageXY,
|
||||
},
|
||||
metric: {
|
||||
dockerContainerCpuUsage: dockerContainerCpuUsageMetric,
|
||||
k8sContainerCpuUsage: containerK8sCpuUsageMetric,
|
||||
},
|
||||
} as const;
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { cpu } from './cpu';
|
||||
import { memory } from './memory';
|
||||
|
||||
export const charts = {
|
||||
cpu,
|
||||
memory,
|
||||
} as const;
|
||||
|
||||
export type ContainerCharts = typeof charts;
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { LensConfigWithId } from '../../../types';
|
||||
import {
|
||||
DEFAULT_XY_FITTING_FUNCTION,
|
||||
DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
DEFAULT_XY_YBOUNDS,
|
||||
MEMORY_USAGE_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
import { formulas } from '../formulas';
|
||||
|
||||
const dockerContainerMemoryUsageXY: LensConfigWithId = {
|
||||
id: 'memoryUsage',
|
||||
chartType: 'xy',
|
||||
title: MEMORY_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'line',
|
||||
type: 'series',
|
||||
xAxis: '@timestamp',
|
||||
yAxis: [formulas.dockerContainerMemoryUsage],
|
||||
},
|
||||
],
|
||||
...DEFAULT_XY_FITTING_FUNCTION,
|
||||
...DEFAULT_XY_HIDDEN_LEGEND,
|
||||
...DEFAULT_XY_YBOUNDS,
|
||||
...DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
};
|
||||
|
||||
const k8sContainerMemoryUsageXY: LensConfigWithId = {
|
||||
id: 'k8sMemoryUsage',
|
||||
chartType: 'xy',
|
||||
title: MEMORY_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'line',
|
||||
type: 'series',
|
||||
xAxis: '@timestamp',
|
||||
yAxis: [formulas.k8sContainerMemoryUsage],
|
||||
},
|
||||
],
|
||||
...DEFAULT_XY_FITTING_FUNCTION,
|
||||
...DEFAULT_XY_HIDDEN_LEGEND,
|
||||
...DEFAULT_XY_YBOUNDS,
|
||||
...DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
};
|
||||
|
||||
const dockerContainerMemoryUsageMetric: LensConfigWithId = {
|
||||
id: 'memoryUsage',
|
||||
chartType: 'metric',
|
||||
title: MEMORY_USAGE_LABEL,
|
||||
trendLine: true,
|
||||
...formulas.dockerContainerMemoryUsage,
|
||||
};
|
||||
|
||||
const k8sContainerMemoryUsageMetric: LensConfigWithId = {
|
||||
id: 'k8sMemoryUsage',
|
||||
chartType: 'metric',
|
||||
title: MEMORY_USAGE_LABEL,
|
||||
trendLine: true,
|
||||
...formulas.k8sContainerMemoryUsage,
|
||||
};
|
||||
|
||||
export const memory = {
|
||||
xy: {
|
||||
dockerContainerMemoryUsage: dockerContainerMemoryUsageXY,
|
||||
k8sContainerMemoryUsage: k8sContainerMemoryUsageXY,
|
||||
},
|
||||
metric: {
|
||||
dockerContainerMemoryUsage: dockerContainerMemoryUsageMetric,
|
||||
k8sContainerMemoryUsage: k8sContainerMemoryUsageMetric,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
import { CPU_USAGE_LABEL } from '../../../shared/charts/constants';
|
||||
|
||||
export const dockerContainerCpuUsage: LensBaseLayer = {
|
||||
label: CPU_USAGE_LABEL,
|
||||
value: 'average(docker.cpu.total.pct)',
|
||||
format: 'percent',
|
||||
decimals: 1,
|
||||
};
|
||||
|
||||
export const k8sContainerCpuUsage: LensBaseLayer = {
|
||||
label: CPU_USAGE_LABEL,
|
||||
value: 'average(kubernetes.container.cpu.usage.limit.pct)',
|
||||
format: 'percent',
|
||||
decimals: 1,
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { dockerContainerCpuUsage, k8sContainerCpuUsage } from './cpu';
|
||||
import { dockerContainerMemoryUsage, k8sContainerMemoryUsage } from './memory';
|
||||
|
||||
export const formulas = {
|
||||
dockerContainerCpuUsage,
|
||||
dockerContainerMemoryUsage,
|
||||
k8sContainerCpuUsage,
|
||||
k8sContainerMemoryUsage,
|
||||
} as const;
|
||||
|
||||
export type ContainerFormulas = typeof formulas;
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
import { MEMORY_USAGE_LABEL } from '../../../shared/charts/constants';
|
||||
|
||||
export const dockerContainerMemoryUsage: LensBaseLayer = {
|
||||
label: MEMORY_USAGE_LABEL,
|
||||
value: 'average(docker.memory.usage.pct)',
|
||||
format: 'percent',
|
||||
decimals: 1,
|
||||
};
|
||||
|
||||
export const k8sContainerMemoryUsage: LensBaseLayer = {
|
||||
label: MEMORY_USAGE_LABEL,
|
||||
value: 'average(kubernetes.container.memory.usage.limit.pct)',
|
||||
format: 'percent',
|
||||
decimals: 1,
|
||||
};
|
|
@ -5,22 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { InventoryMetrics } from '../../types';
|
||||
import { InventoryMetricsWithCharts } from '../../types';
|
||||
import { cpu } from './snapshot/cpu';
|
||||
import { memory } from './snapshot/memory';
|
||||
import { rx } from './snapshot/rx';
|
||||
import { tx } from './snapshot/tx';
|
||||
|
||||
import { containerOverview } from './tsvb/container_overview';
|
||||
import { containerCpuUsage } from './tsvb/container_cpu_usage';
|
||||
import { containerCpuKernel } from './tsvb/container_cpu_kernel';
|
||||
import { containerCpuUsage } from './tsvb/container_cpu_usage';
|
||||
import { containerDiskIOOps } from './tsvb/container_diskio_ops';
|
||||
import { containerDiskIOBytes } from './tsvb/container_disk_io_bytes';
|
||||
import { containerMemory } from './tsvb/container_memory';
|
||||
import { containerNetworkTraffic } from './tsvb/container_network_traffic';
|
||||
import { containerK8sOverview } from './tsvb/container_k8s_overview';
|
||||
import { containerK8sCpuUsage } from './tsvb/container_k8s_cpu_usage';
|
||||
import { containerK8sMemoryUsage } from './tsvb/container_k8s_memory_usage';
|
||||
import { containerK8sOverview } from './tsvb/container_k8s_overview';
|
||||
import { containerMemory } from './tsvb/container_memory';
|
||||
import { containerNetworkTraffic } from './tsvb/container_network_traffic';
|
||||
import { containerOverview } from './tsvb/container_overview';
|
||||
import type { ContainerFormulas } from './formulas';
|
||||
import { ContainerCharts } from './charts';
|
||||
|
||||
const containerSnapshotMetrics = { cpu, memory, rx, tx };
|
||||
|
||||
|
@ -28,7 +29,7 @@ export const containerSnapshotMetricTypes = Object.keys(containerSnapshotMetrics
|
|||
keyof typeof containerSnapshotMetrics
|
||||
>;
|
||||
|
||||
export const metrics: InventoryMetrics = {
|
||||
export const metrics: InventoryMetricsWithCharts<ContainerFormulas, ContainerCharts> = {
|
||||
tsvb: {
|
||||
containerOverview,
|
||||
containerCpuUsage,
|
||||
|
@ -42,6 +43,8 @@ export const metrics: InventoryMetrics = {
|
|||
containerK8sMemoryUsage,
|
||||
},
|
||||
snapshot: containerSnapshotMetrics,
|
||||
getFormulas: async () => await import('./formulas').then(({ formulas }) => formulas),
|
||||
getCharts: async () => await import('./charts').then(({ charts }) => charts),
|
||||
defaultSnapshot: 'cpu',
|
||||
defaultTimeRangeInSeconds: 3600, // 1 hour
|
||||
};
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
CPU_USAGE_LABEL,
|
||||
LOAD_LABEL,
|
||||
DEFAULT_XY_FITTING_FUNCTION,
|
||||
DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
|
@ -19,9 +20,7 @@ import { formulas } from '../formulas';
|
|||
const cpuUsageBreakdown: LensConfigWithId = {
|
||||
id: 'cpuUsageBreakdown',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.cpuUsage', {
|
||||
defaultMessage: 'CPU Usage',
|
||||
}),
|
||||
title: CPU_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
@ -47,9 +46,7 @@ const cpuUsageBreakdown: LensConfigWithId = {
|
|||
const loadBreakdown: LensConfigWithId = {
|
||||
id: 'loadBreakdown',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.load', {
|
||||
defaultMessage: 'Load',
|
||||
}),
|
||||
title: LOAD_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
|
|
@ -14,14 +14,15 @@ import {
|
|||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
DEFAULT_XY_LEGEND,
|
||||
DEFAULT_XY_YBOUNDS,
|
||||
DISK_IOPS_LABEL,
|
||||
DISK_THROUGHPUT_LABEL,
|
||||
DISK_USAGE_BY_MOUNT_POINT_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
|
||||
const diskIOReadWrite: LensConfigWithId = {
|
||||
id: 'diskIOReadWrite',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskIOPS', {
|
||||
defaultMessage: 'Disk IOPS',
|
||||
}),
|
||||
title: DISK_IOPS_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
@ -51,9 +52,7 @@ const diskIOReadWrite: LensConfigWithId = {
|
|||
const diskUsageByMountPoint: LensConfigWithId = {
|
||||
id: 'diskUsageByMountPoint',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint', {
|
||||
defaultMessage: 'Disk Usage by Mount Point',
|
||||
}),
|
||||
title: DISK_USAGE_BY_MOUNT_POINT_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
@ -86,9 +85,7 @@ const diskUsageByMountPoint: LensConfigWithId = {
|
|||
const diskThroughputReadWrite: LensConfigWithId = {
|
||||
id: 'diskThroughputReadWrite',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskThroughput', {
|
||||
defaultMessage: 'Disk Throughput',
|
||||
}),
|
||||
title: DISK_THROUGHPUT_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
|
|
@ -14,14 +14,13 @@ import {
|
|||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
DEFAULT_XY_LEGEND,
|
||||
DEFAULT_XY_YBOUNDS,
|
||||
MEMORY_USAGE_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
|
||||
const memoryUsageBreakdown: LensConfigWithId = {
|
||||
id: 'memoryUsageBreakdown',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.memoryUsage', {
|
||||
defaultMessage: 'Memory Usage',
|
||||
}),
|
||||
title: MEMORY_USAGE_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
|
|
@ -13,14 +13,13 @@ import {
|
|||
DEFAULT_XY_HIDDEN_AXIS_TITLE,
|
||||
DEFAULT_XY_HIDDEN_LEGEND,
|
||||
DEFAULT_XY_LEGEND,
|
||||
NETWORK_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
|
||||
const rxTx: LensConfigWithId = {
|
||||
id: 'rxTx',
|
||||
chartType: 'xy',
|
||||
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network', {
|
||||
defaultMessage: 'Network',
|
||||
}),
|
||||
title: NETWORK_LABEL,
|
||||
layers: [
|
||||
{
|
||||
seriesType: 'area',
|
||||
|
|
|
@ -7,6 +7,13 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
import {
|
||||
CPU_USAGE_LABEL,
|
||||
LOAD_15M_LABEL,
|
||||
LOAD_1M_LABEL,
|
||||
LOAD_5M_LABEL,
|
||||
NORMALIZED_LOAD_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
|
||||
export const cpuUsageIowait: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel', {
|
||||
|
@ -72,45 +79,35 @@ export const cpuUsageUser: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const cpuUsage: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage', {
|
||||
defaultMessage: 'CPU Usage',
|
||||
}),
|
||||
label: CPU_USAGE_LABEL,
|
||||
value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
|
||||
format: 'percent',
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
export const load1m: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load1m', {
|
||||
defaultMessage: 'Load (1m)',
|
||||
}),
|
||||
label: LOAD_1M_LABEL,
|
||||
value: 'average(system.load.1)',
|
||||
format: 'number',
|
||||
decimals: 1,
|
||||
};
|
||||
|
||||
export const load5m: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load5m', {
|
||||
defaultMessage: 'Load (5m)',
|
||||
}),
|
||||
label: LOAD_5M_LABEL,
|
||||
value: 'average(system.load.5)',
|
||||
format: 'number',
|
||||
decimals: 1,
|
||||
};
|
||||
|
||||
export const load15m: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load15m', {
|
||||
defaultMessage: 'Load (15m)',
|
||||
}),
|
||||
label: LOAD_15M_LABEL,
|
||||
value: 'average(system.load.15)',
|
||||
format: 'number',
|
||||
decimals: 1,
|
||||
};
|
||||
|
||||
export const normalizedLoad1m: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.normalizedLoad1m', {
|
||||
defaultMessage: 'Normalized Load',
|
||||
}),
|
||||
label: NORMALIZED_LOAD_LABEL,
|
||||
value: 'average(system.load.1) / max(system.load.cores)',
|
||||
format: 'percent',
|
||||
decimals: 0,
|
||||
|
|
|
@ -5,13 +5,20 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
import {
|
||||
DISK_READ_IOPS_LABEL,
|
||||
DISK_READ_THROUGHPUT_LABEL,
|
||||
DISK_SPACE_AVAILABILITY_LABEL,
|
||||
DISK_SPACE_AVAILABLE_LABEL,
|
||||
DISK_USAGE_AVERAGE_LABEL,
|
||||
DISK_USAGE_LABEL,
|
||||
DISK_WRITE_IOPS_LABEL,
|
||||
DISK_WRITE_THROUGHPUT_LABEL,
|
||||
} from '../../../shared/charts/constants';
|
||||
|
||||
export const diskIORead: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIORead', {
|
||||
defaultMessage: 'Disk Read IOPS',
|
||||
}),
|
||||
label: DISK_READ_IOPS_LABEL,
|
||||
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
|
||||
format: 'number',
|
||||
decimals: 0,
|
||||
|
@ -19,9 +26,7 @@ export const diskIORead: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const diskReadThroughput: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskReadThroughput', {
|
||||
defaultMessage: 'Disk Read Throughput',
|
||||
}),
|
||||
label: DISK_READ_THROUGHPUT_LABEL,
|
||||
value: "counter_rate(max(system.diskio.read.bytes), kql='system.diskio.read.bytes: *')",
|
||||
format: 'bytes',
|
||||
decimals: 1,
|
||||
|
@ -29,45 +34,35 @@ export const diskReadThroughput: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const diskSpaceAvailable: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailable', {
|
||||
defaultMessage: 'Disk Space Available',
|
||||
}),
|
||||
label: DISK_SPACE_AVAILABLE_LABEL,
|
||||
value: 'average(system.filesystem.free)',
|
||||
format: 'bytes',
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
export const diskSpaceAvailability: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailability', {
|
||||
defaultMessage: 'Disk Space Availability',
|
||||
}),
|
||||
label: DISK_SPACE_AVAILABILITY_LABEL,
|
||||
value: '1 - average(system.filesystem.used.pct)',
|
||||
format: 'percent',
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
export const diskUsage: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskUsage', {
|
||||
defaultMessage: 'Disk Usage',
|
||||
}),
|
||||
label: DISK_USAGE_LABEL,
|
||||
value: 'max(system.filesystem.used.pct)',
|
||||
format: 'percent',
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
export const diskUsageAverage: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskUsageAverage', {
|
||||
defaultMessage: 'Disk Usage Average',
|
||||
}),
|
||||
label: DISK_USAGE_AVERAGE_LABEL,
|
||||
value: 'average(system.filesystem.used.pct)',
|
||||
format: 'percent',
|
||||
decimals: 0,
|
||||
};
|
||||
|
||||
export const diskIOWrite: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIOWrite', {
|
||||
defaultMessage: 'Disk Write IOPS',
|
||||
}),
|
||||
label: DISK_WRITE_IOPS_LABEL,
|
||||
value: "counter_rate(max(system.diskio.write.count), kql='system.diskio.write.count: *')",
|
||||
format: 'number',
|
||||
decimals: 0,
|
||||
|
@ -75,9 +70,7 @@ export const diskIOWrite: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const diskWriteThroughput: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskWriteThroughput', {
|
||||
defaultMessage: 'Disk Write Throughput',
|
||||
}),
|
||||
label: DISK_WRITE_THROUGHPUT_LABEL,
|
||||
value: "counter_rate(max(system.diskio.write.bytes), kql='system.diskio.write.bytes: *')",
|
||||
format: 'bytes',
|
||||
decimals: 1,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
import { MEMORY_FREE_LABEL, MEMORY_USAGE_LABEL } from '../../../shared/charts/constants';
|
||||
|
||||
export const memoryCache: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.cache', {
|
||||
|
@ -18,9 +19,7 @@ export const memoryCache: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const memoryFree: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryFree', {
|
||||
defaultMessage: 'Memory Free',
|
||||
}),
|
||||
label: MEMORY_FREE_LABEL,
|
||||
value: 'max(system.memory.total) - average(system.memory.actual.used.bytes)',
|
||||
format: 'bytes',
|
||||
decimals: 1,
|
||||
|
@ -36,9 +35,7 @@ export const memoryFreeExcludingCache: LensBaseLayer = {
|
|||
};
|
||||
|
||||
export const memoryUsage: LensBaseLayer = {
|
||||
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryUsage', {
|
||||
defaultMessage: 'Memory Usage',
|
||||
}),
|
||||
label: MEMORY_USAGE_LABEL,
|
||||
value: 'average(system.memory.actual.used.pct)',
|
||||
format: 'percent',
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { LensXYConfigBase } from '@kbn/lens-embeddable-utils/config_builder';
|
||||
|
||||
export const DEFAULT_XY_FITTING_FUNCTION: Pick<LensXYConfigBase, 'fittingFunction'> = {
|
||||
|
@ -38,3 +39,134 @@ export const DEFAULT_XY_HIDDEN_AXIS_TITLE: Pick<LensXYConfigBase, 'axisTitleVisi
|
|||
showYAxisTitle: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CPU_USAGE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.cpuUsage',
|
||||
{
|
||||
defaultMessage: 'CPU Usage',
|
||||
}
|
||||
);
|
||||
|
||||
export const MEMORY_USAGE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.memoryUsage',
|
||||
{
|
||||
defaultMessage: 'Memory Usage',
|
||||
}
|
||||
);
|
||||
|
||||
export const MEMORY_FREE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.memoryFree',
|
||||
{
|
||||
defaultMessage: 'Memory Free',
|
||||
}
|
||||
);
|
||||
|
||||
export const LOAD_LABEL = i18n.translate('xpack.metricsData.assetDetails.metrics.label.load', {
|
||||
defaultMessage: 'Load',
|
||||
});
|
||||
|
||||
export const LOAD_1M_LABEL = i18n.translate('xpack.metricsData.assetDetails.metrics.label.load1m', {
|
||||
defaultMessage: 'Load (1m)',
|
||||
});
|
||||
|
||||
export const LOAD_5M_LABEL = i18n.translate('xpack.metricsData.assetDetails.metrics.label.load5m', {
|
||||
defaultMessage: 'Load (5m)',
|
||||
});
|
||||
|
||||
export const LOAD_15M_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.load15m',
|
||||
{
|
||||
defaultMessage: 'Load (15m)',
|
||||
}
|
||||
);
|
||||
|
||||
export const NORMALIZED_LOAD_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.normalizedLoad',
|
||||
{
|
||||
defaultMessage: 'Normalized Load',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_USAGE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskUsage',
|
||||
{
|
||||
defaultMessage: 'Disk Usage',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_USAGE_AVERAGE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskUsageAverage',
|
||||
{
|
||||
defaultMessage: 'Disk Usage Average',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_IOPS_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskIOPS',
|
||||
{
|
||||
defaultMessage: 'Disk IOPS',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_READ_IOPS_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskReadIOPS',
|
||||
{
|
||||
defaultMessage: 'Disk Read IOPS',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_WRITE_IOPS_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskWriteIOPS',
|
||||
{
|
||||
defaultMessage: 'Disk Write IOPS',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_USAGE_BY_MOUNT_POINT_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskUsageByMountingPoint',
|
||||
{
|
||||
defaultMessage: 'Disk Usage by Mount Point',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_THROUGHPUT_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskThroughput',
|
||||
{
|
||||
defaultMessage: 'Disk Throughput',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_READ_THROUGHPUT_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskReadThroughput',
|
||||
{
|
||||
defaultMessage: 'Disk Read Throughput',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_WRITE_THROUGHPUT_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskWriteThroughput',
|
||||
{
|
||||
defaultMessage: 'Disk Write Throughput',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_SPACE_AVAILABLE_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskSpaceAvailable',
|
||||
{
|
||||
defaultMessage: 'Disk Space Available',
|
||||
}
|
||||
);
|
||||
|
||||
export const DISK_SPACE_AVAILABILITY_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.diskSpaceAvailablity',
|
||||
{
|
||||
defaultMessage: 'Disk Space Availability',
|
||||
}
|
||||
);
|
||||
|
||||
export const NETWORK_LABEL = i18n.translate(
|
||||
'xpack.metricsData.assetDetails.metrics.label.network',
|
||||
{
|
||||
defaultMessage: 'Network',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -32,6 +32,7 @@ export {
|
|||
apmTraceExplorerTab,
|
||||
apmLabsButton,
|
||||
enableInfrastructureHostsView,
|
||||
enableInfrastructureContainerAssetView,
|
||||
enableInfrastructureProfilingIntegration,
|
||||
enableInfrastructureAssetCustomDashboards,
|
||||
enableAwsLambdaMetrics,
|
||||
|
|
|
@ -21,6 +21,8 @@ export const enableInfrastructureProfilingIntegration =
|
|||
'observability:enableInfrastructureProfilingIntegration';
|
||||
export const enableInfrastructureAssetCustomDashboards =
|
||||
'observability:enableInfrastructureAssetCustomDashboards';
|
||||
export const enableInfrastructureContainerAssetView =
|
||||
'observability:enableInfrastructureContainerAssetView';
|
||||
export const enableAwsLambdaMetrics = 'observability:enableAwsLambdaMetrics';
|
||||
export const enableAgentExplorerView = 'observability:apmAgentExplorerView';
|
||||
export const apmEnableTableSearchBar = 'observability:apmEnableTableSearchBar';
|
||||
|
|
|
@ -41,6 +41,7 @@ export {
|
|||
enableComparisonByDefault,
|
||||
apmServiceGroupMaxNumberOfServices,
|
||||
enableInfrastructureHostsView,
|
||||
enableInfrastructureContainerAssetView,
|
||||
enableAgentExplorerView,
|
||||
apmEnableTableSearchBar,
|
||||
} from '../common/ui_settings_keys';
|
||||
|
|
|
@ -45,6 +45,7 @@ import {
|
|||
enableInfrastructureAssetCustomDashboards,
|
||||
apmEnableServiceInventoryTableSearchBar,
|
||||
profilingFetchTopNFunctionsFromStacktraces,
|
||||
enableInfrastructureContainerAssetView,
|
||||
} from '../common/ui_settings_keys';
|
||||
|
||||
const betaLabel = i18n.translate('xpack.observability.uiSettings.betaLabel', {
|
||||
|
@ -244,6 +245,20 @@ export const uiSettings: Record<string, UiSettings> = {
|
|||
}),
|
||||
schema: schema.boolean(),
|
||||
},
|
||||
[enableInfrastructureContainerAssetView]: {
|
||||
category: [observabilityFeatureId],
|
||||
name: i18n.translate('xpack.observability.enableInfrastructureContainerAssetView', {
|
||||
defaultMessage: 'Container view',
|
||||
}),
|
||||
value: false,
|
||||
description: i18n.translate(
|
||||
'xpack.observability.enableInfrastructureContainerAssetViewDescription',
|
||||
{
|
||||
defaultMessage: 'Enable the Container asset view in the Infrastructure app.',
|
||||
}
|
||||
),
|
||||
schema: schema.boolean(),
|
||||
},
|
||||
[enableInfrastructureProfilingIntegration]: {
|
||||
category: [observabilityFeatureId],
|
||||
name: i18n.translate('xpack.observability.enableInfrastructureProfilingIntegration', {
|
||||
|
|
|
@ -21088,10 +21088,8 @@
|
|||
"xpack.infra.assetDetails.tabs.metadata.seeLess": "Afficher moins",
|
||||
"xpack.infra.assetDetails.tabs.metadata.seeMore": "+{count} de plus",
|
||||
"xpack.infra.assetDetails.tabs.metadata": "Métadonnées",
|
||||
"xpack.infra.assetDetails.tabs.osquery": "Osquery",
|
||||
"xpack.infra.assetDetails.tabs.overview": "Aperçu",
|
||||
"xpack.infra.assetDetails.tabs.processes": "Processus",
|
||||
"xpack.infra.assetDetails.tabs.profiling": "Universal Profiling",
|
||||
"xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "Dernières {duration} de données pour l'heure sélectionnée",
|
||||
"xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "Une erreur s'est produite lors de la création d'une vue de données : {metricAlias}. Essayez de recharger la page.",
|
||||
"xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "Moyenne (de {limit} hôtes)",
|
||||
|
@ -44918,7 +44916,6 @@
|
|||
"xpack.features.savedQueryManagementFeatureName": "Gestion des requêtes enregistrées",
|
||||
"xpack.features.savedQueryManagementTooltip": "Si \"All\" (Tout) est défini, les requêtes enregistrées peuvent être gérées grâce à Kibana dans toutes les applications compatibles. Si \"None\" est défini, les privilèges relatifs aux requêtes enregistrées sont fixés indépendamment pour chaque application.",
|
||||
"xpack.features.visualizeFeatureName": "Bibliothèque Visualize",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage": "Utilisation CPU",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice",
|
||||
|
@ -44926,45 +44923,25 @@
|
|||
"xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "system",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "utilisateur",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIORead": "Entrées et sorties par seconde en lecture sur le disque",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIOWrite": "Entrées et sorties par seconde en écriture sur le disque",
|
||||
"xpack.metricsData.assetDetails.formulas.diskReadThroughput": "Rendement de lecture du disque",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "Disponibilité de l'espace disque",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "Espace disque disponible",
|
||||
"xpack.metricsData.assetDetails.formulas.diskUsage": "Utilisation du disque",
|
||||
"xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "Rendement d’écriture du disque",
|
||||
"xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "Hôtes",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "Capacité",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.used": "Utilisé",
|
||||
"xpack.metricsData.assetDetails.formulas.load15m": "Charge (15 min)",
|
||||
"xpack.metricsData.assetDetails.formulas.load1m": "Charge (1 min)",
|
||||
"xpack.metricsData.assetDetails.formulas.load5m": "Charge (5 min)",
|
||||
"xpack.metricsData.assetDetails.formulas.logRate": "Taux de log",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryFree": "Sans mémoire",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryUsage": "Utilisation mémoire",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.cache": "cache",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.free": "gratuit",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.used": "utilisé",
|
||||
"xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "Charge normalisée",
|
||||
"xpack.metricsData.assetDetails.formulas.rx": "Réseau entrant (RX)",
|
||||
"xpack.metricsData.assetDetails.formulas.tx": "Réseau sortant (TX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.cpuUsage": "Utilisation CPU",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "Entrées et sorties par seconde (IOPS) sur le disque",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "Rendement du disque",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "Utilisé",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "Utilisation du disque par point de montage",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "Capacité CPU du nœud",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "Capacité du disque du nœud",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "Capacité de mémoire du nœud",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "Capacité de pod du nœud",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.load": "Charge",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.memoryUsage": "Utilisation mémoire",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "Cache",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "Gratuit",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "Lire",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "Utilisé",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "Écrire",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network": "Réseau",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "Entrant (RX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "Sortant (TX)",
|
||||
"xpack.metricsData.hostsPage.goToMetricsSettings": "Vérifier les paramètres",
|
||||
|
|
|
@ -21228,10 +21228,8 @@
|
|||
"xpack.infra.assetDetails.tabs.metadata.seeLess": "簡易表示",
|
||||
"xpack.infra.assetDetails.tabs.metadata.seeMore": "他 {count} 件",
|
||||
"xpack.infra.assetDetails.tabs.metadata": "メタデータ",
|
||||
"xpack.infra.assetDetails.tabs.osquery": "Osquery",
|
||||
"xpack.infra.assetDetails.tabs.overview": "概要",
|
||||
"xpack.infra.assetDetails.tabs.processes": "プロセス",
|
||||
"xpack.infra.assetDetails.tabs.profiling": "ユニバーサルプロファイリング",
|
||||
"xpack.infra.assetDetails.tooltip.activeAlertsExplanation": "アクティブアラート",
|
||||
"xpack.infra.bottomDrawer.kubernetesDashboardsLink": "Kubernetesダッシュボード",
|
||||
"xpack.infra.chartSection.missingMetricDataBody": "このチャートはデータが欠けています。",
|
||||
|
@ -44888,7 +44886,6 @@
|
|||
"xpack.features.savedQueryManagementFeatureName": "保存されたクエリ管理",
|
||||
"xpack.features.savedQueryManagementTooltip": "[すべて]に設定すると、保存されたクエリは、クエリをサポートするすべてのアプリケーションのKibana全体で管理できます。[なし]に設定すると、保存されたクエリ権限は各アプリケーションで独自に決定されます。",
|
||||
"xpack.features.visualizeFeatureName": "Visualizeライブラリ",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage": "CPU使用状況",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice",
|
||||
|
@ -44896,45 +44893,25 @@
|
|||
"xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "システム",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "ユーザー",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIORead": "ディスク読み取りIOPS",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIOWrite": "ディスク書き込みIOPS",
|
||||
"xpack.metricsData.assetDetails.formulas.diskReadThroughput": "ディスク読み取りスループット",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "空きディスク容量",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "空きディスク容量",
|
||||
"xpack.metricsData.assetDetails.formulas.diskUsage": "ディスク使用量",
|
||||
"xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "ディスク書き込みスループット",
|
||||
"xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "ホスト",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "容量",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.used": "使用中",
|
||||
"xpack.metricsData.assetDetails.formulas.load15m": "読み込み(15m)",
|
||||
"xpack.metricsData.assetDetails.formulas.load1m": "読み込み(1m)",
|
||||
"xpack.metricsData.assetDetails.formulas.load5m": "読み込み(5m)",
|
||||
"xpack.metricsData.assetDetails.formulas.logRate": "ログレート",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryFree": "空きメモリー",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryUsage": "メモリー使用状況",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.cache": "キャッシュ",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.free": "空き",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.used": "使用中",
|
||||
"xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "正規化された負荷",
|
||||
"xpack.metricsData.assetDetails.formulas.rx": "ネットワーク受信(RX)",
|
||||
"xpack.metricsData.assetDetails.formulas.tx": "ネットワーク送信(TX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.cpuUsage": "CPU使用状況",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "Disk IOPS",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "Disk Throughput",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "使用中",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "マウントポイント別ディスク使用量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "ノード CPU 処理能力",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "ノードディスク容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "ノードメモリー容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "ノードポッド容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.load": "読み込み",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.memoryUsage": "メモリー使用状況",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "キャッシュ",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "空き",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "読み取り",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "使用中",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "書き込み",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network": "ネットワーク",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "受信(RX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "送信(TX)",
|
||||
"xpack.metricsData.hostsPage.goToMetricsSettings": "設定を確認",
|
||||
|
|
|
@ -21094,10 +21094,8 @@
|
|||
"xpack.infra.assetDetails.tabs.metadata.seeLess": "显示更少",
|
||||
"xpack.infra.assetDetails.tabs.metadata.seeMore": "另外 {count} 个",
|
||||
"xpack.infra.assetDetails.tabs.metadata": "元数据",
|
||||
"xpack.infra.assetDetails.tabs.osquery": "Osquery",
|
||||
"xpack.infra.assetDetails.tabs.overview": "概览",
|
||||
"xpack.infra.assetDetails.tabs.processes": "进程",
|
||||
"xpack.infra.assetDetails.tabs.profiling": "Universal Profiling",
|
||||
"xpack.infra.homePage.toolbar.showingLastOneMinuteDataText": "选定时间过去 {duration}的数据",
|
||||
"xpack.infra.hostsViewPage.errorOnCreateOrLoadDataview": "尝试创建数据视图时出错:{metricAlias}。尝试重新加载该页面。",
|
||||
"xpack.infra.hostsViewPage.kpi.subtitle.average.limit": "平均值(属于 {limit} 台主机)",
|
||||
|
@ -44936,7 +44934,6 @@
|
|||
"xpack.features.savedQueryManagementFeatureName": "已保存查询管理",
|
||||
"xpack.features.savedQueryManagementTooltip": "如果设置为“全部”,可以在支持已保存查询的所有应用程序中管理整个 Kibana 中的已保存查询。如果设置为“无”,将由每个应用程序单独确定已保存查询权限。",
|
||||
"xpack.features.visualizeFeatureName": "Visualize 库",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage": "CPU 使用率",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel": "iowait",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel": "irq",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel": "nice",
|
||||
|
@ -44944,45 +44941,25 @@
|
|||
"xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel": "steal",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel": "system",
|
||||
"xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel": "用户",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIORead": "磁盘读取 IOPS",
|
||||
"xpack.metricsData.assetDetails.formulas.diskIOWrite": "磁盘写入 IOPS",
|
||||
"xpack.metricsData.assetDetails.formulas.diskReadThroughput": "磁盘读取吞吐量",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailability": "磁盘空间可用性",
|
||||
"xpack.metricsData.assetDetails.formulas.diskSpaceAvailable": "可用磁盘空间",
|
||||
"xpack.metricsData.assetDetails.formulas.diskUsage": "磁盘使用率",
|
||||
"xpack.metricsData.assetDetails.formulas.diskWriteThroughput": "磁盘写入吞吐量",
|
||||
"xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel": "主机",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.capacity": "容量",
|
||||
"xpack.metricsData.assetDetails.formulas.kubernetes.used": "已使用",
|
||||
"xpack.metricsData.assetDetails.formulas.load15m": "负载(15 分钟)",
|
||||
"xpack.metricsData.assetDetails.formulas.load1m": "负载(1 分钟)",
|
||||
"xpack.metricsData.assetDetails.formulas.load5m": "负载(5 分钟)",
|
||||
"xpack.metricsData.assetDetails.formulas.logRate": "日志速率",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryFree": "可用内存",
|
||||
"xpack.metricsData.assetDetails.formulas.memoryUsage": "内存利用率",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.cache": "缓存",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.free": "可用",
|
||||
"xpack.metricsData.assetDetails.formulas.metric.label.used": "已使用",
|
||||
"xpack.metricsData.assetDetails.formulas.normalizedLoad1m": "标准化负载",
|
||||
"xpack.metricsData.assetDetails.formulas.rx": "网络入站数据 (RX)",
|
||||
"xpack.metricsData.assetDetails.formulas.tx": "网络出站数据 (TX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.cpuUsage": "CPU 使用率",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskIOPS": "磁盘 IOPS",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskThroughput": "磁盘吞吐量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsage.label.used": "已使用",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint": "磁盘使用率(按装载点)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity": "节点 CPU 容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity": "节点磁盘容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity": "节点内存容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity": "节点 Pod 容量",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.load": "加载",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.memoryUsage": "内存利用率",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.cache": "缓存",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.free": "可用",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.read": "读取",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.used": "已使用",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.metric.label.write": "写入",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network": "网络",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.rx": "入站 (RX)",
|
||||
"xpack.metricsData.assetDetails.metricsCharts.network.label.tx": "出站 (TX)",
|
||||
"xpack.metricsData.hostsPage.goToMetricsSettings": "检查设置",
|
||||
|
|
|
@ -23,8 +23,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
await synthtrace.clean();
|
||||
});
|
||||
|
||||
it('should return container assets', async () => {
|
||||
await synthtrace.index(generateContainersData({ from, to, count: 5 }));
|
||||
it('should return docker container assets', async () => {
|
||||
await synthtrace.index(generateDockerContainersData({ from, to, count: 5 }));
|
||||
|
||||
const response = await supertest
|
||||
.get(routePaths.GET_CONTAINERS)
|
||||
|
@ -38,8 +38,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(response.body.containers.length).to.equal(5);
|
||||
});
|
||||
|
||||
it('should return a specific container asset by EAN', async () => {
|
||||
await synthtrace.index(generateContainersData({ from, to, count: 5 }));
|
||||
it('should return a specific docker container asset by EAN', async () => {
|
||||
await synthtrace.index(generateDockerContainersData({ from, to, count: 5 }));
|
||||
const testEan = 'container:container-id-1';
|
||||
|
||||
const response = await supertest
|
||||
|
@ -56,8 +56,68 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(response.body.containers[0]['asset.ean']).to.equal(testEan);
|
||||
});
|
||||
|
||||
it('should return a filtered list of container assets by ID wildcard pattern', async () => {
|
||||
await synthtrace.index(generateContainersData({ from, to, count: 15 }));
|
||||
it('should return a filtered list of docker container assets by ID wildcard pattern', async () => {
|
||||
await synthtrace.index(generateDockerContainersData({ from, to, count: 15 }));
|
||||
const testIdPattern = '*id-1*';
|
||||
|
||||
const response = await supertest
|
||||
.get(routePaths.GET_CONTAINERS)
|
||||
.query({
|
||||
from,
|
||||
to,
|
||||
stringFilters: JSON.stringify({ id: testIdPattern }),
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).to.have.property('containers');
|
||||
expect(response.body.containers.length).to.equal(6);
|
||||
|
||||
const ids = response.body.containers.map((result: Asset) => result['asset.id']);
|
||||
|
||||
expect(ids).to.eql([
|
||||
'container-id-1',
|
||||
'container-id-10',
|
||||
'container-id-11',
|
||||
'container-id-12',
|
||||
'container-id-13',
|
||||
'container-id-14',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return k8s container assets', async () => {
|
||||
await synthtrace.index(generateK8sContainersData({ from, to, count: 5 }));
|
||||
const response = await supertest
|
||||
.get(routePaths.GET_CONTAINERS)
|
||||
.query({
|
||||
from,
|
||||
to,
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).to.have.property('containers');
|
||||
expect(response.body.containers.length).to.equal(5);
|
||||
});
|
||||
|
||||
it('should return a specific k8s container asset by EAN', async () => {
|
||||
await synthtrace.index(generateK8sContainersData({ from, to, count: 5 }));
|
||||
const testEan = 'container:container-id-1';
|
||||
|
||||
const response = await supertest
|
||||
.get(routePaths.GET_CONTAINERS)
|
||||
.query({
|
||||
from,
|
||||
to,
|
||||
stringFilters: JSON.stringify({ ean: testEan }),
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(response.body).to.have.property('containers');
|
||||
expect(response.body.containers.length).to.equal(1);
|
||||
expect(response.body.containers[0]['asset.ean']).to.equal(testEan);
|
||||
});
|
||||
|
||||
it('should return a filtered list of k8s container assets by ID wildcard pattern', async () => {
|
||||
await synthtrace.index(generateK8sContainersData({ from, to, count: 15 }));
|
||||
const testIdPattern = '*id-1*';
|
||||
|
||||
const response = await supertest
|
||||
|
@ -86,7 +146,30 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
}
|
||||
|
||||
function generateContainersData({
|
||||
function generateDockerContainersData({
|
||||
from,
|
||||
to,
|
||||
count = 1,
|
||||
}: {
|
||||
from: string;
|
||||
to: string;
|
||||
count: number;
|
||||
}) {
|
||||
const range = timerange(from, to);
|
||||
|
||||
const containers = Array(count)
|
||||
.fill(0)
|
||||
.map((_, idx) => infra.dockerContainer(`container-id-${idx}`));
|
||||
|
||||
return range
|
||||
.interval('1m')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
containers.map((container) => container.metrics().timestamp(timestamp))
|
||||
);
|
||||
}
|
||||
|
||||
function generateK8sContainersData({
|
||||
from,
|
||||
to,
|
||||
count = 1,
|
||||
|
@ -100,7 +183,7 @@ function generateContainersData({
|
|||
const containers = Array(count)
|
||||
.fill(0)
|
||||
.map((_, idx) =>
|
||||
infra.container(`container-id-${idx}`, `container-uid-${idx + 1000}`, `node-name-${idx}`)
|
||||
infra.k8sContainer(`container-id-${idx}`, `container-uid-${idx + 1000}`, `node-name-${idx}`)
|
||||
);
|
||||
|
||||
return range
|
||||
|
|
|
@ -11,6 +11,7 @@ import { InfraLogViewsServiceProvider } from './infra_log_views';
|
|||
import { SpacesServiceProvider } from './spaces';
|
||||
import { BsearchSecureService } from './bsearch_secure';
|
||||
import { ApmSynthtraceKibanaClientProvider } from './apm_synthtrace_kibana_client';
|
||||
import { InfraSynthtraceKibanaClientProvider } from './infra_synthtrace_kibana_client';
|
||||
|
||||
export const services = {
|
||||
...kibanaCommonServices,
|
||||
|
@ -19,4 +20,5 @@ export const services = {
|
|||
spaces: SpacesServiceProvider,
|
||||
secureBsearch: BsearchSecureService,
|
||||
apmSynthtraceKibanaClient: ApmSynthtraceKibanaClientProvider,
|
||||
infraSynthtraceKibanaClient: InfraSynthtraceKibanaClientProvider,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import url from 'url';
|
||||
import { kbnTestConfig } from '@kbn/test';
|
||||
import { InfraSynthtraceKibanaClient, createLogger, LogLevel } from '@kbn/apm-synthtrace';
|
||||
|
||||
const getKibanaServerUrlWithAuth = () => {
|
||||
const kibanaServerUrl = url.format(kbnTestConfig.getUrlParts() as url.UrlObject);
|
||||
const kibanaServerUrlWithAuth = url
|
||||
.format({
|
||||
...url.parse(kibanaServerUrl),
|
||||
auth: `elastic:${kbnTestConfig.getUrlParts().password}`,
|
||||
})
|
||||
.slice(0, -1);
|
||||
return kibanaServerUrlWithAuth;
|
||||
};
|
||||
|
||||
export function InfraSynthtraceKibanaClientProvider() {
|
||||
const kibanaServerUrlWithAuth = getKibanaServerUrlWithAuth();
|
||||
const target = kibanaServerUrlWithAuth;
|
||||
const logger = createLogger(LogLevel.debug);
|
||||
const username = 'elastic';
|
||||
const password = kbnTestConfig.getUrlParts().password || 'changeme';
|
||||
const kibanaClient = new InfraSynthtraceKibanaClient({
|
||||
target,
|
||||
logger,
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
return kibanaClient;
|
||||
}
|
17
x-pack/test/common/utils/synthtrace/infra_es_client.ts
Normal file
17
x-pack/test/common/utils/synthtrace/infra_es_client.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Client } from '@elastic/elasticsearch';
|
||||
import { InfraSynthtraceEsClient, createLogger, LogLevel } from '@kbn/apm-synthtrace';
|
||||
|
||||
export async function getInfraSynthtraceEsClient(client: Client) {
|
||||
return new InfraSynthtraceEsClient({
|
||||
client,
|
||||
logger: createLogger(LogLevel.info),
|
||||
refreshAfterIndex: true,
|
||||
});
|
||||
}
|
|
@ -51,7 +51,11 @@ export const ML_JOB_IDS = [
|
|||
export const HOSTS_LINK_LOCAL_STORAGE_KEY = 'inventoryUI:hostsLinkClicked';
|
||||
|
||||
export const INVENTORY_PATH = 'metrics/inventory';
|
||||
export const NODE_DETAILS_PATH = 'detail/host';
|
||||
export const NODE_DETAILS_PATH = 'detail';
|
||||
export const HOSTS_VIEW_PATH = 'metrics/hosts';
|
||||
|
||||
export const DATE_PICKER_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS';
|
||||
|
||||
export const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z';
|
||||
export const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z';
|
||||
export const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:59 PM';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { apm, timerange } from '@kbn/apm-synthtrace-client';
|
||||
import { apm, timerange, infra } from '@kbn/apm-synthtrace-client';
|
||||
|
||||
const SERVICE_PREFIX = 'service';
|
||||
// generates traces, metrics for services
|
||||
|
@ -46,3 +46,26 @@ export function generateAddServicesToExistingHost({
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function generateDockerContainersData({
|
||||
from,
|
||||
to,
|
||||
count = 1,
|
||||
}: {
|
||||
from: string;
|
||||
to: string;
|
||||
count?: number;
|
||||
}) {
|
||||
const range = timerange(from, to);
|
||||
|
||||
const containers = Array(count)
|
||||
.fill(0)
|
||||
.map((_, idx) => infra.dockerContainer(`container-id-${idx}`));
|
||||
|
||||
return range
|
||||
.interval('30s')
|
||||
.rate(1)
|
||||
.generator((timestamp) =>
|
||||
containers.flatMap((container) => container.metrics().timestamp(timestamp))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,17 +8,25 @@
|
|||
import expect from '@kbn/expect';
|
||||
import { parse } from 'url';
|
||||
import { KUBERNETES_TOUR_STORAGE_KEY } from '@kbn/infra-plugin/public/pages/metrics/inventory_view/components/kubernetes_tour';
|
||||
import { InfraSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { DATES, INVENTORY_PATH } from './constants';
|
||||
import { generateDockerContainersData } from './helpers';
|
||||
import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client';
|
||||
|
||||
const DATE_WITH_DATA = DATES.metricsAndLogs.hosts.withData;
|
||||
const DATE_WITHOUT_DATA = DATES.metricsAndLogs.hosts.withoutData;
|
||||
const DATE_WITH_POD_WITH_DATA = DATES.metricsAndLogs.pods.withData;
|
||||
const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z';
|
||||
const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z';
|
||||
const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:00 PM';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const browser = getService('browser');
|
||||
const retry = getService('retry');
|
||||
const esClient = getService('es');
|
||||
const infraSynthtraceKibanaClient = getService('infraSynthtraceKibanaClient');
|
||||
const pageObjects = getPageObjects([
|
||||
'common',
|
||||
'header',
|
||||
|
@ -355,7 +363,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
await returnTo(INVENTORY_PATH);
|
||||
});
|
||||
|
||||
it('Should redirect to Node Details page', async () => {
|
||||
it('Should redirect to Pod Details page', async () => {
|
||||
await pageObjects.infraHome.goToPods();
|
||||
await pageObjects.infraHome.goToTime(DATE_WITH_POD_WITH_DATA);
|
||||
await pageObjects.infraHome.clickOnFirstNode();
|
||||
|
@ -370,6 +378,41 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
await returnTo(INVENTORY_PATH);
|
||||
});
|
||||
|
||||
describe('Redirect to Container Details page', () => {
|
||||
let synthEsClient: InfraSynthtraceEsClient;
|
||||
before(async () => {
|
||||
const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion();
|
||||
await infraSynthtraceKibanaClient.installSystemPackage(version);
|
||||
synthEsClient = await getInfraSynthtraceEsClient(esClient);
|
||||
await synthEsClient.index(
|
||||
generateDockerContainersData({
|
||||
from: DATE_WITH_DOCKER_DATA_FROM,
|
||||
to: DATE_WITH_DOCKER_DATA_TO,
|
||||
count: 5,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
return await synthEsClient.clean();
|
||||
});
|
||||
it('Should redirect to Container Details page', async () => {
|
||||
await pageObjects.infraHome.goToContainer();
|
||||
await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA);
|
||||
await pageObjects.infraHome.clickOnFirstNode();
|
||||
await pageObjects.infraHome.clickOnGoToNodeDetails();
|
||||
|
||||
await retry.try(async () => {
|
||||
const documentTitle = await browser.getTitle();
|
||||
expect(documentTitle).to.contain(
|
||||
'container-id-4 - Inventory - Infrastructure - Observability - Elastic'
|
||||
);
|
||||
});
|
||||
|
||||
await returnTo(INVENTORY_PATH);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -7,14 +7,26 @@
|
|||
|
||||
import moment from 'moment';
|
||||
import expect from '@kbn/expect';
|
||||
import { enableInfrastructureProfilingIntegration } from '@kbn/observability-plugin/common';
|
||||
import { InfraSynthtraceEsClient } from '@kbn/apm-synthtrace';
|
||||
import {
|
||||
enableInfrastructureContainerAssetView,
|
||||
enableInfrastructureProfilingIntegration,
|
||||
} from '@kbn/observability-plugin/common';
|
||||
import {
|
||||
ALERT_STATUS_ACTIVE,
|
||||
ALERT_STATUS_RECOVERED,
|
||||
ALERT_STATUS_UNTRACKED,
|
||||
} from '@kbn/rule-data-utils';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
import { DATES, NODE_DETAILS_PATH, DATE_PICKER_FORMAT } from './constants';
|
||||
import {
|
||||
DATES,
|
||||
NODE_DETAILS_PATH,
|
||||
DATE_PICKER_FORMAT,
|
||||
DATE_WITH_DOCKER_DATA_FROM,
|
||||
DATE_WITH_DOCKER_DATA_TO,
|
||||
} from './constants';
|
||||
import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client';
|
||||
import { generateDockerContainersData } from './helpers';
|
||||
|
||||
const START_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.min);
|
||||
const END_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.max);
|
||||
|
@ -32,6 +44,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const browser = getService('browser');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const infraSynthtraceKibanaClient = getService('infraSynthtraceKibanaClient');
|
||||
const esClient = getService('es');
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects([
|
||||
|
@ -50,10 +64,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
return queryParams.toString();
|
||||
};
|
||||
|
||||
const navigateToNodeDetails = async (assetId: string, assetName: string) => {
|
||||
const navigateToNodeDetails = async (assetId: string, assetName: string, assetType: string) => {
|
||||
await pageObjects.common.navigateToUrlWithBrowserHistory(
|
||||
'infraOps',
|
||||
`/${NODE_DETAILS_PATH}/${assetId}`,
|
||||
`/${NODE_DETAILS_PATH}/${assetType}/${assetId}`,
|
||||
getNodeDetailsUrl(assetName),
|
||||
{
|
||||
insertTimestamp: false,
|
||||
|
@ -79,6 +93,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
};
|
||||
|
||||
const setInfrastructureContainerAssetViewUiSetting = async (value: boolean = true) => {
|
||||
await kibanaServer.uiSettings.update({ [enableInfrastructureContainerAssetView]: value });
|
||||
await browser.refresh();
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
};
|
||||
|
||||
describe('Node Details', () => {
|
||||
describe('#With Asset Details', () => {
|
||||
before(async () => {
|
||||
|
@ -90,7 +110,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
]);
|
||||
await browser.setWindowSize(1600, 1200);
|
||||
|
||||
await navigateToNodeDetails('Jennys-MBP.fritz.box', 'Jennys-MBP.fritz.box');
|
||||
await navigateToNodeDetails('Jennys-MBP.fritz.box', 'Jennys-MBP.fritz.box', 'host');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
|
@ -102,7 +122,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
]);
|
||||
});
|
||||
|
||||
describe('#Date picker', () => {
|
||||
describe('#Date picker: host', () => {
|
||||
before(async () => {
|
||||
await pageObjects.assetDetails.clickOverviewTab();
|
||||
|
||||
|
@ -247,7 +267,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const ALL_ALERTS = ACTIVE_ALERTS + RECOVERED_ALERTS;
|
||||
const COLUMNS = 11;
|
||||
before(async () => {
|
||||
await navigateToNodeDetails('demo-stack-apache-01', 'demo-stack-apache-01');
|
||||
await navigateToNodeDetails('demo-stack-apache-01', 'demo-stack-apache-01', 'host');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
await pageObjects.timePicker.setAbsoluteRange(
|
||||
|
@ -259,7 +279,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
});
|
||||
|
||||
after(async () => {
|
||||
await navigateToNodeDetails('Jennys-MBP.fritz.box', 'Jennys-MBP.fritz.box');
|
||||
await navigateToNodeDetails('Jennys-MBP.fritz.box', 'Jennys-MBP.fritz.box', 'host');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
await pageObjects.timePicker.setAbsoluteRange(
|
||||
|
@ -482,7 +502,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('Host with alerts and no processes', () => {
|
||||
before(async () => {
|
||||
await navigateToNodeDetails('demo-stack-mysql-01', 'demo-stack-mysql-01');
|
||||
await navigateToNodeDetails('demo-stack-mysql-01', 'demo-stack-mysql-01', 'host');
|
||||
await pageObjects.timePicker.setAbsoluteRange(
|
||||
START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT),
|
||||
END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT)
|
||||
|
@ -516,7 +536,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
|
||||
describe('#With Kubernetes section', () => {
|
||||
before(async () => {
|
||||
await navigateToNodeDetails('demo-stack-kubernetes-01', 'demo-stack-kubernetes-01');
|
||||
await navigateToNodeDetails(
|
||||
'demo-stack-kubernetes-01',
|
||||
'demo-stack-kubernetes-01',
|
||||
'host'
|
||||
);
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
|
@ -597,6 +621,57 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#Asset Type: container', () => {
|
||||
let synthEsClient: InfraSynthtraceEsClient;
|
||||
before(async () => {
|
||||
const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion();
|
||||
await infraSynthtraceKibanaClient.installSystemPackage(version);
|
||||
synthEsClient = await getInfraSynthtraceEsClient(esClient);
|
||||
await synthEsClient.index(
|
||||
generateDockerContainersData({
|
||||
from: DATE_WITH_DOCKER_DATA_FROM,
|
||||
to: DATE_WITH_DOCKER_DATA_TO,
|
||||
count: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await synthEsClient.clean();
|
||||
});
|
||||
|
||||
describe('when container asset view is disabled', () => {
|
||||
it('should show old view of container details', async () => {
|
||||
await setInfrastructureContainerAssetViewUiSetting(false);
|
||||
await navigateToNodeDetails('container-id-0', 'container-id-0', 'container');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.find('metricsEmptyViewState');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when container asset view is enabled', () => {
|
||||
it('should show asset container details page', async () => {
|
||||
await setInfrastructureContainerAssetViewUiSetting(true);
|
||||
await navigateToNodeDetails('container-id-0', 'container-id-0', 'container');
|
||||
await pageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
||||
await pageObjects.assetDetails.getOverviewTab();
|
||||
});
|
||||
|
||||
[
|
||||
{ metric: 'cpu', chartsCount: 1 },
|
||||
{ metric: 'memory', chartsCount: 1 },
|
||||
].forEach(({ metric, chartsCount }) => {
|
||||
it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => {
|
||||
const charts = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts(
|
||||
metric
|
||||
);
|
||||
expect(charts.length).to.equal(chartsCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -30,6 +30,10 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
|
|||
return testSubjects.click('infraAssetDetailsOverviewTab');
|
||||
},
|
||||
|
||||
async getOverviewTab() {
|
||||
return testSubjects.find('infraAssetDetailsOverviewTab');
|
||||
},
|
||||
|
||||
async getAssetDetailsKPITileValue(type: string) {
|
||||
const element = await testSubjects.find(`infraAssetDetailsKPI${type}`);
|
||||
const div = await element.findByClassName('echMetricText__value');
|
||||
|
@ -103,6 +107,15 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
|
|||
return section.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricChart"]');
|
||||
},
|
||||
|
||||
async getOverviewTabDockerMetricCharts(metric: string) {
|
||||
const container = await testSubjects.find('infraAssetDetailsOverviewTabContent');
|
||||
const section = await container.findByTestSubject(
|
||||
`infraAssetDetailsDockerChartsSection${metric}`
|
||||
);
|
||||
|
||||
return section.findAllByCssSelector('[data-test-subj*="infraAssetDetailsMetricChart"]');
|
||||
},
|
||||
|
||||
async getOverviewTabKubernetesMetricCharts() {
|
||||
const container = await testSubjects.find('infraAssetDetailsOverviewTabContent');
|
||||
const section = await container.findByTestSubject(`infraAssetDetailsKubernetesChartsSection`);
|
||||
|
|
|
@ -212,10 +212,10 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide
|
|||
return testSubjects.click('goToPods');
|
||||
},
|
||||
|
||||
async goToDocker() {
|
||||
async goToContainer() {
|
||||
await testSubjects.click('openInventorySwitcher');
|
||||
await testSubjects.find('goToHost');
|
||||
return testSubjects.click('goToDocker');
|
||||
return testSubjects.click('goToContainer');
|
||||
},
|
||||
|
||||
async goToSettings() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue