mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[Infra IU] Disable Metrics Explorer for serverless (#167022)
Closes #163282 ## Summary This PR: * Adds a `featureFlags.metricsExplorerEnabled` property to the Infra plugin config to enable and disable Metrics Explorer depending on the offering type * Prevents `MetricsExplorerViewsService` initialization for serveless based on the feature flag * Prevents creating Metrics Explorer frontend routes when in serverless * Prevents registration of the MetricsExplorerViews saved object when in serverless * Prevents initialization of the `metrics_explorer_views` API routes when in serverless **Trying to access Metrics Explorer in serverless** <img width="1829" alt="CleanShot 2023-09-22 at 12 59 35@2x" src="2b039925
-0f0b-4c07-be29-bbe910de7a34"> **Trying to access views API** <img width="1829" alt="CleanShot 2023-09-22 at 13 00 00@2x" src="15269ec2
-becd-4ee3-9b5e-d916df28a7b8"> **`infra/metrics_explorer` API still works as per ticket requirements** <img width="1829" alt="CleanShot 2023-09-22 at 13 00 06@2x" src="fb23f912
-c6fd-46c8-9084-c17c51e5b064"> ## How to test * Checkout locally * Enable Infra in `serverless.oblt.yml`: `xpack.infra.enabled: true` * Run Kibana in serverless mode * Try accessing `/app/metrics/explorer` route and make sure it's not available * Make sure other Infra routes (`/app/metrics/inventory` and `/app/metrics/hosts`) still load as expected * In Kibana dev console make sure you get 404 for `GET kbn:/api/infra/metrics_explorer_views` * Also check that you don't see `metrics-explorer-view` saved object in the response for `GET kbn:/api/kibana/management/saved_objects/_allowed_types` * Run Kibana in non-serverless mode and make sure Metrics Explorer is accessible and works as usual --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
4c1ca7e92f
commit
d0a0a1f9e6
22 changed files with 239 additions and 62 deletions
|
@ -250,6 +250,11 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||||
'xpack.index_management.enableLegacyTemplates (any)',
|
'xpack.index_management.enableLegacyTemplates (any)',
|
||||||
'xpack.index_management.enableIndexStats (any)',
|
'xpack.index_management.enableIndexStats (any)',
|
||||||
'xpack.infra.sources.default.fields.message (array)',
|
'xpack.infra.sources.default.fields.message (array)',
|
||||||
|
/**
|
||||||
|
* xpack.infra.featureFlags.metricsExplorerEnabled is conditional based on traditional/serverless offering
|
||||||
|
* and will resolve to (boolean)
|
||||||
|
*/
|
||||||
|
'xpack.infra.featureFlags.metricsExplorerEnabled (any)',
|
||||||
'xpack.license_management.ui.enabled (boolean)',
|
'xpack.license_management.ui.enabled (boolean)',
|
||||||
'xpack.maps.preserveDrawingBuffer (boolean)',
|
'xpack.maps.preserveDrawingBuffer (boolean)',
|
||||||
'xpack.maps.showMapsInspectorAdapter (boolean)',
|
'xpack.maps.showMapsInspectorAdapter (boolean)',
|
||||||
|
|
|
@ -9,7 +9,8 @@ import { either } from 'fp-ts/Either';
|
||||||
import { metricsExplorerViewRT } from '../../../metrics_explorer_views';
|
import { metricsExplorerViewRT } from '../../../metrics_explorer_views';
|
||||||
|
|
||||||
export const METRICS_EXPLORER_VIEW_URL = '/api/infra/metrics_explorer_views';
|
export const METRICS_EXPLORER_VIEW_URL = '/api/infra/metrics_explorer_views';
|
||||||
export const METRICS_EXPLORER_VIEW_URL_ENTITY = `${METRICS_EXPLORER_VIEW_URL}/{metricsExplorerViewId}`;
|
export const METRICS_EXPLORER_VIEW_URL_ENTITY =
|
||||||
|
`${METRICS_EXPLORER_VIEW_URL}/{metricsExplorerViewId}` as const;
|
||||||
export const getMetricsExplorerViewUrl = (metricsExplorerViewId?: string) =>
|
export const getMetricsExplorerViewUrl = (metricsExplorerViewId?: string) =>
|
||||||
[METRICS_EXPLORER_VIEW_URL, metricsExplorerViewId].filter(Boolean).join('/');
|
[METRICS_EXPLORER_VIEW_URL, metricsExplorerViewId].filter(Boolean).join('/');
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,14 @@ export interface InfraConfig {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
featureFlags: {
|
||||||
|
metricsExplorerEnabled: boolean;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const publicConfigKeys = {
|
export const publicConfigKeys = {
|
||||||
sources: true,
|
sources: true,
|
||||||
|
featureFlags: true,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type InfraPublicConfigKey = keyof {
|
export type InfraPublicConfigKey = keyof {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router';
|
||||||
import { AppMountParameters } from '@kbn/core/public';
|
import { AppMountParameters } from '@kbn/core/public';
|
||||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||||
import '../index.scss';
|
import '../index.scss';
|
||||||
|
import { InfraPublicConfig } from '../../common/plugin_config_types';
|
||||||
import { LinkToMetricsPage } from '../pages/link_to/link_to_metrics';
|
import { LinkToMetricsPage } from '../pages/link_to/link_to_metrics';
|
||||||
import { InfrastructurePage } from '../pages/metrics';
|
import { InfrastructurePage } from '../pages/metrics';
|
||||||
import { InfraClientStartDeps, InfraClientStartExports } from '../types';
|
import { InfraClientStartDeps, InfraClientStartExports } from '../types';
|
||||||
|
@ -20,6 +21,7 @@ import { RedirectWithQueryParams } from '../utils/redirect_with_query_params';
|
||||||
import { CommonInfraProviders, CoreProviders } from './common_providers';
|
import { CommonInfraProviders, CoreProviders } from './common_providers';
|
||||||
import { prepareMountElement } from './common_styles';
|
import { prepareMountElement } from './common_styles';
|
||||||
import { SourceProvider } from '../containers/metrics_source';
|
import { SourceProvider } from '../containers/metrics_source';
|
||||||
|
import { PluginConfigProvider } from '../containers/plugin_config_context';
|
||||||
|
|
||||||
export const METRICS_APP_DATA_TEST_SUBJ = 'infraMetricsPage';
|
export const METRICS_APP_DATA_TEST_SUBJ = 'infraMetricsPage';
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ export const renderApp = (
|
||||||
core: CoreStart,
|
core: CoreStart,
|
||||||
plugins: InfraClientStartDeps,
|
plugins: InfraClientStartDeps,
|
||||||
pluginStart: InfraClientStartExports,
|
pluginStart: InfraClientStartExports,
|
||||||
|
pluginConfig: InfraPublicConfig,
|
||||||
{ element, history, setHeaderActionMenu, theme$ }: AppMountParameters
|
{ element, history, setHeaderActionMenu, theme$ }: AppMountParameters
|
||||||
) => {
|
) => {
|
||||||
const storage = new Storage(window.localStorage);
|
const storage = new Storage(window.localStorage);
|
||||||
|
@ -39,6 +42,7 @@ export const renderApp = (
|
||||||
history={history}
|
history={history}
|
||||||
plugins={plugins}
|
plugins={plugins}
|
||||||
pluginStart={pluginStart}
|
pluginStart={pluginStart}
|
||||||
|
pluginConfig={pluginConfig}
|
||||||
setHeaderActionMenu={setHeaderActionMenu}
|
setHeaderActionMenu={setHeaderActionMenu}
|
||||||
storage={storage}
|
storage={storage}
|
||||||
theme$={theme$}
|
theme$={theme$}
|
||||||
|
@ -56,11 +60,21 @@ const MetricsApp: React.FC<{
|
||||||
core: CoreStart;
|
core: CoreStart;
|
||||||
history: History<unknown>;
|
history: History<unknown>;
|
||||||
pluginStart: InfraClientStartExports;
|
pluginStart: InfraClientStartExports;
|
||||||
|
pluginConfig: InfraPublicConfig;
|
||||||
plugins: InfraClientStartDeps;
|
plugins: InfraClientStartDeps;
|
||||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||||
storage: Storage;
|
storage: Storage;
|
||||||
theme$: AppMountParameters['theme$'];
|
theme$: AppMountParameters['theme$'];
|
||||||
}> = ({ core, history, pluginStart, plugins, setHeaderActionMenu, storage, theme$ }) => {
|
}> = ({
|
||||||
|
core,
|
||||||
|
history,
|
||||||
|
pluginStart,
|
||||||
|
pluginConfig,
|
||||||
|
plugins,
|
||||||
|
setHeaderActionMenu,
|
||||||
|
storage,
|
||||||
|
theme$,
|
||||||
|
}) => {
|
||||||
const uiCapabilities = core.application.capabilities;
|
const uiCapabilities = core.application.capabilities;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -74,23 +88,25 @@ const MetricsApp: React.FC<{
|
||||||
observabilityAIAssistant={plugins.observabilityAIAssistant}
|
observabilityAIAssistant={plugins.observabilityAIAssistant}
|
||||||
>
|
>
|
||||||
<SourceProvider sourceId="default">
|
<SourceProvider sourceId="default">
|
||||||
<Router history={history}>
|
<PluginConfigProvider value={pluginConfig}>
|
||||||
<Routes>
|
<Router history={history}>
|
||||||
<Route path="/link-to" component={LinkToMetricsPage} />
|
<Routes>
|
||||||
{uiCapabilities?.infrastructure?.show && (
|
<Route path="/link-to" component={LinkToMetricsPage} />
|
||||||
<RedirectWithQueryParams from="/" exact={true} to="/inventory" />
|
{uiCapabilities?.infrastructure?.show && (
|
||||||
)}
|
<RedirectWithQueryParams from="/" exact={true} to="/inventory" />
|
||||||
{uiCapabilities?.infrastructure?.show && (
|
)}
|
||||||
<RedirectWithQueryParams from="/snapshot" exact={true} to="/inventory" />
|
{uiCapabilities?.infrastructure?.show && (
|
||||||
)}
|
<RedirectWithQueryParams from="/snapshot" exact={true} to="/inventory" />
|
||||||
{uiCapabilities?.infrastructure?.show && (
|
)}
|
||||||
<RedirectWithQueryParams from="/metrics-explorer" exact={true} to="/explorer" />
|
{uiCapabilities?.infrastructure?.show && (
|
||||||
)}
|
<RedirectWithQueryParams from="/metrics-explorer" exact={true} to="/explorer" />
|
||||||
{uiCapabilities?.infrastructure?.show && (
|
)}
|
||||||
<Route path="/" component={InfrastructurePage} />
|
{uiCapabilities?.infrastructure?.show && (
|
||||||
)}
|
<Route path="/" component={InfrastructurePage} />
|
||||||
</Routes>
|
)}
|
||||||
</Router>
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
</PluginConfigProvider>
|
||||||
</SourceProvider>
|
</SourceProvider>
|
||||||
</CommonInfraProviders>
|
</CommonInfraProviders>
|
||||||
</CoreProviders>
|
</CoreProviders>
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 React from 'react';
|
||||||
|
import { PluginConfigProvider, usePluginConfig } from './plugin_config_context';
|
||||||
|
|
||||||
|
describe('usePluginConfig()', () => {
|
||||||
|
it('throws an error if the context value was not set before using the hook', () => {
|
||||||
|
const { result } = renderHook(() => usePluginConfig());
|
||||||
|
|
||||||
|
expect(result.error).not.toEqual(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the plugin config what was set through the provider', () => {
|
||||||
|
const config = {
|
||||||
|
featureFlags: { metricsExplorerEnabled: false },
|
||||||
|
};
|
||||||
|
const { result } = renderHook(() => usePluginConfig(), {
|
||||||
|
wrapper: ({ children }) => {
|
||||||
|
return <PluginConfigProvider value={config}>{children}</PluginConfigProvider>;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.error).toEqual(undefined);
|
||||||
|
expect(result.current).toEqual(config);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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 { createContext, useContext } from 'react';
|
||||||
|
import { InfraPublicConfig } from '../../common/plugin_config_types';
|
||||||
|
|
||||||
|
const PluginConfigContext = createContext<InfraPublicConfig | undefined>(undefined);
|
||||||
|
|
||||||
|
export const usePluginConfig = (): InfraPublicConfig => {
|
||||||
|
const context = useContext(PluginConfigContext);
|
||||||
|
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
'PluginConfigContext value was not initialized. Use context provider to set the value before using it.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PluginConfigProvider = PluginConfigContext.Provider;
|
|
@ -24,10 +24,10 @@ import {
|
||||||
UpdateMetricsExplorerViewAttributesRequestPayload,
|
UpdateMetricsExplorerViewAttributesRequestPayload,
|
||||||
} from '../../common/http_api/latest';
|
} from '../../common/http_api/latest';
|
||||||
import { MetricsExplorerView } from '../../common/metrics_explorer_views';
|
import { MetricsExplorerView } from '../../common/metrics_explorer_views';
|
||||||
import { useKibanaContextForPlugin } from './use_kibana';
|
|
||||||
import { useUrlState } from '../utils/use_url_state';
|
import { useUrlState } from '../utils/use_url_state';
|
||||||
import { useSavedViewsNotifier } from './use_saved_views_notifier';
|
import { useSavedViewsNotifier } from './use_saved_views_notifier';
|
||||||
import { useSourceContext } from '../containers/metrics_source';
|
import { useSourceContext } from '../containers/metrics_source';
|
||||||
|
import { useKibanaContextForPlugin } from './use_kibana';
|
||||||
|
|
||||||
export type UseMetricsExplorerViewsResult = SavedViewResult<
|
export type UseMetricsExplorerViewsResult = SavedViewResult<
|
||||||
MetricsExplorerView,
|
MetricsExplorerView,
|
||||||
|
@ -44,6 +44,11 @@ const queryKeys = {
|
||||||
|
|
||||||
export const useMetricsExplorerViews = (): UseMetricsExplorerViewsResult => {
|
export const useMetricsExplorerViews = (): UseMetricsExplorerViewsResult => {
|
||||||
const { metricsExplorerViews } = useKibanaContextForPlugin().services;
|
const { metricsExplorerViews } = useKibanaContextForPlugin().services;
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
throw new Error('MetricsExplorerViews service has not been initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
const trackMetric = useUiTracker({ app: 'infra_metrics' });
|
const trackMetric = useUiTracker({ app: 'infra_metrics' });
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { RouteComponentProps } from 'react-router-dom';
|
|
||||||
import { Routes, Route } from '@kbn/shared-ux-router';
|
import { Routes, Route } from '@kbn/shared-ux-router';
|
||||||
|
|
||||||
import { EuiErrorBoundary, EuiHeaderLinks, EuiHeaderLink } from '@elastic/eui';
|
import { EuiErrorBoundary, EuiHeaderLinks, EuiHeaderLink } from '@elastic/eui';
|
||||||
|
@ -37,12 +36,14 @@ import { HeaderActionMenuContext } from '../../utils/header_action_menu_provider
|
||||||
import { CreateDerivedIndexPattern, useSourceContext } from '../../containers/metrics_source';
|
import { CreateDerivedIndexPattern, useSourceContext } from '../../containers/metrics_source';
|
||||||
import { NotFoundPage } from '../404';
|
import { NotFoundPage } from '../404';
|
||||||
import { ReactQueryProvider } from '../../containers/react_query_provider';
|
import { ReactQueryProvider } from '../../containers/react_query_provider';
|
||||||
|
import { usePluginConfig } from '../../containers/plugin_config_context';
|
||||||
|
|
||||||
const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLabel', {
|
const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLabel', {
|
||||||
defaultMessage: 'Add data',
|
defaultMessage: 'Add data',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const InfrastructurePage = ({ match }: RouteComponentProps) => {
|
export const InfrastructurePage = () => {
|
||||||
|
const config = usePluginConfig();
|
||||||
const uiCapabilities = useKibana().services.application?.capabilities;
|
const uiCapabilities = useKibana().services.application?.capabilities;
|
||||||
const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext);
|
const { setHeaderActionMenu, theme$ } = useContext(HeaderActionMenuContext);
|
||||||
|
|
||||||
|
@ -96,19 +97,21 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => {
|
||||||
)}
|
)}
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={'/inventory'} component={SnapshotPage} />
|
<Route path={'/inventory'} component={SnapshotPage} />
|
||||||
<Route path={'/explorer'}>
|
{config.featureFlags.metricsExplorerEnabled && (
|
||||||
<MetricsExplorerOptionsContainer>
|
<Route path={'/explorer'}>
|
||||||
<WithMetricsExplorerOptionsUrlState />
|
<MetricsExplorerOptionsContainer>
|
||||||
{source?.configuration ? (
|
<WithMetricsExplorerOptionsUrlState />
|
||||||
<PageContent
|
{source?.configuration ? (
|
||||||
configuration={source.configuration}
|
<PageContent
|
||||||
createDerivedIndexPattern={createDerivedIndexPattern}
|
configuration={source.configuration}
|
||||||
/>
|
createDerivedIndexPattern={createDerivedIndexPattern}
|
||||||
) : (
|
/>
|
||||||
<SourceLoadingPage />
|
) : (
|
||||||
)}
|
<SourceLoadingPage />
|
||||||
</MetricsExplorerOptionsContainer>
|
)}
|
||||||
</Route>
|
</MetricsExplorerOptionsContainer>
|
||||||
|
</Route>
|
||||||
|
)}
|
||||||
<Route path="/detail/:type/:node" component={NodeDetail} />
|
<Route path="/detail/:type/:node" component={NodeDetail} />
|
||||||
<Route path={'/hosts'} component={HostsLandingPage} />
|
<Route path={'/hosts'} component={HostsLandingPage} />
|
||||||
<Route path={'/settings'} component={MetricsSettingsPage} />
|
<Route path={'/settings'} component={MetricsSettingsPage} />
|
||||||
|
@ -131,10 +134,6 @@ const PageContent = (props: {
|
||||||
const { createDerivedIndexPattern, configuration } = props;
|
const { createDerivedIndexPattern, configuration } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MetricsExplorerPage
|
<MetricsExplorerPage derivedIndexPattern={createDerivedIndexPattern()} source={configuration} />
|
||||||
derivedIndexPattern={createDerivedIndexPattern()}
|
|
||||||
source={configuration}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { MetricsPageTemplate } from '../page_template';
|
||||||
import { metricsExplorerTitle } from '../../../translations';
|
import { metricsExplorerTitle } from '../../../translations';
|
||||||
import { DerivedIndexPattern } from '../../../containers/metrics_source';
|
import { DerivedIndexPattern } from '../../../containers/metrics_source';
|
||||||
import { SavedViews } from './components/saved_views';
|
import { SavedViews } from './components/saved_views';
|
||||||
|
|
||||||
interface MetricsExplorerPageProps {
|
interface MetricsExplorerPageProps {
|
||||||
source: MetricsSourceConfigurationProperties;
|
source: MetricsSourceConfigurationProperties;
|
||||||
derivedIndexPattern: DerivedIndexPattern;
|
derivedIndexPattern: DerivedIndexPattern;
|
||||||
|
|
|
@ -50,7 +50,7 @@ import { getLogsHasDataFetcher, getLogsOverviewDataFetcher } from './utils/logs_
|
||||||
export class Plugin implements InfraClientPluginClass {
|
export class Plugin implements InfraClientPluginClass {
|
||||||
public config: InfraPublicConfig;
|
public config: InfraPublicConfig;
|
||||||
private inventoryViews: InventoryViewsService;
|
private inventoryViews: InventoryViewsService;
|
||||||
private metricsExplorerViews: MetricsExplorerViewsService;
|
private metricsExplorerViews?: MetricsExplorerViewsService;
|
||||||
private telemetry: TelemetryService;
|
private telemetry: TelemetryService;
|
||||||
private locators?: InfraLocators;
|
private locators?: InfraLocators;
|
||||||
private kibanaVersion: string;
|
private kibanaVersion: string;
|
||||||
|
@ -60,7 +60,9 @@ export class Plugin implements InfraClientPluginClass {
|
||||||
this.config = context.config.get();
|
this.config = context.config.get();
|
||||||
|
|
||||||
this.inventoryViews = new InventoryViewsService();
|
this.inventoryViews = new InventoryViewsService();
|
||||||
this.metricsExplorerViews = new MetricsExplorerViewsService();
|
this.metricsExplorerViews = this.config.featureFlags.metricsExplorerEnabled
|
||||||
|
? new MetricsExplorerViewsService()
|
||||||
|
: undefined;
|
||||||
this.telemetry = new TelemetryService();
|
this.telemetry = new TelemetryService();
|
||||||
this.kibanaVersion = context.env.packageInfo.version;
|
this.kibanaVersion = context.env.packageInfo.version;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +107,9 @@ export class Plugin implements InfraClientPluginClass {
|
||||||
/** !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts */
|
/** !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts */
|
||||||
const infraEntries = [
|
const infraEntries = [
|
||||||
{ label: 'Inventory', app: 'metrics', path: '/inventory' },
|
{ label: 'Inventory', app: 'metrics', path: '/inventory' },
|
||||||
{ label: 'Metrics Explorer', app: 'metrics', path: '/explorer' },
|
...(this.config.featureFlags.metricsExplorerEnabled
|
||||||
|
? [{ label: 'Metrics Explorer', app: 'metrics', path: '/explorer' }]
|
||||||
|
: []),
|
||||||
{ label: 'Hosts', isBetaFeature: true, app: 'metrics', path: '/hosts' },
|
{ label: 'Hosts', isBetaFeature: true, app: 'metrics', path: '/hosts' },
|
||||||
];
|
];
|
||||||
pluginsSetup.observabilityShared.navigation.registerSections(
|
pluginsSetup.observabilityShared.navigation.registerSections(
|
||||||
|
@ -231,13 +235,17 @@ export class Plugin implements InfraClientPluginClass {
|
||||||
}),
|
}),
|
||||||
path: '/hosts',
|
path: '/hosts',
|
||||||
},
|
},
|
||||||
{
|
...(this.config.featureFlags.metricsExplorerEnabled
|
||||||
id: 'metrics-explorer',
|
? [
|
||||||
title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', {
|
{
|
||||||
defaultMessage: 'Metrics Explorer',
|
id: 'metrics-explorer',
|
||||||
}),
|
title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', {
|
||||||
path: '/explorer',
|
defaultMessage: 'Metrics Explorer',
|
||||||
},
|
}),
|
||||||
|
path: '/explorer',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
id: 'settings',
|
id: 'settings',
|
||||||
title: i18n.translate('xpack.infra.homePage.settingsTabTitle', {
|
title: i18n.translate('xpack.infra.homePage.settingsTabTitle', {
|
||||||
|
@ -266,6 +274,7 @@ export class Plugin implements InfraClientPluginClass {
|
||||||
coreStart,
|
coreStart,
|
||||||
{ ...plugins, kibanaVersion: this.kibanaVersion },
|
{ ...plugins, kibanaVersion: this.kibanaVersion },
|
||||||
pluginStart,
|
pluginStart,
|
||||||
|
this.config,
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -313,7 +322,7 @@ export class Plugin implements InfraClientPluginClass {
|
||||||
http: core.http,
|
http: core.http,
|
||||||
});
|
});
|
||||||
|
|
||||||
const metricsExplorerViews = this.metricsExplorerViews.start({
|
const metricsExplorerViews = this.metricsExplorerViews?.start({
|
||||||
http: core.http,
|
http: core.http,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ export interface InfraClientSetupExports {
|
||||||
|
|
||||||
export interface InfraClientStartExports {
|
export interface InfraClientStartExports {
|
||||||
inventoryViews: InventoryViewsServiceStart;
|
inventoryViews: InventoryViewsServiceStart;
|
||||||
metricsExplorerViews: MetricsExplorerViewsServiceStart;
|
metricsExplorerViews?: MetricsExplorerViewsServiceStart;
|
||||||
telemetry: ITelemetryClient;
|
telemetry: ITelemetryClient;
|
||||||
locators: InfraLocators;
|
locators: InfraLocators;
|
||||||
ContainerMetricsTable: (
|
ContainerMetricsTable: (
|
||||||
|
|
|
@ -34,6 +34,7 @@ interface FrozenIndexParams {
|
||||||
export class KibanaFramework {
|
export class KibanaFramework {
|
||||||
public router: IRouter<InfraPluginRequestHandlerContext>;
|
public router: IRouter<InfraPluginRequestHandlerContext>;
|
||||||
public plugins: InfraServerPluginSetupDeps;
|
public plugins: InfraServerPluginSetupDeps;
|
||||||
|
public config: InfraConfig;
|
||||||
private core: CoreSetup<InfraServerPluginStartDeps>;
|
private core: CoreSetup<InfraServerPluginStartDeps>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -44,6 +45,7 @@ export class KibanaFramework {
|
||||||
this.router = core.http.createRouter();
|
this.router = core.http.createRouter();
|
||||||
this.plugins = plugins;
|
this.plugins = plugins;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerRoute<Params = any, Query = any, Body = any, Method extends RouteMethod = any>(
|
public registerRoute<Params = any, Query = any, Body = any, Method extends RouteMethod = any>(
|
||||||
|
|
|
@ -1898,6 +1898,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({
|
||||||
inventory: {
|
inventory: {
|
||||||
compositeSize: 2000,
|
compositeSize: 2000,
|
||||||
},
|
},
|
||||||
|
featureFlags: {
|
||||||
|
metricsExplorerEnabled: true,
|
||||||
|
},
|
||||||
enabled: true,
|
enabled: true,
|
||||||
sources,
|
sources,
|
||||||
});
|
});
|
||||||
|
|
|
@ -125,6 +125,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({
|
||||||
inventory: {
|
inventory: {
|
||||||
compositeSize: 2000,
|
compositeSize: 2000,
|
||||||
},
|
},
|
||||||
|
featureFlags: {
|
||||||
|
metricsExplorerEnabled: true,
|
||||||
|
},
|
||||||
sources,
|
sources,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Server } from '@hapi/hapi';
|
import { Server } from '@hapi/hapi';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema, offeringBasedSchema } from '@kbn/config-schema';
|
||||||
import {
|
import {
|
||||||
CoreStart,
|
CoreStart,
|
||||||
Plugin,
|
Plugin,
|
||||||
|
@ -80,6 +80,12 @@ export const config: PluginConfigDescriptor<InfraConfig> = {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
featureFlags: schema.object({
|
||||||
|
metricsExplorerEnabled: offeringBasedSchema({
|
||||||
|
traditional: schema.boolean({ defaultValue: true }),
|
||||||
|
serverless: schema.boolean({ defaultValue: false }),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
deprecations: configDeprecations,
|
deprecations: configDeprecations,
|
||||||
exposeToBrowser: publicConfigKeys,
|
exposeToBrowser: publicConfigKeys,
|
||||||
|
@ -111,7 +117,7 @@ export class InfraServerPlugin
|
||||||
private logsRules: RulesService;
|
private logsRules: RulesService;
|
||||||
private metricsRules: RulesService;
|
private metricsRules: RulesService;
|
||||||
private inventoryViews: InventoryViewsService;
|
private inventoryViews: InventoryViewsService;
|
||||||
private metricsExplorerViews: MetricsExplorerViewsService;
|
private metricsExplorerViews?: MetricsExplorerViewsService;
|
||||||
|
|
||||||
constructor(context: PluginInitializerContext<InfraConfig>) {
|
constructor(context: PluginInitializerContext<InfraConfig>) {
|
||||||
this.config = context.config.get();
|
this.config = context.config.get();
|
||||||
|
@ -129,9 +135,9 @@ export class InfraServerPlugin
|
||||||
);
|
);
|
||||||
|
|
||||||
this.inventoryViews = new InventoryViewsService(this.logger.get('inventoryViews'));
|
this.inventoryViews = new InventoryViewsService(this.logger.get('inventoryViews'));
|
||||||
this.metricsExplorerViews = new MetricsExplorerViewsService(
|
this.metricsExplorerViews = this.config.featureFlags.metricsExplorerEnabled
|
||||||
this.logger.get('metricsExplorerViews')
|
? new MetricsExplorerViewsService(this.logger.get('metricsExplorerViews'))
|
||||||
);
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup(core: InfraPluginCoreSetup, plugins: InfraServerPluginSetupDeps) {
|
setup(core: InfraPluginCoreSetup, plugins: InfraServerPluginSetupDeps) {
|
||||||
|
@ -155,12 +161,14 @@ export class InfraServerPlugin
|
||||||
|
|
||||||
// Setup infra services
|
// Setup infra services
|
||||||
const inventoryViews = this.inventoryViews.setup();
|
const inventoryViews = this.inventoryViews.setup();
|
||||||
const metricsExplorerViews = this.metricsExplorerViews.setup();
|
const metricsExplorerViews = this.metricsExplorerViews?.setup();
|
||||||
|
|
||||||
// Register saved object types
|
// Register saved object types
|
||||||
core.savedObjects.registerType(infraSourceConfigurationSavedObjectType);
|
core.savedObjects.registerType(infraSourceConfigurationSavedObjectType);
|
||||||
core.savedObjects.registerType(inventoryViewSavedObjectType);
|
core.savedObjects.registerType(inventoryViewSavedObjectType);
|
||||||
core.savedObjects.registerType(metricsExplorerViewSavedObjectType);
|
if (this.config.featureFlags.metricsExplorerEnabled) {
|
||||||
|
core.savedObjects.registerType(metricsExplorerViewSavedObjectType);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: separate these out individually and do away with "domains" as a temporary group
|
// TODO: separate these out individually and do away with "domains" as a temporary group
|
||||||
// and make them available via the request context so we can do away with
|
// and make them available via the request context so we can do away with
|
||||||
|
@ -255,7 +263,7 @@ export class InfraServerPlugin
|
||||||
savedObjects: core.savedObjects,
|
savedObjects: core.savedObjects,
|
||||||
});
|
});
|
||||||
|
|
||||||
const metricsExplorerViews = this.metricsExplorerViews.start({
|
const metricsExplorerViews = this.metricsExplorerViews?.start({
|
||||||
infraSources: this.libs.sources,
|
infraSources: this.libs.sources,
|
||||||
savedObjects: core.savedObjects,
|
savedObjects: core.savedObjects,
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,6 +15,13 @@ import {
|
||||||
} from '../../../common/http_api/latest';
|
} from '../../../common/http_api/latest';
|
||||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||||
|
|
||||||
|
const NON_STARTED_SERVICE_ERROR = {
|
||||||
|
statusCode: 500,
|
||||||
|
body: {
|
||||||
|
message: `Handler for "POST ${METRICS_EXPLORER_VIEW_URL}" was registered but MetricsViewService has not started.`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const initCreateMetricsExplorerViewRoute = ({
|
export const initCreateMetricsExplorerViewRoute = ({
|
||||||
framework,
|
framework,
|
||||||
getStartServices,
|
getStartServices,
|
||||||
|
@ -31,6 +38,11 @@ export const initCreateMetricsExplorerViewRoute = ({
|
||||||
async (_requestContext, request, response) => {
|
async (_requestContext, request, response) => {
|
||||||
const { body, query } = request;
|
const { body, query } = request;
|
||||||
const [, , { metricsExplorerViews }] = await getStartServices();
|
const [, , { metricsExplorerViews }] = await getStartServices();
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
return response.customError(NON_STARTED_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,6 +13,13 @@ import {
|
||||||
} from '../../../common/http_api/latest';
|
} from '../../../common/http_api/latest';
|
||||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||||
|
|
||||||
|
const NON_STARTED_SERVICE_ERROR = {
|
||||||
|
statusCode: 500,
|
||||||
|
body: {
|
||||||
|
message: `Handler for "DELETE ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const initDeleteMetricsExplorerViewRoute = ({
|
export const initDeleteMetricsExplorerViewRoute = ({
|
||||||
framework,
|
framework,
|
||||||
getStartServices,
|
getStartServices,
|
||||||
|
@ -28,6 +35,11 @@ export const initDeleteMetricsExplorerViewRoute = ({
|
||||||
async (_requestContext, request, response) => {
|
async (_requestContext, request, response) => {
|
||||||
const { params } = request;
|
const { params } = request;
|
||||||
const [, , { metricsExplorerViews }] = await getStartServices();
|
const [, , { metricsExplorerViews }] = await getStartServices();
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
return response.customError(NON_STARTED_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,6 +13,13 @@ import {
|
||||||
} from '../../../common/http_api/latest';
|
} from '../../../common/http_api/latest';
|
||||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||||
|
|
||||||
|
const NON_STARTED_SERVICE_ERROR = {
|
||||||
|
statusCode: 500,
|
||||||
|
body: {
|
||||||
|
message: `Handler for "GET ${METRICS_EXPLORER_VIEW_URL}" was registered but MetricsViewService has not started.`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const initFindMetricsExplorerViewRoute = ({
|
export const initFindMetricsExplorerViewRoute = ({
|
||||||
framework,
|
framework,
|
||||||
getStartServices,
|
getStartServices,
|
||||||
|
@ -28,6 +35,11 @@ export const initFindMetricsExplorerViewRoute = ({
|
||||||
async (_requestContext, request, response) => {
|
async (_requestContext, request, response) => {
|
||||||
const { query } = request;
|
const { query } = request;
|
||||||
const [, , { metricsExplorerViews }] = await getStartServices();
|
const [, , { metricsExplorerViews }] = await getStartServices();
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
return response.customError(NON_STARTED_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -15,6 +15,13 @@ import {
|
||||||
} from '../../../common/http_api/latest';
|
} from '../../../common/http_api/latest';
|
||||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||||
|
|
||||||
|
const NON_STARTED_SERVICE_ERROR = {
|
||||||
|
statusCode: 500,
|
||||||
|
body: {
|
||||||
|
message: `Handler for "GET ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const initGetMetricsExplorerViewRoute = ({
|
export const initGetMetricsExplorerViewRoute = ({
|
||||||
framework,
|
framework,
|
||||||
getStartServices,
|
getStartServices,
|
||||||
|
@ -31,6 +38,11 @@ export const initGetMetricsExplorerViewRoute = ({
|
||||||
async (_requestContext, request, response) => {
|
async (_requestContext, request, response) => {
|
||||||
const { params, query } = request;
|
const { params, query } = request;
|
||||||
const [, , { metricsExplorerViews }] = await getStartServices();
|
const [, , { metricsExplorerViews }] = await getStartServices();
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
return response.customError(NON_STARTED_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -15,6 +15,10 @@ import { initUpdateMetricsExplorerViewRoute } from './update_metrics_explorer_vi
|
||||||
export const initMetricsExplorerViewRoutes = (
|
export const initMetricsExplorerViewRoutes = (
|
||||||
dependencies: Pick<InfraBackendLibs, 'framework' | 'getStartServices'>
|
dependencies: Pick<InfraBackendLibs, 'framework' | 'getStartServices'>
|
||||||
) => {
|
) => {
|
||||||
|
if (!dependencies.framework.config.featureFlags.metricsExplorerEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
initCreateMetricsExplorerViewRoute(dependencies);
|
initCreateMetricsExplorerViewRoute(dependencies);
|
||||||
initDeleteMetricsExplorerViewRoute(dependencies);
|
initDeleteMetricsExplorerViewRoute(dependencies);
|
||||||
initFindMetricsExplorerViewRoute(dependencies);
|
initFindMetricsExplorerViewRoute(dependencies);
|
||||||
|
|
|
@ -16,6 +16,13 @@ import {
|
||||||
} from '../../../common/http_api/latest';
|
} from '../../../common/http_api/latest';
|
||||||
import type { InfraBackendLibs } from '../../lib/infra_types';
|
import type { InfraBackendLibs } from '../../lib/infra_types';
|
||||||
|
|
||||||
|
const NON_STARTED_SERVICE_ERROR = {
|
||||||
|
statusCode: 500,
|
||||||
|
body: {
|
||||||
|
message: `Handler for "PUT ${METRICS_EXPLORER_VIEW_URL_ENTITY}" was registered but MetricsViewService has not started.`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const initUpdateMetricsExplorerViewRoute = ({
|
export const initUpdateMetricsExplorerViewRoute = ({
|
||||||
framework,
|
framework,
|
||||||
getStartServices,
|
getStartServices,
|
||||||
|
@ -33,6 +40,11 @@ export const initUpdateMetricsExplorerViewRoute = ({
|
||||||
async (_requestContext, request, response) => {
|
async (_requestContext, request, response) => {
|
||||||
const { body, params, query } = request;
|
const { body, params, query } = request;
|
||||||
const [, , { metricsExplorerViews }] = await getStartServices();
|
const [, , { metricsExplorerViews }] = await getStartServices();
|
||||||
|
|
||||||
|
if (metricsExplorerViews === undefined) {
|
||||||
|
return response.customError(NON_STARTED_SERVICE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
const metricsExplorerViewsClient = metricsExplorerViews.getScopedClient(request);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -27,12 +27,12 @@ export interface InfraPluginSetup {
|
||||||
sourceProperties: InfraStaticSourceConfiguration
|
sourceProperties: InfraStaticSourceConfiguration
|
||||||
) => void;
|
) => void;
|
||||||
inventoryViews: InventoryViewsServiceSetup;
|
inventoryViews: InventoryViewsServiceSetup;
|
||||||
metricsExplorerViews: MetricsExplorerViewsServiceSetup;
|
metricsExplorerViews?: MetricsExplorerViewsServiceSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfraPluginStart {
|
export interface InfraPluginStart {
|
||||||
inventoryViews: InventoryViewsServiceStart;
|
inventoryViews: InventoryViewsServiceStart;
|
||||||
metricsExplorerViews: MetricsExplorerViewsServiceStart;
|
metricsExplorerViews?: MetricsExplorerViewsServiceStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MlSystem = ReturnType<MlPluginSetup['mlSystemProvider']>;
|
export type MlSystem = ReturnType<MlPluginSetup['mlSystemProvider']>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue