diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index d36fd2251176a..64a382e539fb0 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -102,35 +102,42 @@ const createPlugin = ( }); }; -describe('PluginsService', () => { - beforeEach(async () => { - mockPackage.raw = { - branch: 'feature-v1', - version: 'v1', - build: { - distributable: true, - number: 100, - sha: 'feature-v1-build-sha', - }, - }; +async function testSetup(options: { isDevClusterMaster?: boolean } = {}) { + mockPackage.raw = { + branch: 'feature-v1', + version: 'v1', + build: { + distributable: true, + number: 100, + sha: 'feature-v1-build-sha', + }, + }; - coreId = Symbol('core'); - env = Env.createDefault(REPO_ROOT, getEnvOptions()); + coreId = Symbol('core'); + env = Env.createDefault(REPO_ROOT, { + ...getEnvOptions(), + isDevClusterMaster: options.isDevClusterMaster ?? false, + }); - config$ = new BehaviorSubject>({ plugins: { initialize: true } }); - const rawConfigService = rawConfigServiceMock.create({ rawConfig$: config$ }); - configService = new ConfigService(rawConfigService, env, logger); - await configService.setSchema(config.path, config.schema); - pluginsService = new PluginsService({ coreId, env, logger, configService }); + config$ = new BehaviorSubject>({ plugins: { initialize: true } }); + const rawConfigService = rawConfigServiceMock.create({ rawConfig$: config$ }); + configService = new ConfigService(rawConfigService, env, logger); + await configService.setSchema(config.path, config.schema); + pluginsService = new PluginsService({ coreId, env, logger, configService }); - [mockPluginSystem] = MockPluginsSystem.mock.instances as any; - mockPluginSystem.uiPlugins.mockReturnValue(new Map()); + [mockPluginSystem] = MockPluginsSystem.mock.instances as any; + mockPluginSystem.uiPlugins.mockReturnValue(new Map()); - environmentSetup = environmentServiceMock.createSetupContract(); - }); + environmentSetup = environmentServiceMock.createSetupContract(); +} - afterEach(() => { - jest.clearAllMocks(); +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('PluginsService', () => { + beforeEach(async () => { + await testSetup(); }); describe('#discover()', () => { @@ -613,3 +620,29 @@ describe('PluginsService', () => { }); }); }); + +describe('PluginService when isDevClusterMaster is true', () => { + beforeEach(async () => { + await testSetup({ + isDevClusterMaster: true, + }); + }); + + describe('#discover()', () => { + it('does not try to run discovery', async () => { + await expect(pluginsService.discover({ environment: environmentSetup })).resolves + .toMatchInlineSnapshot(` + Object { + "pluginTree": undefined, + "uiPlugins": Object { + "browserConfigs": Map {}, + "internal": Map {}, + "public": Map {}, + }, + } + `); + + expect(mockDiscover).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index e8fe42ee491ca..a1062bde7765f 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -18,7 +18,7 @@ */ import Path from 'path'; -import { Observable } from 'rxjs'; +import { Observable, EMPTY } from 'rxjs'; import { filter, first, map, mergeMap, tap, toArray } from 'rxjs/operators'; import { pick } from '@kbn/std'; @@ -86,9 +86,11 @@ export class PluginsService implements CoreService; private readonly pluginConfigDescriptors = new Map(); private readonly uiPluginInternalInfo = new Map(); + private readonly discoveryDisabled: boolean; constructor(private readonly coreContext: CoreContext) { this.log = coreContext.logger.get('plugins-service'); + this.discoveryDisabled = coreContext.env.isDevClusterMaster; this.pluginsSystem = new PluginsSystem(coreContext); this.configService = coreContext.configService; this.config$ = coreContext.configService @@ -97,13 +99,17 @@ export class PluginsService implements CoreService { + const devParentEnv = Env.createDefault(REPO_ROOT, { + ...getEnvOptions(), + isDevClusterMaster: true, + }); + + const server = new Server(rawConfigService, devParentEnv, logger); + await server.setup(); + + expect(mockEnsureValidConfiguration).not.toHaveBeenCalled(); + expect(mockContextService.setup).toHaveBeenCalled(); + expect(mockAuditTrailService.setup).toHaveBeenCalled(); + expect(mockHttpService.setup).toHaveBeenCalled(); + expect(mockElasticsearchService.setup).toHaveBeenCalled(); + expect(mockSavedObjectsService.setup).toHaveBeenCalled(); +}); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index fcefc12ab01f3..f38cac4f43768 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -120,10 +120,13 @@ export class Server { }); const legacyConfigSetup = await this.legacy.setupLegacyConfig(); - // Immediately terminate in case of invalid configuration - // This needs to be done after plugin discovery - await this.configService.validate(); - await ensureValidConfiguration(this.configService, legacyConfigSetup); + // rely on dev server to validate config, don't validate in the parent process + if (!this.env.isDevClusterMaster) { + // Immediately terminate in case of invalid configuration + // This needs to be done after plugin discovery + await this.configService.validate(); + await ensureValidConfiguration(this.configService, legacyConfigSetup); + } const contextServiceSetup = this.context.setup({ // We inject a fake "legacy plugin" with dependencies on every plugin so that legacy plugins: