From 37d965ab842b550eea55935298bf38ae8309ab8d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 15:11:59 +0100 Subject: [PATCH 01/32] first pass --- src/core/server/index.ts | 1 + .../integration_tests/plugins_service.test.ts | 4 +- src/core/server/plugins/plugin.ts | 4 +- src/core/server/plugins/types.ts | 37 ++++++++++++++++++- src/plugins/apm_oss/server/plugin.ts | 7 ++-- src/plugins/console/server/plugin.ts | 7 ++-- src/plugins/usage_collection/server/plugin.ts | 12 ++---- x-pack/plugins/apm/server/plugin.ts | 7 +++- x-pack/plugins/cloud/server/plugin.ts | 17 ++++----- x-pack/plugins/event_log/server/plugin.ts | 22 ++++------- x-pack/plugins/event_log/server/types.ts | 2 - x-pack/plugins/fleet/server/plugin.ts | 4 +- .../fleet/server/services/app_context.ts | 8 ++-- x-pack/plugins/global_search/server/plugin.ts | 11 ++---- x-pack/plugins/licensing/server/plugin.ts | 12 +++--- x-pack/plugins/observability/server/plugin.ts | 7 +--- .../plugins/remote_clusters/server/plugin.ts | 11 ++---- x-pack/plugins/task_manager/server/plugin.ts | 9 ++--- .../triggers_actions_ui/server/plugin.ts | 4 +- 19 files changed, 96 insertions(+), 90 deletions(-) diff --git a/src/core/server/index.ts b/src/core/server/index.ts index af6d511a58779f..7fa45506090a46 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -235,6 +235,7 @@ export { export { DiscoveredPlugin, Plugin, + AsyncPlugin, PluginConfigDescriptor, PluginConfigSchema, PluginInitializer, diff --git a/src/core/server/plugins/integration_tests/plugins_service.test.ts b/src/core/server/plugins/integration_tests/plugins_service.test.ts index b100cd23470ddf..b342a1fe0e70ac 100644 --- a/src/core/server/plugins/integration_tests/plugins_service.test.ts +++ b/src/core/server/plugins/integration_tests/plugins_service.test.ts @@ -20,7 +20,7 @@ import { config } from '../plugins_config'; import { loggingSystemMock } from '../../logging/logging_system.mock'; import { environmentServiceMock } from '../../environment/environment_service.mock'; import { coreMock } from '../../mocks'; -import { Plugin } from '../types'; +import { AsyncPlugin } from '../types'; import { PluginWrapper } from '../plugin'; describe('PluginsService', () => { @@ -138,7 +138,7 @@ describe('PluginsService', () => { expect(startDependenciesResolved).toBe(false); return pluginStartContract; }, - } as Plugin); + } as AsyncPlugin); jest.doMock( join(pluginPath, 'server'), diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index 7f115ed77a6ef5..8f9ab2d6ec7dbf 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -14,7 +14,7 @@ import { isConfigSchema } from '@kbn/config-schema'; import { Logger } from '../logging'; import { - Plugin, + SyncOrAsyncPlugin, PluginInitializerContext, PluginManifest, PluginInitializer, @@ -49,7 +49,7 @@ export class PluginWrapper< private readonly log: Logger; private readonly initializerContext: PluginInitializerContext; - private instance?: Plugin; + private instance?: SyncOrAsyncPlugin; private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>(); public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise(); diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index 8858d7bbbda0be..ca1737972c44b7 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -242,12 +242,45 @@ export interface Plugin< TStart = void, TPluginsSetup extends object = object, TPluginsStart extends object = object +> { + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; + start(core: CoreStart, plugins: TPluginsStart): TStart; + stop?(): void; +} + +/** + * The interface that should be returned by a `PluginInitializer`. + * + * @deprecated Asynchronous plugins should be migrated to {@link Plugin} + * @public + */ +export interface AsyncPlugin< + TSetup = void, + TStart = void, + TPluginsSetup extends object = object, + TPluginsStart extends object = object > { setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; stop?(): void; } +/** + * Internal representation of a synchronous or asynchronous plugin. + * + * Should be removed and usages replaced by `Plugin` once sync lifecycle migration is complete + * + * @internal + */ +export type SyncOrAsyncPlugin< + TSetup = void, + TStart = void, + TPluginsSetup extends object = object, + TPluginsStart extends object = object +> = + | Plugin + | AsyncPlugin; + export const SharedGlobalConfigKeys = { // We can add more if really needed kibana: ['index', 'autocompleteTerminateAfter', 'autocompleteTimeout'] as const, @@ -383,4 +416,6 @@ export type PluginInitializer< TStart, TPluginsSetup extends object = object, TPluginsStart extends object = object -> = (core: PluginInitializerContext) => Plugin; +> = ( + core: PluginInitializerContext +) => SyncOrAsyncPlugin; diff --git a/src/plugins/apm_oss/server/plugin.ts b/src/plugins/apm_oss/server/plugin.ts index f3a66458e8b31a..e84df30c4eef5f 100644 --- a/src/plugins/apm_oss/server/plugin.ts +++ b/src/plugins/apm_oss/server/plugin.ts @@ -8,7 +8,6 @@ import { Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; import { Observable } from 'rxjs'; -import { take } from 'rxjs/operators'; import { APMOSSConfig } from './'; import { HomeServerPluginSetup, TutorialProvider } from '../../home/server'; import { tutorialProvider } from './tutorial'; @@ -17,10 +16,10 @@ export class APMOSSPlugin implements Plugin { constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; } - public async setup(core: CoreSetup, plugins: { home: HomeServerPluginSetup }) { + public setup(core: CoreSetup, plugins: { home: HomeServerPluginSetup }) { const config$ = this.initContext.config.create(); - const config = await config$.pipe(take(1)).toPromise(); + const config = this.initContext.config.get(); const apmTutorialProvider = tutorialProvider({ indexPatternTitle: config.indexPattern, @@ -35,6 +34,7 @@ export class APMOSSPlugin implements Plugin { plugins.home.tutorials.registerTutorial(apmTutorialProvider); return { + config, config$, getRegisteredTutorialProvider: () => apmTutorialProvider, }; @@ -45,6 +45,7 @@ export class APMOSSPlugin implements Plugin { } export interface APMOSSPluginSetup { + config: APMOSSConfig; config$: Observable; getRegisteredTutorialProvider(): TutorialProvider; } diff --git a/src/plugins/console/server/plugin.ts b/src/plugins/console/server/plugin.ts index a8c973a7c3ef08..b1019e5cfdee75 100644 --- a/src/plugins/console/server/plugin.ts +++ b/src/plugins/console/server/plugin.ts @@ -6,7 +6,6 @@ * Public License, v 1. */ -import { first } from 'rxjs/operators'; import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server'; import { ProxyConfigCollection } from './lib'; @@ -28,7 +27,7 @@ export class ConsoleServerPlugin implements Plugin { this.log = this.ctx.logger.get(); } - async setup({ http, capabilities, getStartServices, elasticsearch }: CoreSetup) { + setup({ http, capabilities, getStartServices, elasticsearch }: CoreSetup) { capabilities.registerProvider(() => ({ dev_tools: { show: true, @@ -36,8 +35,8 @@ export class ConsoleServerPlugin implements Plugin { }, })); - const config = await this.ctx.config.create().pipe(first()).toPromise(); - const globalConfig = await this.ctx.config.legacy.globalConfig$.pipe(first()).toPromise(); + const config = this.ctx.config.get(); + const globalConfig = this.ctx.config.legacy.get(); const proxyPathFilters = config.proxyFilter.map((str: string) => new RegExp(str)); this.esLegacyConfigService.setup(elasticsearch.legacy.config$); diff --git a/src/plugins/usage_collection/server/plugin.ts b/src/plugins/usage_collection/server/plugin.ts index 083acea5a02ccf..3cce553f4f6ace 100644 --- a/src/plugins/usage_collection/server/plugin.ts +++ b/src/plugins/usage_collection/server/plugin.ts @@ -6,7 +6,6 @@ * Public License, v 1. */ -import { first } from 'rxjs/operators'; import { PluginInitializerContext, Logger, @@ -27,20 +26,15 @@ export class UsageCollectionPlugin implements Plugin { this.logger = this.initializerContext.logger.get(); } - public async setup(core: CoreSetup) { - const config = await this.initializerContext.config - .create() - .pipe(first()) - .toPromise(); + public setup(core: CoreSetup) { + const config = this.initializerContext.config.get(); const collectorSet = new CollectorSet({ logger: this.logger.get('collector-set'), maximumWaitTimeForAllCollectorsInS: config.maximumWaitTimeForAllCollectorsInS, }); - const globalConfig = await this.initializerContext.config.legacy.globalConfig$ - .pipe(first()) - .toPromise(); + const globalConfig = this.initializerContext.config.legacy.get(); const router = core.http.createRouter(); setupRoutes({ diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index 3e01523aa8e31c..53482a9a42897a 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -60,7 +60,7 @@ export class APMPlugin implements Plugin { this.initContext = initContext; } - public async setup( + public setup( core: CoreSetup, plugins: { apmOss: APMOSSPluginSetup; @@ -97,7 +97,10 @@ export class APMPlugin implements Plugin { }); } - this.currentConfig = await mergedConfig$.pipe(take(1)).toPromise(); + this.currentConfig = mergeConfigs( + plugins.apmOss.config, + this.initContext.config.get() + ); if ( plugins.taskManager && diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index 784e8a755f9213..31477ccd83645b 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; -import { Observable } from 'rxjs'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; import { CloudConfigType } from './config'; @@ -27,25 +25,24 @@ export interface CloudSetup { export class CloudPlugin implements Plugin { private readonly logger: Logger; - private readonly config$: Observable; + private readonly config: CloudConfigType; constructor(private readonly context: PluginInitializerContext) { this.logger = this.context.logger.get(); - this.config$ = this.context.config.create(); + this.config = this.context.config.get(); } - public async setup(core: CoreSetup, { usageCollection }: PluginsSetup) { + public setup(core: CoreSetup, { usageCollection }: PluginsSetup) { this.logger.debug('Setting up Cloud plugin'); - const config = await this.config$.pipe(first()).toPromise(); - const isCloudEnabled = getIsCloudEnabled(config.id); + const isCloudEnabled = getIsCloudEnabled(this.config.id); registerCloudUsageCollector(usageCollection, { isCloudEnabled }); return { - cloudId: config.id, + cloudId: this.config.id, isCloudEnabled, apm: { - url: config.apm?.url, - secretToken: config.apm?.secret_token, + url: this.config.apm?.url, + secretToken: this.config.apm?.secret_token, }, }; } diff --git a/x-pack/plugins/event_log/server/plugin.ts b/x-pack/plugins/event_log/server/plugin.ts index 3bf726de718567..0d0663484dfb0d 100644 --- a/x-pack/plugins/event_log/server/plugin.ts +++ b/x-pack/plugins/event_log/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { CoreSetup, CoreStart, @@ -23,7 +21,6 @@ import type { IEventLogConfig, IEventLogService, IEventLogger, - IEventLogConfig$, IEventLogClientService, } from './types'; import { findRoute } from './routes'; @@ -47,32 +44,29 @@ interface PluginStartDeps { } export class Plugin implements CorePlugin { - private readonly config$: IEventLogConfig$; + private readonly config: IEventLogConfig; private systemLogger: Logger; private eventLogService?: EventLogService; private esContext?: EsContext; private eventLogger?: IEventLogger; - private globalConfig$: Observable; + private globalConfig: SharedGlobalConfig; private eventLogClientService?: EventLogClientService; private savedObjectProviderRegistry: SavedObjectProviderRegistry; private kibanaVersion: PluginInitializerContext['env']['packageInfo']['version']; constructor(private readonly context: PluginInitializerContext) { this.systemLogger = this.context.logger.get(); - this.config$ = this.context.config.create(); - this.globalConfig$ = this.context.config.legacy.globalConfig$; + this.config = this.context.config.get(); + this.globalConfig = this.context.config.legacy.get(); this.savedObjectProviderRegistry = new SavedObjectProviderRegistry(); this.kibanaVersion = this.context.env.packageInfo.version; } - async setup(core: CoreSetup): Promise { - const globalConfig = await this.globalConfig$.pipe(first()).toPromise(); - const kibanaIndex = globalConfig.kibana.index; + setup(core: CoreSetup): IEventLogService { + const kibanaIndex = this.globalConfig.kibana.index; this.systemLogger.debug('setting up plugin'); - const config = await this.config$.pipe(first()).toPromise(); - this.esContext = createEsContext({ logger: this.systemLogger, // TODO: get index prefix from config.get(kibana.index) @@ -84,7 +78,7 @@ export class Plugin implements CorePlugin { + start(core: CoreStart, { spaces }: PluginStartDeps): IEventLogClientService { this.systemLogger.debug('starting plugin'); if (!this.esContext) throw new Error('esContext not initialized'); diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index e995e979a08080..6248864ff9376b 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; import { schema, TypeOf } from '@kbn/config-schema'; import type { IRouter, KibanaRequest, RequestHandlerContext } from 'src/core/server'; @@ -24,7 +23,6 @@ export const ConfigSchema = schema.object({ }); export type IEventLogConfig = TypeOf; -export type IEventLogConfig$ = Observable>; // the object exposed by plugin.setup() export interface IEventLogService { diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index 253b614dc228aa..28704af410cfa6 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -10,7 +10,7 @@ import { CoreStart, ElasticsearchServiceStart, Logger, - Plugin, + AsyncPlugin, PluginInitializerContext, SavedObjectsServiceStart, HttpServiceSetup, @@ -167,7 +167,7 @@ export interface FleetStartContract { } export class FleetPlugin - implements Plugin { + implements AsyncPlugin { private licensing$!: Observable; private config$: Observable; private cloud: CloudSetup | undefined; diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index 66ffd3ca53081f..9ff51f57fcf300 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import { BehaviorSubject, Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { ElasticsearchClient, SavedObjectsServiceStart, @@ -38,7 +37,7 @@ class AppContextService { private httpSetup?: HttpServiceSetup; private externalCallbacks: ExternalCallbacksStorage = new Map(); - public async start(appContext: FleetAppContext) { + public start(appContext: FleetAppContext) { this.esClient = appContext.elasticsearch.client.asInternalUser; this.encryptedSavedObjects = appContext.encryptedSavedObjectsStart?.getClient(); this.encryptedSavedObjectsSetup = appContext.encryptedSavedObjectsSetup; @@ -51,10 +50,9 @@ class AppContextService { this.kibanaBranch = appContext.kibanaBranch; this.httpSetup = appContext.httpSetup; - if (appContext.config$) { + if (appContext.config$ && appContext.initialConfig) { this.config$ = appContext.config$; - const initialValue = await this.config$.pipe(first()).toPromise(); - this.configSubject$ = new BehaviorSubject(initialValue); + this.configSubject$ = new BehaviorSubject(appContext.initialConfig); this.config$.subscribe(this.configSubject$); } } diff --git a/x-pack/plugins/global_search/server/plugin.ts b/x-pack/plugins/global_search/server/plugin.ts index 29c63efd64df0d..2d6876e6aa153d 100644 --- a/x-pack/plugins/global_search/server/plugin.ts +++ b/x-pack/plugins/global_search/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; -import { take } from 'rxjs/operators'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/server'; import { LicensingPluginStart } from '../../licensing/server'; import { LicenseChecker, ILicenseChecker } from '../common/license_checker'; @@ -32,20 +30,19 @@ export class GlobalSearchPlugin GlobalSearchPluginSetupDeps, GlobalSearchPluginStartDeps > { - private readonly config$: Observable; + private readonly config: GlobalSearchConfigType; private readonly searchService = new SearchService(); private searchServiceStart?: SearchServiceStart; private licenseChecker?: ILicenseChecker; constructor(context: PluginInitializerContext) { - this.config$ = context.config.create(); + this.config = context.config.get(); } - public async setup(core: CoreSetup<{}, GlobalSearchPluginStart>) { - const config = await this.config$.pipe(take(1)).toPromise(); + public setup(core: CoreSetup<{}, GlobalSearchPluginStart>) { const { registerResultProvider } = this.searchService.setup({ basePath: core.http.basePath, - config, + config: this.config, }); registerRoutes(core.http.createRouter()); diff --git a/x-pack/plugins/licensing/server/plugin.ts b/x-pack/plugins/licensing/server/plugin.ts index 3823f251fb7fb3..394c88bd984b70 100644 --- a/x-pack/plugins/licensing/server/plugin.ts +++ b/x-pack/plugins/licensing/server/plugin.ts @@ -5,7 +5,6 @@ */ import { Observable, Subject, Subscription, timer } from 'rxjs'; -import { take } from 'rxjs/operators'; import moment from 'moment'; import { createHash } from 'crypto'; import stringify from 'json-stable-stringify'; @@ -82,7 +81,7 @@ function sign({ export class LicensingPlugin implements Plugin { private stop$ = new Subject(); private readonly logger: Logger; - private readonly config$: Observable; + private readonly config: LicenseConfigType; private loggingSubscription?: Subscription; private featureUsage = new FeatureUsageService(); @@ -91,13 +90,12 @@ export class LicensingPlugin implements Plugin(); + this.config = this.context.config.get(); } - public async setup(core: CoreSetup<{}, LicensingPluginStart>) { + public setup(core: CoreSetup<{}, LicensingPluginStart>) { this.logger.debug('Setting up Licensing plugin'); - const config = await this.config$.pipe(take(1)).toPromise(); - const pollingFrequency = config.api_polling_frequency; + const pollingFrequency = this.config.api_polling_frequency; async function callAsInternalUser( ...args: Parameters @@ -224,7 +222,7 @@ export class LicensingPlugin implements Plugin { this.initContext = initContext; } - public async setup(core: CoreSetup, plugins: {}): Promise { - const config$ = this.initContext.config.create(); - - const config = await config$.pipe(take(1)).toPromise(); + public setup(core: CoreSetup, plugins: {}): ObservabilityPluginSetup { + const config = this.initContext.config.get(); let annotationsApiPromise: Promise | undefined; diff --git a/x-pack/plugins/remote_clusters/server/plugin.ts b/x-pack/plugins/remote_clusters/server/plugin.ts index 0bef5d70fe70dd..1138956b5d9977 100644 --- a/x-pack/plugins/remote_clusters/server/plugin.ts +++ b/x-pack/plugins/remote_clusters/server/plugin.ts @@ -6,8 +6,6 @@ import { i18n } from '@kbn/i18n'; import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { PLUGIN } from '../common/constants'; import { Dependencies, LicenseStatus, RouteDependencies } from './types'; @@ -27,17 +25,16 @@ export class RemoteClustersServerPlugin implements Plugin { licenseStatus: LicenseStatus; log: Logger; - config$: Observable; + config: ConfigType; constructor({ logger, config }: PluginInitializerContext) { this.log = logger.get(); - this.config$ = config.create(); + this.config = config.get(); this.licenseStatus = { valid: false }; } - async setup({ http }: CoreSetup, { features, licensing, cloud }: Dependencies) { + setup({ http }: CoreSetup, { features, licensing, cloud }: Dependencies) { const router = http.createRouter(); - const config = await this.config$.pipe(first()).toPromise(); const routeDependencies: RouteDependencies = { router, @@ -87,7 +84,7 @@ export class RemoteClustersServerPlugin }); return { - isUiEnabled: config.ui.enabled, + isUiEnabled: this.config.ui.enabled, }; } diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 260d12565d4b41..fb265d9da73799 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { combineLatest, Observable, Subject } from 'rxjs'; -import { first, map, distinctUntilChanged } from 'rxjs/operators'; +import { map, distinctUntilChanged } from 'rxjs/operators'; import { PluginInitializerContext, Plugin, @@ -57,11 +57,8 @@ export class TaskManagerPlugin this.definitions = new TaskTypeDictionary(this.logger); } - public async setup(core: CoreSetup): Promise { - this.config = await this.initContext.config - .create() - .pipe(first()) - .toPromise(); + public setup(core: CoreSetup): TaskManagerSetupContract { + this.config = this.initContext.config.get(); this.elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); diff --git a/x-pack/plugins/triggers_actions_ui/server/plugin.ts b/x-pack/plugins/triggers_actions_ui/server/plugin.ts index c0d29341e217bb..92eeac83e6fc3f 100644 --- a/x-pack/plugins/triggers_actions_ui/server/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/server/plugin.ts @@ -20,7 +20,7 @@ export class TriggersActionsPlugin implements Plugin this.data = getService(); } - public async setup(core: CoreSetup): Promise { + public setup(core: CoreSetup): void { registerDataService({ logger: this.logger, data: this.data, @@ -29,7 +29,7 @@ export class TriggersActionsPlugin implements Plugin }); } - public async start(): Promise { + public start(): PluginStartContract { return { data: this.data, }; From 8bd7c216e673955f40106702a6063480ce91367e Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 16:07:58 +0100 Subject: [PATCH 02/32] migrate more plugins --- src/plugins/maps_legacy/server/index.ts | 8 ++-- x-pack/plugins/actions/server/plugin.ts | 45 ++++++++----------- .../plugins/beats_management/server/plugin.ts | 18 +++++--- x-pack/plugins/canvas/server/plugin.ts | 7 +-- x-pack/plugins/case/server/plugin.ts | 9 ++-- x-pack/plugins/code/server/plugin.ts | 10 ++--- .../encrypted_saved_objects/server/index.ts | 4 +- .../encrypted_saved_objects/server/plugin.ts | 23 ++++------ .../enterprise_search/server/plugin.ts | 12 +++-- x-pack/plugins/features/server/index.ts | 4 +- x-pack/plugins/features/server/plugin.test.ts | 12 ++--- x-pack/plugins/features/server/plugin.ts | 9 ++-- x-pack/plugins/graph/server/plugin.ts | 2 +- .../server/plugin.ts | 13 ++---- x-pack/plugins/infra/server/plugin.ts | 18 +++----- x-pack/plugins/lists/server/create_config.ts | 17 ------- x-pack/plugins/lists/server/plugin.ts | 8 ++-- x-pack/plugins/maps/server/plugin.ts | 8 ++-- x-pack/plugins/monitoring/server/index.ts | 4 +- .../plugins/monitoring/server/plugin.test.ts | 6 +-- x-pack/plugins/monitoring/server/plugin.ts | 17 +++---- .../plugins/osquery/server/create_config.ts | 8 +--- x-pack/plugins/osquery/server/plugin.ts | 7 ++- x-pack/plugins/painless_lab/server/plugin.ts | 2 +- .../plugins/searchprofiler/server/plugin.ts | 2 +- 25 files changed, 105 insertions(+), 168 deletions(-) delete mode 100644 x-pack/plugins/lists/server/create_config.ts diff --git a/src/plugins/maps_legacy/server/index.ts b/src/plugins/maps_legacy/server/index.ts index e6e7520a1a7107..0c08671ca6def5 100644 --- a/src/plugins/maps_legacy/server/index.ts +++ b/src/plugins/maps_legacy/server/index.ts @@ -8,7 +8,6 @@ import { Plugin, PluginConfigDescriptor } from 'kibana/server'; import { CoreSetup, PluginInitializerContext } from 'src/core/server'; -import { Observable } from 'rxjs'; import { configSchema, MapsLegacyConfig } from '../config'; import { getUiSettings } from './ui_settings'; @@ -30,7 +29,7 @@ export const config: PluginConfigDescriptor = { }; export interface MapsLegacyPluginSetup { - config$: Observable; + config: MapsLegacyConfig; } export class MapsLegacyPlugin implements Plugin { @@ -43,10 +42,9 @@ export class MapsLegacyPlugin implements Plugin { public setup(core: CoreSetup) { core.uiSettings.register(getUiSettings()); - // @ts-ignore - const config$ = this._initializerContext.config.create(); + const pluginConfig = this._initializerContext.config.get(); return { - config$, + config: pluginConfig, }; } diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 1543f8d7a07cea..168713b5a6d576 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { first } from 'rxjs/operators'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; -import { Observable } from 'rxjs'; import { PluginInitializerContext, Plugin, @@ -134,11 +132,9 @@ const includedHiddenTypes = [ ALERT_SAVED_OBJECT_TYPE, ]; -export class ActionsPlugin implements Plugin, PluginStartContract> { - private readonly config: Promise; - +export class ActionsPlugin implements Plugin { private readonly logger: Logger; - private actionsConfig?: ActionsConfig; + private readonly actionsConfig: ActionsConfig; private taskRunnerFactory?: TaskRunnerFactory; private actionTypeRegistry?: ActionTypeRegistry; private actionExecutor?: ActionExecutor; @@ -149,20 +145,20 @@ export class ActionsPlugin implements Plugin, Plugi private isESOUsingEphemeralEncryptionKey?: boolean; private readonly telemetryLogger: Logger; private readonly preconfiguredActions: PreConfiguredAction[]; - private readonly kibanaIndexConfig: Observable<{ kibana: { index: string } }>; + private readonly kibanaIndexConfig: { kibana: { index: string } }; constructor(initContext: PluginInitializerContext) { - this.config = initContext.config.create().pipe(first()).toPromise(); + this.actionsConfig = initContext.config.get(); this.logger = initContext.logger.get('actions'); this.telemetryLogger = initContext.logger.get('usage'); this.preconfiguredActions = []; - this.kibanaIndexConfig = initContext.config.legacy.globalConfig$; + this.kibanaIndexConfig = initContext.config.legacy.get(); } - public async setup( + public setup( core: CoreSetup, plugins: ActionsPluginsSetup - ): Promise { + ): PluginSetupContract { this.licenseState = new LicenseState(plugins.licensing.license$); this.isESOUsingEphemeralEncryptionKey = plugins.encryptedSavedObjects.usingEphemeralEncryptionKey; @@ -188,7 +184,6 @@ export class ActionsPlugin implements Plugin, Plugi // get executions count const taskRunnerFactory = new TaskRunnerFactory(actionExecutor); - this.actionsConfig = (await this.config) as ActionsConfig; const actionsConfigUtils = getActionsConfigurationUtilities(this.actionsConfig); for (const preconfiguredId of Object.keys(this.actionsConfig.preconfigured)) { @@ -227,20 +222,18 @@ export class ActionsPlugin implements Plugin, Plugi ); } - this.kibanaIndexConfig.subscribe((config) => { - core.http.registerRouteHandlerContext( - 'actions', - this.createRouteHandlerContext(core, config.kibana.index) + core.http.registerRouteHandlerContext( + 'actions', + this.createRouteHandlerContext(core, this.kibanaIndexConfig.kibana.index) + ); + if (usageCollection) { + initializeActionsTelemetry( + this.telemetryLogger, + plugins.taskManager, + core, + this.kibanaIndexConfig.kibana.index ); - if (usageCollection) { - initializeActionsTelemetry( - this.telemetryLogger, - plugins.taskManager, - core, - config.kibana.index - ); - } - }); + } // Routes const router = core.http.createRouter(); @@ -302,7 +295,7 @@ export class ActionsPlugin implements Plugin, Plugi request ); - const kibanaIndex = (await kibanaIndexConfig.pipe(first()).toPromise()).kibana.index; + const kibanaIndex = kibanaIndexConfig.kibana.index; return new ActionsClient({ unsecuredSavedObjectsClient, diff --git a/x-pack/plugins/beats_management/server/plugin.ts b/x-pack/plugins/beats_management/server/plugin.ts index d52de39ed458f1..c1f7b5b27e2e4e 100644 --- a/x-pack/plugins/beats_management/server/plugin.ts +++ b/x-pack/plugins/beats_management/server/plugin.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { take } from 'rxjs/operators'; -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/server'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext, Logger } from 'src/core/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; import { SecurityPluginSetup } from '../../security/server'; import { LicensingPluginStart } from '../../licensing/server'; @@ -26,14 +25,17 @@ interface StartDeps { } export class BeatsManagementPlugin implements Plugin<{}, {}, SetupDeps, StartDeps> { + private readonly logger: Logger; private securitySetup?: SecurityPluginSetup; private beatsLibs?: CMServerLibs; constructor( private readonly initializerContext: PluginInitializerContext - ) {} + ) { + this.logger = initializerContext.logger.get(); + } - public async setup(core: CoreSetup, { features, security }: SetupDeps) { + public setup(core: CoreSetup, { features, security }: SetupDeps) { this.securitySetup = security; const router = core.http.createRouter(); @@ -63,8 +65,8 @@ export class BeatsManagementPlugin implements Plugin<{}, {}, SetupDeps, StartDep return {}; } - public async start({ elasticsearch }: CoreStart, { licensing }: StartDeps) { - const config = await this.initializerContext.config.create().pipe(take(1)).toPromise(); + public start({ elasticsearch }: CoreStart, { licensing }: StartDeps) { + const config = this.initializerContext.config.get(); const logger = this.initializerContext.logger.get(); const kibanaVersion = this.initializerContext.env.packageInfo.version; @@ -77,7 +79,9 @@ export class BeatsManagementPlugin implements Plugin<{}, {}, SetupDeps, StartDep kibanaVersion, }); - await this.beatsLibs.database.putTemplate(INDEX_NAMES.BEATS, beatsIndexTemplate); + this.beatsLibs.database.putTemplate(INDEX_NAMES.BEATS, beatsIndexTemplate).catch((e) => { + this.logger.error(`Error create beats template: ${e.message}`); + }); return {}; } diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 02499eae7eb670..518f40c4830c81 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; import { CoreSetup, PluginInitializerContext, Plugin, Logger, CoreStart } from 'src/core/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { BfetchServerSetup } from 'src/plugins/bfetch/server'; @@ -33,7 +32,7 @@ export class CanvasPlugin implements Plugin { this.logger = initializerContext.logger.get(); } - public async setup(coreSetup: CoreSetup, plugins: PluginsSetup) { + public setup(coreSetup: CoreSetup, plugins: PluginsSetup) { coreSetup.savedObjects.registerType(customElementType); coreSetup.savedObjects.registerType(workpadType); coreSetup.savedObjects.registerType(workpadTemplateType); @@ -83,9 +82,7 @@ export class CanvasPlugin implements Plugin { ); // we need the kibana index provided by global config for the Canvas usage collector - const globalConfig = await this.initializerContext.config.legacy.globalConfig$ - .pipe(first()) - .toPromise(); + const globalConfig = this.initializerContext.config.legacy.get(); registerCanvasUsageCollector(plugins.usageCollection, globalConfig.kibana.index); setupInterpreter(plugins.expressions); diff --git a/x-pack/plugins/case/server/plugin.ts b/x-pack/plugins/case/server/plugin.ts index 0b9712e78c2bc9..915d4c40db2845 100644 --- a/x-pack/plugins/case/server/plugin.ts +++ b/x-pack/plugins/case/server/plugin.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first, map } from 'rxjs/operators'; import { IContextProvider, KibanaRequest, Logger, PluginInitializerContext } from 'kibana/server'; import { CoreSetup, CoreStart } from 'src/core/server'; @@ -37,8 +36,8 @@ import { createCaseClient } from './client'; import { registerConnectors } from './connectors'; import type { CasesRequestHandlerContext } from './types'; -function createConfig$(context: PluginInitializerContext) { - return context.config.create().pipe(map((config) => config)); +function createConfig(context: PluginInitializerContext) { + return context.config.get(); } export interface PluginsSetup { @@ -59,7 +58,7 @@ export class CasePlugin { } public async setup(core: CoreSetup, plugins: PluginsSetup) { - const config = await createConfig$(this.initializerContext).pipe(first()).toPromise(); + const config = createConfig(this.initializerContext); if (!config.enabled) { return; @@ -117,7 +116,7 @@ export class CasePlugin { }); } - public async start(core: CoreStart) { + public start(core: CoreStart) { this.log.debug(`Starting Case Workflow`); this.alertsService!.initialize(core.elasticsearch.client); diff --git a/x-pack/plugins/code/server/plugin.ts b/x-pack/plugins/code/server/plugin.ts index 8acff96eef3aa5..f6ede4904c0db6 100644 --- a/x-pack/plugins/code/server/plugin.ts +++ b/x-pack/plugins/code/server/plugin.ts @@ -4,22 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; import { TypeOf } from '@kbn/config-schema'; -import { PluginInitializerContext } from 'src/core/server'; +import { PluginInitializerContext, Plugin } from 'src/core/server'; import { CodeConfigSchema } from './config'; /** * Represents Code Plugin instance that will be managed by the Kibana plugin system. */ -export class CodePlugin { +export class CodePlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} public async setup() { - const config = await this.initializerContext.config - .create>() - .pipe(first()) - .toPromise(); + const config = this.initializerContext.config.get>(); if (config && Object.keys(config).length > 0) { this.initializerContext.logger diff --git a/x-pack/plugins/encrypted_saved_objects/server/index.ts b/x-pack/plugins/encrypted_saved_objects/server/index.ts index c8f7acf952c222..a97d165e85a603 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/index.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/index.ts @@ -6,7 +6,7 @@ import { PluginInitializerContext } from 'src/core/server'; import { ConfigSchema } from './config'; -import { Plugin } from './plugin'; +import { EncryptedSavedObjectsPlugin } from './plugin'; export { EncryptedSavedObjectTypeRegistration, EncryptionError } from './crypto'; export { EncryptedSavedObjectsPluginSetup, EncryptedSavedObjectsPluginStart } from './plugin'; @@ -14,4 +14,4 @@ export { EncryptedSavedObjectsClient } from './saved_objects'; export const config = { schema: ConfigSchema }; export const plugin = (initializerContext: PluginInitializerContext) => - new Plugin(initializerContext); + new EncryptedSavedObjectsPlugin(initializerContext); diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts index 6e3724fa3fe588..d828526fa986c5 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first, map } from 'rxjs/operators'; import nodeCrypto from '@elastic/node-crypto'; -import { Logger, PluginInitializerContext, CoreSetup } from 'src/core/server'; +import { Logger, PluginInitializerContext, CoreSetup, Plugin } from 'src/core/server'; import { TypeOf } from '@kbn/config-schema'; import { SecurityPluginSetup } from '../../security/server'; import { createConfig, ConfigSchema } from './config'; @@ -39,7 +38,9 @@ export interface EncryptedSavedObjectsPluginStart { /** * Represents EncryptedSavedObjects Plugin instance that will be managed by the Kibana plugin system. */ -export class Plugin { +export class EncryptedSavedObjectsPlugin + implements + Plugin { private readonly logger: Logger; private savedObjectsSetup!: ClientInstanciator; @@ -47,17 +48,11 @@ export class Plugin { this.logger = this.initializerContext.logger.get(); } - public async setup( - core: CoreSetup, - deps: PluginsSetup - ): Promise { - const config = await this.initializerContext.config - .create>() - .pipe( - map((rawConfig) => createConfig(rawConfig, this.initializerContext.logger.get('config'))) - ) - .pipe(first()) - .toPromise(); + public setup(core: CoreSetup, deps: PluginsSetup): EncryptedSavedObjectsPluginSetup { + const config = createConfig( + this.initializerContext.config.get>(), + this.initializerContext.logger.get('config') + ); const auditLogger = new EncryptedSavedObjectsAuditLogger( deps.security?.audit.getLogger('encryptedSavedObjects') ); diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index 2d3b27783e3a14..f9338491d6e319 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { Plugin, PluginInitializerContext, @@ -65,19 +63,19 @@ export interface RouteDependencies { } export class EnterpriseSearchPlugin implements Plugin { - private config: Observable; - private logger: Logger; + private readonly config: ConfigType; + private readonly logger: Logger; constructor(initializerContext: PluginInitializerContext) { - this.config = initializerContext.config.create(); + this.config = initializerContext.config.get(); this.logger = initializerContext.logger.get(); } - public async setup( + public setup( { capabilities, http, savedObjects, getStartServices }: CoreSetup, { usageCollection, security, features }: PluginsSetup ) { - const config = await this.config.pipe(first()).toPromise(); + const config = this.config; const log = this.logger; /** diff --git a/x-pack/plugins/features/server/index.ts b/x-pack/plugins/features/server/index.ts index 28c0fee041594d..64c71f4efe02b1 100644 --- a/x-pack/plugins/features/server/index.ts +++ b/x-pack/plugins/features/server/index.ts @@ -5,7 +5,7 @@ */ import { PluginInitializerContext } from '../../../../src/core/server'; -import { Plugin } from './plugin'; +import { FeaturesPlugin } from './plugin'; // These exports are part of public Features plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. Ideally we should @@ -24,4 +24,4 @@ export { export { PluginSetupContract, PluginStartContract } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => - new Plugin(initializerContext); + new FeaturesPlugin(initializerContext); diff --git a/x-pack/plugins/features/server/plugin.test.ts b/x-pack/plugins/features/server/plugin.test.ts index ce6fb548ae6d2d..ef90573d078425 100644 --- a/x-pack/plugins/features/server/plugin.test.ts +++ b/x-pack/plugins/features/server/plugin.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { coreMock, savedObjectsServiceMock } from 'src/core/server/mocks'; -import { Plugin } from './plugin'; +import { FeaturesPlugin } from './plugin'; describe('Features Plugin', () => { let initContext: ReturnType; @@ -29,7 +29,7 @@ describe('Features Plugin', () => { }); it('returns OSS + registered kibana features', async () => { - const plugin = new Plugin(initContext); + const plugin = new FeaturesPlugin(initContext); const { registerKibanaFeature } = await plugin.setup(coreSetup, {}); registerKibanaFeature({ id: 'baz', @@ -56,7 +56,7 @@ describe('Features Plugin', () => { }); it('returns OSS + registered kibana features with timelion when available', async () => { - const plugin = new Plugin(initContext); + const plugin = new FeaturesPlugin(initContext); const { registerKibanaFeature: registerFeature } = await plugin.setup(coreSetup, { visTypeTimelion: { uiEnabled: true }, }); @@ -86,7 +86,7 @@ describe('Features Plugin', () => { }); it('registers kibana features with not hidden saved objects types', async () => { - const plugin = new Plugin(initContext); + const plugin = new FeaturesPlugin(initContext); await plugin.setup(coreSetup, {}); const { getKibanaFeatures } = plugin.start(coreStart); @@ -99,7 +99,7 @@ describe('Features Plugin', () => { }); it('returns registered elasticsearch features', async () => { - const plugin = new Plugin(initContext); + const plugin = new FeaturesPlugin(initContext); const { registerElasticsearchFeature } = await plugin.setup(coreSetup, {}); registerElasticsearchFeature({ id: 'baz', @@ -121,7 +121,7 @@ describe('Features Plugin', () => { }); it('registers a capabilities provider', async () => { - const plugin = new Plugin(initContext); + const plugin = new FeaturesPlugin(initContext); await plugin.setup(coreSetup, {}); expect(coreSetup.capabilities.registerProvider).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/features/server/plugin.ts b/x-pack/plugins/features/server/plugin.ts index c3e2ad06fb85c6..d0d125fe4d7b94 100644 --- a/x-pack/plugins/features/server/plugin.ts +++ b/x-pack/plugins/features/server/plugin.ts @@ -10,6 +10,7 @@ import { CoreStart, SavedObjectsServiceStart, Logger, + Plugin, PluginInitializerContext, } from '../../../../src/core/server'; import { Capabilities as UICapabilities } from '../../../../src/core/server'; @@ -57,7 +58,9 @@ interface TimelionSetupContract { /** * Represents Features Plugin instance that will be managed by the Kibana plugin system. */ -export class Plugin { +export class FeaturesPlugin + implements + Plugin, RecursiveReadonly> { private readonly logger: Logger; private readonly featureRegistry: FeatureRegistry = new FeatureRegistry(); private isTimelionEnabled: boolean = false; @@ -66,10 +69,10 @@ export class Plugin { this.logger = this.initializerContext.logger.get(); } - public async setup( + public setup( core: CoreSetup, { visTypeTimelion }: { visTypeTimelion?: TimelionSetupContract } - ): Promise> { + ): RecursiveReadonly { this.isTimelionEnabled = visTypeTimelion !== undefined && visTypeTimelion.uiEnabled; defineRoutes({ diff --git a/x-pack/plugins/graph/server/plugin.ts b/x-pack/plugins/graph/server/plugin.ts index 7a827db7aba4b5..a5492b1951202b 100644 --- a/x-pack/plugins/graph/server/plugin.ts +++ b/x-pack/plugins/graph/server/plugin.ts @@ -19,7 +19,7 @@ import { graphWorkspace } from './saved_objects'; export class GraphPlugin implements Plugin { private licenseState: LicenseState | null = null; - public async setup( + public setup( core: CoreSetup, { licensing, diff --git a/x-pack/plugins/index_lifecycle_management/server/plugin.ts b/x-pack/plugins/index_lifecycle_management/server/plugin.ts index e87f4aa17c0ef2..16737a537259c2 100644 --- a/x-pack/plugins/index_lifecycle_management/server/plugin.ts +++ b/x-pack/plugins/index_lifecycle_management/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { CoreSetup, @@ -51,22 +49,19 @@ const indexLifecycleDataEnricher = async ( }; export class IndexLifecycleManagementServerPlugin implements Plugin { - private readonly config$: Observable; + private readonly config: IndexLifecycleManagementConfig; private readonly license: License; private readonly logger: Logger; constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); - this.config$ = initializerContext.config.create(); + this.config = initializerContext.config.get(); this.license = new License(); } - async setup( - { http }: CoreSetup, - { licensing, indexManagement, features }: Dependencies - ): Promise { + setup({ http }: CoreSetup, { licensing, indexManagement, features }: Dependencies): void { const router = http.createRouter(); - const config = await this.config$.pipe(first()).toPromise(); + const config = this.config; this.license.setup( { diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 207c2efa0f13f2..d00c15e10bc08f 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -7,8 +7,7 @@ import { Server } from '@hapi/hapi'; import { schema, TypeOf } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { Observable } from 'rxjs'; -import { CoreSetup, PluginInitializerContext } from 'src/core/server'; +import { CoreSetup, PluginInitializerContext, Plugin } from 'src/core/server'; import { InfraStaticSourceConfiguration } from '../common/http_api/source_api'; import { inventoryViewSavedObjectType } from '../common/saved_objects/inventory_view'; import { metricsExplorerViewSavedObjectType } from '../common/saved_objects/metrics_explorer_view'; @@ -78,22 +77,15 @@ export interface InfraPluginSetup { ) => void; } -export class InfraServerPlugin { - private config$: Observable; - public config = {} as InfraConfig; +export class InfraServerPlugin implements Plugin { + public config: InfraConfig; public libs: InfraBackendLibs | undefined; constructor(context: PluginInitializerContext) { - this.config$ = context.config.create(); + this.config = context.config.get(); } - async setup(core: CoreSetup, plugins: InfraServerPluginSetupDeps) { - await new Promise((resolve) => { - this.config$.subscribe((configValue) => { - this.config = configValue; - resolve(); - }); - }); + setup(core: CoreSetup, plugins: InfraServerPluginSetupDeps) { const framework = new KibanaFramework(core, this.config, plugins); const sources = new InfraSources({ config: this.config, diff --git a/x-pack/plugins/lists/server/create_config.ts b/x-pack/plugins/lists/server/create_config.ts deleted file mode 100644 index e46c71798eb9fa..00000000000000 --- a/x-pack/plugins/lists/server/create_config.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { map } from 'rxjs/operators'; -import { PluginInitializerContext } from 'kibana/server'; -import { Observable } from 'rxjs'; - -import { ConfigType } from './config'; - -export const createConfig$ = ( - context: PluginInitializerContext -): Observable> => { - return context.config.create().pipe(map((config) => config)); -}; diff --git a/x-pack/plugins/lists/server/plugin.ts b/x-pack/plugins/lists/server/plugin.ts index c6d42e5ac4f23f..7769824ade9f53 100644 --- a/x-pack/plugins/lists/server/plugin.ts +++ b/x-pack/plugins/lists/server/plugin.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; import { Logger, Plugin, PluginInitializerContext } from 'kibana/server'; import type { CoreSetup, CoreStart } from 'src/core/server'; @@ -22,7 +21,6 @@ import type { ListsRequestHandlerContext, PluginsStart, } from './types'; -import { createConfig$ } from './create_config'; import { getSpaceId } from './get_space_id'; import { getUser } from './get_user'; import { initSavedObjects } from './saved_objects'; @@ -31,17 +29,17 @@ import { ExceptionListClient } from './services/exception_lists/exception_list_c export class ListPlugin implements Plugin, ListsPluginStart, {}, PluginsStart> { private readonly logger: Logger; + private readonly config: ConfigType; private spaces: SpacesServiceStart | undefined | null; - private config: ConfigType | undefined | null; private security: SecurityPluginStart | undefined | null; constructor(private readonly initializerContext: PluginInitializerContext) { this.logger = this.initializerContext.logger.get(); + this.config = this.initializerContext.config.get(); } public async setup(core: CoreSetup): Promise { - const config = await createConfig$(this.initializerContext).pipe(first()).toPromise(); - this.config = config; + const { config } = this; initSavedObjects(core.savedObjects); diff --git a/x-pack/plugins/maps/server/plugin.ts b/x-pack/plugins/maps/server/plugin.ts index f3241b79759a15..3daa4174b35e0f 100644 --- a/x-pack/plugins/maps/server/plugin.ts +++ b/x-pack/plugins/maps/server/plugin.ts @@ -5,7 +5,6 @@ */ import { i18n } from '@kbn/i18n'; import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from 'src/core/server'; -import { take } from 'rxjs/operators'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server'; import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server'; // @ts-ignore @@ -132,12 +131,11 @@ export class MapsPlugin implements Plugin { } // @ts-ignore - async setup(core: CoreSetup, plugins: SetupDeps) { + setup(core: CoreSetup, plugins: SetupDeps) { const { usageCollection, home, licensing, features, mapsLegacy } = plugins; - // @ts-ignore + const mapsLegacyConfig = mapsLegacy.config; const config$ = this._initializerContext.config.create(); - const mapsLegacyConfig = await mapsLegacy.config$.pipe(take(1)).toPromise(); - const currentConfig = await config$.pipe(take(1)).toPromise(); + const currentConfig = this._initializerContext.config.get(); // @ts-ignore const mapsEnabled = currentConfig.enabled; diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts index de679a2834d7b5..687a861e4bc6ea 100644 --- a/x-pack/plugins/monitoring/server/index.ts +++ b/x-pack/plugins/monitoring/server/index.ts @@ -6,13 +6,13 @@ import { TypeOf } from '@kbn/config-schema'; import { PluginInitializerContext, PluginConfigDescriptor } from '../../../../src/core/server'; -import { Plugin } from './plugin'; +import { MonitoringPlugin } from './plugin'; import { configSchema } from './config'; import { deprecations } from './deprecations'; export { KibanaSettingsCollector } from './kibana_monitoring/collectors'; export { MonitoringConfig } from './config'; -export const plugin = (initContext: PluginInitializerContext) => new Plugin(initContext); +export const plugin = (initContext: PluginInitializerContext) => new MonitoringPlugin(initContext); export const config: PluginConfigDescriptor> = { schema: configSchema, deprecations, diff --git a/x-pack/plugins/monitoring/server/plugin.test.ts b/x-pack/plugins/monitoring/server/plugin.test.ts index b376fc2eec60bb..0f8460f3052fac 100644 --- a/x-pack/plugins/monitoring/server/plugin.test.ts +++ b/x-pack/plugins/monitoring/server/plugin.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { coreMock } from 'src/core/server/mocks'; -import { Plugin } from './plugin'; +import { MonitoringPlugin } from './plugin'; import { combineLatest } from 'rxjs'; import { AlertsFactory } from './alerts'; @@ -102,14 +102,14 @@ describe('Monitoring plugin', () => { }); it('always create the bulk uploader', async () => { - const plugin = new Plugin(initializerContext as any); + const plugin = new MonitoringPlugin(initializerContext as any); await plugin.setup(coreSetup, setupPlugins as any); expect(coreSetup.status.overall$.subscribe).toHaveBeenCalled(); }); it('should register all alerts', async () => { const alerts = AlertsFactory.getAll(); - const plugin = new Plugin(initializerContext as any); + const plugin = new MonitoringPlugin(initializerContext as any); await plugin.setup(coreSetup as any, setupPlugins as any); expect(setupPlugins.alerts.registerType).toHaveBeenCalledTimes(alerts.length); }); diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index a78c50722368d3..ae34acad143b50 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from '@hapi/boom'; -import { combineLatest } from 'rxjs'; -import { first, map } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { has, get } from 'lodash'; import { TypeOf } from '@kbn/config-schema'; @@ -19,6 +17,7 @@ import { CoreStart, CustomHttpResponseOptions, ResponseError, + Plugin, } from 'kibana/server'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server'; import { @@ -64,7 +63,7 @@ const wrapError = (error: any): CustomHttpResponseOptions => { }; }; -export class Plugin { +export class MonitoringPlugin implements Plugin { private readonly initializerContext: PluginInitializerContext; private readonly log: Logger; private readonly getLogger: (...scopes: string[]) => Logger; @@ -80,15 +79,9 @@ export class Plugin { this.getLogger = (...scopes: string[]) => initializerContext.logger.get(LOGGING_TAG, ...scopes); } - async setup(core: CoreSetup, plugins: PluginsSetup) { - const [config, legacyConfig] = await combineLatest([ - this.initializerContext.config - .create>() - .pipe(map((rawConfig) => createConfig(rawConfig))), - this.initializerContext.config.legacy.globalConfig$, - ]) - .pipe(first()) - .toPromise(); + setup(core: CoreSetup, plugins: PluginsSetup) { + const config = createConfig(this.initializerContext.config.get>()); + const legacyConfig = this.initializerContext.config.legacy.get(); const router = core.http.createRouter(); this.legacyShimDependencies = { diff --git a/x-pack/plugins/osquery/server/create_config.ts b/x-pack/plugins/osquery/server/create_config.ts index e46c71798eb9fa..1f6416224e1207 100644 --- a/x-pack/plugins/osquery/server/create_config.ts +++ b/x-pack/plugins/osquery/server/create_config.ts @@ -4,14 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { map } from 'rxjs/operators'; import { PluginInitializerContext } from 'kibana/server'; -import { Observable } from 'rxjs'; import { ConfigType } from './config'; -export const createConfig$ = ( - context: PluginInitializerContext -): Observable> => { - return context.config.create().pipe(map((config) => config)); +export const createConfig = (context: PluginInitializerContext): Readonly => { + return context.config.get(); }; diff --git a/x-pack/plugins/osquery/server/plugin.ts b/x-pack/plugins/osquery/server/plugin.ts index 3e59faa55d057f..14d6b31dda2002 100644 --- a/x-pack/plugins/osquery/server/plugin.ts +++ b/x-pack/plugins/osquery/server/plugin.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; import { PluginInitializerContext, CoreSetup, @@ -13,7 +12,7 @@ import { Logger, } from '../../../../src/core/server'; -import { createConfig$ } from './create_config'; +import { createConfig } from './create_config'; import { OsqueryPluginSetup, OsqueryPluginStart, SetupPlugins, StartPlugins } from './types'; import { defineRoutes } from './routes'; import { osquerySearchStrategyProvider } from './search_strategy/osquery'; @@ -25,9 +24,9 @@ export class OsqueryPlugin implements Plugin, plugins: SetupPlugins) { + public setup(core: CoreSetup, plugins: SetupPlugins) { this.logger.debug('osquery: Setup'); - const config = await createConfig$(this.initializerContext).pipe(first()).toPromise(); + const config = createConfig(this.initializerContext); if (!config.enabled) { return {}; diff --git a/x-pack/plugins/painless_lab/server/plugin.ts b/x-pack/plugins/painless_lab/server/plugin.ts index 74629a0b035ed0..65ea97d8d0ef50 100644 --- a/x-pack/plugins/painless_lab/server/plugin.ts +++ b/x-pack/plugins/painless_lab/server/plugin.ts @@ -21,7 +21,7 @@ export class PainlessLabServerPlugin implements Plugin { this.license = new License(); } - async setup({ http }: CoreSetup, { licensing }: Dependencies) { + setup({ http }: CoreSetup, { licensing }: Dependencies) { const router = http.createRouter(); this.license.setup( diff --git a/x-pack/plugins/searchprofiler/server/plugin.ts b/x-pack/plugins/searchprofiler/server/plugin.ts index 032593d5e3b316..b11dcdea316923 100644 --- a/x-pack/plugins/searchprofiler/server/plugin.ts +++ b/x-pack/plugins/searchprofiler/server/plugin.ts @@ -20,7 +20,7 @@ export class SearchProfilerServerPlugin implements Plugin { this.licenseStatus = { valid: false }; } - async setup({ http }: CoreSetup, { licensing }: AppServerPluginDependencies) { + setup({ http }: CoreSetup, { licensing }: AppServerPluginDependencies) { const router = http.createRouter(); profileRoute.register({ router, From 235a65677b4fbc04b5f0208e62e9f94f33cebac7 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 16:18:48 +0100 Subject: [PATCH 03/32] migrate yet more plugins --- x-pack/plugins/security/server/index.ts | 4 ++-- x-pack/plugins/security/server/plugin.test.ts | 6 +++--- x-pack/plugins/security/server/plugin.ts | 10 +++++++++- x-pack/plugins/security_solution/server/config.ts | 9 +++------ x-pack/plugins/security_solution/server/plugin.ts | 15 ++++++--------- x-pack/plugins/snapshot_restore/server/plugin.ts | 9 +++------ x-pack/plugins/spaces/server/index.ts | 4 ++-- x-pack/plugins/spaces/server/plugin.test.ts | 12 ++++++------ x-pack/plugins/spaces/server/plugin.ts | 4 +++- x-pack/plugins/stack_alerts/server/plugin.ts | 9 +++------ x-pack/plugins/watcher/server/plugin.ts | 2 +- x-pack/plugins/xpack_legacy/server/plugin.ts | 8 ++------ 12 files changed, 43 insertions(+), 49 deletions(-) diff --git a/x-pack/plugins/security/server/index.ts b/x-pack/plugins/security/server/index.ts index 3233708a5d23b2..139ed69a717eb9 100644 --- a/x-pack/plugins/security/server/index.ts +++ b/x-pack/plugins/security/server/index.ts @@ -14,7 +14,7 @@ import type { import { ConfigSchema } from './config'; import { securityConfigDeprecationProvider } from './config_deprecations'; import { - Plugin, + SecurityPlugin, SecurityPluginSetup, SecurityPluginStart, PluginSetupDependencies, @@ -50,4 +50,4 @@ export const plugin: PluginInitializer< RecursiveReadonly, RecursiveReadonly, PluginSetupDependencies -> = (initializerContext: PluginInitializerContext) => new Plugin(initializerContext); +> = (initializerContext: PluginInitializerContext) => new SecurityPlugin(initializerContext); diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index 256eca376fa026..c00ea74bb7c826 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -7,7 +7,7 @@ import { of } from 'rxjs'; import { ByteSizeValue } from '@kbn/config-schema'; import { ConfigSchema } from './config'; -import { Plugin, PluginSetupDependencies, PluginStartDependencies } from './plugin'; +import { SecurityPlugin, PluginSetupDependencies, PluginStartDependencies } from './plugin'; import { coreMock } from '../../../../src/core/server/mocks'; import { featuresPluginMock } from '../../features/server/mocks'; @@ -15,13 +15,13 @@ import { taskManagerMock } from '../../task_manager/server/mocks'; import { licensingMock } from '../../licensing/server/mocks'; describe('Security Plugin', () => { - let plugin: Plugin; + let plugin: SecurityPlugin; let mockCoreSetup: ReturnType; let mockCoreStart: ReturnType; let mockSetupDependencies: PluginSetupDependencies; let mockStartDependencies: PluginStartDependencies; beforeEach(() => { - plugin = new Plugin( + plugin = new SecurityPlugin( coreMock.createPluginInitializerContext( ConfigSchema.validate({ session: { idleTimeout: 1500 }, diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 8d8e4c096f37e5..0be4f22c963081 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -7,6 +7,7 @@ import { combineLatest, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import { TypeOf } from '@kbn/config-schema'; +import { RecursiveReadonly } from '@kbn/utility-types'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { SecurityOssPluginSetup } from 'src/plugins/security_oss/server'; import { @@ -15,6 +16,7 @@ import { KibanaRequest, Logger, PluginInitializerContext, + Plugin, } from '../../../../src/core/server'; import { SpacesPluginSetup, SpacesPluginStart } from '../../spaces/server'; import { PluginSetupContract as FeaturesSetupContract } from '../../features/server'; @@ -100,7 +102,13 @@ export interface PluginStartDependencies { /** * Represents Security Plugin instance that will be managed by the Kibana plugin system. */ -export class Plugin { +export class SecurityPlugin + implements + Plugin< + RecursiveReadonly, + RecursiveReadonly, + PluginSetupDependencies + > { private readonly logger: Logger; private authorizationSetup?: AuthorizationServiceSetup; private auditSetup?: AuditServiceSetup; diff --git a/x-pack/plugins/security_solution/server/config.ts b/x-pack/plugins/security_solution/server/config.ts index e2c06ae9f931f1..44a705e7625fa2 100644 --- a/x-pack/plugins/security_solution/server/config.ts +++ b/x-pack/plugins/security_solution/server/config.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Observable } from 'rxjs'; import { schema, TypeOf } from '@kbn/config-schema'; import { PluginInitializerContext } from '../../../../src/core/server'; import { SIGNALS_INDEX_KEY, DEFAULT_SIGNALS_INDEX } from '../common/constants'; @@ -37,9 +36,7 @@ export const configSchema = schema.object({ validateArtifactDownloads: schema.boolean({ defaultValue: true }), }); -export const createConfig$ = (context: PluginInitializerContext) => - context.config.create>(); +export const createConfig = (context: PluginInitializerContext) => + context.config.get>(); -export type ConfigType = ReturnType extends Observable - ? T - : ReturnType; +export type ConfigType = TypeOf; diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 4e1521cb0f8d12..68fb830efd7792 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -5,7 +5,6 @@ */ import { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import LRU from 'lru-cache'; @@ -46,7 +45,7 @@ import { isNotificationAlertExecutor } from './lib/detection_engine/notification import { ManifestTask } from './endpoint/lib/artifacts'; import { initSavedObjects, savedObjectTypes } from './saved_objects'; import { AppClientFactory } from './client'; -import { createConfig$, ConfigType } from './config'; +import { createConfig, ConfigType } from './config'; import { initUiSettings } from './ui_settings'; import { APP_ID, @@ -118,8 +117,7 @@ const securitySubPlugins = [ export class Plugin implements IPlugin { private readonly logger: Logger; - private readonly config$: Observable; - private config?: ConfigType; + private readonly config: ConfigType; private context: PluginInitializerContext; private appClientFactory: AppClientFactory; private setupPlugins?: SetupPlugins; @@ -136,7 +134,7 @@ export class Plugin implements IPlugin({ max: 3, maxAge: 1000 * 60 * 5 }); @@ -145,13 +143,12 @@ export class Plugin implements IPlugin, plugins: SetupPlugins) { + public setup(core: CoreSetup, plugins: SetupPlugins) { this.logger.debug('plugin setup'); this.setupPlugins = plugins; - const config = await this.config$.pipe(first()).toPromise(); - this.config = config; - const globalConfig = await this.context.config.legacy.globalConfig$.pipe(first()).toPromise(); + const config = this.config; + const globalConfig = this.context.config.legacy.get(); initSavedObjects(core.savedObjects); initUiSettings(core.uiSettings); diff --git a/x-pack/plugins/snapshot_restore/server/plugin.ts b/x-pack/plugins/snapshot_restore/server/plugin.ts index baf39b25af4c9d..a3948e1e17d309 100644 --- a/x-pack/plugins/snapshot_restore/server/plugin.ts +++ b/x-pack/plugins/snapshot_restore/server/plugin.ts @@ -41,14 +41,11 @@ export class SnapshotRestoreServerPlugin implements Plugin this.license = new License(); } - public async setup( + public setup( { http, getStartServices }: CoreSetup, { licensing, features, security, cloud }: Dependencies - ): Promise { - const pluginConfig = await this.context.config - .create() - .pipe(first()) - .toPromise(); + ): void { + const pluginConfig = this.context.config.get(); if (!pluginConfig.enabled) { return; diff --git a/x-pack/plugins/spaces/server/index.ts b/x-pack/plugins/spaces/server/index.ts index 1150dfdf1c9809..a78fa7a9c46563 100644 --- a/x-pack/plugins/spaces/server/index.ts +++ b/x-pack/plugins/spaces/server/index.ts @@ -6,7 +6,7 @@ import type { PluginConfigDescriptor, PluginInitializerContext } from '../../../../src/core/server'; import { ConfigSchema, spacesConfigDeprecationProvider } from './config'; -import { Plugin } from './plugin'; +import { SpacesPlugin } from './plugin'; // These exports are part of public Spaces plugin contract, any change in signature of exported // functions or removal of exports should be considered as a breaking change. Ideally we should @@ -31,4 +31,4 @@ export const config: PluginConfigDescriptor = { deprecations: spacesConfigDeprecationProvider, }; export const plugin = (initializerContext: PluginInitializerContext) => - new Plugin(initializerContext); + new SpacesPlugin(initializerContext); diff --git a/x-pack/plugins/spaces/server/plugin.test.ts b/x-pack/plugins/spaces/server/plugin.test.ts index fad54ceaa882b1..e3bd7c4fbe7b47 100644 --- a/x-pack/plugins/spaces/server/plugin.test.ts +++ b/x-pack/plugins/spaces/server/plugin.test.ts @@ -8,7 +8,7 @@ import { CoreSetup } from 'src/core/server'; import { coreMock } from 'src/core/server/mocks'; import { featuresPluginMock } from '../../features/server/mocks'; import { licensingMock } from '../../licensing/server/mocks'; -import { Plugin, PluginsStart } from './plugin'; +import { SpacesPlugin, PluginsStart } from './plugin'; import { usageCollectionPluginMock } from '../../../../src/plugins/usage_collection/server/mocks'; describe('Spaces Plugin', () => { @@ -19,7 +19,7 @@ describe('Spaces Plugin', () => { const features = featuresPluginMock.createSetup(); const licensing = licensingMock.createSetup(); - const plugin = new Plugin(initializerContext); + const plugin = new SpacesPlugin(initializerContext); const spacesSetup = plugin.setup(core, { features, licensing }); expect(spacesSetup).toMatchInlineSnapshot(` Object { @@ -42,7 +42,7 @@ describe('Spaces Plugin', () => { const features = featuresPluginMock.createSetup(); const licensing = licensingMock.createSetup(); - const plugin = new Plugin(initializerContext); + const plugin = new SpacesPlugin(initializerContext); plugin.setup(core, { features, licensing }); @@ -58,7 +58,7 @@ describe('Spaces Plugin', () => { const usageCollection = usageCollectionPluginMock.createSetupContract(); - const plugin = new Plugin(initializerContext); + const plugin = new SpacesPlugin(initializerContext); plugin.setup(core, { features, licensing, usageCollection }); @@ -71,7 +71,7 @@ describe('Spaces Plugin', () => { const features = featuresPluginMock.createSetup(); const licensing = licensingMock.createSetup(); - const plugin = new Plugin(initializerContext); + const plugin = new SpacesPlugin(initializerContext); plugin.setup(core, { features, licensing }); @@ -98,7 +98,7 @@ describe('Spaces Plugin', () => { const features = featuresPluginMock.createSetup(); const licensing = licensingMock.createSetup(); - const plugin = new Plugin(initializerContext); + const plugin = new SpacesPlugin(initializerContext); plugin.setup(coreSetup, { features, licensing }); const coreStart = coreMock.createStart(); diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index 24bf96e81ce1a8..6cd04466b346ff 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -12,6 +12,7 @@ import { CoreStart, Logger, PluginInitializerContext, + Plugin, } from '../../../../src/core/server'; import { PluginSetupContract as FeaturesPluginSetup, @@ -61,7 +62,8 @@ export interface SpacesPluginStart { spacesService: SpacesServiceStart; } -export class Plugin { +export class SpacesPlugin + implements Plugin { private readonly config$: Observable; private readonly kibanaIndexConfig$: Observable<{ kibana: { index: string } }>; diff --git a/x-pack/plugins/stack_alerts/server/plugin.ts b/x-pack/plugins/stack_alerts/server/plugin.ts index 66ac9e455e8b6a..a4e6c6a698b798 100644 --- a/x-pack/plugins/stack_alerts/server/plugin.ts +++ b/x-pack/plugins/stack_alerts/server/plugin.ts @@ -18,10 +18,7 @@ export class AlertingBuiltinsPlugin this.logger = ctx.logger.get(); } - public async setup( - core: CoreSetup, - { alerts, features }: StackAlertsDeps - ): Promise { + public setup(core: CoreSetup, { alerts, features }: StackAlertsDeps) { features.registerKibanaFeature(BUILT_IN_ALERTS_FEATURE); registerBuiltInAlertTypes({ @@ -33,6 +30,6 @@ export class AlertingBuiltinsPlugin }); } - public async start(): Promise {} - public async stop(): Promise {} + public start() {} + public stop() {} } diff --git a/x-pack/plugins/watcher/server/plugin.ts b/x-pack/plugins/watcher/server/plugin.ts index 8ce63ab0097792..7c5ddecb81285b 100644 --- a/x-pack/plugins/watcher/server/plugin.ts +++ b/x-pack/plugins/watcher/server/plugin.ts @@ -45,7 +45,7 @@ export class WatcherServerPlugin implements Plugin { this.log = ctx.logger.get(); } - async setup({ http, getStartServices }: CoreSetup, { licensing, features }: Dependencies) { + setup({ http, getStartServices }: CoreSetup, { licensing, features }: Dependencies) { const router = http.createRouter(); const routeDependencies: RouteDependencies = { router, diff --git a/x-pack/plugins/xpack_legacy/server/plugin.ts b/x-pack/plugins/xpack_legacy/server/plugin.ts index 2905f8e4bf3d4a..c23930ad424799 100644 --- a/x-pack/plugins/xpack_legacy/server/plugin.ts +++ b/x-pack/plugins/xpack_legacy/server/plugin.ts @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; - import { CoreStart, CoreSetup, @@ -22,11 +20,9 @@ interface SetupPluginDeps { export class XpackLegacyPlugin implements Plugin { constructor(private readonly initContext: PluginInitializerContext) {} - public async setup(core: CoreSetup, { usageCollection }: SetupPluginDeps) { + public setup(core: CoreSetup, { usageCollection }: SetupPluginDeps) { const router = core.http.createRouter(); - const globalConfig = await this.initContext.config.legacy.globalConfig$ - .pipe(first()) - .toPromise(); + const globalConfig = this.initContext.config.legacy.get(); const serverInfo = core.http.getServerInfo(); registerSettingsRoute({ From 19f8ee0eb9b18fdcafd2e3a0a987804e8f3ccbf3 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 16:32:45 +0100 Subject: [PATCH 04/32] more oss plugins --- src/plugins/legacy_export/server/plugin.ts | 7 ++----- .../saved_objects_management/server/plugin.ts | 4 ++-- src/plugins/share/server/plugin.ts | 2 +- src/plugins/vis_type_timelion/server/index.ts | 4 ++-- src/plugins/vis_type_timelion/server/plugin.ts | 13 +++++-------- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/plugins/legacy_export/server/plugin.ts b/src/plugins/legacy_export/server/plugin.ts index 8cd31d6d87ad59..9cc0578361fa7b 100644 --- a/src/plugins/legacy_export/server/plugin.ts +++ b/src/plugins/legacy_export/server/plugin.ts @@ -7,16 +7,13 @@ */ import { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server'; -import { first } from 'rxjs/operators'; import { registerRoutes } from './routes'; export class LegacyExportPlugin implements Plugin<{}, {}> { constructor(private readonly initContext: PluginInitializerContext) {} - public async setup({ http }: CoreSetup) { - const globalConfig = await this.initContext.config.legacy.globalConfig$ - .pipe(first()) - .toPromise(); + public setup({ http }: CoreSetup) { + const globalConfig = this.initContext.config.legacy.get(); const router = http.createRouter(); registerRoutes( diff --git a/src/plugins/saved_objects_management/server/plugin.ts b/src/plugins/saved_objects_management/server/plugin.ts index 0bef4cff5209a3..938838a2f18ad5 100644 --- a/src/plugins/saved_objects_management/server/plugin.ts +++ b/src/plugins/saved_objects_management/server/plugin.ts @@ -23,7 +23,7 @@ export class SavedObjectsManagementPlugin this.logger = this.context.logger.get(); } - public async setup({ http, capabilities }: CoreSetup) { + public setup({ http, capabilities }: CoreSetup) { this.logger.debug('Setting up SavedObjectsManagement plugin'); registerRoutes({ http, @@ -35,7 +35,7 @@ export class SavedObjectsManagementPlugin return {}; } - public async start(core: CoreStart) { + public start(core: CoreStart) { this.logger.debug('Starting up SavedObjectsManagement plugin'); const managementService = new SavedObjectsManagement(core.savedObjects.getTypeRegistry()); this.managementService$.next(managementService); diff --git a/src/plugins/share/server/plugin.ts b/src/plugins/share/server/plugin.ts index 11f75731b48ae1..9e6b2dbe909248 100644 --- a/src/plugins/share/server/plugin.ts +++ b/src/plugins/share/server/plugin.ts @@ -16,7 +16,7 @@ import { CSV_SEPARATOR_SETTING, CSV_QUOTE_VALUES_SETTING } from '../common/const export class SharePlugin implements Plugin { constructor(private readonly initializerContext: PluginInitializerContext) {} - public async setup(core: CoreSetup) { + public setup(core: CoreSetup) { createRoutes(core, this.initializerContext.logger.get()); core.savedObjects.registerType(url); core.uiSettings.register({ diff --git a/src/plugins/vis_type_timelion/server/index.ts b/src/plugins/vis_type_timelion/server/index.ts index bf1f41d5886755..ac57eb5e2f9072 100644 --- a/src/plugins/vis_type_timelion/server/index.ts +++ b/src/plugins/vis_type_timelion/server/index.ts @@ -8,7 +8,7 @@ import { PluginConfigDescriptor, PluginInitializerContext } from '../../../../src/core/server'; import { configSchema, ConfigSchema } from '../config'; -import { Plugin } from './plugin'; +import { TimelionPlugin } from './plugin'; export { PluginSetupContract } from './plugin'; @@ -25,4 +25,4 @@ export const config: PluginConfigDescriptor = { ], }; export const plugin = (initializerContext: PluginInitializerContext) => - new Plugin(initializerContext); + new TimelionPlugin(initializerContext); diff --git a/src/plugins/vis_type_timelion/server/plugin.ts b/src/plugins/vis_type_timelion/server/plugin.ts index fca557efc01e34..1f183e7fa9790a 100644 --- a/src/plugins/vis_type_timelion/server/plugin.ts +++ b/src/plugins/vis_type_timelion/server/plugin.ts @@ -7,7 +7,6 @@ */ import { i18n } from '@kbn/i18n'; -import { first } from 'rxjs/operators'; import { TypeOf, schema } from '@kbn/config-schema'; import { RecursiveReadonly } from '@kbn/utility-types'; import { deepFreeze } from '@kbn/std'; @@ -17,7 +16,7 @@ import type { PluginStart, DataApiRequestHandlerContext, } from '../../../../src/plugins/data/server'; -import { CoreSetup, PluginInitializerContext } from '../../../../src/core/server'; +import { CoreSetup, PluginInitializerContext, Plugin } from '../../../../src/core/server'; import { configSchema } from '../config'; import loadFunctions from './lib/load_functions'; import { functionsRoute } from './routes/functions'; @@ -43,14 +42,12 @@ export interface TimelionPluginStartDeps { /** * Represents Timelion Plugin instance that will be managed by the Kibana plugin system. */ -export class Plugin { +export class TimelionPlugin + implements Plugin, void, TimelionPluginStartDeps> { constructor(private readonly initializerContext: PluginInitializerContext) {} - public async setup(core: CoreSetup): Promise> { - const config = await this.initializerContext.config - .create>() - .pipe(first()) - .toPromise(); + public setup(core: CoreSetup): RecursiveReadonly { + const config = this.initializerContext.config.get>(); const configManager = new ConfigManager(this.initializerContext.config); From d2325e205745039d69ace713150b7ed58a221645 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 16:33:36 +0100 Subject: [PATCH 05/32] fix test file --- .../plugins/encrypted_saved_objects/server/plugin.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts index 8d8f1a51f68021..ee54bb43f871aa 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Plugin } from './plugin'; +import { EncryptedSavedObjectsPlugin } from './plugin'; import { ConfigSchema } from './config'; import { coreMock } from 'src/core/server/mocks'; @@ -13,7 +13,7 @@ import { securityMock } from '../../security/server/mocks'; describe('EncryptedSavedObjects Plugin', () => { describe('setup()', () => { it('exposes proper contract', async () => { - const plugin = new Plugin( + const plugin = new EncryptedSavedObjectsPlugin( coreMock.createPluginInitializerContext(ConfigSchema.validate({}, { dist: true })) ); await expect(plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() })) @@ -29,7 +29,7 @@ describe('EncryptedSavedObjects Plugin', () => { describe('start()', () => { it('exposes proper contract', async () => { - const plugin = new Plugin( + const plugin = new EncryptedSavedObjectsPlugin( coreMock.createPluginInitializerContext(ConfigSchema.validate({}, { dist: true })) ); await plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() }); From 1f4beba7a1373ac667ea675c13a33ef7883e87d6 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Thu, 28 Jan 2021 16:43:45 +0100 Subject: [PATCH 06/32] change Plugin signature on the client-side too --- src/core/public/index.ts | 9 ++++++++- src/core/public/plugins/index.ts | 2 +- src/core/public/plugins/plugin.ts | 27 +++++++++++++++++++++++++-- src/core/server/plugins/plugin.ts | 7 +++++-- src/core/server/plugins/types.ts | 24 +++++------------------- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 66dd4f3028aafd..7454e25a4e9a14 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -53,7 +53,13 @@ import { HttpSetup, HttpStart } from './http'; import { I18nStart } from './i18n'; import { NotificationsSetup, NotificationsStart } from './notifications'; import { OverlayStart } from './overlays'; -import { Plugin, PluginInitializer, PluginInitializerContext, PluginOpaqueId } from './plugins'; +import { + Plugin, + AsyncPlugin, + PluginInitializer, + PluginInitializerContext, + PluginOpaqueId, +} from './plugins'; import { UiSettingsState, IUiSettingsClient } from './ui_settings'; import { ApplicationSetup, Capabilities, ApplicationStart } from './application'; import { DocLinksStart } from './doc_links'; @@ -304,6 +310,7 @@ export { NotificationsSetup, NotificationsStart, Plugin, + AsyncPlugin, PluginInitializer, PluginInitializerContext, SavedObjectsStart, diff --git a/src/core/public/plugins/index.ts b/src/core/public/plugins/index.ts index 795340e73f80ce..9e31beeca9bfca 100644 --- a/src/core/public/plugins/index.ts +++ b/src/core/public/plugins/index.ts @@ -7,6 +7,6 @@ */ export * from './plugins_service'; -export { Plugin, PluginInitializer } from './plugin'; +export { Plugin, AsyncPlugin, PluginInitializer } from './plugin'; export { PluginInitializerContext } from './plugin_context'; export { PluginOpaqueId } from '../../server/types'; diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index 26bd6a3cfc290d..bace0f4ea35a62 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -23,6 +23,23 @@ export interface Plugin< TStart = void, TPluginsSetup extends object = object, TPluginsStart extends object = object +> { + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; + start(core: CoreStart, plugins: TPluginsStart): TStart; + stop?(): void; +} + +/** + * A plugin with asynchronous lifecycle methods. + * + * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync + * @public + */ +export interface AsyncPlugin< + TSetup = void, + TStart = void, + TPluginsSetup extends object = object, + TPluginsStart extends object = object > { setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; @@ -40,7 +57,11 @@ export type PluginInitializer< TStart, TPluginsSetup extends object = object, TPluginsStart extends object = object -> = (core: PluginInitializerContext) => Plugin; +> = ( + core: PluginInitializerContext +) => + | Plugin + | AsyncPlugin; /** * Lightweight wrapper around discovered plugin that is responsible for instantiating @@ -58,7 +79,9 @@ export class PluginWrapper< public readonly configPath: DiscoveredPlugin['configPath']; public readonly requiredPlugins: DiscoveredPlugin['requiredPlugins']; public readonly optionalPlugins: DiscoveredPlugin['optionalPlugins']; - private instance?: Plugin; + private instance?: + | Plugin + | AsyncPlugin; private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>(); public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise(); diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index 8f9ab2d6ec7dbf..a7346460f540b6 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -14,7 +14,8 @@ import { isConfigSchema } from '@kbn/config-schema'; import { Logger } from '../logging'; import { - SyncOrAsyncPlugin, + Plugin, + AsyncPlugin, PluginInitializerContext, PluginManifest, PluginInitializer, @@ -49,7 +50,9 @@ export class PluginWrapper< private readonly log: Logger; private readonly initializerContext: PluginInitializerContext; - private instance?: SyncOrAsyncPlugin; + private instance?: + | Plugin + | AsyncPlugin; private readonly startDependencies$ = new Subject<[CoreStart, TPluginsStart, TStart]>(); public readonly startDependencies = this.startDependencies$.pipe(first()).toPromise(); diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index ca1737972c44b7..a46cb87adb973e 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -249,9 +249,9 @@ export interface Plugin< } /** - * The interface that should be returned by a `PluginInitializer`. + * A plugin with asynchronous lifecycle methods. * - * @deprecated Asynchronous plugins should be migrated to {@link Plugin} + * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync * @public */ export interface AsyncPlugin< @@ -265,22 +265,6 @@ export interface AsyncPlugin< stop?(): void; } -/** - * Internal representation of a synchronous or asynchronous plugin. - * - * Should be removed and usages replaced by `Plugin` once sync lifecycle migration is complete - * - * @internal - */ -export type SyncOrAsyncPlugin< - TSetup = void, - TStart = void, - TPluginsSetup extends object = object, - TPluginsStart extends object = object -> = - | Plugin - | AsyncPlugin; - export const SharedGlobalConfigKeys = { // We can add more if really needed kibana: ['index', 'autocompleteTerminateAfter', 'autocompleteTimeout'] as const, @@ -418,4 +402,6 @@ export type PluginInitializer< TPluginsStart extends object = object > = ( core: PluginInitializerContext -) => SyncOrAsyncPlugin; +) => + | Plugin + | AsyncPlugin; From 7f0816aeb5732034ba42a536d8aa081e7a222986 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 08:09:29 +0100 Subject: [PATCH 07/32] fix test types --- src/core/public/plugins/plugins_service.test.mocks.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/public/plugins/plugins_service.test.mocks.ts b/src/core/public/plugins/plugins_service.test.mocks.ts index 7a2ec6ed72e14b..b89c4ccf0f226e 100644 --- a/src/core/public/plugins/plugins_service.test.mocks.ts +++ b/src/core/public/plugins/plugins_service.test.mocks.ts @@ -7,9 +7,12 @@ */ import { PluginName } from 'kibana/server'; -import { Plugin } from './plugin'; +import { Plugin, AsyncPlugin } from './plugin'; -export type MockedPluginInitializer = jest.Mock>, any>; +export type MockedPluginInitializer = jest.Mock< + Plugin> | AsyncPlugin>, + any +>; export const mockPluginInitializerProvider: jest.Mock< MockedPluginInitializer, From 36e4e4a9f2bf90401f555d1220d92a27a7068088 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 08:24:50 +0100 Subject: [PATCH 08/32] migrate OSS client-side plugins --- src/plugins/inspector/public/plugin.tsx | 2 +- src/plugins/region_map/public/plugin.ts | 2 +- src/plugins/tile_map/public/plugin.ts | 2 +- src/plugins/vis_type_table/public/plugin.ts | 5 ++--- src/plugins/vis_type_timeseries/public/plugin.ts | 4 ++-- src/plugins/vis_type_vega/public/plugin.ts | 4 ++-- src/plugins/vis_type_vislib/public/plugin.ts | 2 +- src/plugins/vis_type_xy/public/plugin.ts | 2 +- src/plugins/visualize/public/plugin.ts | 2 +- 9 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/plugins/inspector/public/plugin.tsx b/src/plugins/inspector/public/plugin.tsx index 9ed3bd4cb3815c..14da2f41df1dd1 100644 --- a/src/plugins/inspector/public/plugin.tsx +++ b/src/plugins/inspector/public/plugin.tsx @@ -56,7 +56,7 @@ export class InspectorPublicPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} - public async setup(core: CoreSetup) { + public setup(core: CoreSetup) { this.views = new InspectorViewRegistry(); this.views.register(getRequestsViewDescription()); diff --git a/src/plugins/region_map/public/plugin.ts b/src/plugins/region_map/public/plugin.ts index 698c962c09d515..19f47b8ebb3da0 100644 --- a/src/plugins/region_map/public/plugin.ts +++ b/src/plugins/region_map/public/plugin.ts @@ -79,7 +79,7 @@ export class RegionMapPlugin implements Plugin, void, TablePluginSetupDependencies, TablePluginStartDependencies> { + implements AsyncPlugin { initializerContext: PluginInitializerContext; constructor(initializerContext: PluginInitializerContext) { diff --git a/src/plugins/vis_type_timeseries/public/plugin.ts b/src/plugins/vis_type_timeseries/public/plugin.ts index 46fd75ef715555..0cbfd6d4977b46 100644 --- a/src/plugins/vis_type_timeseries/public/plugin.ts +++ b/src/plugins/vis_type_timeseries/public/plugin.ts @@ -43,14 +43,14 @@ export interface MetricsPluginStartDependencies { } /** @internal */ -export class MetricsPlugin implements Plugin, void> { +export class MetricsPlugin implements Plugin { initializerContext: PluginInitializerContext; constructor(initializerContext: PluginInitializerContext) { this.initializerContext = initializerContext; } - public async setup( + public setup( core: CoreSetup, { expressions, visualizations, charts, visualize }: MetricsPluginSetupDependencies ) { diff --git a/src/plugins/vis_type_vega/public/plugin.ts b/src/plugins/vis_type_vega/public/plugin.ts index 376ef84de23c32..89300fbbf0968c 100644 --- a/src/plugins/vis_type_vega/public/plugin.ts +++ b/src/plugins/vis_type_vega/public/plugin.ts @@ -53,14 +53,14 @@ export interface VegaPluginStartDependencies { } /** @internal */ -export class VegaPlugin implements Plugin, void> { +export class VegaPlugin implements Plugin { initializerContext: PluginInitializerContext; constructor(initializerContext: PluginInitializerContext) { this.initializerContext = initializerContext; } - public async setup( + public setup( core: CoreSetup, { inspector, data, expressions, visualizations, mapsLegacy }: VegaPluginSetupDependencies ) { diff --git a/src/plugins/vis_type_vislib/public/plugin.ts b/src/plugins/vis_type_vislib/public/plugin.ts index cdd53fcb2e3349..979c7b11b2abc0 100644 --- a/src/plugins/vis_type_vislib/public/plugin.ts +++ b/src/plugins/vis_type_vislib/public/plugin.ts @@ -46,7 +46,7 @@ export class VisTypeVislibPlugin Plugin { constructor(public initializerContext: PluginInitializerContext) {} - public async setup( + public setup( core: VisTypeVislibCoreSetup, { expressions, visualizations, charts }: VisTypeVislibPluginSetupDependencies ) { diff --git a/src/plugins/vis_type_xy/public/plugin.ts b/src/plugins/vis_type_xy/public/plugin.ts index bd0211bd945cb5..e186d5640c9646 100644 --- a/src/plugins/vis_type_xy/public/plugin.ts +++ b/src/plugins/vis_type_xy/public/plugin.ts @@ -59,7 +59,7 @@ export class VisTypeXyPlugin VisTypeXyPluginSetupDependencies, VisTypeXyPluginStartDependencies > { - public async setup( + public setup( core: VisTypeXyCoreSetup, { expressions, visualizations, charts, usageCollection }: VisTypeXyPluginSetupDependencies ) { diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 111ee7b0041ed3..b16ae454313296 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -92,7 +92,7 @@ export class VisualizePlugin constructor(private initializerContext: PluginInitializerContext) {} - public async setup( + public setup( core: CoreSetup, { home, urlForwarding, data, share, uiActions }: VisualizePluginSetupDependencies ) { From f7efac035721302297c91a97b30f8ab4c9e696ce Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 08:27:23 +0100 Subject: [PATCH 09/32] migrate OSS client-side test plugins --- test/plugin_functional/plugins/app_link_test/public/plugin.ts | 2 +- test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/plugin_functional/plugins/app_link_test/public/plugin.ts b/test/plugin_functional/plugins/app_link_test/public/plugin.ts index f63605032a218f..63599931ab0c75 100644 --- a/test/plugin_functional/plugins/app_link_test/public/plugin.ts +++ b/test/plugin_functional/plugins/app_link_test/public/plugin.ts @@ -10,7 +10,7 @@ import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public'; import { renderApp } from './app'; export class CoreAppLinkPlugin implements Plugin { - public async setup(core: CoreSetup, deps: {}) { + public setup(core: CoreSetup, deps: {}) { core.application.register({ id: 'applink_start', title: 'AppLink Start', diff --git a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx index 9ba549a82b46f9..9dc3623af60383 100644 --- a/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx +++ b/test/plugin_functional/plugins/core_plugin_b/public/plugin.tsx @@ -42,7 +42,7 @@ export class CorePluginBPlugin }; } - public async start(core: CoreStart, deps: {}) { + public start(core: CoreStart, deps: {}) { return { sendSystemRequest: async (asSystemRequest: boolean) => { const response = await core.http.post('/core_plugin_b/system_request', { From 9162085b84785d9b8801a3ed677d38633254a1e8 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 08:39:51 +0100 Subject: [PATCH 10/32] migrate xpack client-side plugins --- x-pack/plugins/cloud/public/plugin.ts | 2 +- x-pack/plugins/fleet/public/plugin.ts | 2 +- x-pack/plugins/licensing/public/plugin.ts | 2 +- x-pack/plugins/monitoring/public/plugin.ts | 9 +++++++-- x-pack/plugins/uptime/public/apps/plugin.ts | 5 +---- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/cloud/public/plugin.ts b/x-pack/plugins/cloud/public/plugin.ts index bc410b89c30e7a..d35e48229335bf 100644 --- a/x-pack/plugins/cloud/public/plugin.ts +++ b/x-pack/plugins/cloud/public/plugin.ts @@ -44,7 +44,7 @@ export class CloudPlugin implements Plugin { this.isCloudEnabled = false; } - public async setup(core: CoreSetup, { home }: CloudSetupDependencies) { + public setup(core: CoreSetup, { home }: CloudSetupDependencies) { const { id, resetPasswordUrl, deploymentUrl } = this.config; this.isCloudEnabled = getIsCloudEnabled(id); diff --git a/x-pack/plugins/fleet/public/plugin.ts b/x-pack/plugins/fleet/public/plugin.ts index 31b53f41b3a913..82ddc2e7f02584 100644 --- a/x-pack/plugins/fleet/public/plugin.ts +++ b/x-pack/plugins/fleet/public/plugin.ts @@ -153,7 +153,7 @@ export class FleetPlugin implements Plugin { + public start(core: CoreStart): FleetStart { let successPromise: ReturnType; return { diff --git a/x-pack/plugins/licensing/public/plugin.ts b/x-pack/plugins/licensing/public/plugin.ts index f5832d0bb7d93d..d191ac0d54d54b 100644 --- a/x-pack/plugins/licensing/public/plugin.ts +++ b/x-pack/plugins/licensing/public/plugin.ts @@ -121,7 +121,7 @@ export class LicensingPlugin implements Plugin { + AsyncPlugin< + boolean, + void, + MonitoringSetupPluginDependencies, + MonitoringStartPluginDependencies + > { constructor(private initializerContext: PluginInitializerContext) {} public async setup( diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index cd30203b5c2392..769932bac96ee5 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -49,10 +49,7 @@ export class UptimePlugin implements Plugin { constructor(_context: PluginInitializerContext) {} - public async setup( - core: CoreSetup, - plugins: ClientPluginsSetup - ): Promise { + public setup(core: CoreSetup, plugins: ClientPluginsSetup): void { if (plugins.home) { plugins.home.featureCatalogue.register({ id: PLUGIN.ID, From 08659e5512b67241344d2a2882a2413055b32be1 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 09:18:45 +0100 Subject: [PATCH 11/32] revert fix attempt on fleet plugin --- x-pack/plugins/fleet/server/services/app_context.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index 9ff51f57fcf300..66ffd3ca53081f 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { BehaviorSubject, Observable } from 'rxjs'; +import { first } from 'rxjs/operators'; import { ElasticsearchClient, SavedObjectsServiceStart, @@ -37,7 +38,7 @@ class AppContextService { private httpSetup?: HttpServiceSetup; private externalCallbacks: ExternalCallbacksStorage = new Map(); - public start(appContext: FleetAppContext) { + public async start(appContext: FleetAppContext) { this.esClient = appContext.elasticsearch.client.asInternalUser; this.encryptedSavedObjects = appContext.encryptedSavedObjectsStart?.getClient(); this.encryptedSavedObjectsSetup = appContext.encryptedSavedObjectsSetup; @@ -50,9 +51,10 @@ class AppContextService { this.kibanaBranch = appContext.kibanaBranch; this.httpSetup = appContext.httpSetup; - if (appContext.config$ && appContext.initialConfig) { + if (appContext.config$) { this.config$ = appContext.config$; - this.configSubject$ = new BehaviorSubject(appContext.initialConfig); + const initialValue = await this.config$.pipe(first()).toPromise(); + this.configSubject$ = new BehaviorSubject(initialValue); this.config$.subscribe(this.configSubject$); } } From d9d830b0a6e3a2a00b6335d1bdd881990b135c4d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 09:41:14 +0100 Subject: [PATCH 12/32] fix presentation start signature --- src/plugins/presentation_util/public/plugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/presentation_util/public/plugin.ts b/src/plugins/presentation_util/public/plugin.ts index 5d3618b0346567..dc3244fd5c908e 100644 --- a/src/plugins/presentation_util/public/plugin.ts +++ b/src/plugins/presentation_util/public/plugin.ts @@ -31,10 +31,10 @@ export class PresentationUtilPlugin return {}; } - public async start( + public start( coreStart: CoreStart, startPlugins: PresentationUtilPluginStartDeps - ): Promise { + ): PresentationUtilPluginStart { pluginServices.setRegistry(registry.start({ coreStart, startPlugins })); return { From 147fe61d5726519a9b5d84b9de050350dd3fadcf Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 09:55:51 +0100 Subject: [PATCH 13/32] fix yet another signature --- x-pack/plugins/triggers_actions_ui/server/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/server/plugin.ts b/x-pack/plugins/triggers_actions_ui/server/plugin.ts index 9a319524931f05..6faae8bc36eb22 100644 --- a/x-pack/plugins/triggers_actions_ui/server/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/server/plugin.ts @@ -29,7 +29,7 @@ export class TriggersActionsPlugin implements Plugin this.data = getService(); } - public setup(core: CoreSetup, plugins: PluginsSetup): Promise { + public setup(core: CoreSetup, plugins: PluginsSetup): void { const router = core.http.createRouter(); registerDataService({ logger: this.logger, From 55d0a68109c4253272b1fadb87993edcf7e2d29e Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 10:34:46 +0100 Subject: [PATCH 14/32] add warnings for server-side async plugins in dev mode --- packages/kbn-std/src/index.ts | 2 +- packages/kbn-std/src/promise.test.ts | 24 ++- packages/kbn-std/src/promise.ts | 4 + src/core/server/plugins/plugin.test.ts | 36 ++--- src/core/server/plugins/plugin.ts | 22 ++- .../server/plugins/plugins_system.test.ts | 144 ++++++++++++++++-- src/core/server/plugins/plugins_system.ts | 56 ++++--- 7 files changed, 231 insertions(+), 57 deletions(-) diff --git a/packages/kbn-std/src/index.ts b/packages/kbn-std/src/index.ts index 2973e088f6e591..ae7b4cb28337ae 100644 --- a/packages/kbn-std/src/index.ts +++ b/packages/kbn-std/src/index.ts @@ -12,7 +12,7 @@ export { get } from './get'; export { mapToObject } from './map_to_object'; export { merge } from './merge'; export { pick } from './pick'; -export { withTimeout } from './promise'; +export { withTimeout, isPromise } from './promise'; export { isRelativeUrl, modifyUrl, getUrlOrigin, URLMeaningfulParts } from './url'; export { unset } from './unset'; export { getFlattenedObject } from './get_flattened_object'; diff --git a/packages/kbn-std/src/promise.test.ts b/packages/kbn-std/src/promise.test.ts index 168bfdb2fbf5ba..1f5bf18b1c3280 100644 --- a/packages/kbn-std/src/promise.test.ts +++ b/packages/kbn-std/src/promise.test.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { withTimeout } from './promise'; +import { withTimeout, isPromise } from './promise'; const delay = (ms: number, resolveValue?: any) => new Promise((resolve) => setTimeout(resolve, ms, resolveValue)); @@ -50,3 +50,25 @@ describe('withTimeout', () => { ).rejects.toMatchInlineSnapshot(`[Error: from-promise]`); }); }); + +describe('isPromise', () => { + it('returns true when arg is a Promise', () => { + expect(isPromise(Promise.resolve('foo'))).toEqual(true); + expect(isPromise(Promise.reject('foo').catch(() => undefined))).toEqual(true); + }); + + it('returns false when arg is not a Promise', () => { + expect(isPromise(12)).toEqual(false); + expect(isPromise('foo')).toEqual(false); + expect(isPromise({ hello: 'dolly' })).toEqual(false); + expect(isPromise([1, 2, 3])).toEqual(false); + }); + + it('returns false for objects with a non-function `then` property', () => { + expect(isPromise({ then: 'bar' })).toEqual(false); + }); + + it('returns true for Promise-Like objects', () => { + expect(isPromise({ then: () => 12 })).toEqual(true); + }); +}); diff --git a/packages/kbn-std/src/promise.ts b/packages/kbn-std/src/promise.ts index bcd6c7b4d4fdae..41618c4b721a21 100644 --- a/packages/kbn-std/src/promise.ts +++ b/packages/kbn-std/src/promise.ts @@ -20,3 +20,7 @@ export function withTimeout({ new Promise((resolve, reject) => setTimeout(() => reject(new Error(errorMessage)), timeout)), ]) as Promise; } + +export function isPromise(maybePromise: T | Promise): maybePromise is Promise { + return typeof (maybePromise as Promise).then === 'function'; +} diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts index f4ecc42eb7c307..15e7ce33e44ffc 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/src/core/server/plugins/plugin.test.ts @@ -100,7 +100,7 @@ test('`constructor` correctly initializes plugin instance', () => { expect(plugin.optionalPlugins).toEqual(['some-optional-dep']); }); -test('`setup` fails if `plugin` initializer is not exported', async () => { +test('`setup` fails if `plugin` initializer is not exported', () => { const manifest = createPluginManifest(); const opaqueId = Symbol(); const plugin = new PluginWrapper({ @@ -115,14 +115,14 @@ test('`setup` fails if `plugin` initializer is not exported', async () => { ), }); - await expect( + expect(() => plugin.setup(createPluginSetupContext(coreContext, setupDeps, plugin), {}) - ).rejects.toMatchInlineSnapshot( - `[Error: Plugin "some-plugin-id" does not export "plugin" definition (plugin-without-initializer-path).]` + ).toThrowErrorMatchingInlineSnapshot( + `"Plugin \\"some-plugin-id\\" does not export \\"plugin\\" definition (plugin-without-initializer-path)."` ); }); -test('`setup` fails if plugin initializer is not a function', async () => { +test('`setup` fails if plugin initializer is not a function', () => { const manifest = createPluginManifest(); const opaqueId = Symbol(); const plugin = new PluginWrapper({ @@ -137,14 +137,14 @@ test('`setup` fails if plugin initializer is not a function', async () => { ), }); - await expect( + expect(() => plugin.setup(createPluginSetupContext(coreContext, setupDeps, plugin), {}) - ).rejects.toMatchInlineSnapshot( - `[Error: Definition of plugin "some-plugin-id" should be a function (plugin-with-wrong-initializer-path).]` + ).toThrowErrorMatchingInlineSnapshot( + `"Definition of plugin \\"some-plugin-id\\" should be a function (plugin-with-wrong-initializer-path)."` ); }); -test('`setup` fails if initializer does not return object', async () => { +test('`setup` fails if initializer does not return object', () => { const manifest = createPluginManifest(); const opaqueId = Symbol(); const plugin = new PluginWrapper({ @@ -161,14 +161,14 @@ test('`setup` fails if initializer does not return object', async () => { mockPluginInitializer.mockReturnValue(null); - await expect( + expect(() => plugin.setup(createPluginSetupContext(coreContext, setupDeps, plugin), {}) - ).rejects.toMatchInlineSnapshot( - `[Error: Initializer for plugin "some-plugin-id" is expected to return plugin instance, but returned "null".]` + ).toThrowErrorMatchingInlineSnapshot( + `"Initializer for plugin \\"some-plugin-id\\" is expected to return plugin instance, but returned \\"null\\"."` ); }); -test('`setup` fails if object returned from initializer does not define `setup` function', async () => { +test('`setup` fails if object returned from initializer does not define `setup` function', () => { const manifest = createPluginManifest(); const opaqueId = Symbol(); const plugin = new PluginWrapper({ @@ -186,10 +186,10 @@ test('`setup` fails if object returned from initializer does not define `setup` const mockPluginInstance = { run: jest.fn() }; mockPluginInitializer.mockReturnValue(mockPluginInstance); - await expect( + expect(() => plugin.setup(createPluginSetupContext(coreContext, setupDeps, plugin), {}) - ).rejects.toMatchInlineSnapshot( - `[Error: Instance of plugin "some-plugin-id" does not define "setup" function.]` + ).toThrowErrorMatchingInlineSnapshot( + `"Instance of plugin \\"some-plugin-id\\" does not define \\"setup\\" function."` ); }); @@ -223,7 +223,7 @@ test('`setup` initializes plugin and calls appropriate lifecycle hook', async () expect(mockPluginInstance.setup).toHaveBeenCalledWith(setupContext, setupDependencies); }); -test('`start` fails if setup is not called first', async () => { +test('`start` fails if setup is not called first', () => { const manifest = createPluginManifest(); const opaqueId = Symbol(); const plugin = new PluginWrapper({ @@ -238,7 +238,7 @@ test('`start` fails if setup is not called first', async () => { ), }); - await expect(plugin.start({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( + expect(() => plugin.start({} as any, {} as any)).toThrowErrorMatchingInlineSnapshot( `"Plugin \\"some-plugin-id\\" can't be started since it isn't set up."` ); }); diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index a7346460f540b6..cead1b7a15e1d2 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -6,6 +6,7 @@ * Public License, v 1. */ +import { isPromise } from '@kbn/std'; import { join } from 'path'; import typeDetect from 'type-detect'; import { Subject } from 'rxjs'; @@ -86,9 +87,11 @@ export class PluginWrapper< * @param plugins The dictionary where the key is the dependency name and the value * is the contract returned by the dependency's `setup` function. */ - public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) { + public setup( + setupContext: CoreSetup, + plugins: TPluginsSetup + ): TSetup | Promise { this.instance = this.createPluginInstance(); - return this.instance.setup(setupContext, plugins); } @@ -99,14 +102,21 @@ export class PluginWrapper< * @param plugins The dictionary where the key is the dependency name and the value * is the contract returned by the dependency's `start` function. */ - public async start(startContext: CoreStart, plugins: TPluginsStart) { + public start(startContext: CoreStart, plugins: TPluginsStart): TStart | Promise { if (this.instance === undefined) { throw new Error(`Plugin "${this.name}" can't be started since it isn't set up.`); } - const startContract = await this.instance.start(startContext, plugins); - this.startDependencies$.next([startContext, plugins, startContract]); - return startContract; + const startContract = this.instance.start(startContext, plugins); + if (isPromise(startContract)) { + return startContract.then((resolvedContract) => { + this.startDependencies$.next([startContext, plugins, resolvedContract]); + return resolvedContract; + }); + } else { + this.startDependencies$.next([startContext, plugins, startContract]); + return startContract; + } } /** diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index 63522071f9310c..eeee196c83777f 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -25,7 +25,6 @@ import { PluginsSystem } from './plugins_system'; import { coreMock } from '../mocks'; import { Logger } from '../logging'; -const logger = loggingSystemMock.create(); function createPlugin( id: string, { @@ -34,8 +33,8 @@ function createPlugin( server = true, ui = true, }: { required?: string[]; optional?: string[]; server?: boolean; ui?: boolean } = {} -) { - return new PluginWrapper({ +): PluginWrapper { + return new PluginWrapper({ path: 'some-path', manifest: { id, @@ -53,27 +52,27 @@ function createPlugin( }); } +const setupDeps = coreMock.createInternalSetup(); +const startDeps = coreMock.createInternalStart(); + let pluginsSystem: PluginsSystem; -const configService = configServiceMock.create(); -configService.atPath.mockReturnValue(new BehaviorSubject({ initialize: true })); +let configService: ReturnType; +let logger: ReturnType; let env: Env; let coreContext: CoreContext; -const setupDeps = coreMock.createInternalSetup(); -const startDeps = coreMock.createInternalStart(); - beforeEach(() => { + logger = loggingSystemMock.create(); env = Env.createDefault(REPO_ROOT, getEnvOptions()); + configService = configServiceMock.create(); + configService.atPath.mockReturnValue(new BehaviorSubject({ initialize: true })); + coreContext = { coreId: Symbol(), env, logger, configService: configService as any }; pluginsSystem = new PluginsSystem(coreContext); }); -afterEach(() => { - jest.clearAllMocks(); -}); - test('can be setup even without plugins', async () => { const pluginsSetup = await pluginsSystem.setupPlugins(setupDeps); @@ -208,7 +207,7 @@ test('correctly orders plugins and returns exposed values for "setup" and "start start: { 'order-2': 'started-as-2' }, }, ], - ] as Array<[PluginWrapper, Contracts]>); + ] as Array<[PluginWrapper, Contracts]>); const setupContextMap = new Map(); const startContextMap = new Map(); @@ -472,7 +471,7 @@ describe('start', () => { jest.useRealTimers(); }); it('throws timeout error if "start" was not completed in 30 sec.', async () => { - const plugin: PluginWrapper = createPlugin('timeout-start'); + const plugin = createPlugin('timeout-start'); jest.spyOn(plugin, 'setup').mockResolvedValue({}); jest.spyOn(plugin, 'start').mockImplementation(() => new Promise((i) => i)); @@ -505,3 +504,120 @@ describe('start', () => { expect(log.info).toHaveBeenCalledWith(`Starting [2] plugins: [order-1,order-0]`); }); }); + +describe('asynchronous plugins', () => { + const runScenario = async ({ + production, + asyncSetup, + asyncStart, + }: { + production: boolean; + asyncSetup: boolean; + asyncStart: boolean; + }) => { + env = Env.createDefault( + REPO_ROOT, + getEnvOptions({ + cliArgs: { + dev: !production, + envName: production ? 'production' : 'development', + }, + }) + ); + coreContext = { coreId: Symbol(), env, logger, configService: configService as any }; + pluginsSystem = new PluginsSystem(coreContext); + + const syncPlugin = createPlugin('sync-plugin'); + jest.spyOn(syncPlugin, 'setup').mockReturnValue('setup-sync'); + jest.spyOn(syncPlugin, 'start').mockReturnValue('start-sync'); + pluginsSystem.addPlugin(syncPlugin); + + const asyncPlugin = createPlugin('async-plugin'); + jest + .spyOn(asyncPlugin, 'setup') + .mockReturnValue(asyncSetup ? Promise.resolve('setup-async') : 'setup-sync'); + jest + .spyOn(asyncPlugin, 'start') + .mockReturnValue(asyncStart ? Promise.resolve('start-async') : 'start-sync'); + pluginsSystem.addPlugin(asyncPlugin); + + await pluginsSystem.setupPlugins(setupDeps); + await pluginsSystem.startPlugins(startDeps); + }; + + it('logs a warning if a plugin returns a promise from its setup contract in dev mode', async () => { + await runScenario({ + production: false, + asyncSetup: true, + asyncStart: false, + }); + + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.warn.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); + + it('does not log warnings if a plugin returns a promise from its setup contract in prod mode', async () => { + await runScenario({ + production: true, + asyncSetup: true, + asyncStart: false, + }); + + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.warn).not.toHaveBeenCalled(); + }); + + it('logs a warning if a plugin returns a promise from its start contract in dev mode', async () => { + await runScenario({ + production: false, + asyncSetup: false, + asyncStart: true, + }); + + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.warn.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); + + it('does not log warnings if a plugin returns a promise from its start contract in prod mode', async () => { + await runScenario({ + production: true, + asyncSetup: false, + asyncStart: true, + }); + + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.warn).not.toHaveBeenCalled(); + }); + + it('logs multiple warnings if both `setup` and `start` return promises', async () => { + await runScenario({ + production: false, + asyncSetup: true, + asyncStart: true, + }); + + const log = logger.get.mock.results[0].value as jest.Mocked; + expect(log.warn.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + Array [ + "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); +}); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index 7e0075bf2619bb..ad1d84a4f6a73b 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { withTimeout } from '@kbn/std'; +import { withTimeout, isPromise } from '@kbn/std'; import { CoreContext } from '../core_context'; import { Logger } from '../logging'; import { PluginWrapper } from './plugin'; @@ -94,14 +94,25 @@ export class PluginsSystem { return depContracts; }, {} as Record); - const contract = await withTimeout({ - promise: plugin.setup( - createPluginSetupContext(this.coreContext, deps, plugin), - pluginDepContracts - ), - timeout: 30 * Sec, - errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, - }); + let contract: unknown; + const contractOrPromise = plugin.setup( + createPluginSetupContext(this.coreContext, deps, plugin), + pluginDepContracts + ); + if (isPromise(contractOrPromise)) { + if (this.coreContext.env.mode.dev) { + this.log.warn( + `Plugin ${pluginName} is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.` + ); + } + contract = await withTimeout({ + promise: contractOrPromise, + timeout: 30 * Sec, + errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + }); + } else { + contract = contractOrPromise; + } contracts.set(pluginName, contract); this.satupPlugins.push(pluginName); @@ -132,14 +143,25 @@ export class PluginsSystem { return depContracts; }, {} as Record); - const contract = await withTimeout({ - promise: plugin.start( - createPluginStartContext(this.coreContext, deps, plugin), - pluginDepContracts - ), - timeout: 30 * Sec, - errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, - }); + let contract: unknown; + const contractOrPromise = plugin.start( + createPluginStartContext(this.coreContext, deps, plugin), + pluginDepContracts + ); + if (isPromise(contractOrPromise)) { + if (this.coreContext.env.mode.dev) { + this.log.warn( + `Plugin ${pluginName} is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.` + ); + } + contract = await withTimeout({ + promise: contractOrPromise, + timeout: 30 * Sec, + errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + }); + } else { + contract = contractOrPromise; + } contracts.set(pluginName, contract); } From 9d775f2dd41fbb2fd5d6f5cee670bee72fe3d58c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 10:35:23 +0100 Subject: [PATCH 15/32] remove unused import --- x-pack/plugins/snapshot_restore/server/plugin.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/snapshot_restore/server/plugin.ts b/x-pack/plugins/snapshot_restore/server/plugin.ts index a3948e1e17d309..b7f5cec1f0bfec 100644 --- a/x-pack/plugins/snapshot_restore/server/plugin.ts +++ b/x-pack/plugins/snapshot_restore/server/plugin.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; import { i18n } from '@kbn/i18n'; import { CoreSetup, From 63651afbe32a66356af8ff4c6f18a9fac640e6d0 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 11:02:23 +0100 Subject: [PATCH 16/32] fix isPromise --- packages/kbn-std/src/promise.test.ts | 5 +++++ packages/kbn-std/src/promise.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/kbn-std/src/promise.test.ts b/packages/kbn-std/src/promise.test.ts index 1f5bf18b1c3280..df61e9c726b328 100644 --- a/packages/kbn-std/src/promise.test.ts +++ b/packages/kbn-std/src/promise.test.ts @@ -68,6 +68,11 @@ describe('isPromise', () => { expect(isPromise({ then: 'bar' })).toEqual(false); }); + it('returns false for null and undefined', () => { + expect(isPromise(null)).toEqual(false); + expect(isPromise(undefined)).toEqual(false); + }); + it('returns true for Promise-Like objects', () => { expect(isPromise({ then: () => 12 })).toEqual(true); }); diff --git a/packages/kbn-std/src/promise.ts b/packages/kbn-std/src/promise.ts index 41618c4b721a21..8ee86711b19511 100644 --- a/packages/kbn-std/src/promise.ts +++ b/packages/kbn-std/src/promise.ts @@ -22,5 +22,5 @@ export function withTimeout({ } export function isPromise(maybePromise: T | Promise): maybePromise is Promise { - return typeof (maybePromise as Promise).then === 'function'; + return maybePromise ? typeof (maybePromise as Promise).then === 'function' : false; } From d64d04ff5ecda8d2332234939c41f2756137027c Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 11:20:22 +0100 Subject: [PATCH 17/32] Add client-side deprecations --- src/core/public/mocks.ts | 8 +- src/core/public/plugins/plugin.test.ts | 12 +- src/core/public/plugins/plugin.ts | 30 ++-- .../plugins/plugins_service.test.mocks.ts | 2 +- .../public/plugins/plugins_service.test.ts | 140 ++++++++++++++++-- src/core/public/plugins/plugins_service.ts | 63 +++++--- src/core/server/plugins/plugin.ts | 2 +- 7 files changed, 206 insertions(+), 51 deletions(-) diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index ba0bf87191dc3f..4bb5c928f39f0b 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -110,14 +110,14 @@ function pluginInitializerContextMock(config: any = {}) { return mock; } -function createCoreContext(): CoreContext { +function createCoreContext({ production = false }: { production?: boolean } = {}): CoreContext { return { coreId: Symbol('core context mock'), env: { mode: { - dev: true, - name: 'development', - prod: false, + dev: !production, + name: production ? 'production' : 'development', + prod: production, }, packageInfo: { version: 'version', diff --git a/src/core/public/plugins/plugin.test.ts b/src/core/public/plugins/plugin.test.ts index 1141a27e67d2ce..83839d90fcab6f 100644 --- a/src/core/public/plugins/plugin.test.ts +++ b/src/core/public/plugins/plugin.test.ts @@ -39,16 +39,16 @@ beforeEach(() => { }); describe('PluginWrapper', () => { - test('`setup` fails if plugin.setup is not a function', async () => { + test('`setup` fails if plugin.setup is not a function', () => { mockInitializer.mockReturnValueOnce({ start: jest.fn() } as any); - await expect(plugin.setup({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( + expect(() => plugin.setup({} as any, {} as any)).toThrowErrorMatchingInlineSnapshot( `"Instance of plugin \\"plugin-a\\" does not define \\"setup\\" function."` ); }); - test('`setup` fails if plugin.start is not a function', async () => { + test('`setup` fails if plugin.start is not a function', () => { mockInitializer.mockReturnValueOnce({ setup: jest.fn() } as any); - await expect(plugin.setup({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( + expect(() => plugin.setup({} as any, {} as any)).toThrowErrorMatchingInlineSnapshot( `"Instance of plugin \\"plugin-a\\" does not define \\"start\\" function."` ); }); @@ -65,8 +65,8 @@ describe('PluginWrapper', () => { expect(mockPlugin.setup).toHaveBeenCalledWith(context, deps); }); - test('`start` fails if setup is not called first', async () => { - await expect(plugin.start({} as any, {} as any)).rejects.toThrowErrorMatchingInlineSnapshot( + test('`start` fails if setup is not called first', () => { + expect(() => plugin.start({} as any, {} as any)).toThrowErrorMatchingInlineSnapshot( `"Plugin \\"plugin-a\\" can't be started since it isn't set up."` ); }); diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index bace0f4ea35a62..0238b6773ae616 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -8,6 +8,7 @@ import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; +import { isPromise } from '@kbn/std'; import { DiscoveredPlugin, PluginOpaqueId } from '../../server'; import { PluginInitializerContext } from './plugin_context'; import { read } from './plugin_reader'; @@ -104,10 +105,12 @@ export class PluginWrapper< * @param plugins The dictionary where the key is the dependency name and the value * is the contract returned by the dependency's `setup` function. */ - public async setup(setupContext: CoreSetup, plugins: TPluginsSetup) { - this.instance = await this.createPluginInstance(); - - return await this.instance.setup(setupContext, plugins); + public setup( + setupContext: CoreSetup, + plugins: TPluginsSetup + ): TSetup | Promise { + this.instance = this.createPluginInstance(); + return this.instance.setup(setupContext, plugins); } /** @@ -117,16 +120,21 @@ export class PluginWrapper< * @param plugins The dictionary where the key is the dependency name and the value * is the contract returned by the dependency's `start` function. */ - public async start(startContext: CoreStart, plugins: TPluginsStart) { + public start(startContext: CoreStart, plugins: TPluginsStart) { if (this.instance === undefined) { throw new Error(`Plugin "${this.name}" can't be started since it isn't set up.`); } - const startContract = await this.instance.start(startContext, plugins); - - this.startDependencies$.next([startContext, plugins, startContract]); - - return startContract; + const startContract = this.instance.start(startContext, plugins); + if (isPromise(startContract)) { + return startContract.then((resolvedContract) => { + this.startDependencies$.next([startContext, plugins, resolvedContract]); + return resolvedContract; + }); + } else { + this.startDependencies$.next([startContext, plugins, startContract]); + return startContract; + } } /** @@ -144,7 +152,7 @@ export class PluginWrapper< this.instance = undefined; } - private async createPluginInstance() { + private createPluginInstance() { const initializer = read(this.name) as PluginInitializer< TSetup, TStart, diff --git a/src/core/public/plugins/plugins_service.test.mocks.ts b/src/core/public/plugins/plugins_service.test.mocks.ts index b89c4ccf0f226e..cf4ed5d5c4c3b6 100644 --- a/src/core/public/plugins/plugins_service.test.mocks.ts +++ b/src/core/public/plugins/plugins_service.test.mocks.ts @@ -10,7 +10,7 @@ import { PluginName } from 'kibana/server'; import { Plugin, AsyncPlugin } from './plugin'; export type MockedPluginInitializer = jest.Mock< - Plugin> | AsyncPlugin>, + Plugin | AsyncPlugin, any >; diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 8da59e4438d114..348b182ec2fbe1 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -146,16 +146,16 @@ describe('PluginsService', () => { it('returns dependency tree of symbols', () => { const pluginsService = new PluginsService(mockCoreContext, plugins); expect(pluginsService.getOpaqueIds()).toMatchInlineSnapshot(` - Map { - Symbol(pluginA) => Array [], - Symbol(pluginB) => Array [ - Symbol(pluginA), - ], - Symbol(pluginC) => Array [ - Symbol(pluginA), - ], - } - `); + Map { + Symbol(pluginA) => Array [], + Symbol(pluginB) => Array [ + Symbol(pluginA), + ], + Symbol(pluginC) => Array [ + Symbol(pluginA), + ], + } + `); }); }); @@ -366,4 +366,124 @@ describe('PluginsService', () => { expect(pluginCInstance.stop).toHaveBeenCalled(); }); }); + + describe('asynchronous plugins', () => { + let consoleSpy: jest.SpyInstance; + + beforeEach(() => { + consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => undefined); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); + + const runScenario = async ({ + production, + asyncSetup, + asyncStart, + }: { + production: boolean; + asyncSetup: boolean; + asyncStart: boolean; + }) => { + const coreContext = coreMock.createCoreContext({ production }); + + const syncPlugin = { id: 'sync-plugin', plugin: createManifest('sync-plugin') }; + mockPluginInitializers.set( + 'sync-plugin', + jest.fn(() => ({ + setup: jest.fn(() => 'setup-sync'), + start: jest.fn(() => 'start-sync'), + stop: jest.fn(), + })) + ); + + const asyncPlugin = { id: 'async-plugin', plugin: createManifest('async-plugin') }; + mockPluginInitializers.set( + 'async-plugin', + jest.fn(() => ({ + setup: jest.fn(() => (asyncSetup ? Promise.resolve('setup-async') : 'setup-sync')), + start: jest.fn(() => (asyncStart ? Promise.resolve('start-async') : 'start-sync')), + stop: jest.fn(), + })) + ); + + const pluginsService = new PluginsService(coreContext, [syncPlugin, asyncPlugin]); + + await pluginsService.setup(mockSetupDeps); + await pluginsService.start(mockStartDeps); + }; + + it('logs a warning if a plugin returns a promise from its setup contract in dev mode', async () => { + await runScenario({ + production: false, + asyncSetup: true, + asyncStart: false, + }); + + expect(consoleSpy.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); + + it('does not log warnings if a plugin returns a promise from its setup contract in prod mode', async () => { + await runScenario({ + production: true, + asyncSetup: true, + asyncStart: false, + }); + + expect(consoleSpy).not.toHaveBeenCalled(); + }); + + it('logs a warning if a plugin returns a promise from its start contract in dev mode', async () => { + await runScenario({ + production: false, + asyncSetup: false, + asyncStart: true, + }); + + expect(consoleSpy.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); + + it('does not log warnings if a plugin returns a promise from its start contract in prod mode', async () => { + await runScenario({ + production: true, + asyncSetup: false, + asyncStart: true, + }); + + expect(consoleSpy).not.toHaveBeenCalled(); + }); + + it('logs multiple warnings if both `setup` and `start` return promises', async () => { + await runScenario({ + production: false, + asyncSetup: true, + asyncStart: true, + }); + + expect(consoleSpy.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "Plugin async-plugin is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + Array [ + "Plugin async-plugin is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.", + ], + ] + `); + }); + }); }); diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts index ea6e7130f4fa27..483d0e2d4baac6 100644 --- a/src/core/public/plugins/plugins_service.ts +++ b/src/core/public/plugins/plugins_service.ts @@ -6,7 +6,7 @@ * Public License, v 1. */ -import { withTimeout } from '@kbn/std'; +import { withTimeout, isPromise } from '@kbn/std'; import { PluginName, PluginOpaqueId } from '../../server'; import { CoreService } from '../../types'; import { CoreContext } from '../core_system'; @@ -98,16 +98,29 @@ export class PluginsService implements CoreService ); - const contract = await withTimeout({ - promise: plugin.setup( - createPluginSetupContext(this.coreContext, deps, plugin), - pluginDepContracts - ), - timeout: 30 * Sec, - errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, - }); - contracts.set(pluginName, contract); + let contract: unknown; + const contractOrPromise = plugin.setup( + createPluginSetupContext(this.coreContext, deps, plugin), + pluginDepContracts + ); + if (isPromise(contractOrPromise)) { + if (this.coreContext.env.mode.dev) { + // eslint-disable-next-line no-console + console.log( + `Plugin ${pluginName} is using asynchronous setup lifecycle. Asynchronous plugins support will be removed in a later version.` + ); + } + + contract = await withTimeout({ + promise: contractOrPromise, + timeout: 30 * Sec, + errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + }); + } else { + contract = contractOrPromise; + } + contracts.set(pluginName, contract); this.satupPlugins.push(pluginName); } @@ -132,14 +145,28 @@ export class PluginsService implements CoreService ); - const contract = await withTimeout({ - promise: plugin.start( - createPluginStartContext(this.coreContext, deps, plugin), - pluginDepContracts - ), - timeout: 30 * Sec, - errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, - }); + let contract: unknown; + const contractOrPromise = plugin.start( + createPluginStartContext(this.coreContext, deps, plugin), + pluginDepContracts + ); + if (isPromise(contractOrPromise)) { + if (this.coreContext.env.mode.dev) { + // eslint-disable-next-line no-console + console.log( + `Plugin ${pluginName} is using asynchronous start lifecycle. Asynchronous plugins support will be removed in a later version.` + ); + } + + contract = await withTimeout({ + promise: contractOrPromise, + timeout: 30 * Sec, + errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + }); + } else { + contract = contractOrPromise; + } + contracts.set(pluginName, contract); } diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index cead1b7a15e1d2..2db639638e6967 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -6,11 +6,11 @@ * Public License, v 1. */ -import { isPromise } from '@kbn/std'; import { join } from 'path'; import typeDetect from 'type-detect'; import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; +import { isPromise } from '@kbn/std'; import { isConfigSchema } from '@kbn/config-schema'; import { Logger } from '../logging'; From daf9db08ef44ba9e57d63d70c308bec95fb48316 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 11:24:49 +0100 Subject: [PATCH 18/32] update migration examples --- .../migrating-legacy-plugins-examples.asciidoc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc b/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc index a033bbd26a1a78..92a624649d3c50 100644 --- a/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc +++ b/docs/developer/plugin/migrating-legacy-plugins-examples.asciidoc @@ -71,22 +71,20 @@ export function plugin(initializerContext: PluginInitializerContext) { *plugins/my_plugin/(public|server)/plugin.ts* [source,typescript] ---- -import type { Observable } from 'rxjs'; -import { first } from 'rxjs/operators'; import { CoreSetup, Logger, Plugin, PluginInitializerContext, PluginName } from 'kibana/server'; import type { MyPluginConfig } from './config'; export class MyPlugin implements Plugin { - private readonly config$: Observable; + private readonly config: MyPluginConfig; private readonly log: Logger; constructor(private readonly initializerContext: PluginInitializerContext) { this.log = initializerContext.logger.get(); - this.config$ = initializerContext.config.create(); + this.config = initializerContext.config.get(); } - public async setup(core: CoreSetup, deps: Record) { - const isEnabled = await this.config$.pipe(first()).toPromise(); + public setup(core: CoreSetup, deps: Record) { + const { someConfigValue } = this.config; } } ---- @@ -96,7 +94,7 @@ Additionally, some plugins need to access the runtime env configuration. [source,typescript] ---- export class MyPlugin implements Plugin { - public async setup(core: CoreSetup, deps: Record) { + public setup(core: CoreSetup, deps: Record) { const { mode: { dev }, packageInfo: { version } } = this.initializerContext.env } ---- From 1cbb228b579a4e46d196654de3beebcb1965e410 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 11:30:30 +0100 Subject: [PATCH 19/32] update generated doc --- .../kibana-plugin-core-public.asyncplugin.md | 27 +++++++++++++++++++ ...na-plugin-core-public.asyncplugin.setup.md | 23 ++++++++++++++++ ...na-plugin-core-public.asyncplugin.start.md | 23 ++++++++++++++++ ...ana-plugin-core-public.asyncplugin.stop.md | 15 +++++++++++ .../core/public/kibana-plugin-core-public.md | 1 + .../kibana-plugin-core-public.plugin.setup.md | 4 +-- .../kibana-plugin-core-public.plugin.start.md | 4 +-- ...na-plugin-core-public.plugininitializer.md | 2 +- .../kibana-plugin-core-server.asyncplugin.md | 27 +++++++++++++++++++ ...na-plugin-core-server.asyncplugin.setup.md | 23 ++++++++++++++++ ...na-plugin-core-server.asyncplugin.start.md | 23 ++++++++++++++++ ...ana-plugin-core-server.asyncplugin.stop.md | 15 +++++++++++ .../core/server/kibana-plugin-core-server.md | 1 + .../kibana-plugin-core-server.plugin.setup.md | 4 +-- .../kibana-plugin-core-server.plugin.start.md | 4 +-- ...na-plugin-core-server.plugininitializer.md | 2 +- src/core/public/public.api.md | 16 ++++++++--- src/core/server/server.api.md | 24 ++++++++++++----- 18 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 docs/development/core/public/kibana-plugin-core-public.asyncplugin.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md create mode 100644 docs/development/core/server/kibana-plugin-core-server.asyncplugin.md create mode 100644 docs/development/core/server/kibana-plugin-core-server.asyncplugin.setup.md create mode 100644 docs/development/core/server/kibana-plugin-core-server.asyncplugin.start.md create mode 100644 docs/development/core/server/kibana-plugin-core-server.asyncplugin.stop.md diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md new file mode 100644 index 00000000000000..979d4ed2825054 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) + +## AsyncPlugin interface + +> Warning: This API is now obsolete. +> +> Asynchronous lifecycles are deprecated, and should be migrated to sync +> + +A plugin with asynchronous lifecycle methods. + +Signature: + +```typescript +export interface AsyncPlugin +``` + +## Methods + +| Method | Description | +| --- | --- | +| [setup(core, plugins)](./kibana-plugin-core-public.asyncplugin.setup.md) | | +| [start(core, plugins)](./kibana-plugin-core-public.asyncplugin.start.md) | | +| [stop()](./kibana-plugin-core-public.asyncplugin.stop.md) | | + diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md new file mode 100644 index 00000000000000..54507b44cdd72a --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.setup.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [setup](./kibana-plugin-core-public.asyncplugin.setup.md) + +## AsyncPlugin.setup() method + +Signature: + +```typescript +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreSetup<TPluginsStart, TStart> | | +| plugins | TPluginsSetup | | + +Returns: + +`TSetup | Promise` + diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md new file mode 100644 index 00000000000000..f16d3c46bf8499 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.start.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [start](./kibana-plugin-core-public.asyncplugin.start.md) + +## AsyncPlugin.start() method + +Signature: + +```typescript +start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreStart | | +| plugins | TPluginsStart | | + +Returns: + +`TStart | Promise` + diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md new file mode 100644 index 00000000000000..f809f75783c26c --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.stop.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) > [stop](./kibana-plugin-core-public.asyncplugin.stop.md) + +## AsyncPlugin.stop() method + +Signature: + +```typescript +stop?(): void; +``` +Returns: + +`void` + diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index efd499823ffadc..e307b5c9971b0b 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -39,6 +39,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ApplicationStart](./kibana-plugin-core-public.applicationstart.md) | | | [AppMeta](./kibana-plugin-core-public.appmeta.md) | Input type for meta data for an application.Meta fields include keywords and searchDeepLinks Keywords is an array of string with which to associate the app, must include at least one unique string as an array. searchDeepLinks is an array of links that represent secondary in-app locations for the app. | | [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) | | +| [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) | A plugin with asynchronous lifecycle methods. | | [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | | [ChromeBadge](./kibana-plugin-core-public.chromebadge.md) | | | [ChromeBrand](./kibana-plugin-core-public.chromebrand.md) | | diff --git a/docs/development/core/public/kibana-plugin-core-public.plugin.setup.md b/docs/development/core/public/kibana-plugin-core-public.plugin.setup.md index 7fa05588a33012..232851cd342cee 100644 --- a/docs/development/core/public/kibana-plugin-core-public.plugin.setup.md +++ b/docs/development/core/public/kibana-plugin-core-public.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; ``` ## Parameters @@ -19,5 +19,5 @@ setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Returns: -`TSetup | Promise` +`TSetup` diff --git a/docs/development/core/public/kibana-plugin-core-public.plugin.start.md b/docs/development/core/public/kibana-plugin-core-public.plugin.start.md index 0d3c19a8217a67..ec5ed211a9d2ba 100644 --- a/docs/development/core/public/kibana-plugin-core-public.plugin.start.md +++ b/docs/development/core/public/kibana-plugin-core-public.plugin.start.md @@ -7,7 +7,7 @@ Signature: ```typescript -start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; +start(core: CoreStart, plugins: TPluginsStart): TStart; ``` ## Parameters @@ -19,5 +19,5 @@ start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; Returns: -`TStart | Promise` +`TStart` diff --git a/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md b/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md index 1fcc2999dfd2ed..b7c3e11e492bd7 100644 --- a/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md +++ b/docs/development/core/public/kibana-plugin-core-public.plugininitializer.md @@ -9,5 +9,5 @@ The `plugin` export at the root of a plugin's `public` directory should conform Signature: ```typescript -export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin; +export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin | AsyncPlugin; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md new file mode 100644 index 00000000000000..682a164ce397a0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [AsyncPlugin](./kibana-plugin-core-server.asyncplugin.md) + +## AsyncPlugin interface + +> Warning: This API is now obsolete. +> +> Asynchronous lifecycles are deprecated, and should be migrated to sync +> + +A plugin with asynchronous lifecycle methods. + +Signature: + +```typescript +export interface AsyncPlugin +``` + +## Methods + +| Method | Description | +| --- | --- | +| [setup(core, plugins)](./kibana-plugin-core-server.asyncplugin.setup.md) | | +| [start(core, plugins)](./kibana-plugin-core-server.asyncplugin.start.md) | | +| [stop()](./kibana-plugin-core-server.asyncplugin.stop.md) | | + diff --git a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.setup.md b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.setup.md new file mode 100644 index 00000000000000..1d033b7b88b051 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.setup.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [AsyncPlugin](./kibana-plugin-core-server.asyncplugin.md) > [setup](./kibana-plugin-core-server.asyncplugin.setup.md) + +## AsyncPlugin.setup() method + +Signature: + +```typescript +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreSetup | | +| plugins | TPluginsSetup | | + +Returns: + +`TSetup | Promise` + diff --git a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.start.md b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.start.md new file mode 100644 index 00000000000000..3cce90f01603bb --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.start.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [AsyncPlugin](./kibana-plugin-core-server.asyncplugin.md) > [start](./kibana-plugin-core-server.asyncplugin.start.md) + +## AsyncPlugin.start() method + +Signature: + +```typescript +start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| core | CoreStart | | +| plugins | TPluginsStart | | + +Returns: + +`TStart | Promise` + diff --git a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.stop.md b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.stop.md new file mode 100644 index 00000000000000..9272fc2c4eba06 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.stop.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [AsyncPlugin](./kibana-plugin-core-server.asyncplugin.md) > [stop](./kibana-plugin-core-server.asyncplugin.stop.md) + +## AsyncPlugin.stop() method + +Signature: + +```typescript +stop?(): void; +``` +Returns: + +`void` + diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 82f4a285409c95..5fe5eda7a81729 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -49,6 +49,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AppCategory](./kibana-plugin-core-server.appcategory.md) | A category definition for nav links to know where to sort them in the left hand nav | | [AssistanceAPIResponse](./kibana-plugin-core-server.assistanceapiresponse.md) | | | [AssistantAPIClientParams](./kibana-plugin-core-server.assistantapiclientparams.md) | | +| [AsyncPlugin](./kibana-plugin-core-server.asyncplugin.md) | A plugin with asynchronous lifecycle methods. | | [Authenticated](./kibana-plugin-core-server.authenticated.md) | | | [AuthNotHandled](./kibana-plugin-core-server.authnothandled.md) | | | [AuthRedirected](./kibana-plugin-core-server.authredirected.md) | | diff --git a/docs/development/core/server/kibana-plugin-core-server.plugin.setup.md b/docs/development/core/server/kibana-plugin-core-server.plugin.setup.md index b4e6623098736d..a8b0aae28d251b 100644 --- a/docs/development/core/server/kibana-plugin-core-server.plugin.setup.md +++ b/docs/development/core/server/kibana-plugin-core-server.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; +setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; ``` ## Parameters @@ -19,5 +19,5 @@ setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; Returns: -`TSetup | Promise` +`TSetup` diff --git a/docs/development/core/server/kibana-plugin-core-server.plugin.start.md b/docs/development/core/server/kibana-plugin-core-server.plugin.start.md index 03e889a018b6f0..851f84474fe11f 100644 --- a/docs/development/core/server/kibana-plugin-core-server.plugin.start.md +++ b/docs/development/core/server/kibana-plugin-core-server.plugin.start.md @@ -7,7 +7,7 @@ Signature: ```typescript -start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; +start(core: CoreStart, plugins: TPluginsStart): TStart; ``` ## Parameters @@ -19,5 +19,5 @@ start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; Returns: -`TStart | Promise` +`TStart` diff --git a/docs/development/core/server/kibana-plugin-core-server.plugininitializer.md b/docs/development/core/server/kibana-plugin-core-server.plugininitializer.md index 839eabff29a189..fe55e131065ddd 100644 --- a/docs/development/core/server/kibana-plugin-core-server.plugininitializer.md +++ b/docs/development/core/server/kibana-plugin-core-server.plugininitializer.md @@ -9,5 +9,5 @@ The `plugin` export at the root of a plugin's `server` directory should conform Signature: ```typescript -export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin; +export declare type PluginInitializer = (core: PluginInitializerContext) => Plugin | AsyncPlugin; ``` diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 0097127924a5cd..ff97b79c92c941 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -194,6 +194,16 @@ export type AppUpdatableFields = Pick Partial | undefined; +// @public @deprecated +export interface AsyncPlugin { + // (undocumented) + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + // (undocumented) + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + // (undocumented) + stop?(): void; +} + // @public export interface Capabilities { [key: string]: Record>; @@ -984,15 +994,15 @@ export { PackageInfo } // @public export interface Plugin { // (undocumented) - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; // (undocumented) - start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart; // (undocumented) stop?(): void; } // @public -export type PluginInitializer = (core: PluginInitializerContext) => Plugin; +export type PluginInitializer = (core: PluginInitializerContext) => Plugin | AsyncPlugin; // @public export interface PluginInitializerContext { diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index aadd16bde0ee62..79b37a4896d448 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -203,6 +203,16 @@ export interface AssistantAPIClientParams extends GenericParams { path: '/_migration/assistance'; } +// @public @deprecated +export interface AsyncPlugin { + // (undocumented) + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + // (undocumented) + start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + // (undocumented) + stop?(): void; +} + // @public (undocumented) export interface Authenticated extends AuthResultParams { // (undocumented) @@ -1816,9 +1826,9 @@ export { PackageInfo } // @public export interface Plugin { // (undocumented) - setup(core: CoreSetup, plugins: TPluginsSetup): TSetup | Promise; + setup(core: CoreSetup, plugins: TPluginsSetup): TSetup; // (undocumented) - start(core: CoreStart, plugins: TPluginsStart): TStart | Promise; + start(core: CoreStart, plugins: TPluginsStart): TStart; // (undocumented) stop?(): void; } @@ -1837,7 +1847,7 @@ export interface PluginConfigDescriptor { export type PluginConfigSchema = Type; // @public -export type PluginInitializer = (core: PluginInitializerContext) => Plugin; +export type PluginInitializer = (core: PluginInitializerContext) => Plugin | AsyncPlugin; // @public export interface PluginInitializerContext { @@ -3136,9 +3146,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // Warnings were encountered during analysis: // // src/core/server/http/router/response.ts:306:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:263:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:263:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:266:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:371:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" +// src/core/server/plugins/types.ts:280:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:280:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:283:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:388:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" ``` From fb4cb34c44bd09eaad01c0958445401da132b1c8 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 13:29:22 +0100 Subject: [PATCH 20/32] fix xpack unit tests --- .../server/plugin.test.ts | 12 ++--- .../plugins/monitoring/server/plugin.test.ts | 50 ++----------------- .../task_manager/server/plugin.test.ts | 2 +- 3 files changed, 12 insertions(+), 52 deletions(-) diff --git a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts index ee54bb43f871aa..d23eab4a33aeca 100644 --- a/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts +++ b/x-pack/plugins/encrypted_saved_objects/server/plugin.test.ts @@ -12,12 +12,12 @@ import { securityMock } from '../../security/server/mocks'; describe('EncryptedSavedObjects Plugin', () => { describe('setup()', () => { - it('exposes proper contract', async () => { + it('exposes proper contract', () => { const plugin = new EncryptedSavedObjectsPlugin( coreMock.createPluginInitializerContext(ConfigSchema.validate({}, { dist: true })) ); - await expect(plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() })) - .resolves.toMatchInlineSnapshot(` + expect(plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() })) + .toMatchInlineSnapshot(` Object { "createMigration": [Function], "registerType": [Function], @@ -28,14 +28,14 @@ describe('EncryptedSavedObjects Plugin', () => { }); describe('start()', () => { - it('exposes proper contract', async () => { + it('exposes proper contract', () => { const plugin = new EncryptedSavedObjectsPlugin( coreMock.createPluginInitializerContext(ConfigSchema.validate({}, { dist: true })) ); - await plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() }); + plugin.setup(coreMock.createSetup(), { security: securityMock.createSetup() }); const startContract = plugin.start(); - await expect(startContract).toMatchInlineSnapshot(` + expect(startContract).toMatchInlineSnapshot(` Object { "getClient": [Function], "isEncryptionError": [Function], diff --git a/x-pack/plugins/monitoring/server/plugin.test.ts b/x-pack/plugins/monitoring/server/plugin.test.ts index 0f8460f3052fac..618f31e03b0c05 100644 --- a/x-pack/plugins/monitoring/server/plugin.test.ts +++ b/x-pack/plugins/monitoring/server/plugin.test.ts @@ -5,15 +5,8 @@ */ import { coreMock } from 'src/core/server/mocks'; import { MonitoringPlugin } from './plugin'; -import { combineLatest } from 'rxjs'; import { AlertsFactory } from './alerts'; -jest.mock('rxjs', () => ({ - // @ts-ignore - ...jest.requireActual('rxjs'), - combineLatest: jest.fn(), -})); - jest.mock('./es_client/instantiate_client', () => ({ instantiateClient: jest.fn().mockImplementation(() => ({ cluster: {}, @@ -30,30 +23,11 @@ jest.mock('./kibana_monitoring/collectors', () => ({ registerCollectors: jest.fn(), })); -describe('Monitoring plugin', () => { - const initializerContext = { - logger: { - get: jest.fn().mockImplementation(() => ({ - info: jest.fn(), - })), - }, - config: { - create: jest.fn().mockImplementation(() => ({ - pipe: jest.fn().mockImplementation(() => ({ - toPromise: jest.fn(), - })), - })), - legacy: { - globalConfig$: {}, - }, - }, - env: { - packageInfo: { - version: '1.0.0', - }, - }, - }; +jest.mock('./config', () => ({ + createConfig: (config: any) => config, +})); +describe('Monitoring plugin', () => { const coreSetup = coreMock.createSetup(); coreSetup.http.getServerInfo.mockReturnValue({ port: 5601 } as any); coreSetup.status.overall$.subscribe = jest.fn(); @@ -69,7 +43,6 @@ describe('Monitoring plugin', () => { }, }; - let config = {}; const defaultConfig = { ui: { elasticsearch: {}, @@ -81,20 +54,7 @@ describe('Monitoring plugin', () => { }, }; - beforeEach(() => { - config = defaultConfig; - (combineLatest as jest.Mock).mockImplementation(() => { - return { - pipe: jest.fn().mockImplementation(() => { - return { - toPromise: jest.fn().mockImplementation(() => { - return [config, 2]; - }), - }; - }), - }; - }); - }); + const initializerContext = coreMock.createPluginInitializerContext(defaultConfig); afterEach(() => { (setupPlugins.alerts.registerType as jest.Mock).mockReset(); diff --git a/x-pack/plugins/task_manager/server/plugin.test.ts b/x-pack/plugins/task_manager/server/plugin.test.ts index a73ba2d2958f4a..8ddf361fbce6e1 100644 --- a/x-pack/plugins/task_manager/server/plugin.test.ts +++ b/x-pack/plugins/task_manager/server/plugin.test.ts @@ -38,7 +38,7 @@ describe('TaskManagerPlugin', () => { pluginInitializerContext.env.instanceUuid = ''; const taskManagerPlugin = new TaskManagerPlugin(pluginInitializerContext); - expect(taskManagerPlugin.setup(coreMock.createSetup())).rejects.toEqual( + expect(() => taskManagerPlugin.setup(coreMock.createSetup())).toThrow( new Error(`TaskManager is unable to start as Kibana has no valid UUID assigned to it.`) ); }); From d3a24d0cc7a7dc5ac938d32dcb6b09b9cbb0964d Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 13:33:16 +0100 Subject: [PATCH 21/32] nit --- x-pack/plugins/task_manager/server/plugin.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index fb265d9da73799..28d3811b987e74 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -44,7 +44,7 @@ export class TaskManagerPlugin implements Plugin { private taskPollingLifecycle?: TaskPollingLifecycle; private taskManagerId?: string; - private config?: TaskManagerConfig; + private config: TaskManagerConfig; private logger: Logger; private definitions: TaskTypeDictionary; private middleware: Middleware = createInitialMiddleware(); @@ -54,12 +54,11 @@ export class TaskManagerPlugin constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; this.logger = initContext.logger.get(); + this.config = initContext.config.get(); this.definitions = new TaskTypeDictionary(this.logger); } public setup(core: CoreSetup): TaskManagerSetupContract { - this.config = this.initContext.config.get(); - this.elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); setupSavedObjects(core.savedObjects, this.config); From fdf73feb0ae7358cf6f2286848f4c77b81909ecf Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 15:54:00 +0100 Subject: [PATCH 22/32] (will be reverted) explicitly await for license to be ready in the auth hook --- x-pack/plugins/security/common/licensing/index.mock.ts | 1 + x-pack/plugins/security/common/licensing/license_service.ts | 5 +++++ .../security/server/authentication/authentication_service.ts | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/x-pack/plugins/security/common/licensing/index.mock.ts b/x-pack/plugins/security/common/licensing/index.mock.ts index ed89ad5cc50529..6540afab3ea53f 100644 --- a/x-pack/plugins/security/common/licensing/index.mock.ts +++ b/x-pack/plugins/security/common/licensing/index.mock.ts @@ -9,6 +9,7 @@ import { SecurityLicense, SecurityLicenseFeatures } from '.'; export const licenseMock = { create: (features?: Partial): jest.Mocked => ({ + license$: {} as any, isLicenseAvailable: jest.fn().mockReturnValue(true), isEnabled: jest.fn().mockReturnValue(true), getType: jest.fn().mockReturnValue('basic'), diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index 5930c17b928f26..b67b157afd33c7 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -14,6 +14,7 @@ export interface SecurityLicense { isEnabled(): boolean; getType(): LicenseType | undefined; getFeatures(): SecurityLicenseFeatures; + license$: Observable; features$: Observable; } @@ -28,11 +29,15 @@ export class SecurityLicenseService { let rawLicense: Readonly | undefined; this.licenseSubscription = license$.subscribe((nextRawLicense) => { + // eslint-disable-next-line no-console + console.log('***** NEXT RAW LICENSE'); rawLicense = nextRawLicense; }); return { license: Object.freeze({ + license$, + isLicenseAvailable: () => rawLicense?.isAvailable ?? false, isEnabled: () => this.isSecurityEnabledFromRawLicense(rawLicense), diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index 3ab92d0bd211fe..0e0ddb457b30a3 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { take } from 'rxjs/operators'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { LoggerFactory, @@ -66,6 +67,10 @@ export class AuthenticationService { this.license = license; http.registerAuth(async (request, response, t) => { + await license.license$.pipe(take(1)).toPromise(); + // eslint-disable-next-line no-console + console.log('***** AWAIT REGISTER AUTH COMPLETE'); + if (!license.isLicenseAvailable()) { this.logger.error('License is not available, authentication is not possible.'); return response.customError({ From c13d07daf33610d8773c20e20fffd20df43f6db7 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 18:06:22 +0100 Subject: [PATCH 23/32] Revert "(will be reverted) explicitly await for license to be ready in the auth hook" This reverts commit fdf73feb --- x-pack/plugins/security/common/licensing/license_service.ts | 5 ----- .../security/server/authentication/authentication_service.ts | 5 ----- 2 files changed, 10 deletions(-) diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index b67b157afd33c7..5930c17b928f26 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -14,7 +14,6 @@ export interface SecurityLicense { isEnabled(): boolean; getType(): LicenseType | undefined; getFeatures(): SecurityLicenseFeatures; - license$: Observable; features$: Observable; } @@ -29,15 +28,11 @@ export class SecurityLicenseService { let rawLicense: Readonly | undefined; this.licenseSubscription = license$.subscribe((nextRawLicense) => { - // eslint-disable-next-line no-console - console.log('***** NEXT RAW LICENSE'); rawLicense = nextRawLicense; }); return { license: Object.freeze({ - license$, - isLicenseAvailable: () => rawLicense?.isAvailable ?? false, isEnabled: () => this.isSecurityEnabledFromRawLicense(rawLicense), diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index 0e0ddb457b30a3..3ab92d0bd211fe 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { take } from 'rxjs/operators'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { LoggerFactory, @@ -67,10 +66,6 @@ export class AuthenticationService { this.license = license; http.registerAuth(async (request, response, t) => { - await license.license$.pipe(take(1)).toPromise(); - // eslint-disable-next-line no-console - console.log('***** AWAIT REGISTER AUTH COMPLETE'); - if (!license.isLicenseAvailable()) { this.logger.error('License is not available, authentication is not possible.'); return response.customError({ From c5f2fe516bbbbb5dc670fc11871d1ccacfb94312 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 18:08:23 +0100 Subject: [PATCH 24/32] restore await on on promise contracts --- src/core/server/plugins/plugins_system.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index ad1d84a4f6a73b..7cf29f646b81a1 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -111,7 +111,8 @@ export class PluginsSystem { errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, }); } else { - contract = contractOrPromise; + // awaiting non-promise contract to get back in the event queue + contract = await contractOrPromise; } contracts.set(pluginName, contract); @@ -160,7 +161,8 @@ export class PluginsSystem { errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, }); } else { - contract = contractOrPromise; + // awaiting non-promise contract to get back in the event queue + contract = await contractOrPromise; } contracts.set(pluginName, contract); From 59740e41b727dde67f958f021c61e5fca734bb40 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 18:29:56 +0100 Subject: [PATCH 25/32] Revert "(will be reverted) explicitly await for license to be ready in the auth hook" This reverts commit fdf73feb --- x-pack/plugins/security/common/licensing/index.mock.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security/common/licensing/index.mock.ts b/x-pack/plugins/security/common/licensing/index.mock.ts index 6540afab3ea53f..ed89ad5cc50529 100644 --- a/x-pack/plugins/security/common/licensing/index.mock.ts +++ b/x-pack/plugins/security/common/licensing/index.mock.ts @@ -9,7 +9,6 @@ import { SecurityLicense, SecurityLicenseFeatures } from '.'; export const licenseMock = { create: (features?: Partial): jest.Mocked => ({ - license$: {} as any, isLicenseAvailable: jest.fn().mockReturnValue(true), isEnabled: jest.fn().mockReturnValue(true), getType: jest.fn().mockReturnValue('basic'), From 56354874eecb8a3d5e711fcb085cf3f67ead8f3f Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 21:30:55 +0100 Subject: [PATCH 26/32] Revert "restore await on on promise contracts" This reverts commit c5f2fe51 --- src/core/server/plugins/plugins_system.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index 7cf29f646b81a1..ad1d84a4f6a73b 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -111,8 +111,7 @@ export class PluginsSystem { errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, }); } else { - // awaiting non-promise contract to get back in the event queue - contract = await contractOrPromise; + contract = contractOrPromise; } contracts.set(pluginName, contract); @@ -161,8 +160,7 @@ export class PluginsSystem { errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, }); } else { - // awaiting non-promise contract to get back in the event queue - contract = await contractOrPromise; + contract = contractOrPromise; } contracts.set(pluginName, contract); From 320dd5f9bf50a6d09e8fce46dc9177e50275c8a6 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Fri, 29 Jan 2021 21:34:09 +0100 Subject: [PATCH 27/32] add delay before starting tests in FTR --- packages/kbn-test/src/functional_tests/tasks.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kbn-test/src/functional_tests/tasks.js b/packages/kbn-test/src/functional_tests/tasks.js index 4bd7628e9f5359..2bb1f540d00e6f 100644 --- a/packages/kbn-test/src/functional_tests/tasks.js +++ b/packages/kbn-test/src/functional_tests/tasks.js @@ -95,6 +95,8 @@ export async function runTests(options) { try { es = await runElasticsearch({ config, options: opts }); await runKibanaServer({ procs, config, options: opts }); + // wait 5 seconds to let kibana startup completes + await silence(log, 5000); await runFtr({ configPath, options: opts }); } finally { try { From 1dcfcd9436bc5cec23142e81a98490cf5da0ecf9 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 1 Feb 2021 09:13:46 +0100 Subject: [PATCH 28/32] update deprecation ts doc --- .../core/public/kibana-plugin-core-public.asyncplugin.md | 2 +- .../core/server/kibana-plugin-core-server.asyncplugin.md | 2 +- src/core/public/plugins/plugin.ts | 2 +- src/core/server/plugins/types.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md index 979d4ed2825054..cf315e1fd337e3 100644 --- a/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md +++ b/docs/development/core/public/kibana-plugin-core-public.asyncplugin.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Asynchronous lifecycles are deprecated, and should be migrated to sync +> Asynchronous lifecycles are deprecated, and should be migrated to sync [plugin](./kibana-plugin-core-public.plugin.md) > A plugin with asynchronous lifecycle methods. diff --git a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md index 682a164ce397a0..1ad1d87220b748 100644 --- a/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md +++ b/docs/development/core/server/kibana-plugin-core-server.asyncplugin.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Asynchronous lifecycles are deprecated, and should be migrated to sync +> Asynchronous lifecycles are deprecated, and should be migrated to sync [plugin](./kibana-plugin-core-server.plugin.md) > A plugin with asynchronous lifecycle methods. diff --git a/src/core/public/plugins/plugin.ts b/src/core/public/plugins/plugin.ts index 0238b6773ae616..2aeca319de6320 100644 --- a/src/core/public/plugins/plugin.ts +++ b/src/core/public/plugins/plugin.ts @@ -33,7 +33,7 @@ export interface Plugin< /** * A plugin with asynchronous lifecycle methods. * - * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync + * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync {@link Plugin | plugin} * @public */ export interface AsyncPlugin< diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index a46cb87adb973e..3af24f9519d5f3 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -251,7 +251,7 @@ export interface Plugin< /** * A plugin with asynchronous lifecycle methods. * - * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync + * @deprecated Asynchronous lifecycles are deprecated, and should be migrated to sync {@link Plugin | plugin} * @public */ export interface AsyncPlugin< From b6074c7893dba2f1315a58f3d1b385d0576923ac Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 1 Feb 2021 09:15:43 +0100 Subject: [PATCH 29/32] add explicit contract for monitoring setup --- x-pack/plugins/monitoring/server/index.ts | 2 ++ x-pack/plugins/monitoring/server/plugin.ts | 4 +++- x-pack/plugins/monitoring/server/types.ts | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts index 687a861e4bc6ea..4deefb0cdd5b3f 100644 --- a/x-pack/plugins/monitoring/server/index.ts +++ b/x-pack/plugins/monitoring/server/index.ts @@ -12,6 +12,8 @@ import { deprecations } from './deprecations'; export { KibanaSettingsCollector } from './kibana_monitoring/collectors'; export { MonitoringConfig } from './config'; +export { MonitoringPluginSetup, IBulkUploader } from './types'; + export const plugin = (initContext: PluginInitializerContext) => new MonitoringPlugin(initContext); export const config: PluginConfigDescriptor> = { schema: configSchema, diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index ae34acad143b50..c4004f3f7e4ccb 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -40,6 +40,7 @@ import { AlertsFactory } from './alerts'; import { MonitoringCore, MonitoringLicenseService, + MonitoringPluginSetup, LegacyShimDependencies, IBulkUploader, PluginsSetup, @@ -63,7 +64,8 @@ const wrapError = (error: any): CustomHttpResponseOptions => { }; }; -export class MonitoringPlugin implements Plugin { +export class MonitoringPlugin + implements Plugin { private readonly initializerContext: PluginInitializerContext; private readonly log: Logger; private readonly getLogger: (...scopes: string[]) => Logger; diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index fbdd01e56c6573..d024a423f04db3 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -92,6 +92,10 @@ export interface IBulkUploader { stop: () => void; } +export interface MonitoringPluginSetup { + getKibanaStats: IBulkUploader['getKibanaStats']; +} + export interface LegacyRequest { logger: Logger; getLogger: (...scopes: string[]) => Logger; From 326708186c242adc6557311c286ae1113803fea6 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 3 Feb 2021 08:01:38 +0100 Subject: [PATCH 30/32] migrate monitoring plugin to sync --- x-pack/plugins/monitoring/public/plugin.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts index 456e2206c29962..77c7d0bcdda07c 100644 --- a/x-pack/plugins/monitoring/public/plugin.ts +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -10,7 +10,7 @@ import { AppMountParameters, CoreSetup, CoreStart, - AsyncPlugin, + Plugin, PluginInitializerContext, } from 'kibana/public'; import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; @@ -44,15 +44,10 @@ interface MonitoringSetupPluginDependencies { export class MonitoringPlugin implements - AsyncPlugin< - boolean, - void, - MonitoringSetupPluginDependencies, - MonitoringStartPluginDependencies - > { + Plugin { constructor(private initializerContext: PluginInitializerContext) {} - public async setup( + public setup( core: CoreSetup, plugins: MonitoringSetupPluginDependencies ) { From 6a4044f50cece27f63844e6b6a35846c90f777d1 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Wed, 3 Feb 2021 09:09:37 +0100 Subject: [PATCH 31/32] change plugin timeout to 10sec --- src/core/public/plugins/plugins_service.test.ts | 4 ++-- src/core/public/plugins/plugins_service.ts | 8 ++++---- src/core/server/plugins/plugins_system.test.ts | 8 ++++---- src/core/server/plugins/plugins_system.ts | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 348b182ec2fbe1..ddd1f9f6695135 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -264,7 +264,7 @@ describe('PluginsService', () => { jest.runAllTimers(); // setup plugins await expect(promise).rejects.toMatchInlineSnapshot( - `[Error: Setup lifecycle of "pluginA" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` + `[Error: Setup lifecycle of "pluginA" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]` ); }); }); @@ -344,7 +344,7 @@ describe('PluginsService', () => { jest.runAllTimers(); await expect(promise).rejects.toMatchInlineSnapshot( - `[Error: Start lifecycle of "pluginA" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` + `[Error: Start lifecycle of "pluginA" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]` ); }); }); diff --git a/src/core/public/plugins/plugins_service.ts b/src/core/public/plugins/plugins_service.ts index 483d0e2d4baac6..7aa054589d9e5e 100644 --- a/src/core/public/plugins/plugins_service.ts +++ b/src/core/public/plugins/plugins_service.ts @@ -113,8 +113,8 @@ export class PluginsService implements CoreService { afterAll(() => { jest.useRealTimers(); }); - it('throws timeout error if "setup" was not completed in 30 sec.', async () => { + it('throws timeout error if "setup" was not completed in 10 sec.', async () => { const plugin: PluginWrapper = createPlugin('timeout-setup'); jest.spyOn(plugin, 'setup').mockImplementation(() => new Promise((i) => i)); pluginsSystem.addPlugin(plugin); @@ -443,7 +443,7 @@ describe('setup', () => { jest.runAllTimers(); await expect(promise).rejects.toMatchInlineSnapshot( - `[Error: Setup lifecycle of "timeout-setup" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` + `[Error: Setup lifecycle of "timeout-setup" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]` ); }); @@ -470,7 +470,7 @@ describe('start', () => { afterAll(() => { jest.useRealTimers(); }); - it('throws timeout error if "start" was not completed in 30 sec.', async () => { + it('throws timeout error if "start" was not completed in 10 sec.', async () => { const plugin = createPlugin('timeout-start'); jest.spyOn(plugin, 'setup').mockResolvedValue({}); jest.spyOn(plugin, 'start').mockImplementation(() => new Promise((i) => i)); @@ -484,7 +484,7 @@ describe('start', () => { jest.runAllTimers(); await expect(promise).rejects.toMatchInlineSnapshot( - `[Error: Start lifecycle of "timeout-start" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.]` + `[Error: Start lifecycle of "timeout-start" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.]` ); }); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index ad1d84a4f6a73b..31ff3c5d86c067 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -107,8 +107,8 @@ export class PluginsSystem { } contract = await withTimeout({ promise: contractOrPromise, - timeout: 30 * Sec, - errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + timeout: 10 * Sec, + errorMessage: `Setup lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`, }); } else { contract = contractOrPromise; @@ -156,8 +156,8 @@ export class PluginsSystem { } contract = await withTimeout({ promise: contractOrPromise, - timeout: 30 * Sec, - errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 30sec. Consider disabling the plugin and re-start.`, + timeout: 10 * Sec, + errorMessage: `Start lifecycle of "${pluginName}" plugin wasn't completed in 10sec. Consider disabling the plugin and re-start.`, }); } else { contract = contractOrPromise; From 7a31a6997e432ceb48a1fcea0ba8a35358de0501 Mon Sep 17 00:00:00 2001 From: pgayvallet Date: Mon, 8 Feb 2021 08:06:07 +0100 Subject: [PATCH 32/32] use delay instead of silence --- packages/kbn-test/src/functional_tests/tasks.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/kbn-test/src/functional_tests/tasks.js b/packages/kbn-test/src/functional_tests/tasks.js index 9ab1398c5993ea..02c55b6af91dcc 100644 --- a/packages/kbn-test/src/functional_tests/tasks.js +++ b/packages/kbn-test/src/functional_tests/tasks.js @@ -95,8 +95,8 @@ export async function runTests(options) { try { es = await runElasticsearch({ config, options: opts }); await runKibanaServer({ procs, config, options: opts }); - // wait 5 seconds to let kibana startup completes - await silence(log, 5000); + // workaround until https://github.com/elastic/kibana/issues/89828 is addressed + await delay(5000); await runFtr({ configPath, options: opts }); } finally { try { @@ -162,3 +162,7 @@ async function silence(log, milliseconds) { ) .toPromise(); } + +async function delay(ms) { + await new Promise((resolve) => setTimeout(resolve, ms)); +}