mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
Logs Essentials for Observability (#223030)
## Summary disables features under Application for serverless-essentials. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c04d1782b7
commit
d157214e1a
14 changed files with 229 additions and 50 deletions
|
@ -3,7 +3,22 @@
|
|||
## Enabled plugins
|
||||
xpack.infra.enabled: true
|
||||
xpack.slo.enabled: true
|
||||
xpack.uptime.enabled: true
|
||||
|
||||
xpack.features.overrides:
|
||||
### By default, this feature named as `Metrics`, but should be renamed to `Infrastructure`.
|
||||
infrastructure.name: 'Infrastructure'
|
||||
### By default, this feature named as `APM and User Experience`, but should be renamed to `Applications`.
|
||||
apm.name: 'Applications'
|
||||
### Dashboards feature should be moved from Analytics category to the Observability one.
|
||||
dashboard_v2.category: 'observability'
|
||||
### Discover feature should be moved from Analytics category to the Observability one and its privileges are
|
||||
### fine-tuned to grant access to Observability app.
|
||||
discover_v2.category: 'observability'
|
||||
### Machine Learning feature should be moved from Analytics category to the Observability one and renamed to `AI Ops`.
|
||||
ml:
|
||||
category: 'observability'
|
||||
order: 1200
|
||||
### Stack alerts is hidden in Role management since it's not needed.
|
||||
stackAlerts.hidden: true
|
||||
### By default, this feature named as `Synthetics and Uptime`, but should be renamed to `Synthetics` since `Uptime` is not available.
|
||||
uptime.name: 'Synthetics'
|
|
@ -5,3 +5,41 @@ xpack.infra.enabled: false
|
|||
xpack.slo.enabled: false
|
||||
xpack.observabilityAIAssistant.enabled: false
|
||||
xpack.aiops.ui.enabled: false
|
||||
xpack.apm.enabled: false
|
||||
|
||||
xpack.legacy_uptime.enabled: false
|
||||
xpack.ux.enabled: false
|
||||
xpack.uptime.enabled: false
|
||||
|
||||
xpack.fleet.internal.registry.excludePackages: [
|
||||
# Oblt integrations
|
||||
'synthetics',
|
||||
# Security integrations
|
||||
'endpoint',
|
||||
'beaconing',
|
||||
'cloud_security_posture',
|
||||
'cloud_defend',
|
||||
'security_detection_engine',
|
||||
|
||||
# Deprecated security integrations
|
||||
'bluecoat',
|
||||
'cisco',
|
||||
'cyberark',
|
||||
'cylance',
|
||||
'f5',
|
||||
'fortinet_forticlient',
|
||||
'juniper_junos',
|
||||
'juniper_netscreen',
|
||||
'microsoft',
|
||||
'netscout',
|
||||
'radware',
|
||||
'symantec',
|
||||
'tomcat',
|
||||
|
||||
# ML integrations
|
||||
'dga',
|
||||
|
||||
# Profiling integrations
|
||||
'profiler_agent',
|
||||
'synthetics_dashboards',
|
||||
]
|
||||
|
|
|
@ -13,23 +13,6 @@ plugins.allowlistPluginGroups: ['platform', 'observability']
|
|||
xpack.ux.enabled: false
|
||||
xpack.legacy_uptime.enabled: false
|
||||
|
||||
xpack.features.overrides:
|
||||
### By default, this feature named as `APM and User Experience`, but should be renamed to `Applications`.
|
||||
apm.name: 'Applications'
|
||||
### Dashboards feature should be moved from Analytics category to the Observability one.
|
||||
dashboard_v2.category: 'observability'
|
||||
### Discover feature should be moved from Analytics category to the Observability one and its privileges are
|
||||
### fine-tuned to grant access to Observability app.
|
||||
discover_v2.category: 'observability'
|
||||
### Machine Learning feature should be moved from Analytics category to the Observability one and renamed to `AI Ops`.
|
||||
ml:
|
||||
category: 'observability'
|
||||
order: 1200
|
||||
### Stack alerts is hidden in Role management since it's not needed.
|
||||
stackAlerts.hidden: true
|
||||
### By default, this feature named as `Synthetics and Uptime`, but should be renamed to `Synthetics` since `Uptime` is not available.
|
||||
uptime.name: 'Synthetics'
|
||||
|
||||
## Cloud settings
|
||||
xpack.cloud.serverless.project_type: observability
|
||||
|
||||
|
|
|
@ -5,17 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { render } from '@testing-library/react';
|
||||
import { pricingServiceMock } from '@kbn/core-pricing-browser-mocks';
|
||||
import { noop } from 'lodash';
|
||||
import React from 'react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Observable } from 'rxjs';
|
||||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
import { AppMountParameters, CoreStart } from '@kbn/core/public';
|
||||
import { themeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
|
||||
import { ConfigSchema, ObservabilityPublicPluginsStart } from '../plugin';
|
||||
import { createObservabilityRuleTypeRegistryMock } from '../rules/observability_rule_type_registry_mock';
|
||||
import { renderApp } from '.';
|
||||
import { renderApp, App } from '.';
|
||||
import { mockService } from '@kbn/observability-ai-assistant-plugin/public/mock';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
|
||||
|
||||
describe('renderApp', () => {
|
||||
const originalConsole = global.console;
|
||||
|
@ -29,6 +35,8 @@ describe('renderApp', () => {
|
|||
global.console = originalConsole;
|
||||
});
|
||||
|
||||
let pricingStart: ReturnType<typeof pricingServiceMock.createStartContract>;
|
||||
|
||||
const mockSearchSessionClear = jest.fn();
|
||||
|
||||
const plugins = {
|
||||
|
@ -82,6 +90,14 @@ describe('renderApp', () => {
|
|||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
pricingStart = pricingServiceMock.createStartContract();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders', async () => {
|
||||
expect(() => {
|
||||
const unmount = renderApp({
|
||||
|
@ -123,4 +139,42 @@ describe('renderApp', () => {
|
|||
|
||||
expect(mockSearchSessionClear).toBeCalled();
|
||||
});
|
||||
|
||||
function AppWrapper({ children }: { children?: ReactNode }) {
|
||||
return (
|
||||
<KibanaRenderContextProvider {...core}>
|
||||
<KibanaContextProvider services={{ pricing: pricingStart }}>
|
||||
<MemoryRouter initialEntries={['/overview']}>
|
||||
<App />
|
||||
</MemoryRouter>
|
||||
</KibanaContextProvider>
|
||||
</KibanaRenderContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
it('should adjust routes for complete', () => {
|
||||
// Mock feature availability
|
||||
pricingStart.isFeatureAvailable.mockImplementation((featureId) => {
|
||||
if (featureId === 'observability:complete_overview') {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
render(<App />, { wrapper: AppWrapper });
|
||||
expect(document.body.textContent).toContain('Unable to load page');
|
||||
});
|
||||
|
||||
it('should adjust routes for essentials', () => {
|
||||
// Mock feature availability
|
||||
pricingStart.isFeatureAvailable.mockImplementation((featureId) => {
|
||||
if (featureId === 'observability:complete_overview') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
render(<App />, { wrapper: AppWrapper });
|
||||
expect(document.body.textContent).not.toContain('Unable to load page');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,17 +23,23 @@ import { Storage } from '@kbn/kibana-utils-plugin/public';
|
|||
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
||||
import { PluginContext } from '../context/plugin_context/plugin_context';
|
||||
import { ConfigSchema, ObservabilityPublicPluginsStart } from '../plugin';
|
||||
import { routes } from '../routes/routes';
|
||||
import { routes, completeRoutes } from '../routes/routes';
|
||||
import { useKibana } from '../utils/kibana_react';
|
||||
import { ObservabilityRuleTypeRegistry } from '../rules/create_observability_rule_type_registry';
|
||||
import { HideableReactQueryDevTools } from './hideable_react_query_dev_tools';
|
||||
|
||||
function App() {
|
||||
export function App() {
|
||||
const { pricing } = useKibana().services;
|
||||
const isCompleteOverviewEnabled = pricing.isFeatureAvailable('observability:complete_overview');
|
||||
const allRoutes = {
|
||||
...(isCompleteOverviewEnabled ? { ...completeRoutes, ...routes } : { ...routes }),
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Routes enableExecutionContextTracking={true}>
|
||||
{Object.keys(routes).map((key) => {
|
||||
const path = key as keyof typeof routes;
|
||||
const { handler, exact } = routes[path];
|
||||
{Object.keys(allRoutes).map((key) => {
|
||||
const path = key as keyof typeof allRoutes;
|
||||
const { handler, exact } = allRoutes[path];
|
||||
const Wrapper = () => {
|
||||
return handler();
|
||||
};
|
||||
|
|
|
@ -62,7 +62,7 @@ function SimpleRedirect({ to, redirectToApp }: { to: string; redirectToApp?: str
|
|||
return null;
|
||||
}
|
||||
|
||||
export const routes = {
|
||||
export const completeRoutes = {
|
||||
[ROOT_PATH]: {
|
||||
handler: () => {
|
||||
return <SimpleRedirect to={OVERVIEW_PATH} />;
|
||||
|
@ -70,17 +70,6 @@ export const routes = {
|
|||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
[LANDING_PATH]: {
|
||||
handler: () => {
|
||||
return (
|
||||
<HasDataContextProvider>
|
||||
<LandingPage />
|
||||
</HasDataContextProvider>
|
||||
);
|
||||
},
|
||||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
[OVERVIEW_PATH]: {
|
||||
handler: () => {
|
||||
return (
|
||||
|
@ -94,6 +83,20 @@ export const routes = {
|
|||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const routes = {
|
||||
[LANDING_PATH]: {
|
||||
handler: () => {
|
||||
return (
|
||||
<HasDataContextProvider>
|
||||
<LandingPage />
|
||||
</HasDataContextProvider>
|
||||
);
|
||||
},
|
||||
params: {},
|
||||
exact: true,
|
||||
},
|
||||
[CASES_PATH]: {
|
||||
handler: () => {
|
||||
return <CasesPage />;
|
||||
|
|
|
@ -122,7 +122,8 @@
|
|||
"@kbn/object-utils",
|
||||
"@kbn/task-manager-plugin",
|
||||
"@kbn/core-saved-objects-server",
|
||||
"@kbn/esql"
|
||||
"@kbn/core-pricing-browser-mocks",
|
||||
"@kbn/esql",
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../../..',
|
||||
roots: ['<rootDir>/x-pack/solutions/observability/plugins/serverless_observability'],
|
||||
coverageDirectory:
|
||||
'<rootDir>/target/kibana-coverage/jest/x-pack/solutions/observability/plugins/serverless_observability',
|
||||
coverageReporters: ['text', 'html'],
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/x-pack/solutions/observability/plugins/serverless_observability/{common,public,server}/**/*.{js,ts,tsx}',
|
||||
],
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { createNavigationTree } from './navigation_tree';
|
||||
import type { GroupDefinition, AppDeepLinkId } from '@kbn/core-chrome-browser';
|
||||
|
||||
describe('Navigation Tree', () => {
|
||||
it('should generate tree with overview', () => {
|
||||
const navigation = createNavigationTree({});
|
||||
expect((navigation.body[0] as GroupDefinition<AppDeepLinkId, string, string>).children).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
title: 'Overview',
|
||||
link: 'observability-overview',
|
||||
},
|
||||
])
|
||||
);
|
||||
});
|
||||
it('should not generate tree with overview', () => {
|
||||
const navigation = createNavigationTree({ overviewAvailable: false });
|
||||
expect(
|
||||
(navigation.body[0] as GroupDefinition<AppDeepLinkId, string, string>).children
|
||||
).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
title: 'Overview',
|
||||
link: 'observability-overview',
|
||||
},
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
|
@ -10,8 +10,10 @@ import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser';
|
|||
|
||||
export const createNavigationTree = ({
|
||||
streamsAvailable,
|
||||
overviewAvailable = true,
|
||||
}: {
|
||||
streamsAvailable?: boolean;
|
||||
overviewAvailable?: boolean;
|
||||
}): NavigationTreeDefinition => {
|
||||
return {
|
||||
body: [
|
||||
|
@ -24,12 +26,16 @@ export const createNavigationTree = ({
|
|||
isCollapsible: false,
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
title: i18n.translate('xpack.serverlessObservability.nav.overview', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
link: 'observability-overview',
|
||||
},
|
||||
...(overviewAvailable
|
||||
? [
|
||||
{
|
||||
title: i18n.translate('xpack.serverlessObservability.nav.overview', {
|
||||
defaultMessage: 'Overview',
|
||||
}),
|
||||
link: 'observability-overview' as const,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
title: i18n.translate('xpack.serverlessObservability.nav.discover', {
|
||||
defaultMessage: 'Discover',
|
||||
|
|
|
@ -43,7 +43,10 @@ export class ServerlessObservabilityPlugin
|
|||
const { serverless, management, security } = setupDeps;
|
||||
const navigationTree$ = (setupDeps.streams?.status$ || of({ status: 'disabled' })).pipe(
|
||||
map(({ status }) => {
|
||||
return createNavigationTree({ streamsAvailable: status === 'enabled' });
|
||||
return createNavigationTree({
|
||||
streamsAvailable: status === 'enabled',
|
||||
overviewAvailable: core.pricing.isFeatureAvailable('observability:complete_overview'),
|
||||
});
|
||||
})
|
||||
);
|
||||
serverless.setProjectHome('/app/observability/landing');
|
||||
|
|
|
@ -29,12 +29,22 @@ export class ServerlessObservabilityPlugin
|
|||
{
|
||||
constructor(_initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public setup(_coreSetup: CoreSetup, pluginsSetup: SetupDependencies) {
|
||||
public setup(
|
||||
_coreSetup: CoreSetup<StartDependencies, ServerlessObservabilityPluginStart>,
|
||||
pluginsSetup: SetupDependencies
|
||||
) {
|
||||
pluginsSetup.serverless.setupProjectSettings([
|
||||
...OBSERVABILITY_PROJECT_SETTINGS,
|
||||
...(pluginsSetup.observabilityAIAssistant ? OBSERVABILITY_AI_ASSISTANT_PROJECT_SETTINGS : []),
|
||||
]);
|
||||
|
||||
_coreSetup.pricing.registerProductFeatures([
|
||||
{
|
||||
id: 'observability:complete_overview',
|
||||
products: [{ name: 'observability', tier: 'complete' }],
|
||||
description:
|
||||
'Observability Overview Complete - Enables overview of the Observability solution.',
|
||||
},
|
||||
]);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ export function SvlObltNavigationServiceProvider({
|
|||
}: FtrProviderContext) {
|
||||
const retry = getService('retry');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
|
||||
return {
|
||||
async navigateToLandingPage() {
|
||||
|
@ -22,5 +22,11 @@ export function SvlObltNavigationServiceProvider({
|
|||
await testSubjects.existOrFail('obltOnboardingHomeTitle', { timeout: 2000 });
|
||||
});
|
||||
},
|
||||
async navigateToDiscoverPage() {
|
||||
await retry.tryForTime(60 * 1000, async () => {
|
||||
await PageObjects.common.navigateToApp('discover');
|
||||
await testSubjects.exists('discoverQueryTotalHits', { timeout: 20_000 });
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
|
|||
describe('navigation', function () {
|
||||
before(async () => {
|
||||
await svlCommonPage.loginWithPrivilegedRole();
|
||||
await svlObltNavigation.navigateToLandingPage();
|
||||
await svlObltNavigation.navigateToDiscoverPage();
|
||||
});
|
||||
|
||||
it('does not show the SLO entry', async () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue