diff --git a/x-pack/legacy/plugins/ml/server/new_platform/datafeeds_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/datafeeds_schema.ts new file mode 100644 index 0000000000000..02677dcb107c2 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/new_platform/datafeeds_schema.ts @@ -0,0 +1,31 @@ +/* + * 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'; + +export const startDatafeedSchema = schema.object({ + start: schema.maybe(schema.oneOf([schema.number(), schema.string()])), + end: schema.maybe(schema.oneOf([schema.number(), schema.string()])), + timeout: schema.maybe(schema.any()), +}); + +export const datafeedConfigSchema = schema.object({ + datafeed_id: schema.maybe(schema.string()), + feed_id: schema.maybe(schema.string()), + aggregations: schema.maybe(schema.any()), + aggs: schema.maybe(schema.any()), + chunking_config: schema.maybe(schema.any()), + frequency: schema.maybe(schema.string()), + indices: schema.arrayOf(schema.string()), + indexes: schema.maybe(schema.arrayOf(schema.string())), + job_id: schema.maybe(schema.string()), + query: schema.maybe(schema.any()), + max_empty_searches: schema.maybe(schema.number()), + query_delay: schema.maybe(schema.string()), + script_fields: schema.maybe(schema.any()), + scroll_size: schema.maybe(schema.number()), + delayed_data_check_config: schema.maybe(schema.any()), +}); diff --git a/x-pack/legacy/plugins/ml/server/new_platform/job_validation_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/job_validation_schema.ts index 5917ec50884d8..5da825a905e8d 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/job_validation_schema.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/job_validation_schema.ts @@ -6,6 +6,7 @@ import { schema } from '@kbn/config-schema'; import { anomalyDetectionJobSchema } from './anomaly_detectors_schema'; +import { datafeedConfigSchema } from './datafeeds_schema'; export const estimateBucketSpanSchema = schema.object({ aggTypes: schema.arrayOf(schema.nullable(schema.string())), @@ -38,22 +39,6 @@ export const validateJobSchema = schema.object({ job: schema.object(anomalyDetectionJobSchema), }); -const datafeedConfigSchema = schema.object({ - datafeed_id: schema.string(), - aggregations: schema.maybe(schema.any()), - aggs: schema.maybe(schema.any()), - chunking_config: schema.maybe(schema.any()), - frequency: schema.maybe(schema.string()), - indices: schema.arrayOf(schema.string()), - indexes: schema.maybe(schema.arrayOf(schema.string())), - job_id: schema.string(), - query: schema.any(), - query_delay: schema.maybe(schema.string()), - script_fields: schema.maybe(schema.any()), - scroll_size: schema.maybe(schema.number()), - delayed_data_check_config: schema.maybe(schema.any()), -}); - export const validateCardinalitySchema = { ...anomalyDetectionJobSchema, datafeed_config: datafeedConfigSchema, 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 e006ad3d3718f..10961182be841 100644 --- a/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts +++ b/x-pack/legacy/plugins/ml/server/new_platform/plugin.ts @@ -27,7 +27,6 @@ import { mirrorPluginStatus } from '../../../../server/lib/mirror_plugin_status' import { LICENSE_TYPE } from '../../common/constants/license'; import { annotationRoutes } from '../routes/annotations'; import { jobRoutes } from '../routes/anomaly_detectors'; -// @ts-ignore: could not find declaration file for module import { dataFeedRoutes } from '../routes/datafeeds'; // @ts-ignore: could not find declaration file for module import { indicesRoutes } from '../routes/indices'; diff --git a/x-pack/legacy/plugins/ml/server/routes/apidoc.json b/x-pack/legacy/plugins/ml/server/routes/apidoc.json index 89751abdbe20d..7d1f13ead3fef 100644 --- a/x-pack/legacy/plugins/ml/server/routes/apidoc.json +++ b/x-pack/legacy/plugins/ml/server/routes/apidoc.json @@ -94,6 +94,17 @@ "ValidateCardinality", "ValidateJob", "NotificationSettings", - "GetNotificationSettings" + "GetNotificationSettings", + "DatafeedService", + "GetDatafeeds", + "GetDatafeed", + "GetDatafeedsStats", + "GetDatafeedStats", + "CreateDatafeed", + "UpdateDatafeed", + "DeleteDatafeed", + "StartDatafeed", + "StopDatafeed", + "PreviewDatafeed" ] } diff --git a/x-pack/legacy/plugins/ml/server/routes/datafeeds.js b/x-pack/legacy/plugins/ml/server/routes/datafeeds.js deleted file mode 100644 index daa83795ff7d2..0000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/datafeeds.js +++ /dev/null @@ -1,152 +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 { callWithRequestFactory } from '../client/call_with_request_factory'; -import { wrapError } from '../client/errors'; - -export function dataFeedRoutes({ commonRouteConfig, elasticsearchPlugin, route }) { - route({ - method: 'GET', - path: '/api/ml/datafeeds', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.datafeeds').catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/datafeeds/{datafeedId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - return callWithRequest('ml.datafeeds', { datafeedId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/datafeeds/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.datafeedStats').catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/datafeeds/{datafeedId}/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - return callWithRequest('ml.datafeedStats', { datafeedId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'PUT', - path: '/api/ml/datafeeds/{datafeedId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - const body = request.payload; - return callWithRequest('ml.addDatafeed', { datafeedId, body }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/datafeeds/{datafeedId}/_update', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - const body = request.payload; - return callWithRequest('ml.updateDatafeed', { datafeedId, body }).catch(resp => - wrapError(resp) - ); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'DELETE', - path: '/api/ml/datafeeds/{datafeedId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const options = { - datafeedId: request.params.datafeedId, - }; - const force = request.query.force; - if (force !== undefined) { - options.force = force; - } - return callWithRequest('ml.deleteDatafeed', options).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/datafeeds/{datafeedId}/_start', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - const start = request.payload.start; - const end = request.payload.end; - return callWithRequest('ml.startDatafeed', { datafeedId, start, end }).catch(resp => - wrapError(resp) - ); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/datafeeds/{datafeedId}/_stop', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - return callWithRequest('ml.stopDatafeed', { datafeedId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/datafeeds/{datafeedId}/_preview', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const datafeedId = request.params.datafeedId; - return callWithRequest('ml.datafeedPreview', { datafeedId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); -} diff --git a/x-pack/legacy/plugins/ml/server/routes/datafeeds.ts b/x-pack/legacy/plugins/ml/server/routes/datafeeds.ts new file mode 100644 index 0000000000000..9335403616cf7 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/datafeeds.ts @@ -0,0 +1,320 @@ +/* + * 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 { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { wrapError } from '../client/error_wrapper'; +import { RouteInitialization } from '../new_platform/plugin'; +import { startDatafeedSchema, datafeedConfigSchema } from '../new_platform/datafeeds_schema'; + +/** + * Routes for datafeed service + */ +export function dataFeedRoutes({ xpackMainPlugin, router }: RouteInitialization) { + /** + * @apiGroup DatafeedService + * + * @api {get} /api/ml/datafeeds Get all datafeeds + * @apiName GetDatafeeds + * @apiDescription Retrieves configuration information for datafeeds + */ + router.get( + { + path: '/api/ml/datafeeds', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.datafeeds'); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {get} /api/ml/datafeeds/:datafeedId Get datafeed for given datafeed id + * @apiName GetDatafeed + * @apiDescription Retrieves configuration information for datafeed + */ + router.get( + { + path: '/api/ml/datafeeds/{datafeedId}', + validate: { + params: schema.object({ datafeedId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.datafeeds', { datafeedId }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {get} /api/ml/datafeeds/_stats Get stats for all datafeeds + * @apiName GetDatafeedsStats + * @apiDescription Retrieves usage information for datafeeds + */ + router.get( + { + path: '/api/ml/datafeeds/_stats', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.datafeedStats'); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {get} /api/ml/datafeeds/:datafeedId/_stats Get datafeed stats for given datafeed id + * @apiName GetDatafeedStats + * @apiDescription Retrieves usage information for datafeed + */ + router.get( + { + path: '/api/ml/datafeeds/{datafeedId}/_stats', + validate: { + params: schema.object({ datafeedId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.datafeedStats', { + datafeedId, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {put} /api/ml/datafeeds/:datafeedId Creates datafeed + * @apiName CreateDatafeed + * @apiDescription Instantiates a datafeed + */ + router.put( + { + path: '/api/ml/datafeeds/{datafeedId}', + validate: { + params: schema.object({ datafeedId: schema.string() }), + body: datafeedConfigSchema, + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.addDatafeed', { + datafeedId, + body: request.body, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {post} /api/ml/datafeeds/:datafeedId/_update Updates datafeed for given datafeed id + * @apiName UpdateDatafeed + * @apiDescription Updates certain properties of a datafeed + */ + router.post( + { + path: '/api/ml/datafeeds/{datafeedId}/_update', + validate: { + params: schema.object({ datafeedId: schema.string() }), + body: datafeedConfigSchema, + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.updateDatafeed', { + datafeedId, + body: request.body, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {delete} /api/ml/datafeeds/:datafeedId Deletes datafeed + * @apiName DeleteDatafeed + * @apiDescription Deletes an existing datafeed + */ + router.delete( + { + path: '/api/ml/datafeeds/{datafeedId}', + validate: { + params: schema.object({ datafeedId: schema.string() }), + query: schema.maybe(schema.object({ force: schema.maybe(schema.any()) })), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const options: { datafeedId: string; force?: boolean } = { + datafeedId: request.params.jobId, + }; + const force = request.query.force; + if (force !== undefined) { + options.force = force; + } + + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.deleteDatafeed', options); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {post} /api/ml/datafeeds/:datafeedId/_start Starts datafeed for given datafeed id(s) + * @apiName StartDatafeed + * @apiDescription Starts one or more datafeeds + */ + router.post( + { + path: '/api/ml/datafeeds/{datafeedId}/_start', + validate: { + params: schema.object({ datafeedId: schema.string() }), + body: startDatafeedSchema, + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const { start, end } = request.body; + + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.startDatafeed', { + datafeedId, + start, + end, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {post} /api/ml/datafeeds/:datafeedId/_stop Stops datafeed for given datafeed id(s) + * @apiName StopDatafeed + * @apiDescription Stops one or more datafeeds + */ + router.post( + { + path: '/api/ml/datafeeds/{datafeedId}/_stop', + validate: { + params: schema.object({ datafeedId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.stopDatafeed', { + datafeedId, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup DatafeedService + * + * @api {get} /api/ml/datafeeds/:datafeedId/_preview Preview datafeed for given datafeed id + * @apiName PreviewDatafeed + * @apiDescription Previews a datafeed + */ + router.get( + { + path: '/api/ml/datafeeds/{datafeedId}/_preview', + validate: { + params: schema.object({ datafeedId: schema.string() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const datafeedId = request.params.datafeedId; + const resp = await context.ml!.mlClient.callAsCurrentUser('ml.datafeedPreview', { + datafeedId, + }); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); +}