[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:
Mykola Harmash 2023-09-29 11:27:19 +02:00 committed by GitHub
parent 4c1ca7e92f
commit d0a0a1f9e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 239 additions and 62 deletions

View file

@ -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)',

View file

@ -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('/');

View file

@ -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 {

View file

@ -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>

View file

@ -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);
});
});

View file

@ -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;

View file

@ -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();

View file

@ -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}
/>
); );
}; };

View file

@ -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;

View file

@ -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,
}); });

View file

@ -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: (

View file

@ -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>(

View file

@ -1898,6 +1898,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({
inventory: { inventory: {
compositeSize: 2000, compositeSize: 2000,
}, },
featureFlags: {
metricsExplorerEnabled: true,
},
enabled: true, enabled: true,
sources, sources,
}); });

View file

@ -125,6 +125,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({
inventory: { inventory: {
compositeSize: 2000, compositeSize: 2000,
}, },
featureFlags: {
metricsExplorerEnabled: true,
},
sources, sources,
enabled: true, enabled: true,
}); });

View file

@ -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,
}); });

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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);

View file

@ -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 {

View file

@ -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']>;