[8.14] [Infra][APM] Fix uptime links display condition in Infra and APM (#181425) (#181973)

# Backport

This will backport the following commits from `main` to `8.14`:
- [[Infra][APM] Fix uptime links display condition in Infra and APM
(#181425)](https://github.com/elastic/kibana/pull/181425)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Carlos
Crespo","email":"crespocarlos@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-04-29T12:06:03Z","message":"[Infra][APM]
Fix uptime links display condition in Infra and APM (#181425)\n\ncloses
[#178714](https://github.com/elastic/kibana/issues/178714)\r\n\r\n##
Summary\r\n\r\nThis PR changes where link to legacy uptime is displayed
to\r\nconditionally show it according to whether the plugin is enabled
or not.\r\n\r\n<img width=\"962\"
alt=\"image\"\r\nsrc=\"e2e659ae-bc2e-49a6-a34b-9434f04b4617\">\r\n\r\n<img
width=\"962\"
alt=\"image\"\r\nsrc=\"4aa487f5-4a61-4387-a9ed-12c9ed624410\">\r\n\r\n\r\n###
How to test\r\n\r\nThe issue and the fix are the same in serverless and
stateful\r\n\r\n#### APM \r\n- Run\r\n```\r\nnode scripts/synthtrace
simple_trace.ts --from=now-15m --to=now --clean
--target=http://elastic_serverless:changeme@localhost:9200
--kibana=http://elastic_serverless:changeme@0.0.0.0:5601\r\n```\r\n-
Navigate to APM > Traces, click on \"Investigate\" \r\n- if
`xpack.legacy_uptime.enabled: false` in kibana.yml -
\"Status\"\r\n**should** appear\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - \"Status\"\r\n**should not** appear\r\n- if
`xpack.legacy_uptime.enabled: false` and `xpack.uptime.enabled:\r\ntrue`
in kibana.yml - \"Status\" **should not** appear\r\n- if
`observability:enableLegacyUptimeApp` is switched on in
Advanced\r\nsettings - \"Status\" **should** appear\r\n\r\n#### Infra
\r\n- Start a local kibana instance pointing to an oblt cluster\r\n-
Navigate to Infrastructure, select `Kubernetes Pod` (other
asset\r\ntypes, except hosts, share the same code) in `Show`
dropdown\r\n- if `xpack.legacy_uptime.enabled: false` in kibana.yml -
the link\r\nshould be **enabled**\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - the link to\r\nuptime should be **disabled**\r\n-
if `xpack.legacy_uptime.enabled: false` and
`xpack.uptime.enabled:\r\ntrue` in kibana.yml - the link to uptime
should be **disabled**\r\n- if `observability:enableLegacyUptimeApp` is
switched on in Advanced\r\nsettings - the link to uptime should be
**enabled**\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"694acf7040dc56b6e2e4f37156d14a0028ff501b","branchLabelMapping":{"^v8.15.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-infra_services","v8.15.0"],"title":"[Infra][APM]
Fix uptime links display condition in Infra and
APM","number":181425,"url":"https://github.com/elastic/kibana/pull/181425","mergeCommit":{"message":"[Infra][APM]
Fix uptime links display condition in Infra and APM (#181425)\n\ncloses
[#178714](https://github.com/elastic/kibana/issues/178714)\r\n\r\n##
Summary\r\n\r\nThis PR changes where link to legacy uptime is displayed
to\r\nconditionally show it according to whether the plugin is enabled
or not.\r\n\r\n<img width=\"962\"
alt=\"image\"\r\nsrc=\"e2e659ae-bc2e-49a6-a34b-9434f04b4617\">\r\n\r\n<img
width=\"962\"
alt=\"image\"\r\nsrc=\"4aa487f5-4a61-4387-a9ed-12c9ed624410\">\r\n\r\n\r\n###
How to test\r\n\r\nThe issue and the fix are the same in serverless and
stateful\r\n\r\n#### APM \r\n- Run\r\n```\r\nnode scripts/synthtrace
simple_trace.ts --from=now-15m --to=now --clean
--target=http://elastic_serverless:changeme@localhost:9200
--kibana=http://elastic_serverless:changeme@0.0.0.0:5601\r\n```\r\n-
Navigate to APM > Traces, click on \"Investigate\" \r\n- if
`xpack.legacy_uptime.enabled: false` in kibana.yml -
\"Status\"\r\n**should** appear\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - \"Status\"\r\n**should not** appear\r\n- if
`xpack.legacy_uptime.enabled: false` and `xpack.uptime.enabled:\r\ntrue`
in kibana.yml - \"Status\" **should not** appear\r\n- if
`observability:enableLegacyUptimeApp` is switched on in
Advanced\r\nsettings - \"Status\" **should** appear\r\n\r\n#### Infra
\r\n- Start a local kibana instance pointing to an oblt cluster\r\n-
Navigate to Infrastructure, select `Kubernetes Pod` (other
asset\r\ntypes, except hosts, share the same code) in `Show`
dropdown\r\n- if `xpack.legacy_uptime.enabled: false` in kibana.yml -
the link\r\nshould be **enabled**\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - the link to\r\nuptime should be **disabled**\r\n-
if `xpack.legacy_uptime.enabled: false` and
`xpack.uptime.enabled:\r\ntrue` in kibana.yml - the link to uptime
should be **disabled**\r\n- if `observability:enableLegacyUptimeApp` is
switched on in Advanced\r\nsettings - the link to uptime should be
**enabled**\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"694acf7040dc56b6e2e4f37156d14a0028ff501b"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.15.0","branchLabelMappingKey":"^v8.15.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/181425","number":181425,"mergeCommit":{"message":"[Infra][APM]
Fix uptime links display condition in Infra and APM (#181425)\n\ncloses
[#178714](https://github.com/elastic/kibana/issues/178714)\r\n\r\n##
Summary\r\n\r\nThis PR changes where link to legacy uptime is displayed
to\r\nconditionally show it according to whether the plugin is enabled
or not.\r\n\r\n<img width=\"962\"
alt=\"image\"\r\nsrc=\"e2e659ae-bc2e-49a6-a34b-9434f04b4617\">\r\n\r\n<img
width=\"962\"
alt=\"image\"\r\nsrc=\"4aa487f5-4a61-4387-a9ed-12c9ed624410\">\r\n\r\n\r\n###
How to test\r\n\r\nThe issue and the fix are the same in serverless and
stateful\r\n\r\n#### APM \r\n- Run\r\n```\r\nnode scripts/synthtrace
simple_trace.ts --from=now-15m --to=now --clean
--target=http://elastic_serverless:changeme@localhost:9200
--kibana=http://elastic_serverless:changeme@0.0.0.0:5601\r\n```\r\n-
Navigate to APM > Traces, click on \"Investigate\" \r\n- if
`xpack.legacy_uptime.enabled: false` in kibana.yml -
\"Status\"\r\n**should** appear\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - \"Status\"\r\n**should not** appear\r\n- if
`xpack.legacy_uptime.enabled: false` and `xpack.uptime.enabled:\r\ntrue`
in kibana.yml - \"Status\" **should not** appear\r\n- if
`observability:enableLegacyUptimeApp` is switched on in
Advanced\r\nsettings - \"Status\" **should** appear\r\n\r\n#### Infra
\r\n- Start a local kibana instance pointing to an oblt cluster\r\n-
Navigate to Infrastructure, select `Kubernetes Pod` (other
asset\r\ntypes, except hosts, share the same code) in `Show`
dropdown\r\n- if `xpack.legacy_uptime.enabled: false` in kibana.yml -
the link\r\nshould be **enabled**\r\n- if `xpack.legacy_uptime.enabled:
false` in kibana.yml - the link to\r\nuptime should be **disabled**\r\n-
if `xpack.legacy_uptime.enabled: false` and
`xpack.uptime.enabled:\r\ntrue` in kibana.yml - the link to uptime
should be **disabled**\r\n- if `observability:enableLegacyUptimeApp` is
switched on in Advanced\r\nsettings - the link to uptime should be
**enabled**\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"694acf7040dc56b6e2e4f37156d14a0028ff501b"}}]}]
BACKPORT-->

Co-authored-by: Carlos Crespo <crespocarlos@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2024-04-29 11:16:46 -04:00 committed by GitHub
parent 6e730eaaa0
commit a4cb49799d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 167 additions and 106 deletions

View file

@ -211,6 +211,7 @@ export type ApmFields = Fields<{
span: { id: string };
}>;
'url.original': string;
'url.domain': string;
}> &
ApmApplicationMetricFields &
ExperimentalFields;

View file

@ -33,6 +33,9 @@ const scenario: Scenario<ApmFields> = async (runOptions) => {
instance
.transaction({ transactionName })
.timestamp(timestamp)
.defaults({
'url.domain': 'foo.bar',
})
.duration(1000)
.success()
.children(

View file

@ -10,24 +10,26 @@ import { IBasePath } from '@kbn/core/public';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { getSections } from './sections';
import { apmRouter as apmRouterBase, ApmRouter } from '../../routing/apm_route_config';
import {
logsLocatorsMock,
observabilityLogsExplorerLocatorsMock,
} from '../../../context/apm_plugin/mock_apm_plugin_context';
import { logsLocatorsMock } from '../../../context/apm_plugin/mock_apm_plugin_context';
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
const apmRouter = {
...apmRouterBase,
link: (...args: [any]) => `some-basepath/app/apm${apmRouterBase.link(...args)}`,
} as ApmRouter;
const { allDatasetsLocator } = observabilityLogsExplorerLocatorsMock;
const { nodeLogsLocator, traceLogsLocator } = logsLocatorsMock;
const uptimeLocator = sharePluginMock.createLocator();
const expectLogsLocatorsToBeCalled = () => {
expect(nodeLogsLocator.getRedirectUrl).toBeCalledTimes(3);
expect(traceLogsLocator.getRedirectUrl).toBeCalledTimes(1);
};
const expectUptimeLocatorToBeCalled = () => {
expect(uptimeLocator.getRedirectUrl).toBeCalledTimes(1);
};
describe('Transaction action menu', () => {
const basePath = {
prepend: (url: string) => {
@ -60,8 +62,8 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
logsLocators: logsLocatorsMock,
uptimeLocator,
infraLinksAvailable: false,
rangeFrom: 'now-24h',
rangeTo: 'now',
@ -110,6 +112,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});
@ -127,7 +130,7 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
uptimeLocator,
logsLocators: logsLocatorsMock,
infraLinksAvailable: true,
rangeFrom: 'now-24h',
@ -195,6 +198,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});
@ -212,7 +216,7 @@ describe('Transaction action menu', () => {
basePath,
location,
apmRouter,
allDatasetsLocator,
uptimeLocator,
logsLocators: logsLocatorsMock,
infraLinksAvailable: true,
rangeFrom: 'now-24h',
@ -280,6 +284,7 @@ describe('Transaction action menu', () => {
},
],
]);
expectUptimeLocatorToBeCalled();
expectLogsLocatorsToBeCalled();
});
});

View file

@ -10,18 +10,16 @@ import { Location } from 'history';
import { IBasePath } from '@kbn/core/public';
import { isEmpty, pickBy } from 'lodash';
import moment from 'moment';
import url from 'url';
import type { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
import { LocatorPublic } from '@kbn/share-plugin/common';
import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators';
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
import { LocatorPublic } from '@kbn/share-plugin/common';
import { SerializableRecord } from '@kbn/utility-types';
import { Environment } from '../../../../common/environment_rt';
import type { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { getDiscoverHref } from '../links/discover_links/discover_link';
import { getDiscoverQuery } from '../links/discover_links/discover_transaction_link';
import { getInfraHref } from '../links/infra_link';
import { fromQuery } from '../links/url_helpers';
import { SectionRecord, getNonEmptySections, Action } from './sections_helper';
import { HOST_NAME, TRACE_ID } from '../../../../common/es_fields/apm';
import { ApmRouter } from '../../routing/apm_route_config';
@ -42,11 +40,11 @@ export const getSections = ({
location,
apmRouter,
infraLinksAvailable,
uptimeLocator,
profilingLocators,
rangeFrom,
rangeTo,
environment,
allDatasetsLocator,
logsLocators,
dataViewId,
}: {
@ -55,11 +53,11 @@ export const getSections = ({
location: Location;
apmRouter: ApmRouter;
infraLinksAvailable: boolean;
uptimeLocator?: LocatorPublic<SerializableRecord>;
profilingLocators?: ProfilingLocators;
rangeFrom: string;
rangeTo: string;
environment: Environment;
allDatasetsLocator: LocatorPublic<AllDatasetsLocatorParams>;
logsLocators: ReturnType<typeof getLogsLocatorsFromUrlService>;
dataViewId?: string;
}) => {
@ -72,19 +70,16 @@ export const getSections = ({
const time = Math.round(transaction.timestamp.us / 1000);
const infraMetricsQuery = getInfraMetricsQuery(transaction);
const uptimeLink = url.format({
pathname: basePath.prepend('/app/uptime'),
search: `?${fromQuery(
pickBy(
{
dateRangeStart: rangeFrom,
dateRangeEnd: rangeTo,
search: `url.domain:"${transaction.url?.domain}"`,
},
(val) => !isEmpty(val)
)
)}`,
});
const uptimeLink = uptimeLocator?.getRedirectUrl(
pickBy(
{
dateRangeStart: rangeFrom,
dateRangeEnd: rangeTo,
search: `url.domain:"${transaction.url?.domain}"`,
},
(val) => !isEmpty(val)
)
);
// Logs hrefs
const podLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({
@ -231,7 +226,7 @@ export const getSections = ({
defaultMessage: 'Status',
}),
href: uptimeLink,
condition: !!transaction.url?.domain,
condition: !!transaction.url?.domain && !!uptimeLink,
},
];

View file

@ -30,6 +30,8 @@ import * as Transactions from './__fixtures__/mock_data';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import * as useAdHocApmDataView from '../../../hooks/use_adhoc_apm_data_view';
import { useProfilingIntegrationSetting } from '../../../hooks/use_profiling_integration_setting';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
const apmContextMock = {
...mockApmPluginContextValue,
@ -52,6 +54,15 @@ const apmContextMock = {
if (id === TRACE_LOGS_LOCATOR_ID) {
return logsLocatorsMock.traceLogsLocator;
}
if (id === uptimeOverviewLocatorID) {
return {
...sharePluginMock.createLocator(),
getRedirectUrl: jest.fn(
() =>
'http://localhost/basepath/app/uptime?dateRangeStart=now-24h&dateRangeEnd=now&search=url.domain:%22example.com%22'
),
};
}
},
},
},

View file

@ -21,12 +21,9 @@ import {
import React, { useState } from 'react';
import { useLocation } from 'react-router-dom';
import useAsync from 'react-use/lib/useAsync';
import {
AllDatasetsLocatorParams,
ALL_DATASETS_LOCATOR_ID,
} from '@kbn/deeplinks-observability/locators';
import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public';
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { useAnyOfApmParams } from '../../../hooks/use_apm_params';
import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
@ -124,10 +121,10 @@ function ActionMenuSections({
const apmRouter = useApmRouter();
const { dataView } = useAdHocApmDataView();
const allDatasetsLocator =
share.url.locators.get<AllDatasetsLocatorParams>(ALL_DATASETS_LOCATOR_ID)!;
const logsLocators = getLogsLocatorsFromUrlService(share.url);
const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);
const infraLinksAvailable = useApmFeatureFlag(ApmFeatureFlagName.InfraUiAvailable);
const {
@ -145,11 +142,11 @@ function ActionMenuSections({
location,
apmRouter,
infraLinksAvailable,
uptimeLocator,
profilingLocators,
rangeFrom,
rangeTo,
environment,
allDatasetsLocator,
logsLocators,
dataViewId: dataView?.id,
});

View file

@ -24,6 +24,7 @@ import {
import { findInventoryModel, findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/common';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { AlertFlyout } from '../../../../../alerting/inventory/components/alert_flyout';
import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib';
@ -46,6 +47,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
const { services } = useKibanaContextForPlugin();
const { application, share } = services;
const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url);
const uptimeLocator = share.url.locators.get(uptimeOverviewLocatorID);
const uiCapabilities = application?.capabilities;
// Due to the changing nature of the fields between APM and this UI,
// We need to have some exceptions until 7.0 & ECS is finalized. Reference
@ -60,7 +62,8 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
inventoryModel.crosslinkSupport.apm && uiCapabilities?.apm && uiCapabilities?.apm.show;
const showUptimeLink =
inventoryModel.crosslinkSupport.uptime &&
(['pod', 'container'].includes(nodeType) || node.ip);
(['pod', 'container'].includes(nodeType) || node.ip) &&
!!uptimeLocator;
const showCreateAlertLink = uiCapabilities?.infrastructure?.save;
const inventoryId = useMemo(() => {
@ -144,7 +147,7 @@ export const NodeContextMenu: React.FC<Props & { theme?: EuiTheme }> = withTheme
defaultMessage: '{inventoryName} in Uptime',
values: { inventoryName: inventoryModel.singularDisplayName },
}),
onClick: () => navigateToUptime(share.url.locators, nodeType, node),
onClick: () => (showUptimeLink ? navigateToUptime({ uptimeLocator, nodeType, node }) : {}),
isDisabled: !showUptimeLink,
};

View file

@ -5,15 +5,19 @@
* 2.0.
*/
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/public';
import { LocatorClient } from '@kbn/share-plugin/common/url_service/locators';
import { LocatorPublic } from '@kbn/share-plugin/common/url_service/locators';
import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common';
import { SerializableRecord } from '@kbn/utility-types';
import { InfraWaffleMapNode } from '../../../../lib/lib';
export const navigateToUptime = (
locators: LocatorClient,
nodeType: InventoryItemType,
node: InfraWaffleMapNode
) => {
return locators.get(uptimeOverviewLocatorID)!.navigate({ [nodeType]: node.id, ip: node.ip });
export const navigateToUptime = ({
uptimeLocator,
nodeType,
node,
}: {
uptimeLocator: LocatorPublic<SerializableRecord>;
nodeType: InventoryItemType;
node: InfraWaffleMapNode;
}) => {
return uptimeLocator.navigate({ [nodeType]: node.id, ip: node.ip });
};

View file

@ -6,13 +6,11 @@
*/
import { LocatorPublic } from '@kbn/share-plugin/public';
import { SerializableRecord } from '@kbn/utility-types';
import { uptimeOverviewNavigatorParams } from './overview';
import { monitorDetailNavigatorParams } from './monitor_detail';
import { editMonitorNavigatorParams } from './edit_monitor';
import { syntheticsSettingsNavigatorParams } from './settings';
export const locators: Array<Pick<LocatorPublic<SerializableRecord>, 'id' | 'getLocation'>> = [
uptimeOverviewNavigatorParams,
monitorDetailNavigatorParams,
editMonitorNavigatorParams,
syntheticsSettingsNavigatorParams,

View file

@ -1,50 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/public';
import { OVERVIEW_ROUTE } from '../../../common/constants/ui';
const formatSearchKey = (key: string, value: string) => `${key}: "${value}"`;
async function navigate({
ip,
host,
container,
pod,
}: {
ip?: string;
host?: string;
container?: string;
pod?: string;
}) {
const searchParams: string[] = [];
if (host) searchParams.push(formatSearchKey('host.name', host));
if (container) searchParams.push(formatSearchKey('container.id', container));
if (pod) searchParams.push(formatSearchKey('kubernetes.pod.uid', pod));
if (ip) {
searchParams.push(formatSearchKey(`host.ip`, ip));
searchParams.push(formatSearchKey(`monitor.ip`, ip));
}
const searchString = searchParams.join(' OR ');
const path =
searchParams.length === 0 ? OVERVIEW_ROUTE : OVERVIEW_ROUTE + `?search=${searchString}`;
return {
app: 'uptime',
path,
state: {},
};
}
export const uptimeOverviewNavigatorParams = {
id: uptimeOverviewLocatorID,
getLocation: navigate,
};

View file

@ -5,34 +5,36 @@
* 2.0.
*/
import { OVERVIEW_ROUTE } from '../../../common/constants';
import { uptimeOverviewNavigatorParams } from './overview';
import { OVERVIEW_ROUTE } from '../../common/constants';
import { UptimeOverviewLocatorDefinition } from './overview';
describe('uptimeOverviewNavigatorParams', () => {
const uptimeOverviewNavigator = new UptimeOverviewLocatorDefinition();
it('supplies the correct app name', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({});
const location = await uptimeOverviewNavigator.getLocation({});
expect(location.app).toEqual('uptime');
});
it('creates the expected path when no params specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({});
const location = await uptimeOverviewNavigator.getLocation({});
expect(location.path).toEqual(OVERVIEW_ROUTE);
});
it('creates a path with expected search when ip is specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({ ip: '127.0.0.1' });
const location = await uptimeOverviewNavigator.getLocation({ ip: '127.0.0.1' });
expect(location.path).toEqual(
`${OVERVIEW_ROUTE}?search=host.ip: "127.0.0.1" OR monitor.ip: "127.0.0.1"`
);
});
it('creates a path with expected search when hostname is specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({ host: 'elastic.co' });
const location = await uptimeOverviewNavigator.getLocation({ host: 'elastic.co' });
expect(location.path).toEqual(`${OVERVIEW_ROUTE}?search=host.name: "elastic.co"`);
});
it('creates a path with expected search when multiple host keys are specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({
const location = await uptimeOverviewNavigator.getLocation({
host: 'elastic.co',
ip: '127.0.0.1',
});
@ -42,7 +44,7 @@ describe('uptimeOverviewNavigatorParams', () => {
});
it('creates a path with expected search when multiple kubernetes pod is specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({
const location = await uptimeOverviewNavigator.getLocation({
pod: 'foo',
ip: '10.0.0.1',
});
@ -52,9 +54,20 @@ describe('uptimeOverviewNavigatorParams', () => {
});
it('creates a path with expected search when docker container is specified', async () => {
const location = await uptimeOverviewNavigatorParams.getLocation({
const location = await uptimeOverviewNavigator.getLocation({
container: 'foo',
});
expect(location.path).toEqual(`${OVERVIEW_ROUTE}?search=container.id: "foo"`);
});
it('creates a path with expected search and date range', async () => {
const location = await uptimeOverviewNavigator.getLocation({
search: 'foo',
dateRangeStart: 'now-15m',
dateRangeEnd: 'now',
});
expect(location.path).toEqual(
`${OVERVIEW_ROUTE}?search=foo&dateRangeStart=now-15m&dateRangeEnd=now`
);
});
});

View file

@ -0,0 +1,78 @@
/*
* 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 { uptimeOverviewLocatorID } from '@kbn/observability-plugin/public';
import type { LocatorDefinition } from '@kbn/share-plugin/common';
import type { SerializableRecord } from '@kbn/utility-types';
import { OVERVIEW_ROUTE } from '../../common/constants';
const formatSearchKey = (key: string, value: string) => `${key}: "${value}"`;
export interface UptimeOverviewLocatorInfraParams extends SerializableRecord {
ip?: string;
host?: string;
container?: string;
pod?: string;
}
export interface UptimeOverviewLocatorParams extends SerializableRecord {
dateRangeStart?: string;
dateRangeEnd?: string;
search?: string;
}
function isUptimeOverviewLocatorParams(
args: UptimeOverviewLocatorInfraParams | UptimeOverviewLocatorParams
): args is UptimeOverviewLocatorParams {
return (
(args as UptimeOverviewLocatorParams).search !== undefined ||
(args as UptimeOverviewLocatorParams).dateRangeEnd !== undefined ||
(args as UptimeOverviewLocatorParams).dateRangeStart !== undefined
);
}
export class UptimeOverviewLocatorDefinition
implements LocatorDefinition<UptimeOverviewLocatorInfraParams | UptimeOverviewLocatorParams>
{
public readonly id = uptimeOverviewLocatorID;
public readonly getLocation = async (
params: UptimeOverviewLocatorInfraParams | UptimeOverviewLocatorParams
) => {
let qs = '';
if (isUptimeOverviewLocatorParams(params)) {
qs = Object.entries(params)
.map(([key, value]) => {
if (value) {
return `${key}=${value}`;
}
})
.join('&');
} else {
const searchParams: string[] = [];
if (params.host) searchParams.push(formatSearchKey('host.name', params.host));
if (params.container) searchParams.push(formatSearchKey('container.id', params.container));
if (params.pod) searchParams.push(formatSearchKey('kubernetes.pod.uid', params.pod));
if (params.ip) {
searchParams.push(formatSearchKey(`host.ip`, params.ip));
searchParams.push(formatSearchKey(`monitor.ip`, params.ip));
}
if (searchParams.length > 0) {
qs = `search=${searchParams.join(' OR ')}`;
}
}
const path = `${OVERVIEW_ROUTE}${qs ? `?${qs}` : ''}`;
return {
app: 'uptime',
path,
state: {},
};
};
}

View file

@ -241,6 +241,9 @@ export class UptimePlugin
function registerUptimeRoutesWithNavigation(coreStart: CoreStart, plugins: ClientPluginsStart) {
async function getUptimeSections() {
if (coreStart.application.capabilities.uptime?.show) {
const { UptimeOverviewLocatorDefinition } = await import('./locators/overview');
plugins.share.url.locators.create(new UptimeOverviewLocatorDefinition());
return [
{
label: 'Uptime',