mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ML] Transforms: Adding execution context to ES requests. (#153649)
Part of https://github.com/elastic/kibana/issues/147378 - Similar to #148746, adds execution context to transform API endpoints. - Moves `createExecutionContext` to package `@kbn/ml-route-utils`.
This commit is contained in:
parent
3930f7aa99
commit
33599ad414
20 changed files with 194 additions and 57 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -459,6 +459,7 @@ x-pack/packages/ml/local_storage @elastic/ml-ui
|
|||
x-pack/packages/ml/nested_property @elastic/ml-ui
|
||||
x-pack/plugins/ml @elastic/ml-ui
|
||||
x-pack/packages/ml/query_utils @elastic/ml-ui
|
||||
x-pack/packages/ml/route_utils @elastic/ml-ui
|
||||
x-pack/packages/ml/string_hash @elastic/ml-ui
|
||||
x-pack/packages/ml/url_state @elastic/ml-ui
|
||||
packages/kbn-monaco @elastic/appex-sharedux
|
||||
|
|
|
@ -474,6 +474,7 @@
|
|||
"@kbn/ml-nested-property": "link:x-pack/packages/ml/nested_property",
|
||||
"@kbn/ml-plugin": "link:x-pack/plugins/ml",
|
||||
"@kbn/ml-query-utils": "link:x-pack/packages/ml/query_utils",
|
||||
"@kbn/ml-route-utils": "link:x-pack/packages/ml/route_utils",
|
||||
"@kbn/ml-string-hash": "link:x-pack/packages/ml/string_hash",
|
||||
"@kbn/ml-url-state": "link:x-pack/packages/ml/url_state",
|
||||
"@kbn/monaco": "link:packages/kbn-monaco",
|
||||
|
|
|
@ -912,6 +912,8 @@
|
|||
"@kbn/ml-plugin/*": ["x-pack/plugins/ml/*"],
|
||||
"@kbn/ml-query-utils": ["x-pack/packages/ml/query_utils"],
|
||||
"@kbn/ml-query-utils/*": ["x-pack/packages/ml/query_utils/*"],
|
||||
"@kbn/ml-route-utils": ["x-pack/packages/ml/route_utils"],
|
||||
"@kbn/ml-route-utils/*": ["x-pack/packages/ml/route_utils/*"],
|
||||
"@kbn/ml-string-hash": ["x-pack/packages/ml/string_hash"],
|
||||
"@kbn/ml-string-hash/*": ["x-pack/packages/ml/string_hash/*"],
|
||||
"@kbn/ml-url-state": ["x-pack/packages/ml/url_state"],
|
||||
|
|
3
x-pack/packages/ml/route_utils/README.md
Normal file
3
x-pack/packages/ml/route_utils/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# @kbn/ml-route-utils
|
||||
|
||||
Route utils maintained by the ML UI team.
|
8
x-pack/packages/ml/route_utils/index.ts
Normal file
8
x-pack/packages/ml/route_utils/index.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
export { createExecutionContext } from './src/create_execution_context';
|
12
x-pack/packages/ml/route_utils/jest.config.js
Normal file
12
x-pack/packages/ml/route_utils/jest.config.js
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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/x-pack/packages/ml/route_utils'],
|
||||
};
|
5
x-pack/packages/ml/route_utils/kibana.jsonc
Normal file
5
x-pack/packages/ml/route_utils/kibana.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/ml-route-utils",
|
||||
"owner": "@elastic/ml-ui"
|
||||
}
|
6
x-pack/packages/ml/route_utils/package.json
Normal file
6
x-pack/packages/ml/route_utils/package.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "@kbn/ml-route-utils",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"license": "Elastic License 2.0"
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CoreStart } from '@kbn/core/server';
|
||||
|
||||
import { createExecutionContext } from './create_execution_context';
|
||||
|
||||
const coreStartMock = {
|
||||
executionContext: {
|
||||
getAsLabels: () => ({ page: 'the-page' }),
|
||||
},
|
||||
} as unknown as CoreStart;
|
||||
|
||||
describe('createExecutionContext', () => {
|
||||
it('returns an execution context based on execution context labels', () => {
|
||||
expect(createExecutionContext(coreStartMock, 'the-name')).toEqual({
|
||||
type: 'application',
|
||||
name: 'the-name',
|
||||
id: 'the-page',
|
||||
page: 'the-page',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an execution context based on a supplied id', () => {
|
||||
expect(createExecutionContext(coreStartMock, 'the-name', 'the-id')).toEqual({
|
||||
type: 'application',
|
||||
name: 'the-name',
|
||||
id: 'the-id',
|
||||
page: 'the-page',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CoreStart } from '@kbn/core/server';
|
||||
|
||||
/**
|
||||
* Creates an execution context to be passed on as part of ES queries.
|
||||
* This allows you to identify the source triggering a request when debugging slow logs.
|
||||
*
|
||||
* @param coreStart Kibana CoreStart
|
||||
* @param name Context name, usually the plugin id
|
||||
* @param id Optional context id, can be used to override the default usage of page as id
|
||||
* @param type Optional context type, defaults to `application`.
|
||||
* @returns
|
||||
*/
|
||||
export function createExecutionContext(
|
||||
coreStart: CoreStart,
|
||||
name: string,
|
||||
id?: string,
|
||||
type = 'application'
|
||||
) {
|
||||
const labels = coreStart.executionContext.getAsLabels();
|
||||
const page = labels.page as string;
|
||||
return {
|
||||
type,
|
||||
name,
|
||||
id: id ?? page,
|
||||
page,
|
||||
};
|
||||
}
|
21
x-pack/packages/ml/route_utils/tsconfig.json
Normal file
21
x-pack/packages/ml/route_utils/tsconfig.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"react"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
]
|
||||
}
|
|
@ -13,14 +13,14 @@ import type {
|
|||
RequestHandler,
|
||||
SavedObjectsClientContract,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
} from '@kbn/core/server';
|
||||
import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
|
||||
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
|
||||
|
||||
import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server';
|
||||
import type { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server';
|
||||
import type { DataViewsService } from '@kbn/data-views-plugin/common';
|
||||
import { createExecutionContext } from '@kbn/ml-route-utils';
|
||||
|
||||
import { PLUGIN_ID } from '../../common/constants/app';
|
||||
import { mlSavedObjectServiceFactory, MLSavedObjectService } from '../saved_objects';
|
||||
import type { MlLicense } from '../../common/license';
|
||||
|
@ -117,7 +117,7 @@ export class RouteGuard {
|
|||
);
|
||||
|
||||
const [coreStart] = await this._getStartServices();
|
||||
const executionContext = await createExecutionContext(coreStart, request.route.path);
|
||||
const executionContext = createExecutionContext(coreStart, PLUGIN_ID, request.route.path);
|
||||
|
||||
return await coreStart.executionContext.withContext(executionContext, () =>
|
||||
handler({
|
||||
|
@ -138,14 +138,3 @@ export class RouteGuard {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function createExecutionContext(coreStart: CoreStart, id?: string) {
|
||||
const labels = coreStart.executionContext.getAsLabels();
|
||||
const page = labels.page as string;
|
||||
return {
|
||||
type: 'application',
|
||||
name: PLUGIN_ID,
|
||||
id: id ?? page,
|
||||
page,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -86,5 +86,6 @@
|
|||
"@kbn/saved-objects-finder-plugin",
|
||||
"@kbn/monaco",
|
||||
"@kbn/repo-info",
|
||||
"@kbn/ml-route-utils",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { CoreSetup, CoreStart, Plugin, Logger, PluginInitializerContext } from '
|
|||
import { LicenseType } from '@kbn/licensing-plugin/common/types';
|
||||
|
||||
import { PluginSetupDependencies, PluginStartDependencies } from './types';
|
||||
import { ApiRoutes } from './routes';
|
||||
import { registerRoutes } from './routes';
|
||||
import { License } from './services';
|
||||
import { registerTransformHealthRuleType } from './lib/alerting';
|
||||
|
||||
|
@ -27,38 +27,18 @@ const PLUGIN = {
|
|||
};
|
||||
|
||||
export class TransformServerPlugin implements Plugin<{}, void, any, any> {
|
||||
private readonly apiRoutes: ApiRoutes;
|
||||
private readonly license: License;
|
||||
private readonly logger: Logger;
|
||||
|
||||
private fieldFormatsStart: PluginStartDependencies['fieldFormats'] | null = null;
|
||||
|
||||
constructor(initContext: PluginInitializerContext) {
|
||||
this.logger = initContext.logger.get();
|
||||
this.apiRoutes = new ApiRoutes();
|
||||
this.license = new License();
|
||||
}
|
||||
|
||||
setup(
|
||||
{ http, getStartServices, elasticsearch }: CoreSetup<PluginStartDependencies>,
|
||||
{ licensing, features, alerting }: PluginSetupDependencies
|
||||
): {} {
|
||||
const router = http.createRouter();
|
||||
|
||||
this.license.setup(
|
||||
{
|
||||
pluginId: PLUGIN.id,
|
||||
minimumLicenseType: PLUGIN.minimumLicenseType,
|
||||
defaultErrorMessage: i18n.translate('xpack.transform.licenseCheckErrorMessage', {
|
||||
defaultMessage: 'License check failed',
|
||||
}),
|
||||
},
|
||||
{
|
||||
licensing,
|
||||
logger: this.logger,
|
||||
}
|
||||
);
|
||||
|
||||
features.registerElasticsearchFeature({
|
||||
id: PLUGIN.id,
|
||||
management: {
|
||||
|
@ -73,10 +53,24 @@ export class TransformServerPlugin implements Plugin<{}, void, any, any> {
|
|||
],
|
||||
});
|
||||
|
||||
this.apiRoutes.setup({
|
||||
router,
|
||||
license: this.license,
|
||||
getStartServices,
|
||||
getStartServices().then(([coreStart, { dataViews }]) => {
|
||||
const license = new License({
|
||||
pluginId: PLUGIN.id,
|
||||
minimumLicenseType: PLUGIN.minimumLicenseType,
|
||||
defaultErrorMessage: i18n.translate('xpack.transform.licenseCheckErrorMessage', {
|
||||
defaultMessage: 'License check failed',
|
||||
}),
|
||||
licensing,
|
||||
logger: this.logger,
|
||||
coreStart,
|
||||
});
|
||||
|
||||
registerRoutes({
|
||||
router: http.createRouter(),
|
||||
license,
|
||||
dataViews,
|
||||
coreStart,
|
||||
});
|
||||
});
|
||||
|
||||
if (alerting) {
|
||||
|
|
|
@ -79,7 +79,7 @@ enum TRANSFORM_ACTIONS {
|
|||
}
|
||||
|
||||
export function registerTransformsRoutes(routeDependencies: RouteDependencies) {
|
||||
const { router, license, getStartServices } = routeDependencies;
|
||||
const { router, license, coreStart, dataViews } = routeDependencies;
|
||||
/**
|
||||
* @apiGroup Transforms
|
||||
*
|
||||
|
@ -314,7 +314,7 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) {
|
|||
license.guardApiRoute<undefined, undefined, DeleteTransformsRequestSchema>(
|
||||
async (ctx, req, res) => {
|
||||
try {
|
||||
const [{ savedObjects, elasticsearch }, { dataViews }] = await getStartServices();
|
||||
const { savedObjects, elasticsearch } = coreStart;
|
||||
const savedObjectsClient = savedObjects.getScopedClient(req);
|
||||
const esClient = elasticsearch.client.asScoped(req).asCurrentUser;
|
||||
|
||||
|
|
|
@ -15,10 +15,8 @@ import { API_BASE_PATH } from '../../common/constants';
|
|||
|
||||
export const addBasePath = (uri: string): string => `${API_BASE_PATH}${uri}`;
|
||||
|
||||
export class ApiRoutes {
|
||||
setup(dependencies: RouteDependencies) {
|
||||
registerFieldHistogramsRoutes(dependencies);
|
||||
registerPrivilegesRoute(dependencies);
|
||||
registerTransformsRoutes(dependencies);
|
||||
}
|
||||
export function registerRoutes(dependencies: RouteDependencies) {
|
||||
registerFieldHistogramsRoutes(dependencies);
|
||||
registerPrivilegesRoute(dependencies);
|
||||
registerTransformsRoutes(dependencies);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { Logger } from '@kbn/core/server';
|
||||
import {
|
||||
CoreStart,
|
||||
IKibanaResponse,
|
||||
KibanaRequest,
|
||||
KibanaResponseFactory,
|
||||
|
@ -16,6 +17,9 @@ import {
|
|||
|
||||
import { LicensingPluginSetup, LicenseType } from '@kbn/licensing-plugin/server';
|
||||
import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server';
|
||||
import { createExecutionContext } from '@kbn/ml-route-utils';
|
||||
|
||||
import { PLUGIN } from '../../common/constants';
|
||||
|
||||
export interface LicenseStatus {
|
||||
isValid: boolean;
|
||||
|
@ -27,6 +31,9 @@ interface SetupSettings {
|
|||
pluginId: string;
|
||||
minimumLicenseType: LicenseType;
|
||||
defaultErrorMessage: string;
|
||||
licensing: LicensingPluginSetup;
|
||||
logger: Logger;
|
||||
coreStart: CoreStart;
|
||||
}
|
||||
|
||||
type TransformRequestHandlerContext = CustomRequestHandlerContext<{
|
||||
|
@ -34,16 +41,22 @@ type TransformRequestHandlerContext = CustomRequestHandlerContext<{
|
|||
}>;
|
||||
|
||||
export class License {
|
||||
private coreStart: CoreStart;
|
||||
private licenseStatus: LicenseStatus = {
|
||||
isValid: false,
|
||||
isSecurityEnabled: false,
|
||||
message: 'Invalid License',
|
||||
};
|
||||
|
||||
setup(
|
||||
{ pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings,
|
||||
{ licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger }
|
||||
) {
|
||||
constructor({
|
||||
pluginId,
|
||||
minimumLicenseType,
|
||||
defaultErrorMessage,
|
||||
licensing,
|
||||
logger,
|
||||
coreStart,
|
||||
}: SetupSettings) {
|
||||
this.coreStart = coreStart;
|
||||
licensing.license$.subscribe((license) => {
|
||||
const { state, message } = license.check(pluginId, minimumLicenseType);
|
||||
const hasRequiredLicense = state === 'valid';
|
||||
|
@ -74,12 +87,17 @@ export class License {
|
|||
) {
|
||||
const license = this;
|
||||
|
||||
return function licenseCheck(
|
||||
return async function licenseCheck(
|
||||
ctx: TransformRequestHandlerContext,
|
||||
request: KibanaRequest<Params, Query, Body>,
|
||||
response: KibanaResponseFactory
|
||||
): IKibanaResponse<any> | Promise<IKibanaResponse<any>> {
|
||||
): Promise<IKibanaResponse<any>> {
|
||||
const licenseStatus = license.getStatus();
|
||||
const executionContext = createExecutionContext(
|
||||
license.coreStart,
|
||||
PLUGIN.ID,
|
||||
request.route.path
|
||||
);
|
||||
|
||||
if (!licenseStatus.isValid) {
|
||||
return response.customError({
|
||||
|
@ -90,7 +108,9 @@ export class License {
|
|||
});
|
||||
}
|
||||
|
||||
return handler(ctx, request, response);
|
||||
return await license.coreStart.executionContext.withContext(executionContext, () =>
|
||||
handler(ctx, request, response)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { IRouter, CoreSetup } from '@kbn/core/server';
|
||||
import { IRouter, CoreStart } from '@kbn/core/server';
|
||||
import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server';
|
||||
import { LicensingPluginSetup } from '@kbn/licensing-plugin/server';
|
||||
import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server';
|
||||
|
@ -28,5 +28,6 @@ export interface PluginStartDependencies {
|
|||
export interface RouteDependencies {
|
||||
router: IRouter;
|
||||
license: License;
|
||||
getStartServices: CoreSetup<PluginStartDependencies>['getStartServices'];
|
||||
coreStart: CoreStart;
|
||||
dataViews: DataViewsServerPluginStart;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
"@kbn/unified-field-list-plugin",
|
||||
"@kbn/shared-ux-router",
|
||||
"@kbn/saved-objects-management-plugin",
|
||||
"@kbn/saved-objects-finder-plugin"
|
||||
"@kbn/saved-objects-finder-plugin",
|
||||
"@kbn/ml-route-utils"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -4561,6 +4561,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/ml-route-utils@link:x-pack/packages/ml/route_utils":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/ml-string-hash@link:x-pack/packages/ml/string_hash":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue