🌊 Enable streams in the UI for serverless observability (#215533)

# Only merge this if you want streams to go public

This PR changes the logic for the client side "status$" observable for
streams to look for whether it's on serverless in an observability
project (because this is where we want to launch first).

Later on, this logic can be adjusted as necessary for on-prem launches
etc.

To make this work locally, you need to add
`xpack.cloud.serverless.project_id: "project_id"` to your
`config/kibana.dev.yml`

It still shows the streams app if wired streams are enabled (basically
it keeps the old behavior plus always defaulting to `enabled` if it's an
observability serverless project.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Joe Reuter 2025-04-11 18:53:10 +02:00 committed by GitHub
parent e0f106f1b7
commit 77ff3c2f62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 27 deletions

View file

@ -9,10 +9,17 @@ import { CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/public
import { Logger } from '@kbn/logging';
import { createRepositoryClient } from '@kbn/server-route-repository-client';
import { from, shareReplay, startWith } from 'rxjs';
import { Observable, from, shareReplay, startWith } from 'rxjs';
import { once } from 'lodash';
import type { StreamsPublicConfig } from '../common/config';
import { StreamsPluginClass, StreamsPluginSetup, StreamsPluginStart } from './types';
import {
StreamsPluginClass,
StreamsPluginSetup,
StreamsPluginSetupDependencies,
StreamsPluginStart,
StreamsPluginStartDependencies,
StreamsStatus,
} from './types';
import { StreamsRepositoryClient } from './api';
export class Plugin implements StreamsPluginClass {
@ -26,37 +33,52 @@ export class Plugin implements StreamsPluginClass {
this.logger = context.logger.get();
}
setup(core: CoreSetup<{}>, pluginSetup: {}): StreamsPluginSetup {
setup(core: CoreSetup, pluginSetup: StreamsPluginSetupDependencies): StreamsPluginSetup {
this.repositoryClient = createRepositoryClient(core);
return {
status$: createStatusObservable(this.logger, this.repositoryClient),
status$: createStreamsStatusObservable(pluginSetup, this.repositoryClient, this.logger),
};
}
start(core: CoreStart, pluginsStart: {}): StreamsPluginStart {
start(core: CoreStart, pluginsStart: StreamsPluginStartDependencies): StreamsPluginStart {
return {
streamsRepositoryClient: this.repositoryClient,
status$: createStatusObservable(this.logger, this.repositoryClient),
status$: createStreamsStatusObservable(pluginsStart, this.repositoryClient, this.logger),
};
}
stop() {}
}
const createStatusObservable = once((logger: Logger, repositoryClient: StreamsRepositoryClient) => {
return from(
repositoryClient
.fetch('GET /api/streams/_status', {
signal: new AbortController().signal,
})
.then(
(response) => ({
status: response.enabled ? ('enabled' as const) : ('disabled' as const),
}),
(error) => {
logger.error(error);
return { status: 'unknown' as const };
}
)
).pipe(startWith({ status: 'unknown' as const }), shareReplay(1));
});
const ENABLED_STATUS: StreamsStatus = { status: 'enabled' };
const DISABLED_STATUS: StreamsStatus = { status: 'disabled' };
const UNKNOWN_STATUS: StreamsStatus = { status: 'unknown' };
const createStreamsStatusObservable = once(
(
deps: StreamsPluginSetupDependencies | StreamsPluginStartDependencies,
repositoryClient: StreamsRepositoryClient,
logger: Logger
): Observable<StreamsStatus> => {
const isObservabilityServerless =
deps.cloud?.isServerlessEnabled && deps.cloud?.serverless.projectType === 'observability';
if (isObservabilityServerless) {
return from([ENABLED_STATUS]);
}
return from(
repositoryClient
.fetch('GET /api/streams/_status', {
signal: new AbortController().signal,
})
.then(
(response) => (response.enabled ? ENABLED_STATUS : DISABLED_STATUS),
(error) => {
logger.error(error);
return UNKNOWN_STATUS;
}
)
).pipe(startWith(UNKNOWN_STATUS), shareReplay(1));
}
);

View file

@ -7,15 +7,33 @@
import type { Plugin as PluginClass } from '@kbn/core/public';
import { Observable } from 'rxjs';
import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
import type { StreamsRepositoryClient } from './api';
export interface StreamsStatus {
status: 'unknown' | 'enabled' | 'disabled';
}
export interface StreamsPluginSetup {
status$: Observable<{ status: 'unknown' | 'enabled' | 'disabled' }>;
status$: Observable<StreamsStatus>;
}
export interface StreamsPluginStart {
streamsRepositoryClient: StreamsRepositoryClient;
status$: Observable<{ status: 'unknown' | 'enabled' | 'disabled' }>;
status$: Observable<StreamsStatus>;
}
export type StreamsPluginClass = PluginClass<StreamsPluginSetup, StreamsPluginStart, {}, {}>;
export interface StreamsPluginSetupDependencies {
cloud?: CloudSetup;
}
export interface StreamsPluginStartDependencies {
cloud?: CloudStart;
}
export type StreamsPluginClass = PluginClass<
StreamsPluginSetup,
StreamsPluginStart,
StreamsPluginSetupDependencies,
StreamsPluginStartDependencies
>;

View file

@ -43,6 +43,7 @@
"@kbn/utils",
"@kbn/core-saved-objects-server-internal",
"@kbn/core-analytics-server",
"@kbn/es-types",
"@kbn/cloud-plugin",
"@kbn/es-types"
]
}