mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Adds node.roles
configuration & exposes via PluginInitializerContext
(#135272)
This commit is contained in:
parent
3b6fc59e55
commit
cf6ae210ef
58 changed files with 1514 additions and 160 deletions
|
@ -96,6 +96,9 @@ enabled:
|
|||
- test/interactive_setup_functional/manual_configuration.config.ts
|
||||
- test/interpreter_functional/config.ts
|
||||
- test/new_visualize_flow/config.ts
|
||||
- test/node_roles_functional/all.config.ts
|
||||
- test/node_roles_functional/background_tasks.config.ts
|
||||
- test/node_roles_functional/ui.config.ts
|
||||
- test/plugin_functional/config.ts
|
||||
- test/server_integration/http/platform/config.status.ts
|
||||
- test/server_integration/http/platform/config.ts
|
||||
|
|
|
@ -311,6 +311,11 @@ Controls whether to enable the newsfeed
|
|||
system for the {kib} UI notification center. Set to `false` to disable the
|
||||
newsfeed system. *Default: `true`*
|
||||
|
||||
`node.roles`::
|
||||
Indicates which roles to configure the {kib} process with, which will effectively
|
||||
run {kib} in different modes. Valid options are `background_tasks` and `ui`,
|
||||
or `*` to select all roles. *Default: `*`*
|
||||
|
||||
[[path-data]] `path.data`::
|
||||
The path where {kib} stores persistent data
|
||||
not saved in {es}. *Default: `data`*
|
||||
|
|
|
@ -181,6 +181,9 @@
|
|||
"@kbn/core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server",
|
||||
"@kbn/core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal",
|
||||
"@kbn/core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks",
|
||||
"@kbn/core-node-server": "link:bazel-bin/packages/core/node/core-node-server",
|
||||
"@kbn/core-node-server-internal": "link:bazel-bin/packages/core/node/core-node-server-internal",
|
||||
"@kbn/core-node-server-mocks": "link:bazel-bin/packages/core/node/core-node-server-mocks",
|
||||
"@kbn/core-theme-browser": "link:bazel-bin/packages/core/theme/core-theme-browser",
|
||||
"@kbn/core-theme-browser-internal": "link:bazel-bin/packages/core/theme/core-theme-browser-internal",
|
||||
"@kbn/core-theme-browser-mocks": "link:bazel-bin/packages/core/theme/core-theme-browser-mocks",
|
||||
|
@ -715,6 +718,9 @@
|
|||
"@types/kbn__core-logging-server": "link:bazel-bin/packages/core/logging/core-logging-server/npm_module_types",
|
||||
"@types/kbn__core-logging-server-internal": "link:bazel-bin/packages/core/logging/core-logging-server-internal/npm_module_types",
|
||||
"@types/kbn__core-logging-server-mocks": "link:bazel-bin/packages/core/logging/core-logging-server-mocks/npm_module_types",
|
||||
"@types/kbn__core-node-server": "link:bazel-bin/packages/core/node/core-node-server/npm_module_types",
|
||||
"@types/kbn__core-node-server-internal": "link:bazel-bin/packages/core/node/core-node-server-internal/npm_module_types",
|
||||
"@types/kbn__core-node-server-mocks": "link:bazel-bin/packages/core/node/core-node-server-mocks/npm_module_types",
|
||||
"@types/kbn__core-public-internal-base": "link:bazel-bin/packages/core/public/internal-base/npm_module_types",
|
||||
"@types/kbn__core-server-internal-base": "link:bazel-bin/packages/core/server/internal-base/npm_module_types",
|
||||
"@types/kbn__core-theme-browser": "link:bazel-bin/packages/core/theme/core-theme-browser/npm_module_types",
|
||||
|
|
|
@ -50,6 +50,9 @@ filegroup(
|
|||
"//packages/core/logging/core-logging-server-internal:build",
|
||||
"//packages/core/logging/core-logging-server-mocks:build",
|
||||
"//packages/core/logging/core-logging-server:build",
|
||||
"//packages/core/node/core-node-server-internal:build",
|
||||
"//packages/core/node/core-node-server-mocks:build",
|
||||
"//packages/core/node/core-node-server:build",
|
||||
"//packages/core/theme/core-theme-browser-internal:build",
|
||||
"//packages/core/theme/core-theme-browser-mocks:build",
|
||||
"//packages/core/theme/core-theme-browser:build",
|
||||
|
@ -217,6 +220,9 @@ filegroup(
|
|||
"//packages/core/logging/core-logging-server-internal:build_types",
|
||||
"//packages/core/logging/core-logging-server-mocks:build_types",
|
||||
"//packages/core/logging/core-logging-server:build_types",
|
||||
"//packages/core/node/core-node-server-internal:build_types",
|
||||
"//packages/core/node/core-node-server-mocks:build_types",
|
||||
"//packages/core/node/core-node-server:build_types",
|
||||
"//packages/core/theme/core-theme-browser-internal:build_types",
|
||||
"//packages/core/theme/core-theme-browser-mocks:build_types",
|
||||
"//packages/core/theme/core-theme-browser:build_types",
|
||||
|
|
104
packages/core/node/core-node-server-internal/BUILD.bazel
Normal file
104
packages/core/node/core-node-server-internal/BUILD.bazel
Normal file
|
@ -0,0 +1,104 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
|
||||
|
||||
PKG_DIRNAME = "core-node-server-internal"
|
||||
PKG_REQUIRE_NAME = "@kbn/core-node-server-internal"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"src/**/*.ts",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
]
|
||||
|
||||
RUNTIME_DEPS = [
|
||||
"@npm//lodash",
|
||||
"@npm//rxjs",
|
||||
"//packages/kbn-config-schema",
|
||||
]
|
||||
|
||||
TYPES_DEPS = [
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/jest",
|
||||
"@npm//@types/lodash",
|
||||
"//packages/kbn-config:npm_module_types",
|
||||
"//packages/kbn-config-schema:npm_module_types",
|
||||
"//packages/kbn-logging:npm_module_types",
|
||||
"//packages/core/base/core-base-server-internal:npm_module_types",
|
||||
"//packages/core/node/core-node-server:npm_module_types",
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_node",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
)
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
"//:tsconfig.bazel.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc_types",
|
||||
args = ['--pretty'],
|
||||
srcs = SRCS,
|
||||
deps = TYPES_DEPS,
|
||||
declaration = True,
|
||||
emit_declaration_only = True,
|
||||
out_dir = "target_types",
|
||||
root_dir = "src",
|
||||
tsconfig = ":tsconfig",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_DIRNAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
deps = RUNTIME_DEPS + [":target_node"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [":" + PKG_DIRNAME],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [":npm_module"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm_types(
|
||||
name = "npm_module_types",
|
||||
srcs = SRCS,
|
||||
deps = [":tsc_types"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
tsconfig = ":tsconfig",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build_types",
|
||||
srcs = [":npm_module_types"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
3
packages/core/node/core-node-server-internal/README.md
Normal file
3
packages/core/node/core-node-server-internal/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/core-node-server-internal
|
||||
|
||||
Contains internal code for Core's server-side `node` service.
|
13
packages/core/node/core-node-server-internal/jest.config.js
Normal file
13
packages/core/node/core-node-server-internal/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/packages/core/node/core-node-server-internal'],
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@kbn/core-node-server-internal",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "./target_node/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
12
packages/core/node/core-node-server-internal/src/index.ts
Normal file
12
packages/core/node/core-node-server-internal/src/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { nodeConfig } from './node_config';
|
||||
|
||||
export { NodeService } from './node_service';
|
||||
export type { InternalNodeServicePreboot } from './node_service';
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { ServiceConfigDescriptor } from '@kbn/core-base-server-internal';
|
||||
|
||||
/** @internal */
|
||||
export const NODE_CONFIG_PATH = 'node' as const;
|
||||
/** @internal */
|
||||
export const NODE_WILDCARD_CHAR = '*';
|
||||
/** @internal */
|
||||
export const NODE_ACCEPTED_ROLES = ['background_tasks', 'ui'];
|
||||
|
||||
/** @internal */
|
||||
export interface NodeConfigType {
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
const configSchema = schema.object({
|
||||
roles: schema.oneOf(
|
||||
[
|
||||
schema.arrayOf(schema.oneOf([schema.literal('background_tasks'), schema.literal('ui')])),
|
||||
schema.arrayOf(schema.literal(NODE_WILDCARD_CHAR), { minSize: 1, maxSize: 1 }),
|
||||
],
|
||||
{
|
||||
defaultValue: [NODE_WILDCARD_CHAR],
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
export const nodeConfig: ServiceConfigDescriptor<NodeConfigType> = {
|
||||
path: NODE_CONFIG_PATH,
|
||||
schema: configSchema,
|
||||
};
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
|
||||
import { NodeService } from './node_service';
|
||||
|
||||
import { configServiceMock } from '@kbn/config-mocks';
|
||||
import { mockCoreContext } from '@kbn/core-base-server-mocks';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
|
||||
const getMockedConfigService = (nodeConfig: unknown) => {
|
||||
const configService = configServiceMock.create();
|
||||
configService.atPath.mockImplementation((path) => {
|
||||
if (path === 'node') {
|
||||
return new BehaviorSubject(nodeConfig);
|
||||
}
|
||||
return new BehaviorSubject({});
|
||||
});
|
||||
return configService;
|
||||
};
|
||||
|
||||
describe('NodeService', () => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.create>;
|
||||
let configService: ReturnType<typeof configServiceMock.create>;
|
||||
let coreContext: CoreContext;
|
||||
let service: NodeService;
|
||||
|
||||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('#preboot()', () => {
|
||||
it('returns default roles values when wildcard is provided', async () => {
|
||||
configService = getMockedConfigService({ roles: ['*'] });
|
||||
coreContext = mockCoreContext.create({ logger, configService });
|
||||
|
||||
service = new NodeService(coreContext);
|
||||
const { roles } = await service.preboot();
|
||||
|
||||
expect(roles.backgroundTasks).toBe(true);
|
||||
expect(roles.ui).toBe(true);
|
||||
});
|
||||
|
||||
it('returns correct roles when node is configured to `background_tasks`', async () => {
|
||||
configService = getMockedConfigService({ roles: ['background_tasks'] });
|
||||
coreContext = mockCoreContext.create({ logger, configService });
|
||||
|
||||
service = new NodeService(coreContext);
|
||||
const { roles } = await service.preboot();
|
||||
|
||||
expect(roles.backgroundTasks).toBe(true);
|
||||
expect(roles.ui).toBe(false);
|
||||
});
|
||||
|
||||
it('returns correct roles when node is configured to `ui`', async () => {
|
||||
configService = getMockedConfigService({ roles: ['ui'] });
|
||||
coreContext = mockCoreContext.create({ logger, configService });
|
||||
|
||||
service = new NodeService(coreContext);
|
||||
const { roles } = await service.preboot();
|
||||
|
||||
expect(roles.backgroundTasks).toBe(false);
|
||||
expect(roles.ui).toBe(true);
|
||||
});
|
||||
|
||||
it('returns correct roles when node is configured to both `background_tasks` and `ui`', async () => {
|
||||
configService = getMockedConfigService({ roles: ['background_tasks', 'ui'] });
|
||||
coreContext = mockCoreContext.create({ logger, configService });
|
||||
|
||||
service = new NodeService(coreContext);
|
||||
const { roles } = await service.preboot();
|
||||
|
||||
expect(roles.backgroundTasks).toBe(true);
|
||||
expect(roles.ui).toBe(true);
|
||||
});
|
||||
|
||||
it('logs the node roles', async () => {
|
||||
const mockLogger = loggingSystemMock.createLogger();
|
||||
logger.get.mockImplementation(() => mockLogger);
|
||||
|
||||
configService = getMockedConfigService({ roles: ['*'] });
|
||||
coreContext = mockCoreContext.create({ logger, configService });
|
||||
|
||||
service = new NodeService(coreContext);
|
||||
await service.preboot();
|
||||
|
||||
expect(logger.get).toHaveBeenCalledTimes(1);
|
||||
expect(logger.get).toHaveBeenCalledWith('node');
|
||||
expect(mockLogger.info).toHaveBeenCalledTimes(1);
|
||||
expect(mockLogger.info.mock.calls[0][0]).toMatchInlineSnapshot(
|
||||
`"Kibana process configured with roles: [background_tasks, ui]"`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { camelCase } from 'lodash';
|
||||
import type { IConfigService } from '@kbn/config';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import type { NodeRoles } from '@kbn/core-node-server';
|
||||
import type { Logger } from '@kbn/logging';
|
||||
import {
|
||||
NodeConfigType,
|
||||
NODE_WILDCARD_CHAR,
|
||||
NODE_ACCEPTED_ROLES,
|
||||
NODE_CONFIG_PATH,
|
||||
} from './node_config';
|
||||
|
||||
const DEFAULT_ROLES = NODE_ACCEPTED_ROLES;
|
||||
const containsWildcard = (roles: string[]) => roles.includes(NODE_WILDCARD_CHAR);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface InternalNodeServicePreboot {
|
||||
/**
|
||||
* Retrieve the Kibana instance uuid.
|
||||
*/
|
||||
roles: NodeRoles;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export class NodeService {
|
||||
private readonly configService: IConfigService;
|
||||
private readonly log: Logger;
|
||||
|
||||
constructor(core: CoreContext) {
|
||||
this.configService = core.configService;
|
||||
this.log = core.logger.get('node');
|
||||
}
|
||||
|
||||
public async preboot(): Promise<InternalNodeServicePreboot> {
|
||||
const nodeRoles = await this.getNodeRoles();
|
||||
this.log.info(`Kibana process configured with roles: [${nodeRoles.join(', ')}]`, {
|
||||
service: {
|
||||
// @ts-expect-error Field not available in ECS until 8.4
|
||||
node: { roles: nodeRoles },
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
roles: NODE_ACCEPTED_ROLES.reduce((acc, curr) => {
|
||||
return { ...acc, [camelCase(curr)]: nodeRoles.includes(curr) };
|
||||
}, {} as NodeRoles),
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {
|
||||
// nothing to do here yet
|
||||
}
|
||||
|
||||
private async getNodeRoles(): Promise<string[]> {
|
||||
const { roles } = await firstValueFrom(
|
||||
this.configService.atPath<NodeConfigType>(NODE_CONFIG_PATH)
|
||||
);
|
||||
|
||||
if (containsWildcard(roles)) {
|
||||
return DEFAULT_ROLES;
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
}
|
17
packages/core/node/core-node-server-internal/tsconfig.json
Normal file
17
packages/core/node/core-node-server-internal/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"rootDir": "src",
|
||||
"stripInternal": false,
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
97
packages/core/node/core-node-server-mocks/BUILD.bazel
Normal file
97
packages/core/node/core-node-server-mocks/BUILD.bazel
Normal file
|
@ -0,0 +1,97 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
|
||||
|
||||
PKG_DIRNAME = "core-node-server-mocks"
|
||||
PKG_REQUIRE_NAME = "@kbn/core-node-server-mocks"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"src/**/*.ts",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
]
|
||||
|
||||
RUNTIME_DEPS = [
|
||||
'//packages/core/node/core-node-server-internal'
|
||||
]
|
||||
|
||||
TYPES_DEPS = [
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/jest",
|
||||
'//packages/core/node/core-node-server-internal:npm_module_types'
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_node",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
)
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
"//:tsconfig.bazel.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc_types",
|
||||
args = ['--pretty'],
|
||||
srcs = SRCS,
|
||||
deps = TYPES_DEPS,
|
||||
declaration = True,
|
||||
emit_declaration_only = True,
|
||||
out_dir = "target_types",
|
||||
root_dir = "src",
|
||||
tsconfig = ":tsconfig",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_DIRNAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
deps = RUNTIME_DEPS + [":target_node"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [":" + PKG_DIRNAME],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [":npm_module"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm_types(
|
||||
name = "npm_module_types",
|
||||
srcs = SRCS,
|
||||
deps = [":tsc_types"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
tsconfig = ":tsconfig",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build_types",
|
||||
srcs = [":npm_module_types"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
3
packages/core/node/core-node-server-mocks/README.md
Normal file
3
packages/core/node/core-node-server-mocks/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/core-node-server-mocks
|
||||
|
||||
Contains mocks for Core's server-side `node` service.
|
13
packages/core/node/core-node-server-mocks/jest.config.js
Normal file
13
packages/core/node/core-node-server-mocks/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/packages/core/node/core-node-server-mocks'],
|
||||
};
|
7
packages/core/node/core-node-server-mocks/package.json
Normal file
7
packages/core/node/core-node-server-mocks/package.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@kbn/core-node-server-mocks",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "./target_node/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
9
packages/core/node/core-node-server-mocks/src/index.ts
Normal file
9
packages/core/node/core-node-server-mocks/src/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { nodeServiceMock } from './node_service.mock';
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { PublicMethodsOf } from '@kbn/utility-types';
|
||||
import type { NodeService, InternalNodeServicePreboot } from '@kbn/core-node-server-internal';
|
||||
|
||||
const createInternalPrebootContractMock = () => {
|
||||
const prebootContract: jest.Mocked<InternalNodeServicePreboot> = {
|
||||
roles: {
|
||||
backgroundTasks: true,
|
||||
ui: true,
|
||||
},
|
||||
};
|
||||
return prebootContract;
|
||||
};
|
||||
|
||||
type NodeServiceContract = PublicMethodsOf<NodeService>;
|
||||
const createMock = () => {
|
||||
const mocked: jest.Mocked<NodeServiceContract> = {
|
||||
preboot: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
};
|
||||
mocked.preboot.mockResolvedValue(createInternalPrebootContractMock());
|
||||
return mocked;
|
||||
};
|
||||
|
||||
export const nodeServiceMock = {
|
||||
create: createMock,
|
||||
createInternalPrebootContract: createInternalPrebootContractMock,
|
||||
};
|
17
packages/core/node/core-node-server-mocks/tsconfig.json
Normal file
17
packages/core/node/core-node-server-mocks/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"rootDir": "src",
|
||||
"stripInternal": false,
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
95
packages/core/node/core-node-server/BUILD.bazel
Normal file
95
packages/core/node/core-node-server/BUILD.bazel
Normal file
|
@ -0,0 +1,95 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
|
||||
|
||||
PKG_DIRNAME = "core-node-server"
|
||||
PKG_REQUIRE_NAME = "@kbn/core-node-server"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"src/**/*.ts",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
]
|
||||
|
||||
RUNTIME_DEPS = [
|
||||
]
|
||||
|
||||
TYPES_DEPS = [
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/jest",
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_node",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
)
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
"//:tsconfig.bazel.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc_types",
|
||||
args = ['--pretty'],
|
||||
srcs = SRCS,
|
||||
deps = TYPES_DEPS,
|
||||
declaration = True,
|
||||
emit_declaration_only = True,
|
||||
out_dir = "target_types",
|
||||
root_dir = "src",
|
||||
tsconfig = ":tsconfig",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_DIRNAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
deps = RUNTIME_DEPS + [":target_node"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [":" + PKG_DIRNAME],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [":npm_module"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm_types(
|
||||
name = "npm_module_types",
|
||||
srcs = SRCS,
|
||||
deps = [":tsc_types"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
tsconfig = ":tsconfig",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build_types",
|
||||
srcs = [":npm_module_types"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
3
packages/core/node/core-node-server/README.md
Normal file
3
packages/core/node/core-node-server/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/core-node-server
|
||||
|
||||
Contains public types for Core's server-side `node` service.
|
13
packages/core/node/core-node-server/jest.config.js
Normal file
13
packages/core/node/core-node-server/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test/jest_node',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/packages/core/node/core-node-server'],
|
||||
};
|
7
packages/core/node/core-node-server/package.json
Normal file
7
packages/core/node/core-node-server/package.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@kbn/core-node-server",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "./target_node/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
9
packages/core/node/core-node-server/src/index.ts
Normal file
9
packages/core/node/core-node-server/src/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type { NodeInfo, NodeRoles } from './types';
|
40
packages/core/node/core-node-server/src/types.ts
Normal file
40
packages/core/node/core-node-server/src/types.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Contains information about how this Kibana process has been configured.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface NodeInfo {
|
||||
/** A list of roles this node has been configured with. */
|
||||
roles: NodeRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Kibana process can be run in dedicated "modes" via `node.roles`.
|
||||
* This configuration is then exposed to plugins via `NodeRoles`,
|
||||
* which is available on the `PluginInitializerContext`.
|
||||
*
|
||||
* The node roles can be used by plugins to adjust their behavior based
|
||||
* on the way the Kibana process has been configured.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface NodeRoles {
|
||||
/**
|
||||
* The backgroundTasks role includes operations which don't involve
|
||||
* responding to incoming http traffic from the UI.
|
||||
*/
|
||||
backgroundTasks: boolean;
|
||||
/**
|
||||
* The ui role covers any operations that need to occur in order
|
||||
* to handle http traffic from the browser.
|
||||
*/
|
||||
ui: boolean;
|
||||
}
|
17
packages/core/node/core-node-server/tsconfig.json
Normal file
17
packages/core/node/core-node-server/tsconfig.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"rootDir": "src",
|
||||
"stripInternal": false,
|
||||
"types": [
|
||||
"jest",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
|
@ -262,6 +262,8 @@ export type {
|
|||
LogLevel,
|
||||
} from '@kbn/logging';
|
||||
|
||||
export type { NodeInfo, NodeRoles } from '@kbn/core-node-server';
|
||||
|
||||
export { PluginType } from '@kbn/core-base-common';
|
||||
|
||||
export type {
|
||||
|
|
|
@ -14,6 +14,7 @@ import type { MockedKeys } from '@kbn/utility-types-jest';
|
|||
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
|
||||
import { loggingSystemMock, loggingServiceMock } from '@kbn/core-logging-server-mocks';
|
||||
import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks';
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
import type {
|
||||
PluginInitializerContext,
|
||||
CoreSetup,
|
||||
|
@ -124,6 +125,7 @@ function pluginInitializerContextMock<T>(config: T = {} as T) {
|
|||
configs: ['/some/path/to/config/kibana.yml'],
|
||||
},
|
||||
config: pluginInitializerContextConfigMock<T>(config),
|
||||
node: nodeServiceMock.createInternalPrebootContract(),
|
||||
};
|
||||
|
||||
return mock;
|
||||
|
|
|
@ -18,6 +18,7 @@ import { map, toArray } from 'rxjs/operators';
|
|||
import { resolve } from 'path';
|
||||
import { ConfigService, Env } from '@kbn/config';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
import { PluginsConfig, PluginsConfigType, config } from '../plugins_config';
|
||||
import type { InstanceInfo } from '../plugin_context';
|
||||
import { discover } from './plugins_discovery';
|
||||
|
@ -128,6 +129,7 @@ const manifestPath = (...pluginPath: string[]) =>
|
|||
describe('plugins discovery system', () => {
|
||||
let logger: ReturnType<typeof loggingSystemMock.create>;
|
||||
let instanceInfo: InstanceInfo;
|
||||
let nodeInfo: NodeInfo;
|
||||
let env: Env;
|
||||
let configService: ConfigService;
|
||||
let pluginConfig: PluginsConfigType;
|
||||
|
@ -142,6 +144,13 @@ describe('plugins discovery system', () => {
|
|||
uuid: 'instance-uuid',
|
||||
};
|
||||
|
||||
nodeInfo = {
|
||||
roles: {
|
||||
backgroundTasks: true,
|
||||
ui: true,
|
||||
},
|
||||
};
|
||||
|
||||
env = Env.createDefault(
|
||||
REPO_ROOT,
|
||||
getEnvOptions({
|
||||
|
@ -180,7 +189,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('discovers plugins in the search locations', async () => {
|
||||
const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo);
|
||||
const { plugin$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -202,11 +216,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('return errors when the manifest is invalid or incompatible', async () => {
|
||||
const { plugin$, error$ } = discover(
|
||||
new PluginsConfig(pluginConfig, env),
|
||||
const { plugin$, error$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -268,11 +283,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('return errors when the plugin search path is not accessible', async () => {
|
||||
const { plugin$, error$ } = discover(
|
||||
new PluginsConfig(pluginConfig, env),
|
||||
const { plugin$, error$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -307,11 +323,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('return an error when the manifest file is not accessible', async () => {
|
||||
const { plugin$, error$ } = discover(
|
||||
new PluginsConfig(pluginConfig, env),
|
||||
const { plugin$, error$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -342,11 +359,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('discovers plugins in nested directories', async () => {
|
||||
const { plugin$, error$ } = discover(
|
||||
new PluginsConfig(pluginConfig, env),
|
||||
const { plugin$, error$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -386,7 +404,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('does not discover plugins nested inside another plugin', async () => {
|
||||
const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo);
|
||||
const { plugin$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -405,7 +428,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('stops scanning when reaching `maxDepth`', async () => {
|
||||
const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo);
|
||||
const { plugin$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
mockFs(
|
||||
{
|
||||
|
@ -430,7 +458,12 @@ describe('plugins discovery system', () => {
|
|||
});
|
||||
|
||||
it('works with symlinks', async () => {
|
||||
const { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo);
|
||||
const { plugin$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
const pluginFolder = resolve(KIBANA_ROOT, '..', 'ext-plugins');
|
||||
|
||||
|
@ -465,16 +498,17 @@ describe('plugins discovery system', () => {
|
|||
})
|
||||
);
|
||||
|
||||
discover(
|
||||
new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env),
|
||||
{
|
||||
discover({
|
||||
config: new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env),
|
||||
coreContext: {
|
||||
coreId: Symbol(),
|
||||
configService,
|
||||
env,
|
||||
logger,
|
||||
},
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
expect(loggingSystemMock.collect(logger).warn).toEqual([
|
||||
[
|
||||
|
@ -493,16 +527,17 @@ describe('plugins discovery system', () => {
|
|||
})
|
||||
);
|
||||
|
||||
discover(
|
||||
new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env),
|
||||
{
|
||||
discover({
|
||||
config: new PluginsConfig({ ...pluginConfig, paths: [extraPluginTestPath] }, env),
|
||||
coreContext: {
|
||||
coreId: Symbol(),
|
||||
configService,
|
||||
env,
|
||||
logger,
|
||||
},
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
expect(loggingSystemMock.collect(logger).warn).toEqual([]);
|
||||
});
|
||||
|
@ -530,7 +565,12 @@ describe('plugins discovery system', () => {
|
|||
])
|
||||
);
|
||||
|
||||
let { plugin$ } = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo);
|
||||
let { plugin$ } = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
expect(scanPluginSearchPathsMock).toHaveBeenCalledTimes(1);
|
||||
let plugins = await firstValueFrom(plugin$.pipe(toArray()));
|
||||
|
@ -549,7 +589,12 @@ describe('plugins discovery system', () => {
|
|||
])
|
||||
);
|
||||
|
||||
plugin$ = discover(new PluginsConfig(pluginConfig, env), coreContext, instanceInfo).plugin$;
|
||||
plugin$ = discover({
|
||||
config: new PluginsConfig(pluginConfig, env),
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}).plugin$;
|
||||
|
||||
expect(scanPluginSearchPathsMock).toHaveBeenCalledTimes(2);
|
||||
plugins = await firstValueFrom(plugin$.pipe(toArray()));
|
||||
|
|
|
@ -10,6 +10,7 @@ import { from, merge } from 'rxjs';
|
|||
import { catchError, filter, map, mergeMap, concatMap, shareReplay, toArray } from 'rxjs/operators';
|
||||
import { Logger } from '@kbn/logging';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
import { PluginWrapper } from '../plugin';
|
||||
import { createPluginInitializerContext, InstanceInfo } from '../plugin_context';
|
||||
import { PluginsConfig } from '../plugins_config';
|
||||
|
@ -27,11 +28,17 @@ import { scanPluginSearchPaths } from './scan_plugin_search_paths';
|
|||
* @param coreContext Kibana core values.
|
||||
* @internal
|
||||
*/
|
||||
export function discover(
|
||||
config: PluginsConfig,
|
||||
coreContext: CoreContext,
|
||||
instanceInfo: InstanceInfo
|
||||
) {
|
||||
export function discover({
|
||||
config,
|
||||
coreContext,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}: {
|
||||
config: PluginsConfig;
|
||||
coreContext: CoreContext;
|
||||
instanceInfo: InstanceInfo;
|
||||
nodeInfo: NodeInfo;
|
||||
}) {
|
||||
const log = coreContext.logger.get('plugins-discovery');
|
||||
log.debug('Discovering plugins...');
|
||||
|
||||
|
@ -55,7 +62,7 @@ export function discover(
|
|||
}),
|
||||
concatMap((pluginPathOrError) => {
|
||||
return typeof pluginPathOrError === 'string'
|
||||
? createPlugin$(pluginPathOrError, log, coreContext, instanceInfo)
|
||||
? createPlugin$(pluginPathOrError, log, coreContext, instanceInfo, nodeInfo)
|
||||
: [pluginPathOrError];
|
||||
}),
|
||||
shareReplay()
|
||||
|
@ -78,12 +85,15 @@ export function discover(
|
|||
* @param path Path to the plugin directory where manifest should be loaded from.
|
||||
* @param log Plugin discovery logger instance.
|
||||
* @param coreContext Kibana core context.
|
||||
* @param instanceInfo Info about the instance running Kibana, including uuid.
|
||||
* @param nodeRoles Roles this process has been configured with.
|
||||
*/
|
||||
function createPlugin$(
|
||||
path: string,
|
||||
log: Logger,
|
||||
coreContext: CoreContext,
|
||||
instanceInfo: InstanceInfo
|
||||
instanceInfo: InstanceInfo,
|
||||
nodeInfo: NodeInfo
|
||||
) {
|
||||
return from(parseManifest(path, coreContext.env.packageInfo)).pipe(
|
||||
map((manifest) => {
|
||||
|
@ -93,12 +103,13 @@ function createPlugin$(
|
|||
path,
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
}),
|
||||
catchError((err) => [err])
|
||||
|
|
|
@ -15,6 +15,7 @@ import { join } from 'path';
|
|||
import { ConfigPath, ConfigService, Env } from '@kbn/config';
|
||||
import { getEnvOptions, rawConfigServiceMock } from '@kbn/config-mocks';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
import { PluginsService } from '../plugins_service';
|
||||
import { BehaviorSubject, from } from 'rxjs';
|
||||
import { config } from '../plugins_config';
|
||||
|
@ -26,6 +27,7 @@ import { PluginWrapper } from '../plugin';
|
|||
describe('PluginsService', () => {
|
||||
const logger = loggingSystemMock.create();
|
||||
const environmentPreboot = environmentServiceMock.createPrebootContract();
|
||||
const nodePreboot = nodeServiceMock.createInternalPrebootContract();
|
||||
let pluginsService: PluginsService;
|
||||
|
||||
const createPlugin = (
|
||||
|
@ -156,7 +158,7 @@ describe('PluginsService', () => {
|
|||
}
|
||||
);
|
||||
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
|
||||
const prebootDeps = coreMock.createInternalPreboot();
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
|
|
|
@ -15,6 +15,8 @@ import { Env } from '@kbn/config';
|
|||
import { configServiceMock, getEnvOptions } from '@kbn/config-mocks';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
import { coreMock } from '../mocks';
|
||||
|
||||
import { PluginWrapper } from './plugin';
|
||||
|
@ -68,6 +70,7 @@ let coreId: symbol;
|
|||
let env: Env;
|
||||
let coreContext: CoreContext;
|
||||
let instanceInfo: InstanceInfo;
|
||||
let nodeInfo: NodeInfo;
|
||||
|
||||
const setupDeps = coreMock.createInternalSetup();
|
||||
|
||||
|
@ -77,6 +80,7 @@ beforeEach(() => {
|
|||
instanceInfo = {
|
||||
uuid: 'instance-uuid',
|
||||
};
|
||||
nodeInfo = nodeServiceMock.createInternalPrebootContract();
|
||||
|
||||
coreContext = { coreId, env, logger, configService: configService as any };
|
||||
});
|
||||
|
@ -92,12 +96,13 @@ test('`constructor` correctly initializes plugin instance', () => {
|
|||
path: 'some-plugin-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(plugin.name).toBe('some-plugin-id');
|
||||
|
@ -116,12 +121,13 @@ describe('`constructor` correctly sets non-external source', () => {
|
|||
path,
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -153,12 +159,13 @@ test('`setup` fails if `plugin` initializer is not exported', () => {
|
|||
path: 'plugin-without-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
|
@ -175,12 +182,13 @@ test('`setup` fails if plugin initializer is not a function', () => {
|
|||
path: 'plugin-with-wrong-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
|
@ -197,12 +205,13 @@ test('`setup` fails if initializer does not return object', () => {
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
mockPluginInitializer.mockReturnValue(null);
|
||||
|
@ -221,12 +230,13 @@ test('`setup` fails if object returned from initializer does not define `setup`
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
const mockPluginInstance = { run: jest.fn() };
|
||||
|
@ -242,12 +252,13 @@ test('`setup` fails if object returned from initializer does not define `setup`
|
|||
test('`setup` initializes plugin and calls appropriate lifecycle hook', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const opaqueId = Symbol();
|
||||
const initializerContext = createPluginInitializerContext(
|
||||
const initializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
const plugin = new PluginWrapper({
|
||||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
|
@ -276,12 +287,13 @@ test('`start` fails if setup is not called first', () => {
|
|||
path: 'some-plugin-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(() => plugin.start({} as any, {} as any)).toThrowErrorMatchingInlineSnapshot(
|
||||
|
@ -296,12 +308,13 @@ test('`start` fails invoked for the `preboot` plugin', async () => {
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
const mockPluginInstance = { setup: jest.fn() };
|
||||
|
@ -321,12 +334,13 @@ test('`start` calls plugin.start with context and dependencies', async () => {
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
const context = { any: 'thing' } as any;
|
||||
const deps = { otherDep: 'value' };
|
||||
|
@ -355,12 +369,13 @@ test("`start` resolves `startDependencies` Promise after plugin's start", async
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
const startContext = { any: 'thing' } as any;
|
||||
const pluginDeps = { someDep: 'value' };
|
||||
|
@ -399,12 +414,13 @@ test('`stop` fails if plugin is not set up', async () => {
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
const mockPluginInstance = { setup: jest.fn(), stop: jest.fn() };
|
||||
|
@ -423,12 +439,13 @@ test('`stop` does nothing if plugin does not define `stop` function', async () =
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
mockPluginInitializer.mockReturnValue({ setup: jest.fn() });
|
||||
|
@ -444,12 +461,13 @@ test('`stop` calls `stop` defined by the plugin instance', async () => {
|
|||
path: 'plugin-with-initializer-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
const mockPluginInstance = { setup: jest.fn(), stop: jest.fn() };
|
||||
|
@ -479,12 +497,13 @@ describe('#getConfigSchema()', () => {
|
|||
path: 'plugin-with-schema',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
expect(plugin.getConfigDescriptor()).toBe(configDescriptor);
|
||||
|
@ -498,12 +517,13 @@ describe('#getConfigSchema()', () => {
|
|||
path: 'plugin-with-no-definition',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
expect(plugin.getConfigDescriptor()).toBe(null);
|
||||
});
|
||||
|
@ -515,12 +535,13 @@ describe('#getConfigSchema()', () => {
|
|||
path: 'plugin-with-no-definition',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
expect(plugin.getConfigDescriptor()).toBe(null);
|
||||
});
|
||||
|
@ -543,12 +564,13 @@ describe('#getConfigSchema()', () => {
|
|||
path: 'plugin-invalid-schema',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
expect(() => plugin.getConfigDescriptor()).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Configuration schema expected to be an instance of Type"`
|
||||
|
|
|
@ -13,6 +13,8 @@ import { fromRoot } from '@kbn/utils';
|
|||
import { rawConfigServiceMock, getEnvOptions, configServiceMock } from '@kbn/config-mocks';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
import {
|
||||
createPluginInitializerContext,
|
||||
createPluginPrebootSetupContext,
|
||||
|
@ -54,6 +56,7 @@ describe('createPluginInitializerContext', () => {
|
|||
let coreContext: CoreContext;
|
||||
let server: Server;
|
||||
let instanceInfo: InstanceInfo;
|
||||
let nodeInfo: NodeInfo;
|
||||
|
||||
beforeEach(async () => {
|
||||
logger = loggingSystemMock.create();
|
||||
|
@ -62,6 +65,7 @@ describe('createPluginInitializerContext', () => {
|
|||
instanceInfo = {
|
||||
uuid: 'instance-uuid',
|
||||
};
|
||||
nodeInfo = nodeServiceMock.createInternalPrebootContract();
|
||||
env = Env.createDefault(REPO_ROOT, getEnvOptions());
|
||||
const config$ = rawConfigServiceMock.create({ rawConfig: {} });
|
||||
server = new Server(config$, env, logger);
|
||||
|
@ -96,12 +100,13 @@ describe('createPluginInitializerContext', () => {
|
|||
configPath: 'plugin',
|
||||
});
|
||||
|
||||
const pluginInitializerContext = createPluginInitializerContext(
|
||||
const pluginInitializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
expect(pluginInitializerContext.config.get()).toEqual({
|
||||
foo: 'bar',
|
||||
|
@ -111,12 +116,13 @@ describe('createPluginInitializerContext', () => {
|
|||
|
||||
it('config.globalConfig$ should be an observable for the global config', async () => {
|
||||
const manifest = createPluginManifest();
|
||||
const pluginInitializerContext = createPluginInitializerContext(
|
||||
const pluginInitializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
|
||||
expect(pluginInitializerContext.config.legacy.globalConfig$).toBeDefined();
|
||||
|
||||
|
@ -141,12 +147,13 @@ describe('createPluginInitializerContext', () => {
|
|||
instanceInfo = {
|
||||
uuid: 'kibana-uuid',
|
||||
};
|
||||
const pluginInitializerContext = createPluginInitializerContext(
|
||||
const pluginInitializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo
|
||||
);
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
expect(pluginInitializerContext.env.instanceUuid).toBe('kibana-uuid');
|
||||
});
|
||||
|
||||
|
@ -160,23 +167,39 @@ describe('createPluginInitializerContext', () => {
|
|||
})
|
||||
),
|
||||
};
|
||||
const pluginInitializerContext = createPluginInitializerContext(
|
||||
const pluginInitializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
createPluginManifest(),
|
||||
instanceInfo
|
||||
);
|
||||
manifest: createPluginManifest(),
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
});
|
||||
expect(pluginInitializerContext.env.configs).toEqual([
|
||||
'/home/kibana/config/kibana.yml',
|
||||
'/home/kibana/config/kibana.dev.yml',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('context.node', () => {
|
||||
it('should expose the correct node roles', () => {
|
||||
const pluginInitializerContext = createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest: createPluginManifest(),
|
||||
instanceInfo,
|
||||
nodeInfo: { roles: { backgroundTasks: false, ui: true } },
|
||||
});
|
||||
expect(pluginInitializerContext.node.roles.backgroundTasks).toBe(false);
|
||||
expect(pluginInitializerContext.node.roles.ui).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createPluginPrebootSetupContext', () => {
|
||||
let coreContext: CoreContext;
|
||||
let opaqueId: symbol;
|
||||
let nodeInfo: NodeInfo;
|
||||
|
||||
beforeEach(async () => {
|
||||
opaqueId = Symbol();
|
||||
|
@ -186,6 +209,7 @@ describe('createPluginPrebootSetupContext', () => {
|
|||
logger: loggingSystemMock.create(),
|
||||
configService: configServiceMock.create(),
|
||||
};
|
||||
nodeInfo = nodeServiceMock.createInternalPrebootContract();
|
||||
});
|
||||
|
||||
it('`holdSetupUntilResolved` captures plugin.name', () => {
|
||||
|
@ -194,8 +218,14 @@ describe('createPluginPrebootSetupContext', () => {
|
|||
path: 'some-path',
|
||||
manifest,
|
||||
opaqueId,
|
||||
initializerContext: createPluginInitializerContext(coreContext, opaqueId, manifest, {
|
||||
uuid: 'instance-uuid',
|
||||
initializerContext: createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo: {
|
||||
uuid: 'instance-uuid',
|
||||
},
|
||||
nodeInfo,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import { shareReplay } from 'rxjs/operators';
|
||||
import type { CoreContext } from '@kbn/core-base-server-internal';
|
||||
import type { PluginOpaqueId } from '@kbn/core-base-common';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
import type { RequestHandlerContext } from '..';
|
||||
import { PluginWrapper } from './plugin';
|
||||
import {
|
||||
|
@ -21,6 +22,7 @@ import { IRouter, RequestHandlerContextProvider } from '../http';
|
|||
import { getGlobalConfig, getGlobalConfig$ } from './legacy_config';
|
||||
import { CorePreboot, CoreSetup, CoreStart } from '..';
|
||||
|
||||
/** @internal */
|
||||
export interface InstanceInfo {
|
||||
uuid: string;
|
||||
}
|
||||
|
@ -35,15 +37,26 @@ export interface InstanceInfo {
|
|||
* We should aim to be restrictive and specific in the APIs that we expose.
|
||||
*
|
||||
* @param coreContext Kibana core context
|
||||
* @param pluginManifest The manifest of the plugin we're building these values for.
|
||||
* @param opaqueId The opaque id created for this particular plugin.
|
||||
* @param manifest The manifest of the plugin we're building these values for.
|
||||
* @param instanceInfo Info about the instance Kibana is running on.
|
||||
* @param nodeInfo Info about how the Kibana process has been configured.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createPluginInitializerContext(
|
||||
coreContext: CoreContext,
|
||||
opaqueId: PluginOpaqueId,
|
||||
pluginManifest: PluginManifest,
|
||||
instanceInfo: InstanceInfo
|
||||
): PluginInitializerContext {
|
||||
export function createPluginInitializerContext({
|
||||
coreContext,
|
||||
opaqueId,
|
||||
manifest,
|
||||
instanceInfo,
|
||||
nodeInfo,
|
||||
}: {
|
||||
coreContext: CoreContext;
|
||||
opaqueId: PluginOpaqueId;
|
||||
manifest: PluginManifest;
|
||||
instanceInfo: InstanceInfo;
|
||||
nodeInfo: NodeInfo;
|
||||
}): PluginInitializerContext {
|
||||
return {
|
||||
opaqueId,
|
||||
|
||||
|
@ -57,12 +70,23 @@ export function createPluginInitializerContext(
|
|||
configs: coreContext.env.configs,
|
||||
},
|
||||
|
||||
/**
|
||||
* Access the configuration for this particular Kibana node.
|
||||
* Can be used to determine which `roles` the current process was started with.
|
||||
*/
|
||||
node: {
|
||||
roles: {
|
||||
backgroundTasks: nodeInfo.roles.backgroundTasks,
|
||||
ui: nodeInfo.roles.ui,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Plugin-scoped logger
|
||||
*/
|
||||
logger: {
|
||||
get(...contextParts) {
|
||||
return coreContext.logger.get('plugins', pluginManifest.id, ...contextParts);
|
||||
return coreContext.logger.get('plugins', manifest.id, ...contextParts);
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -80,10 +104,10 @@ export function createPluginInitializerContext(
|
|||
* manifest.
|
||||
*/
|
||||
create<T>() {
|
||||
return coreContext.configService.atPath<T>(pluginManifest.configPath).pipe(shareReplay(1));
|
||||
return coreContext.configService.atPath<T>(manifest.configPath).pipe(shareReplay(1));
|
||||
},
|
||||
get<T>() {
|
||||
return coreContext.configService.atPathSync<T>(pluginManifest.configPath);
|
||||
return coreContext.configService.atPathSync<T>(manifest.configPath);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ import { ConfigPath, ConfigService, Env } from '@kbn/config';
|
|||
|
||||
import { rawConfigServiceMock, getEnvOptions } from '@kbn/config-mocks';
|
||||
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
import { coreMock } from '../mocks';
|
||||
import { environmentServiceMock } from '../environment/environment_service.mock';
|
||||
import { PluginDiscoveryError } from './discovery';
|
||||
|
@ -37,6 +38,7 @@ let env: Env;
|
|||
let prebootMockPluginSystem: jest.Mocked<PluginsSystem<PluginType.preboot>>;
|
||||
let standardMockPluginSystem: jest.Mocked<PluginsSystem<PluginType.standard>>;
|
||||
let environmentPreboot: ReturnType<typeof environmentServiceMock.createPrebootContract>;
|
||||
let nodePreboot: ReturnType<typeof nodeServiceMock.createInternalPrebootContract>;
|
||||
|
||||
const prebootDeps = coreMock.createInternalPreboot();
|
||||
const setupDeps = coreMock.createInternalSetup();
|
||||
|
@ -140,6 +142,7 @@ async function testSetup() {
|
|||
standardMockPluginSystem.getPlugins.mockReturnValue([]);
|
||||
|
||||
environmentPreboot = environmentServiceMock.createPrebootContract();
|
||||
nodePreboot = nodeServiceMock.createInternalPrebootContract();
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -158,8 +161,8 @@ describe('PluginsService', () => {
|
|||
plugin$: from([]),
|
||||
});
|
||||
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot })).rejects
|
||||
.toMatchInlineSnapshot(`
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot, node: nodePreboot }))
|
||||
.rejects.toMatchInlineSnapshot(`
|
||||
[Error: Failed to initialize plugins:
|
||||
Invalid JSON (invalid-manifest, path-1)]
|
||||
`);
|
||||
|
@ -180,8 +183,8 @@ describe('PluginsService', () => {
|
|||
plugin$: from([]),
|
||||
});
|
||||
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot })).rejects
|
||||
.toMatchInlineSnapshot(`
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot, node: nodePreboot }))
|
||||
.rejects.toMatchInlineSnapshot(`
|
||||
[Error: Failed to initialize plugins:
|
||||
Incompatible version (incompatible-version, path-3)]
|
||||
`);
|
||||
|
@ -216,7 +219,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
|
||||
await expect(
|
||||
pluginsService.discover({ environment: environmentPreboot })
|
||||
pluginsService.discover({ environment: environmentPreboot, node: nodePreboot })
|
||||
).rejects.toMatchInlineSnapshot(
|
||||
`[Error: Plugin with id "conflicting-id" is already registered!]`
|
||||
);
|
||||
|
@ -250,7 +253,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
|
||||
await expect(
|
||||
pluginsService.discover({ environment: environmentPreboot })
|
||||
pluginsService.discover({ environment: environmentPreboot, node: nodePreboot })
|
||||
).rejects.toMatchInlineSnapshot(
|
||||
`[Error: Plugin with id "conflicting-id" is already registered!]`
|
||||
);
|
||||
|
@ -288,16 +291,18 @@ describe('PluginsService', () => {
|
|||
}
|
||||
|
||||
async function expectError() {
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot })).rejects.toThrow(
|
||||
await expect(
|
||||
pluginsService.discover({ environment: environmentPreboot, node: nodePreboot })
|
||||
).rejects.toThrow(
|
||||
`X-Pack plugin or bundle with id "xPackPlugin" is required by OSS plugin "sourcePlugin", which is prohibited. Consider making this an optional dependency instead.`
|
||||
);
|
||||
expect(standardMockPluginSystem.addPlugin).not.toHaveBeenCalled();
|
||||
}
|
||||
|
||||
async function expectSuccess() {
|
||||
await expect(pluginsService.discover({ environment: environmentPreboot })).resolves.toEqual(
|
||||
expect.anything()
|
||||
);
|
||||
await expect(
|
||||
pluginsService.discover({ environment: environmentPreboot, node: nodePreboot })
|
||||
).resolves.toEqual(expect.anything());
|
||||
expect(standardMockPluginSystem.addPlugin).toHaveBeenCalled();
|
||||
}
|
||||
|
||||
|
@ -433,7 +438,7 @@ describe('PluginsService', () => {
|
|||
]),
|
||||
});
|
||||
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
const setup = await pluginsService.setup(setupDeps);
|
||||
|
||||
|
@ -521,6 +526,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect(mockDiscover).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
@ -562,6 +568,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect(preboot.pluginTree).toBeUndefined();
|
||||
expect(standard.pluginTree).toBeUndefined();
|
||||
|
@ -630,6 +637,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { standard, preboot } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect(mockDiscover).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
@ -696,7 +704,7 @@ describe('PluginsService', () => {
|
|||
plugin$: from([...prebootPlugins, ...standardPlugins]),
|
||||
});
|
||||
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
expect(prebootMockPluginSystem.addPlugin).toHaveBeenCalledTimes(2);
|
||||
for (const plugin of prebootPlugins) {
|
||||
expect(prebootMockPluginSystem.addPlugin).toHaveBeenCalledWith(plugin);
|
||||
|
@ -708,8 +716,8 @@ describe('PluginsService', () => {
|
|||
}
|
||||
|
||||
expect(mockDiscover).toHaveBeenCalledTimes(1);
|
||||
expect(mockDiscover).toHaveBeenCalledWith(
|
||||
{
|
||||
expect(mockDiscover).toHaveBeenCalledWith({
|
||||
config: {
|
||||
additionalPluginPaths: [],
|
||||
initialize: true,
|
||||
pluginSearchPaths: [
|
||||
|
@ -719,9 +727,10 @@ describe('PluginsService', () => {
|
|||
resolve(process.cwd(), '..', 'kibana-extra'),
|
||||
],
|
||||
},
|
||||
{ coreId, env, logger, configService },
|
||||
{ uuid: 'uuid' }
|
||||
);
|
||||
coreContext: { coreId, env, logger, configService },
|
||||
instanceInfo: { uuid: 'uuid' },
|
||||
nodeInfo: { roles: { backgroundTasks: true, ui: true } },
|
||||
});
|
||||
|
||||
const logs = loggingSystemMock.collect(logger);
|
||||
expect(logs.info).toHaveLength(0);
|
||||
|
@ -756,7 +765,7 @@ describe('PluginsService', () => {
|
|||
}),
|
||||
]),
|
||||
});
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
expect(configService.setSchema).toBeCalledWith('path-preboot', configSchema);
|
||||
expect(configService.setSchema).toBeCalledWith('path-standard', configSchema);
|
||||
});
|
||||
|
@ -794,7 +803,7 @@ describe('PluginsService', () => {
|
|||
}),
|
||||
]),
|
||||
});
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
expect(configService.addDeprecationProvider).toBeCalledWith(
|
||||
'config-path-preboot',
|
||||
prebootDeprecationProvider
|
||||
|
@ -837,6 +846,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
|
||||
expect(preboot.pluginPaths).toEqual(['/plugin-A-path-preboot', '/plugin-B-path-preboot']);
|
||||
|
@ -926,7 +936,7 @@ describe('PluginsService', () => {
|
|||
]),
|
||||
});
|
||||
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
|
||||
// eslint-disable-next-line dot-notation
|
||||
expect(pluginsService['pluginConfigUsageDescriptors']).toMatchInlineSnapshot(`
|
||||
|
@ -1008,6 +1018,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
|
||||
const prebootUIConfig$ = preboot.uiPlugins.browserConfigs.get('plugin-with-expose-preboot')!;
|
||||
|
@ -1062,6 +1073,7 @@ describe('PluginsService', () => {
|
|||
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect(preboot.uiPlugins.browserConfigs.size).toBe(0);
|
||||
expect(standard.uiPlugins.browserConfigs.size).toBe(0);
|
||||
|
@ -1125,6 +1137,7 @@ describe('PluginsService', () => {
|
|||
await expect(
|
||||
pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
})
|
||||
).resolves.not.toThrow(); // If the rename is not applied, it'll fail
|
||||
});
|
||||
|
@ -1185,6 +1198,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect(preboot.uiPlugins.internal).toMatchInlineSnapshot(`
|
||||
Map {
|
||||
|
@ -1228,6 +1242,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
const { preboot, standard } = await pluginsService.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
expect([...preboot.uiPlugins.internal.keys()].sort()).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
@ -1245,7 +1260,7 @@ describe('PluginsService', () => {
|
|||
|
||||
it('#preboot does initialize `preboot` plugins if plugins.initialize is true', async () => {
|
||||
config$.next({ plugins: { initialize: true } });
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
|
||||
expect(prebootMockPluginSystem.setupPlugins).toHaveBeenCalledTimes(1);
|
||||
|
@ -1255,7 +1270,7 @@ describe('PluginsService', () => {
|
|||
|
||||
it('#preboot does not initialize `preboot` plugins if plugins.initialize is false', async () => {
|
||||
config$.next({ plugins: { initialize: false } });
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
|
||||
expect(prebootMockPluginSystem.setupPlugins).not.toHaveBeenCalled();
|
||||
|
@ -1264,7 +1279,7 @@ describe('PluginsService', () => {
|
|||
|
||||
it('#setup does initialize `standard` plugins if plugins.initialize is true', async () => {
|
||||
config$.next({ plugins: { initialize: true } });
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
|
||||
const { initialized } = await pluginsService.setup(setupDeps);
|
||||
|
@ -1275,7 +1290,7 @@ describe('PluginsService', () => {
|
|||
|
||||
it('#setup does not initialize `standard` plugins if plugins.initialize is false', async () => {
|
||||
config$.next({ plugins: { initialize: false } });
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
const { initialized } = await pluginsService.setup(setupDeps);
|
||||
expect(standardMockPluginSystem.setupPlugins).not.toHaveBeenCalled();
|
||||
|
@ -1312,7 +1327,7 @@ describe('PluginsService', () => {
|
|||
it('does not try to stop `preboot` plugins and start `standard` ones if plugins.initialize is `false`', async () => {
|
||||
config$.next({ plugins: { initialize: false } });
|
||||
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
await pluginsService.setup(setupDeps);
|
||||
|
||||
|
@ -1325,7 +1340,7 @@ describe('PluginsService', () => {
|
|||
});
|
||||
|
||||
it('stops `preboot` plugins and starts `standard` ones', async () => {
|
||||
await pluginsService.discover({ environment: environmentPreboot });
|
||||
await pluginsService.discover({ environment: environmentPreboot, node: nodePreboot });
|
||||
await pluginsService.preboot(prebootDeps);
|
||||
await pluginsService.setup(setupDeps);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import { Logger } from '@kbn/logging';
|
|||
import type { IConfigService } from '@kbn/config';
|
||||
import type { CoreContext, CoreService } from '@kbn/core-base-server-internal';
|
||||
import type { PluginName } from '@kbn/core-base-common';
|
||||
import type { InternalNodeServicePreboot } from '@kbn/core-node-server-internal';
|
||||
import { discover, PluginDiscoveryError, PluginDiscoveryErrorType } from './discovery';
|
||||
import { PluginWrapper } from './plugin';
|
||||
import {
|
||||
|
@ -84,6 +85,7 @@ export type PluginsServiceStartDeps = InternalCoreStart;
|
|||
/** @internal */
|
||||
export interface PluginsServiceDiscoverDeps {
|
||||
environment: InternalEnvironmentServicePreboot;
|
||||
node: InternalNodeServicePreboot;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -109,11 +111,21 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
|
|||
this.standardPluginsSystem = new PluginsSystem(this.coreContext, PluginType.standard);
|
||||
}
|
||||
|
||||
public async discover({ environment }: PluginsServiceDiscoverDeps): Promise<DiscoveredPlugins> {
|
||||
public async discover({
|
||||
environment,
|
||||
node,
|
||||
}: PluginsServiceDiscoverDeps): Promise<DiscoveredPlugins> {
|
||||
const config = await firstValueFrom(this.config$);
|
||||
|
||||
const { error$, plugin$ } = discover(config, this.coreContext, {
|
||||
uuid: environment.instanceUuid,
|
||||
const { error$, plugin$ } = discover({
|
||||
config,
|
||||
coreContext: this.coreContext,
|
||||
instanceInfo: {
|
||||
uuid: environment.instanceUuid,
|
||||
},
|
||||
nodeInfo: {
|
||||
roles: node.roles,
|
||||
},
|
||||
});
|
||||
|
||||
await this.handleDiscoveryErrors(error$);
|
||||
|
|
|
@ -18,6 +18,7 @@ import type {
|
|||
ConfigDeprecationProvider,
|
||||
} from '@kbn/config';
|
||||
import type { PluginName, PluginOpaqueId, PluginType } from '@kbn/core-base-common';
|
||||
import type { NodeInfo } from '@kbn/core-node-server';
|
||||
|
||||
import { ElasticsearchConfigType } from '../elasticsearch/elasticsearch_config';
|
||||
import { SavedObjectsConfigType } from '../saved_objects/saved_objects_config';
|
||||
|
@ -354,6 +355,29 @@ export interface PluginInitializerContext<ConfigSchema = unknown> {
|
|||
instanceUuid: string;
|
||||
configs: readonly string[];
|
||||
};
|
||||
/**
|
||||
* Access the configuration for this particular Kibana node.
|
||||
* Can be used to determine which `roles` the current process was started with.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // plugins/my-plugin/server/plugin.ts
|
||||
*
|
||||
* export class MyPlugin implements Plugin {
|
||||
* constructor(private readonly initContext: PluginInitializerContext) {
|
||||
* this.initContext = initContext;
|
||||
* }
|
||||
* setup() {
|
||||
* if (this.initContext.node.roles.backgroundTasks) {
|
||||
* // run background tasks
|
||||
* } else if (this.initContext.node.roles.ui) {
|
||||
* // register http routes, etc
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
node: NodeInfo;
|
||||
/**
|
||||
* {@link LoggerFactory | logger factory} instance already bound to the plugin's logging context
|
||||
*
|
||||
|
|
|
@ -75,6 +75,13 @@ jest.doMock('./environment/environment_service', () => ({
|
|||
EnvironmentService: jest.fn(() => mockEnvironmentService),
|
||||
}));
|
||||
|
||||
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
|
||||
|
||||
export const mockNodeService = nodeServiceMock.create();
|
||||
jest.doMock('@kbn/core-node-server-internal', () => ({
|
||||
NodeService: jest.fn(() => mockNodeService),
|
||||
}));
|
||||
|
||||
import { metricsServiceMock } from './metrics/metrics_service.mock';
|
||||
|
||||
export const mockMetricsService = metricsServiceMock.create();
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
mockLoggingService,
|
||||
mockI18nService,
|
||||
mockEnvironmentService,
|
||||
mockNodeService,
|
||||
mockPrebootService,
|
||||
mockDeprecationService,
|
||||
mockDocLinksService,
|
||||
|
@ -62,6 +63,7 @@ test('preboot services on "preboot"', async () => {
|
|||
const server = new Server(rawConfigService, env, logger);
|
||||
|
||||
expect(mockEnvironmentService.preboot).not.toHaveBeenCalled();
|
||||
expect(mockNodeService.preboot).not.toHaveBeenCalled();
|
||||
expect(mockContextService.preboot).not.toHaveBeenCalled();
|
||||
expect(mockHttpService.preboot).not.toHaveBeenCalled();
|
||||
expect(mockI18nService.preboot).not.toHaveBeenCalled();
|
||||
|
@ -75,6 +77,7 @@ test('preboot services on "preboot"', async () => {
|
|||
await server.preboot();
|
||||
|
||||
expect(mockEnvironmentService.preboot).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeService.preboot).toHaveBeenCalledTimes(1);
|
||||
expect(mockContextService.preboot).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttpService.preboot).toHaveBeenCalledTimes(1);
|
||||
expect(mockI18nService.preboot).toHaveBeenCalledTimes(1);
|
||||
|
@ -201,6 +204,7 @@ test('stops services on "stop"', async () => {
|
|||
expect(mockHttpService.stop).not.toHaveBeenCalled();
|
||||
expect(mockElasticsearchService.stop).not.toHaveBeenCalled();
|
||||
expect(mockPluginsService.stop).not.toHaveBeenCalled();
|
||||
expect(mockNodeService.stop).not.toHaveBeenCalled();
|
||||
expect(mockSavedObjectsService.stop).not.toHaveBeenCalled();
|
||||
expect(mockUiSettingsService.stop).not.toHaveBeenCalled();
|
||||
expect(mockMetricsService.stop).not.toHaveBeenCalled();
|
||||
|
@ -212,6 +216,7 @@ test('stops services on "stop"', async () => {
|
|||
expect(mockHttpService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockElasticsearchService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockPluginsService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockSavedObjectsService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockUiSettingsService.stop).toHaveBeenCalledTimes(1);
|
||||
expect(mockMetricsService.stop).toHaveBeenCalledTimes(1);
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
coreDeprecationProvider,
|
||||
ensureValidConfiguration,
|
||||
} from '@kbn/core-config-server-internal';
|
||||
import { NodeService, nodeConfig } from '@kbn/core-node-server-internal';
|
||||
import { AnalyticsService } from '@kbn/core-analytics-server-internal';
|
||||
import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server';
|
||||
import { CoreApp } from './core_app';
|
||||
|
@ -88,6 +89,7 @@ export class Server {
|
|||
private readonly savedObjects: SavedObjectsService;
|
||||
private readonly uiSettings: UiSettingsService;
|
||||
private readonly environment: EnvironmentService;
|
||||
private readonly node: NodeService;
|
||||
private readonly metrics: MetricsService;
|
||||
private readonly httpResources: HttpResourcesService;
|
||||
private readonly status: StatusService;
|
||||
|
@ -132,6 +134,7 @@ export class Server {
|
|||
this.uiSettings = new UiSettingsService(core);
|
||||
this.capabilities = new CapabilitiesService(core);
|
||||
this.environment = new EnvironmentService(core);
|
||||
this.node = new NodeService(core);
|
||||
this.metrics = new MetricsService(core);
|
||||
this.status = new StatusService(core);
|
||||
this.coreApp = new CoreApp(core);
|
||||
|
@ -159,9 +162,13 @@ export class Server {
|
|||
const analyticsPreboot = this.analytics.preboot();
|
||||
|
||||
const environmentPreboot = await this.environment.preboot({ analytics: analyticsPreboot });
|
||||
const nodePreboot = await this.node.preboot();
|
||||
|
||||
// Discover any plugins before continuing. This allows other systems to utilize the plugin dependency graph.
|
||||
this.discoveredPlugins = await this.plugins.discover({ environment: environmentPreboot });
|
||||
this.discoveredPlugins = await this.plugins.discover({
|
||||
environment: environmentPreboot,
|
||||
node: nodePreboot,
|
||||
});
|
||||
|
||||
// Immediately terminate in case of invalid configuration. This needs to be done after plugin discovery. We also
|
||||
// silent deprecation warnings until `setup` stage where we'll validate config once again.
|
||||
|
@ -401,6 +408,7 @@ export class Server {
|
|||
await this.metrics.stop();
|
||||
await this.status.stop();
|
||||
await this.logging.stop();
|
||||
this.node.stop();
|
||||
this.deprecations.stop();
|
||||
}
|
||||
|
||||
|
@ -412,22 +420,23 @@ export class Server {
|
|||
|
||||
public setupCoreConfig() {
|
||||
const configDescriptors: Array<ServiceConfigDescriptor<unknown>> = [
|
||||
executionContextConfig,
|
||||
pathConfig,
|
||||
cspConfig,
|
||||
deprecationConfig,
|
||||
elasticsearchConfig,
|
||||
executionContextConfig,
|
||||
externalUrlConfig,
|
||||
loggingConfig,
|
||||
httpConfig,
|
||||
i18nConfig,
|
||||
loggingConfig,
|
||||
nodeConfig,
|
||||
opsConfig,
|
||||
pathConfig,
|
||||
pidConfig,
|
||||
pluginsConfig,
|
||||
savedObjectsConfig,
|
||||
savedObjectsMigrationConfig,
|
||||
uiSettingsConfig,
|
||||
opsConfig,
|
||||
statusConfig,
|
||||
pidConfig,
|
||||
i18nConfig,
|
||||
deprecationConfig,
|
||||
uiSettingsConfig,
|
||||
];
|
||||
|
||||
this.configService.addDeprecationProvider(rootConfigPath, coreDeprecationProvider);
|
||||
|
|
|
@ -126,6 +126,7 @@ kibana_vars=(
|
|||
monitoring.ui.max_bucket_size
|
||||
monitoring.ui.min_interval_seconds
|
||||
newsfeed.enabled
|
||||
node.roles
|
||||
ops.cGroupOverrides.cpuAcctPath
|
||||
ops.cGroupOverrides.cpuPath
|
||||
ops.interval
|
||||
|
|
47
test/node_roles_functional/all.config.ts
Normal file
47
test/node_roles_functional/all.config.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import path from 'path';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js'));
|
||||
|
||||
return {
|
||||
rootTags: ['runOutsideOfCiGroups'],
|
||||
testFiles: [require.resolve('./test_suites/all')],
|
||||
services: {
|
||||
...functionalConfig.get('services'),
|
||||
},
|
||||
pageObjects: functionalConfig.get('pageObjects'),
|
||||
servers: functionalConfig.get('servers'),
|
||||
esTestCluster: {
|
||||
...functionalConfig.get('esTestCluster'),
|
||||
serverArgs: ['xpack.security.enabled=false'],
|
||||
},
|
||||
apps: functionalConfig.get('apps'),
|
||||
screenshots: functionalConfig.get('screenshots'),
|
||||
junit: {
|
||||
reportName: 'Plugin Functional Tests - node roles - all',
|
||||
},
|
||||
kbnTestServer: {
|
||||
...functionalConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...functionalConfig.get('kbnTestServer.serverArgs'),
|
||||
|
||||
// Required to load new platform plugins via `--plugin-path` flag.
|
||||
'--env.name=development',
|
||||
// for testing set buffer duration to 0 to immediately flush counters into saved objects.
|
||||
'--usageCollection.usageCounters.bufferDuration=0',
|
||||
|
||||
`--plugin-path=${path.resolve(__dirname, 'plugins', 'core_plugin_initializer_context')}`,
|
||||
'--node.roles=["*"]',
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
47
test/node_roles_functional/background_tasks.config.ts
Normal file
47
test/node_roles_functional/background_tasks.config.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import path from 'path';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js'));
|
||||
|
||||
return {
|
||||
rootTags: ['runOutsideOfCiGroups'],
|
||||
testFiles: [require.resolve('./test_suites/background_tasks')],
|
||||
services: {
|
||||
...functionalConfig.get('services'),
|
||||
},
|
||||
pageObjects: functionalConfig.get('pageObjects'),
|
||||
servers: functionalConfig.get('servers'),
|
||||
esTestCluster: {
|
||||
...functionalConfig.get('esTestCluster'),
|
||||
serverArgs: ['xpack.security.enabled=false'],
|
||||
},
|
||||
apps: functionalConfig.get('apps'),
|
||||
screenshots: functionalConfig.get('screenshots'),
|
||||
junit: {
|
||||
reportName: 'Plugin Functional Tests - node roles - background tasks',
|
||||
},
|
||||
kbnTestServer: {
|
||||
...functionalConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...functionalConfig.get('kbnTestServer.serverArgs'),
|
||||
|
||||
// Required to load new platform plugins via `--plugin-path` flag.
|
||||
'--env.name=development',
|
||||
// for testing set buffer duration to 0 to immediately flush counters into saved objects.
|
||||
'--usageCollection.usageCounters.bufferDuration=0',
|
||||
|
||||
`--plugin-path=${path.resolve(__dirname, 'plugins', 'core_plugin_initializer_context')}`,
|
||||
'--node.roles=["background_tasks"]',
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"id": "corePluginInitializerContext",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"owner": {
|
||||
"name": "Core",
|
||||
"githubTeam": "kibana-core"
|
||||
},
|
||||
"configPath": ["core_plugin_initializer_context"],
|
||||
"server": true,
|
||||
"ui": false
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "core_plugin_initializer_context",
|
||||
"version": "1.0.0",
|
||||
"main": "target/test/plugin_functional/plugins/core_plugin_initializer_context",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && ../../../../node_modules/.bin/tsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { PluginInitializerContext } from '@kbn/core/server';
|
||||
import { CorePluginInitializerContextPlugin } from './plugin';
|
||||
|
||||
export const plugin = (initializerContext: PluginInitializerContext) =>
|
||||
new CorePluginInitializerContextPlugin(initializerContext);
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Plugin, CoreSetup, PluginInitializerContext } from '@kbn/core/server';
|
||||
|
||||
export class CorePluginInitializerContextPlugin implements Plugin {
|
||||
readonly initializerContext: PluginInitializerContext;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.initializerContext = initializerContext;
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, deps: {}) {
|
||||
const router = core.http.createRouter();
|
||||
router.get(
|
||||
{
|
||||
path: '/core_plugin_initializer_context/node/roles',
|
||||
validate: false,
|
||||
options: {
|
||||
authRequired: false,
|
||||
},
|
||||
},
|
||||
async (context, req, res) => {
|
||||
return res.ok({ body: this.initializerContext.node.roles });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target/types"
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"server/**/*.ts",
|
||||
"../../../../typings/**/*",
|
||||
],
|
||||
"exclude": [],
|
||||
"references": [
|
||||
{ "path": "../../../../src/core/tsconfig.json" }
|
||||
]
|
||||
}
|
11
test/node_roles_functional/services/index.ts
Normal file
11
test/node_roles_functional/services/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../functional/ftr_provider_context';
|
||||
|
||||
export type PluginFunctionalProviderContext = FtrProviderContext;
|
15
test/node_roles_functional/test_suites/all/index.ts
Normal file
15
test/node_roles_functional/test_suites/all/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ loadTestFile }: PluginFunctionalProviderContext) {
|
||||
describe('core plugins - initializer context - node roles - all', () => {
|
||||
loadTestFile(require.resolve('./initializer_context'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
import '@kbn/core-provider-plugin/types';
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('initializer context', () => {
|
||||
it('passes node roles to server PluginInitializerContext', async () => {
|
||||
await supertest.get('/core_plugin_initializer_context/node/roles').expect(200, {
|
||||
backgroundTasks: true,
|
||||
ui: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ loadTestFile }: PluginFunctionalProviderContext) {
|
||||
describe('core plugins - initializer context - node roles - backgroundTasks', () => {
|
||||
loadTestFile(require.resolve('./initializer_context'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
import '@kbn/core-provider-plugin/types';
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('initializer context', () => {
|
||||
it('passes node roles to server PluginInitializerContext', async () => {
|
||||
await supertest.get('/core_plugin_initializer_context/node/roles').expect(200, {
|
||||
backgroundTasks: true,
|
||||
ui: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
15
test/node_roles_functional/test_suites/ui/index.ts
Normal file
15
test/node_roles_functional/test_suites/ui/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
|
||||
export default function ({ loadTestFile }: PluginFunctionalProviderContext) {
|
||||
describe('core plugins - initializer context - node roles - ui', () => {
|
||||
loadTestFile(require.resolve('./initializer_context'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginFunctionalProviderContext } from '../../services';
|
||||
import '@kbn/core-provider-plugin/types';
|
||||
|
||||
export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('initializer context', () => {
|
||||
it('passes node roles to server PluginInitializerContext', async () => {
|
||||
await supertest.get('/core_plugin_initializer_context/node/roles').expect(200, {
|
||||
backgroundTasks: false,
|
||||
ui: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
47
test/node_roles_functional/ui.config.ts
Normal file
47
test/node_roles_functional/ui.config.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import path from 'path';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js'));
|
||||
|
||||
return {
|
||||
rootTags: ['runOutsideOfCiGroups'],
|
||||
testFiles: [require.resolve('./test_suites/ui')],
|
||||
services: {
|
||||
...functionalConfig.get('services'),
|
||||
},
|
||||
pageObjects: functionalConfig.get('pageObjects'),
|
||||
servers: functionalConfig.get('servers'),
|
||||
esTestCluster: {
|
||||
...functionalConfig.get('esTestCluster'),
|
||||
serverArgs: ['xpack.security.enabled=false'],
|
||||
},
|
||||
apps: functionalConfig.get('apps'),
|
||||
screenshots: functionalConfig.get('screenshots'),
|
||||
junit: {
|
||||
reportName: 'Plugin Functional Tests - node roles - ui',
|
||||
},
|
||||
kbnTestServer: {
|
||||
...functionalConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...functionalConfig.get('kbnTestServer.serverArgs'),
|
||||
|
||||
// Required to load new platform plugins via `--plugin-path` flag.
|
||||
'--env.name=development',
|
||||
// for testing set buffer duration to 0 to immediately flush counters into saved objects.
|
||||
'--usageCollection.usageCounters.bufferDuration=0',
|
||||
|
||||
`--plugin-path=${path.resolve(__dirname, 'plugins', 'core_plugin_initializer_context')}`,
|
||||
'--node.roles=["ui"]',
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
24
yarn.lock
24
yarn.lock
|
@ -3167,6 +3167,18 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/core-node-server-internal@link:bazel-bin/packages/core/node/core-node-server-internal":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/core-node-server-mocks@link:bazel-bin/packages/core/node/core-node-server-mocks":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/core-node-server@link:bazel-bin/packages/core/node/core-node-server":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/core-theme-browser-internal@link:bazel-bin/packages/core/theme/core-theme-browser-internal":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
@ -6634,6 +6646,18 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__core-node-server-internal@link:bazel-bin/packages/core/node/core-node-server-internal/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__core-node-server-mocks@link:bazel-bin/packages/core/node/core-node-server-mocks/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__core-node-server@link:bazel-bin/packages/core/node/core-node-server/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__core-public-internal-base@link:bazel-bin/packages/core/public/internal-base/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue