From 5131c6e62cb25e8faa22fdafb3b8a5584038d40d Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Tue, 17 Dec 2019 18:03:41 -0700 Subject: [PATCH 1/7] update dfAnalytics routes to use np router --- x-pack/legacy/plugins/ml/index.ts | 3 +- .../analytics_panel/analytics_panel.tsx | 2 +- .../new_platform/data_analytics_schema.ts | 21 + .../licence_check_pre_routing_factory.ts | 38 ++ .../plugins/ml/server/new_platform/plugin.ts | 26 +- .../ml/server/routes/data_frame_analytics.js | 397 ++++++++++++------ 6 files changed, 347 insertions(+), 140 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/server/new_platform/data_analytics_schema.ts create mode 100644 x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts diff --git a/x-pack/legacy/plugins/ml/index.ts b/x-pack/legacy/plugins/ml/index.ts index 9fe55d15d34a7..c4289389b0d56 100755 --- a/x-pack/legacy/plugins/ml/index.ts +++ b/x-pack/legacy/plugins/ml/index.ts @@ -81,10 +81,11 @@ export const ml = (kibana: any) => { injectUiAppVars: server.injectUiAppVars, http: mlHttpService, savedObjects: server.savedObjects, + elasticsearch: kbnServer.newPlatform.setup.core.elasticsearch, // NP }; const { usageCollection, cloud, home } = kbnServer.newPlatform.setup.plugins; const plugins = { - elasticsearch: server.plugins.elasticsearch, + elasticsearch: server.plugins.elasticsearch, // legacy security: server.plugins.security, xpackMain: server.plugins.xpack_main, spaces: server.plugins.spaces, diff --git a/x-pack/legacy/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx b/x-pack/legacy/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx index 72f4332728e94..b2eda12abc578 100644 --- a/x-pack/legacy/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx +++ b/x-pack/legacy/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx @@ -76,7 +76,7 @@ export const AnalyticsPanel: FC = ({ jobCreationDisabled }) => { )}      - {isInitialized === true && analytics.length === 0 && ( + {errorMessage === undefined && isInitialized === true && analytics.length === 0 && ( +): RequestHandler => { + // License checking and enable/disable logic + return function licensePreRouting( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN_ID).getLicenseCheckResults(); + + if (!licenseCheckResults.isAvailable) { + return response.customError({ + body: { + message: licenseCheckResults.message, + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; +}; diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 7e22a9a5a4c8b..cbc4ca9c670d2 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -8,9 +8,10 @@ import Boom from 'boom'; import { i18n } from '@kbn/i18n'; import { ServerRoute } from 'hapi'; import { KibanaConfig, SavedObjectsLegacyService } from 'src/legacy/server/kbn_server'; -import { Logger, PluginInitializerContext, CoreSetup } from 'src/core/server'; +import { Logger, PluginInitializerContext, CoreSetup, IRouter } from 'src/core/server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { CloudSetup } from '../../../../../plugins/cloud/server'; import { XPackMainPlugin } from '../../../xpack_main/server/xpack_main'; import { addLinksToSampleDatasets } from '../lib/sample_data_sets'; @@ -56,6 +57,8 @@ import { jobAuditMessagesRoutes } from '../routes/job_audit_messages'; import { fileDataVisualizerRoutes } from '../routes/file_data_visualizer'; import { initMlServerLog, LogInitialization } from '../client/log'; import { HomeServerPluginSetup } from '../../../../../../src/plugins/home/server'; +// @ts-ignore: could not find declaration file for module +import { elasticsearchJsPlugin } from '../client/elasticsearch_ml'; type CoreHttpSetup = CoreSetup['http']; export interface MlHttpServiceSetup extends CoreHttpSetup { @@ -70,6 +73,7 @@ export interface MlCoreSetup { injectUiAppVars: (id: string, callback: () => {}) => any; http: MlHttpServiceSetup; savedObjects: SavedObjectsLegacyService; + elasticsearch: ElasticsearchServiceSetup; } export interface MlInitializerContext extends PluginInitializerContext { legacyConfig: KibanaConfig; @@ -86,11 +90,14 @@ export interface PluginsSetup { // TODO: this is temporary for `mirrorPluginStatus` ml: any; } + export interface RouteInitialization { commonRouteConfig: any; config?: any; elasticsearchPlugin: ElasticsearchPlugin; + elasticsearchService: ElasticsearchServiceSetup; route(route: ServerRoute | ServerRoute[]): void; + router: IRouter; xpackMainPlugin?: MlXpackMainPlugin; savedObjects?: SavedObjectsLegacyService; spacesPlugin: any; @@ -101,8 +108,10 @@ export interface UsageInitialization { savedObjects: SavedObjectsLegacyService; } +export const PLUGIN_ID = 'ml'; + export class Plugin { - private readonly pluginId: string = 'ml'; + private readonly pluginId: string = PLUGIN_ID; private config: any; private log: Logger; @@ -183,17 +192,28 @@ export class Plugin { }; }); + // Can access via new platform router's handler function 'context' parameter - context.ml.mlClient + const mlClient = core.elasticsearch.createClient('ml', { plugins: [elasticsearchJsPlugin] }); + // @ts-ignore // 'ml' not 'search' or 'security' or 'licensing + http.registerRouteHandlerContext('ml', (context, request) => { + return { + mlClient: mlClient.asScoped(request), + }; + }); + const routeInitializationDeps: RouteInitialization = { commonRouteConfig, route: http.route, + router: http.createRouter(), elasticsearchPlugin: plugins.elasticsearch, + elasticsearchService: core.elasticsearch, + xpackMainPlugin: plugins.xpackMain, spacesPlugin: plugins.spaces, }; const extendedRouteInitializationDeps: RouteInitialization = { ...routeInitializationDeps, config: this.config, - xpackMainPlugin: plugins.xpackMain, savedObjects: core.savedObjects, spacesPlugin: plugins.spaces, cloud: plugins.cloud, diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js index 567d7e1856a85..21dafd9db8c48 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js @@ -4,171 +4,298 @@ * you may not use this file except in compliance with the Elastic License. */ -import { callWithRequestFactory } from '../client/call_with_request_factory'; -import { wrapError } from '../client/errors'; +import { schema } from '@kbn/config-schema'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; +import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { dataAnalyticsJobConfigSchema } from '../new_platform/data_analytics_schema'; -export function dataFrameAnalyticsRoutes({ commonRouteConfig, elasticsearchPlugin, route }) { - route({ - method: 'GET', - path: '/api/ml/data_frame/analytics', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.getDataFrameAnalytics').catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, +export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { + async function dfAnalyticsGetAllHandler(context, request, response) { + try { + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics'); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.get( + { + path: '/api/ml/data_frame/analytics', + validate: { + params: schema.object({ analyticsId: schema.maybe(schema.string()) }), + }, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetAllHandler) + ); - route({ - method: 'GET', - path: '/api/ml/data_frame/analytics/{analyticsId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); + async function dfAnalyticsGetSingleJobHandler(context, request, response) { + try { const { analyticsId } = request.params; - return callWithRequest('ml.getDataFrameAnalytics', { analyticsId }).catch(resp => - wrapError(resp) - ); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/data_frame/analytics/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.getDataFrameAnalyticsStats').catch(resp => wrapError(resp)); + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, }, - config: { - ...commonRouteConfig, + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetSingleJobHandler) + ); + + async function dfAnalyticsGetAllStatsHandler(context, request, response) { + try { + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalyticsStats'); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.get( + { + path: '/api/ml/data_frame/analytics/_stats', + validate: false, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetAllStatsHandler) + ); - route({ - method: 'GET', - path: '/api/ml/data_frame/analytics/{analyticsId}/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); + async function dfAnalyticsGetSingleJobStatsHandler(context, request, response) { + try { const { analyticsId } = request.params; - return callWithRequest('ml.getDataFrameAnalyticsStats', { analyticsId }).catch(resp => - wrapError(resp) - ); - }, - config: { - ...commonRouteConfig, + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalyticsStats', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_stats', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetSingleJobStatsHandler) + ); - route({ - method: 'PUT', - path: '/api/ml/data_frame/analytics/{analyticsId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); + async function dfAnalyticsCreateJobHandler(context, request, response) { + try { const { analyticsId } = request.params; - return callWithRequest('ml.createDataFrameAnalytics', { - body: request.payload, + const results = await context.ml.mlClient.callAsCurrentUser('ml.createDataFrameAnalytics', { + body: request.body, analyticsId, - }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/data_frame/_evaluate', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.evaluateDataFrameAnalytics', { - body: request.payload, - }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/data_frame/analytics/_explain', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.estimateDataFrameAnalyticsMemoryUsage', { - body: request.payload, - }).catch(resp => wrapError(resp)); + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.put( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + body: schema.object({ ...dataAnalyticsJobConfigSchema }, { allowUnknowns: true }), + }, }, - config: { - ...commonRouteConfig, + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsCreateJobHandler) + ); + + async function dfAnalyticsEvaluateHandler(context, request, response) { + try { + const results = await context.ml.mlClient.callAsCurrentUser('ml.evaluateDataFrameAnalytics', { + body: request.body, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.post( + { + path: '/api/ml/data_frame/_evaluate', + validate: { + body: schema.object({}, { allowUnknowns: true }), + }, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsEvaluateHandler) + ); - route({ - method: 'DELETE', - path: '/api/ml/data_frame/analytics/{analyticsId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { analyticsId } = request.params; - return callWithRequest('ml.deleteDataFrameAnalytics', { analyticsId }).catch(resp => - wrapError(resp) + async function dfAnalyticsExplainHandler(context, request, response) { + try { + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.estimateDataFrameAnalyticsMemoryUsage', + { + body: request.body, + } ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.post( + { + path: '/api/ml/data_frame/analytics/_explain', + validate: { + body: schema.object({}, { allowUnknowns: true }), + }, }, - config: { - ...commonRouteConfig, - }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsExplainHandler) + ); - route({ - method: 'POST', - path: '/api/ml/data_frame/analytics/{analyticsId}/_start', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const options = { - analyticsId: request.params.analyticsId, - }; + async function dfAnalyticsDeleteJobHandler(context, request, response) { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.deleteDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } - return callWithRequest('ml.startDataFrameAnalytics', options).catch(resp => wrapError(resp)); + router.delete( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + }, }, - config: { - ...commonRouteConfig, + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsDeleteJobHandler) + ); + + async function dfAnalyticsStartJobHandler(context, request, response) { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.startDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.post( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_start', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + }, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsStartJobHandler) + ); - route({ - method: 'POST', - path: '/api/ml/data_frame/analytics/{analyticsId}/_stop', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); + async function dfAnalyticsStopJobHandler(context, request, response) { + try { const options = { analyticsId: request.params.analyticsId, }; - if (request.query.force !== undefined) { - options.force = request.query.force; + if (request.url?.query?.force !== undefined) { + options.force = request.url.query.force; } - return callWithRequest('ml.stopDataFrameAnalytics', options).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.stopDataFrameAnalytics', + options + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.post( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_stop', + validate: { + params: schema.object({ + analyticsId: schema.string(), + force: schema.maybe(schema.boolean()), + }), + }, }, - }); - - route({ - method: 'GET', - path: '/api/ml/data_frame/analytics/{analyticsId}/messages', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const { getAnalyticsAuditMessages } = analyticsAuditMessagesProvider(callWithRequest); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsStopJobHandler) + ); + + async function dfAnalyticsGetMessagesHandler(context, request, response) { + try { const { analyticsId } = request.params; - return getAnalyticsAuditMessages(analyticsId).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, + const { getAnalyticsAuditMessages } = analyticsAuditMessagesProvider( + context.ml.mlClient.callAsCurrentUser + ); + + const results = await getAnalyticsAuditMessages(analyticsId); + return response.ok({ + body: results, + }); + } catch (e) { + // Case: default + return response.internalError({ body: e }); + } + } + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/messages', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, }, - }); + licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetMessagesHandler) + ); } From 7defac09951f5961ee31d0bee164650a033ba4fb Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 19 Dec 2019 16:41:18 -0700 Subject: [PATCH 2/7] add route schemas and only show error message --- .../new_platform/data_analytics_schema.ts | 22 ++++++++++++ .../ml/server/routes/data_frame_analytics.js | 34 +++++++++++-------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/x-pack/legacy/plugins/ml/server/new_platform/data_analytics_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/data_analytics_schema.ts index 8b602903f9d46..f5d72c51dc070 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/data_analytics_schema.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/data_analytics_schema.ts @@ -19,3 +19,25 @@ export const dataAnalyticsJobConfigSchema = { analyzed_fields: schema.any(), model_memory_limit: schema.string(), }; + +export const dataAnalyticsEvaluateSchema = { + index: schema.string(), + query: schema.maybe(schema.any()), + evaluation: schema.maybe( + schema.object({ + regression: schema.maybe(schema.any()), + classification: schema.maybe(schema.any()), + }) + ), +}; + +export const dataAnalyticsExplainSchema = { + description: schema.maybe(schema.string()), + dest: schema.maybe(schema.any()), + source: schema.object({ + index: schema.string(), + }), + analysis: schema.any(), + analyzed_fields: schema.maybe(schema.any()), + model_memory_limit: schema.maybe(schema.string()), +}; diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js index 21dafd9db8c48..4da109714e628 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js @@ -7,7 +7,11 @@ import { schema } from '@kbn/config-schema'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; -import { dataAnalyticsJobConfigSchema } from '../new_platform/data_analytics_schema'; +import { + dataAnalyticsJobConfigSchema, + dataAnalyticsEvaluateSchema, + dataAnalyticsExplainSchema, +} from '../new_platform/data_analytics_schema'; export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { async function dfAnalyticsGetAllHandler(context, request, response) { @@ -18,7 +22,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -43,7 +47,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -65,7 +69,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -88,7 +92,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -114,7 +118,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -125,7 +129,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { params: schema.object({ analyticsId: schema.string(), }), - body: schema.object({ ...dataAnalyticsJobConfigSchema }, { allowUnknowns: true }), + body: schema.object({ ...dataAnalyticsJobConfigSchema }), }, }, licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsCreateJobHandler) @@ -141,7 +145,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -149,7 +153,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { { path: '/api/ml/data_frame/_evaluate', validate: { - body: schema.object({}, { allowUnknowns: true }), + body: schema.object({ ...dataAnalyticsEvaluateSchema }), }, }, licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsEvaluateHandler) @@ -168,7 +172,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -176,7 +180,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { { path: '/api/ml/data_frame/analytics/_explain', validate: { - body: schema.object({}, { allowUnknowns: true }), + body: schema.object({ ...dataAnalyticsExplainSchema }), }, }, licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsExplainHandler) @@ -193,7 +197,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -220,7 +224,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -255,7 +259,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } @@ -285,7 +289,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { }); } catch (e) { // Case: default - return response.internalError({ body: e }); + return response.internalError({ body: e.message }); } } From 8255e722972da5b1c16ecc9d77e0ab9082e7323b Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Fri, 20 Dec 2019 11:07:55 -0700 Subject: [PATCH 3/7] convert route file to ts and set handlers inline --- .../licence_check_pre_routing_factory.ts | 4 +- .../plugins/ml/server/new_platform/plugin.ts | 6 + .../ml/server/routes/data_frame_analytics.js | 305 ------------------ .../ml/server/routes/data_frame_analytics.ts | 289 +++++++++++++++++ 4 files changed, 297 insertions(+), 307 deletions(-) delete mode 100644 x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js create mode 100644 x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts diff --git a/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts b/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts index b59870e01d976..356194ac7bf2c 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts @@ -10,10 +10,10 @@ import { RequestHandler, RequestHandlerContext, } from 'src/core/server'; -import { PLUGIN_ID } from './plugin'; +import { PLUGIN_ID, MlXpackMainPlugin } from './plugin'; export const licensePreRoutingFactory = ( - xpackMainPlugin: any, + xpackMainPlugin: MlXpackMainPlugin, handler: RequestHandler ): RequestHandler => { // License checking and enable/disable logic diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index cbc4ca9c670d2..6e701804f9072 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -108,6 +108,12 @@ export interface UsageInitialization { savedObjects: SavedObjectsLegacyService; } +declare module 'kibana/server' { + interface RequestHandlerContext { + ml?: any; + } +} + export const PLUGIN_ID = 'ml'; export class Plugin { diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js deleted file mode 100644 index 4da109714e628..0000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.js +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { schema } from '@kbn/config-schema'; -import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; -import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; -import { - dataAnalyticsJobConfigSchema, - dataAnalyticsEvaluateSchema, - dataAnalyticsExplainSchema, -} from '../new_platform/data_analytics_schema'; - -export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }) { - async function dfAnalyticsGetAllHandler(context, request, response) { - try { - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics'); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.get( - { - path: '/api/ml/data_frame/analytics', - validate: { - params: schema.object({ analyticsId: schema.maybe(schema.string()) }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetAllHandler) - ); - - async function dfAnalyticsGetSingleJobHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics', { - analyticsId, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.get( - { - path: '/api/ml/data_frame/analytics/{analyticsId}', - validate: { - params: schema.object({ analyticsId: schema.string() }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetSingleJobHandler) - ); - - async function dfAnalyticsGetAllStatsHandler(context, request, response) { - try { - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalyticsStats'); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.get( - { - path: '/api/ml/data_frame/analytics/_stats', - validate: false, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetAllStatsHandler) - ); - - async function dfAnalyticsGetSingleJobStatsHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalyticsStats', { - analyticsId, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.get( - { - path: '/api/ml/data_frame/analytics/{analyticsId}/_stats', - validate: { - params: schema.object({ analyticsId: schema.string() }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetSingleJobStatsHandler) - ); - - async function dfAnalyticsCreateJobHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.createDataFrameAnalytics', { - body: request.body, - analyticsId, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.put( - { - path: '/api/ml/data_frame/analytics/{analyticsId}', - validate: { - params: schema.object({ - analyticsId: schema.string(), - }), - body: schema.object({ ...dataAnalyticsJobConfigSchema }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsCreateJobHandler) - ); - - async function dfAnalyticsEvaluateHandler(context, request, response) { - try { - const results = await context.ml.mlClient.callAsCurrentUser('ml.evaluateDataFrameAnalytics', { - body: request.body, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.post( - { - path: '/api/ml/data_frame/_evaluate', - validate: { - body: schema.object({ ...dataAnalyticsEvaluateSchema }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsEvaluateHandler) - ); - - async function dfAnalyticsExplainHandler(context, request, response) { - try { - const results = await context.ml.mlClient.callAsCurrentUser( - 'ml.estimateDataFrameAnalyticsMemoryUsage', - { - body: request.body, - } - ); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.post( - { - path: '/api/ml/data_frame/analytics/_explain', - validate: { - body: schema.object({ ...dataAnalyticsExplainSchema }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsExplainHandler) - ); - - async function dfAnalyticsDeleteJobHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.deleteDataFrameAnalytics', { - analyticsId, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.delete( - { - path: '/api/ml/data_frame/analytics/{analyticsId}', - validate: { - params: schema.object({ - analyticsId: schema.string(), - }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsDeleteJobHandler) - ); - - async function dfAnalyticsStartJobHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.startDataFrameAnalytics', { - analyticsId, - }); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.post( - { - path: '/api/ml/data_frame/analytics/{analyticsId}/_start', - validate: { - params: schema.object({ - analyticsId: schema.string(), - }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsStartJobHandler) - ); - - async function dfAnalyticsStopJobHandler(context, request, response) { - try { - const options = { - analyticsId: request.params.analyticsId, - }; - - if (request.url?.query?.force !== undefined) { - options.force = request.url.query.force; - } - - const results = await context.ml.mlClient.callAsCurrentUser( - 'ml.stopDataFrameAnalytics', - options - ); - return response.ok({ - body: { ...results }, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.post( - { - path: '/api/ml/data_frame/analytics/{analyticsId}/_stop', - validate: { - params: schema.object({ - analyticsId: schema.string(), - force: schema.maybe(schema.boolean()), - }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsStopJobHandler) - ); - - async function dfAnalyticsGetMessagesHandler(context, request, response) { - try { - const { analyticsId } = request.params; - const { getAnalyticsAuditMessages } = analyticsAuditMessagesProvider( - context.ml.mlClient.callAsCurrentUser - ); - - const results = await getAnalyticsAuditMessages(analyticsId); - return response.ok({ - body: results, - }); - } catch (e) { - // Case: default - return response.internalError({ body: e.message }); - } - } - - router.get( - { - path: '/api/ml/data_frame/analytics/{analyticsId}/messages', - validate: { - params: schema.object({ analyticsId: schema.string() }), - }, - }, - licensePreRoutingFactory(xpackMainPlugin, dfAnalyticsGetMessagesHandler) - ); -} diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts new file mode 100644 index 0000000000000..4c54a4bae7aea --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts @@ -0,0 +1,289 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; +import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { MlXpackMainPlugin } from '../new_platform/plugin'; +import { + dataAnalyticsJobConfigSchema, + dataAnalyticsEvaluateSchema, + dataAnalyticsExplainSchema, +} from '../new_platform/data_analytics_schema'; + +export function dataFrameAnalyticsRoutes({ + xpackMainPlugin, + router, +}: { + xpackMainPlugin: MlXpackMainPlugin; + router: IRouter; +}) { + router.get( + { + path: '/api/ml/data_frame/analytics', + validate: { + params: schema.object({ analyticsId: schema.maybe(schema.string()) }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics'); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.get( + { + path: '/api/ml/data_frame/analytics/_stats', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.getDataFrameAnalyticsStats' + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_stats', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.getDataFrameAnalyticsStats', + { + analyticsId, + } + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.put( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + body: schema.object({ ...dataAnalyticsJobConfigSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.createDataFrameAnalytics', { + body: request.body, + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.post( + { + path: '/api/ml/data_frame/_evaluate', + validate: { + body: schema.object({ ...dataAnalyticsEvaluateSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.evaluateDataFrameAnalytics', + { + body: request.body, + } + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.post( + { + path: '/api/ml/data_frame/analytics/_explain', + validate: { + body: schema.object({ ...dataAnalyticsExplainSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.estimateDataFrameAnalyticsMemoryUsage', + { + body: request.body, + } + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.delete( + { + path: '/api/ml/data_frame/analytics/{analyticsId}', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.deleteDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.post( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_start', + validate: { + params: schema.object({ + analyticsId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const results = await context.ml.mlClient.callAsCurrentUser('ml.startDataFrameAnalytics', { + analyticsId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.post( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/_stop', + validate: { + params: schema.object({ + analyticsId: schema.string(), + force: schema.maybe(schema.boolean()), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const options: { analyticsId: string; force?: boolean | undefined } = { + analyticsId: request.params.analyticsId, + }; + // @ts-ignore TODO: update types + if (request.url?.query?.force !== undefined) { + // @ts-ignore TODO: update types + options.force = request.url.query.force; + } + + const results = await context.ml.mlClient.callAsCurrentUser( + 'ml.stopDataFrameAnalytics', + options + ); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); + + router.get( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/messages', + validate: { + params: schema.object({ analyticsId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { analyticsId } = request.params; + const { getAnalyticsAuditMessages } = analyticsAuditMessagesProvider( + context.ml.mlClient.callAsCurrentUser + ); + + const results = await getAnalyticsAuditMessages(analyticsId); + return response.ok({ + body: results, + }); + } catch (e) { + return response.forbidden({ body: e.message }); + } + }) + ); +} From 867faf9d0b2c37e1c5880f04b9c1bb7b167a5a0e Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Fri, 20 Dec 2019 12:45:22 -0700 Subject: [PATCH 4/7] update df analytics param type --- .../legacy/plugins/ml/server/new_platform/plugin.ts | 2 +- .../plugins/ml/server/routes/data_frame_analytics.ts | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 6e701804f9072..0664d8390c91b 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -98,7 +98,7 @@ export interface RouteInitialization { elasticsearchService: ElasticsearchServiceSetup; route(route: ServerRoute | ServerRoute[]): void; router: IRouter; - xpackMainPlugin?: MlXpackMainPlugin; + xpackMainPlugin: MlXpackMainPlugin; savedObjects?: SavedObjectsLegacyService; spacesPlugin: any; cloud?: CloudSetup; diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts index 4c54a4bae7aea..3274f6bb59a59 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts @@ -5,23 +5,16 @@ */ import { schema } from '@kbn/config-schema'; -import { IRouter } from 'src/core/server'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; -import { MlXpackMainPlugin } from '../new_platform/plugin'; +import { RouteInitialization } from '../new_platform/plugin'; import { dataAnalyticsJobConfigSchema, dataAnalyticsEvaluateSchema, dataAnalyticsExplainSchema, } from '../new_platform/data_analytics_schema'; -export function dataFrameAnalyticsRoutes({ - xpackMainPlugin, - router, -}: { - xpackMainPlugin: MlXpackMainPlugin; - router: IRouter; -}) { +export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteInitialization) { router.get( { path: '/api/ml/data_frame/analytics', From 13d66e127fc4f7ea2e9b9705da0c52ddd84c9284 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Fri, 20 Dec 2019 14:22:13 -0700 Subject: [PATCH 5/7] update mlClient type and assert mlClient is not null --- .../plugins/ml/server/new_platform/plugin.ts | 12 +++++- .../ml/server/routes/data_frame_analytics.ts | 38 +++++++++++-------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index 0664d8390c91b..a3d6a060e3a01 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -8,7 +8,13 @@ import Boom from 'boom'; import { i18n } from '@kbn/i18n'; import { ServerRoute } from 'hapi'; import { KibanaConfig, SavedObjectsLegacyService } from 'src/legacy/server/kbn_server'; -import { Logger, PluginInitializerContext, CoreSetup, IRouter } from 'src/core/server'; +import { + Logger, + PluginInitializerContext, + CoreSetup, + IRouter, + IScopedClusterClient, +} from 'src/core/server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { ElasticsearchServiceSetup } from 'src/core/server'; @@ -110,7 +116,9 @@ export interface UsageInitialization { declare module 'kibana/server' { interface RequestHandlerContext { - ml?: any; + ml?: { + mlClient: IScopedClusterClient; + }; } } diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts index 3274f6bb59a59..b3b280ac81e7f 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts @@ -24,7 +24,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }, licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics'); + const results = await context.ml!.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics'); return response.ok({ body: { ...results }, }); @@ -44,7 +44,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics', { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.getDataFrameAnalytics', { analyticsId, }); return response.ok({ @@ -63,7 +63,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }, licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { - const results = await context.ml.mlClient.callAsCurrentUser( + const results = await context.ml!.mlClient.callAsCurrentUser( 'ml.getDataFrameAnalyticsStats' ); return response.ok({ @@ -85,7 +85,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser( + const results = await context.ml!.mlClient.callAsCurrentUser( 'ml.getDataFrameAnalyticsStats', { analyticsId, @@ -113,10 +113,13 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.createDataFrameAnalytics', { - body: request.body, - analyticsId, - }); + const results = await context.ml!.mlClient.callAsCurrentUser( + 'ml.createDataFrameAnalytics', + { + body: request.body, + analyticsId, + } + ); return response.ok({ body: { ...results }, }); @@ -135,7 +138,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }, licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { - const results = await context.ml.mlClient.callAsCurrentUser( + const results = await context.ml!.mlClient.callAsCurrentUser( 'ml.evaluateDataFrameAnalytics', { body: request.body, @@ -159,7 +162,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti }, licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { - const results = await context.ml.mlClient.callAsCurrentUser( + const results = await context.ml!.mlClient.callAsCurrentUser( 'ml.estimateDataFrameAnalyticsMemoryUsage', { body: request.body, @@ -186,9 +189,12 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.deleteDataFrameAnalytics', { - analyticsId, - }); + const results = await context.ml!.mlClient.callAsCurrentUser( + 'ml.deleteDataFrameAnalytics', + { + analyticsId, + } + ); return response.ok({ body: { ...results }, }); @@ -210,7 +216,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { try { const { analyticsId } = request.params; - const results = await context.ml.mlClient.callAsCurrentUser('ml.startDataFrameAnalytics', { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.startDataFrameAnalytics', { analyticsId, }); return response.ok({ @@ -243,7 +249,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti options.force = request.url.query.force; } - const results = await context.ml.mlClient.callAsCurrentUser( + const results = await context.ml!.mlClient.callAsCurrentUser( 'ml.stopDataFrameAnalytics', options ); @@ -267,7 +273,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti try { const { analyticsId } = request.params; const { getAnalyticsAuditMessages } = analyticsAuditMessagesProvider( - context.ml.mlClient.callAsCurrentUser + context.ml!.mlClient.callAsCurrentUser ); const results = await getAnalyticsAuditMessages(analyticsId); From 3c3b4234eb71e593e255eaa5839669e5cd215d72 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Sat, 28 Dec 2019 12:47:19 -0700 Subject: [PATCH 6/7] handle errors correctly --- .../plugins/ml/server/client/error_wrapper.ts | 17 ++++++++++++++ .../licence_check_pre_routing_factory.ts | 3 +-- .../plugins/ml/server/new_platform/plugin.ts | 5 ++-- .../ml/server/routes/data_frame_analytics.ts | 23 ++++++++++--------- 4 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 x-pack/legacy/plugins/ml/server/client/error_wrapper.ts diff --git a/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts b/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts new file mode 100644 index 0000000000000..d800020038a38 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { boomify, isBoom } from 'boom'; +import { ResponseError, CustomHttpResponseOptions } from 'src/core/server'; + +export function wrapError(error: any): CustomHttpResponseOptions { + const boom = isBoom(error) ? error : boomify(error); + return { + body: boom, + headers: boom.output.headers, + statusCode: boom.output.statusCode, + }; +} diff --git a/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts b/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts index 356194ac7bf2c..cc77d2872fb90 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/licence_check_pre_routing_factory.ts @@ -25,11 +25,10 @@ export const licensePreRoutingFactory = ( const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN_ID).getLicenseCheckResults(); if (!licenseCheckResults.isAvailable) { - return response.customError({ + return response.forbidden({ body: { message: licenseCheckResults.message, }, - statusCode: 403, }); } diff --git a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts index a3d6a060e3a01..681b2ff20c8aa 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -66,6 +66,8 @@ import { HomeServerPluginSetup } from '../../../../../../src/plugins/home/server // @ts-ignore: could not find declaration file for module import { elasticsearchJsPlugin } from '../client/elasticsearch_ml'; +export const PLUGIN_ID = 'ml'; + type CoreHttpSetup = CoreSetup['http']; export interface MlHttpServiceSetup extends CoreHttpSetup { route(route: ServerRoute | ServerRoute[]): void; @@ -122,8 +124,6 @@ declare module 'kibana/server' { } } -export const PLUGIN_ID = 'ml'; - export class Plugin { private readonly pluginId: string = PLUGIN_ID; private config: any; @@ -208,7 +208,6 @@ export class Plugin { // Can access via new platform router's handler function 'context' parameter - context.ml.mlClient const mlClient = core.elasticsearch.createClient('ml', { plugins: [elasticsearchJsPlugin] }); - // @ts-ignore // 'ml' not 'search' or 'security' or 'licensing http.registerRouteHandlerContext('ml', (context, request) => { return { mlClient: mlClient.asScoped(request), diff --git a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts index b3b280ac81e7f..2f8db45d9739e 100644 --- a/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/legacy/plugins/ml/server/routes/data_frame_analytics.ts @@ -5,6 +5,7 @@ */ import { schema } from '@kbn/config-schema'; +import { wrapError } from '../client/error_wrapper'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; import { RouteInitialization } from '../new_platform/plugin'; @@ -29,7 +30,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -51,7 +52,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -70,7 +71,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -95,7 +96,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -124,7 +125,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -148,7 +149,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -172,7 +173,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -199,7 +200,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -223,7 +224,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -257,7 +258,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: { ...results }, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); @@ -281,7 +282,7 @@ export function dataFrameAnalyticsRoutes({ xpackMainPlugin, router }: RouteIniti body: results, }); } catch (e) { - return response.forbidden({ body: e.message }); + return response.customError(wrapError(e)); } }) ); From 5174b07aa8f31085247f04a307ee6dfa0b63df82 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 2 Jan 2020 08:00:21 -0700 Subject: [PATCH 7/7] ensure error status gets passed correctly to wrapper --- x-pack/legacy/plugins/ml/server/client/error_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts b/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts index d800020038a38..6ab31d11f4b32 100644 --- a/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts +++ b/x-pack/legacy/plugins/ml/server/client/error_wrapper.ts @@ -8,7 +8,7 @@ import { boomify, isBoom } from 'boom'; import { ResponseError, CustomHttpResponseOptions } from 'src/core/server'; export function wrapError(error: any): CustomHttpResponseOptions { - const boom = isBoom(error) ? error : boomify(error); + const boom = isBoom(error) ? error : boomify(error, { statusCode: error.status }); return { body: boom, headers: boom.output.headers,