diff --git a/x-pack/legacy/plugins/ml/public/application/services/job_service.js b/x-pack/legacy/plugins/ml/public/application/services/job_service.js index 9827d1a5f38a1a..fe3663d6a3ddb1 100644 --- a/x-pack/legacy/plugins/ml/public/application/services/job_service.js +++ b/x-pack/legacy/plugins/ml/public/application/services/job_service.js @@ -416,7 +416,7 @@ class JobService { return { success: true }; }) .catch(err => { - msgs.error( + msgs.notify.error( i18n.translate('xpack.ml.jobService.couldNotUpdateJobErrorMessage', { defaultMessage: 'Could not update job: {jobId}', values: { jobId }, @@ -435,7 +435,7 @@ class JobService { return { success: true, messages }; }) .catch(err => { - msgs.error( + msgs.notify.error( i18n.translate('xpack.ml.jobService.jobValidationErrorMessage', { defaultMessage: 'Job Validation Error: {errorMessage}', values: { errorMessage: err.message }, @@ -628,7 +628,7 @@ class JobService { return { success: true }; }) .catch(err => { - msgs.error( + msgs.notify.error( i18n.translate('xpack.ml.jobService.couldNotUpdateDatafeedErrorMessage', { defaultMessage: 'Could not update datafeed: {datafeedId}', values: { datafeedId }, @@ -659,7 +659,7 @@ class JobService { }) .catch(err => { console.log('jobService error starting datafeed:', err); - msgs.error( + msgs.notify.error( i18n.translate('xpack.ml.jobService.couldNotStartDatafeedErrorMessage', { defaultMessage: 'Could not start datafeed for {jobId}', values: { jobId }, @@ -692,15 +692,15 @@ class JobService { ); if (err.statusCode === 500) { - msgs.error(couldNotStopDatafeedErrorMessage); - msgs.error( + msgs.notify.error(couldNotStopDatafeedErrorMessage); + msgs.notify.error( i18n.translate('xpack.ml.jobService.requestMayHaveTimedOutErrorMessage', { defaultMessage: 'Request may have timed out and may still be running in the background.', }) ); } else { - msgs.error(couldNotStopDatafeedErrorMessage, err); + msgs.notify.error(couldNotStopDatafeedErrorMessage, err); } reject(err); }); diff --git a/x-pack/legacy/plugins/ml/server/new_platform/anomaly_detectors_schema.ts b/x-pack/legacy/plugins/ml/server/new_platform/anomaly_detectors_schema.ts new file mode 100644 index 00000000000000..392d3bfd847684 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/new_platform/anomaly_detectors_schema.ts @@ -0,0 +1,93 @@ +/* + * 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'; + +const detectorSchema = schema.object({ + identifier: schema.maybe(schema.string()), + function: schema.string(), + field_name: schema.maybe(schema.string()), + by_field_name: schema.maybe(schema.string()), + over_field_name: schema.maybe(schema.string()), + partition_field_name: schema.maybe(schema.string()), + detector_description: schema.maybe(schema.string()), +}); + +const customUrlSchema = { + url_name: schema.string(), + url_value: schema.string(), + time_range: schema.maybe(schema.any()), +}; + +const customSettingsSchema = schema.object({ + created_by: schema.maybe(schema.string()), + custom_urls: schema.maybe(schema.arrayOf(schema.maybe(schema.object({ ...customUrlSchema })))), +}); + +export const anomalyDetectionUpdateJobSchema = { + description: schema.maybe(schema.string()), + detectors: schema.maybe( + schema.arrayOf( + schema.maybe( + schema.object({ + detector_index: schema.number(), + custom_rules: schema.arrayOf( + schema.maybe( + schema.object({ + actions: schema.arrayOf(schema.string()), + conditions: schema.arrayOf(schema.any()), + scope: schema.maybe(schema.any()), + }) + ) + ), + }) + ) + ) + ), + custom_settings: schema.maybe(customSettingsSchema), + analysis_limits: schema.object({ + categorization_examples_limit: schema.maybe(schema.number()), + model_memory_limit: schema.maybe(schema.string()), + }), + groups: schema.maybe(schema.arrayOf(schema.maybe(schema.string()))), +}; + +export const anomalyDetectionJobSchema = { + analysis_config: schema.object({ + bucket_span: schema.maybe(schema.string()), + summary_count_field_name: schema.maybe(schema.string()), + detectors: schema.arrayOf(detectorSchema), + influencers: schema.arrayOf(schema.maybe(schema.string())), + categorization_field_name: schema.maybe(schema.string()), + }), + analysis_limits: schema.object({ + categorization_examples_limit: schema.maybe(schema.number()), + model_memory_limit: schema.maybe(schema.string()), + }), + create_time: schema.maybe(schema.number()), + custom_settings: schema.maybe(customSettingsSchema), + allow_lazy_open: schema.maybe(schema.any()), + data_counts: schema.maybe(schema.any()), + data_description: schema.object({ + time_field: schema.string(), + time_format: schema.maybe(schema.string()), + }), + datafeed_config: schema.maybe(schema.any()), + description: schema.maybe(schema.string()), + established_model_memory: schema.maybe(schema.number()), + finished_time: schema.maybe(schema.number()), + job_id: schema.string(), + job_type: schema.maybe(schema.string()), + job_version: schema.maybe(schema.string()), + groups: schema.arrayOf(schema.maybe(schema.string())), + model_plot_config: schema.maybe(schema.any()), + model_size_stats: schema.maybe(schema.any()), + model_snapshot_id: schema.maybe(schema.string()), + model_snapshot_min_version: schema.maybe(schema.string()), + model_snapshot_retention_days: schema.maybe(schema.number()), + results_index_name: schema.maybe(schema.string()), + state: schema.maybe(schema.string()), +}; diff --git a/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.js b/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.js deleted file mode 100644 index 54d447c2881515..00000000000000 --- a/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.js +++ /dev/null @@ -1,202 +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 jobRoutes({ commonRouteConfig, elasticsearchPlugin, route }) { - route({ - method: 'GET', - path: '/api/ml/anomaly_detectors', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.jobs').catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/anomaly_detectors/{jobId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - return callWithRequest('ml.jobs', { jobId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/anomaly_detectors/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.jobStats').catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/anomaly_detectors/{jobId}/_stats', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - return callWithRequest('ml.jobStats', { jobId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'PUT', - path: '/api/ml/anomaly_detectors/{jobId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - const body = request.payload; - return callWithRequest('ml.addJob', { jobId, body }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/{jobId}/_update', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - const body = request.payload; - return callWithRequest('ml.updateJob', { jobId, body }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/{jobId}/_open', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - return callWithRequest('ml.openJob', { jobId }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/{jobId}/_close', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const options = { - jobId: request.params.jobId, - }; - const force = request.query.force; - if (force !== undefined) { - options.force = force; - } - return callWithRequest('ml.closeJob', options).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'DELETE', - path: '/api/ml/anomaly_detectors/{jobId}', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const options = { - jobId: request.params.jobId, - }; - const force = request.query.force; - if (force !== undefined) { - options.force = force; - } - return callWithRequest('ml.deleteJob', options).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/_validate/detector', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const body = request.payload; - return callWithRequest('ml.validateDetector', { body }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/{jobId}/_forecast', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const jobId = request.params.jobId; - const duration = request.payload.duration; - return callWithRequest('ml.forecast', { jobId, duration }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'POST', - path: '/api/ml/anomaly_detectors/{jobId}/results/overall_buckets', - handler(request) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - return callWithRequest('ml.overallBuckets', { - jobId: request.params.jobId, - top_n: request.payload.topN, - bucket_span: request.payload.bucketSpan, - start: request.payload.start, - end: request.payload.end, - }).catch(resp => wrapError(resp)); - }, - config: { - ...commonRouteConfig, - }, - }); - - route({ - method: 'GET', - path: '/api/ml/anomaly_detectors/{jobId}/results/categories/{categoryId}', - handler(request, reply) { - const callWithRequest = callWithRequestFactory(elasticsearchPlugin, request); - const options = { - jobId: request.params.jobId, - categoryId: request.params.categoryId, - }; - return callWithRequest('ml.categories', options) - .then(resp => reply(resp)) - .catch(resp => reply(wrapError(resp))); - }, - config: { - ...commonRouteConfig, - }, - }); -} diff --git a/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts b/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts new file mode 100644 index 00000000000000..64af1f67bce297 --- /dev/null +++ b/x-pack/legacy/plugins/ml/server/routes/anomaly_detectors.ts @@ -0,0 +1,459 @@ +/* + * 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 { wrapError } from '../client/error_wrapper'; +import { licensePreRoutingFactory } from '../new_platform/licence_check_pre_routing_factory'; +import { RouteInitialization } from '../new_platform/plugin'; +import { + anomalyDetectionJobSchema, + anomalyDetectionUpdateJobSchema, +} from '../new_platform/anomaly_detectors_schema'; + +/** + * Routes for the anomaly detectors + */ +export function jobRoutes({ xpackMainPlugin, router }: RouteInitialization) { + /** + * @apiGroup AnomalyDetectors + * + * @api {get} /api/ml/anomaly_detectors Get anomaly detectors data + * @apiName GetAnomalyDetectors + * @apiDescription Returns the list of anomaly detection jobs. + * + * @apiSuccess {Number} count + * @apiSuccess {Object[]} jobs + */ + router.get( + { + path: '/api/ml/anomaly_detectors', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.jobs'); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {get} /api/ml/anomaly_detectors/:jobId Get anomaly detection data by id + * @apiName GetAnomalyDetectorsById + * @apiDescription Returns the anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.get( + { + path: '/api/ml/anomaly_detectors/{jobId}', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { jobId } = request.params; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.jobs', { jobId }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {get} /api/ml/anomaly_detectors/_stats Get anomaly detection stats + * @apiName GetAnomalyDetectorsStats + * @apiDescription Returns anomaly detection jobs statistics. + * + * @apiSuccess {Number} count + * @apiSuccess {Object[]} jobs + */ + router.get( + { + path: '/api/ml/anomaly_detectors/_stats', + validate: false, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.jobStats'); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {get} /api/ml/anomaly_detectors/:jobId/_stats Get stats for requested anomaly detection job + * @apiName GetAnomalyDetectorsStatsById + * @apiDescription Returns anomaly detection job statistics. + * + * @apiParam {String} jobId Job ID. + */ + router.get( + { + path: '/api/ml/anomaly_detectors/{jobId}/_stats', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { jobId } = request.params; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.jobStats', { jobId }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {put} /api/ml/anomaly_detectors/:jobId Instantiate an anomaly detection job + * @apiName CreateAnomalyDetectors + * @apiDescription Creates an anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.put( + { + path: '/api/ml/anomaly_detectors/{jobId}', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + body: schema.object({ ...anomalyDetectionJobSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { jobId } = request.params; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.addJob', { + jobId, + body: request.body, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/_update Update an anomaly detection job + * @apiName UpdateAnomalyDetectors + * @apiDescription Updates certain properties of an anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/_update', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + body: schema.object({ ...anomalyDetectionUpdateJobSchema }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { jobId } = request.params; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.updateJob', { + jobId, + body: request.body, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/_open Open specified job + * @apiName OpenAnomalyDetectorsJob + * @apiDescription Opens an anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/_open', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const { jobId } = request.params; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.openJob', { + jobId, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/_close Close specified job + * @apiName CloseAnomalyDetectorsJob + * @apiDescription Closes an anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/_close', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const options: { jobId: string; force?: boolean } = { + jobId: request.params.jobId, + }; + const force = request.query.force; + if (force !== undefined) { + options.force = force; + } + const results = await context.ml!.mlClient.callAsCurrentUser('ml.closeJob', options); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {delete} /api/ml/anomaly_detectors/:jobId Delete specified job + * @apiName DeleteAnomalyDetectorsJob + * @apiDescription Deletes specified anomaly detection job. + * + * @apiParam {String} jobId Job ID. + */ + router.delete( + { + path: '/api/ml/anomaly_detectors/{jobId}', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const options: { jobId: string; force?: boolean } = { + jobId: request.params.jobId, + }; + const force = request.query.force; + if (force !== undefined) { + options.force = force; + } + const results = await context.ml!.mlClient.callAsCurrentUser('ml.deleteJob', options); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/_validate/detector Validate detector + * @apiName ValidateAnomalyDetector + * @apiDescription Validates specified detector. + * + * @apiParam {String} jobId Job ID. + */ + router.post( + { + path: '/api/ml/anomaly_detectors/_validate/detector', + validate: { + body: schema.any(), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.validateDetector', { + body: request.body, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/_forecast Create forecast for specified job + * @apiName ForecastAnomalyDetector + * @apiDescription Creates a forecast for the specified anomaly detection job, predicting the future behavior of a time series by using its historical behavior. + * + * @apiParam {String} jobId Job ID. + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/_forecast', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + body: schema.object({ duration: schema.any() }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const jobId = request.params.jobId; + const duration = request.body.duration; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.forecast', { + jobId, + duration, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {post} /api/ml/anomaly_detectors/:jobId/results/overall_buckets Obtain overall bucket scores for the specified job ID + * @apiName GetOverallBuckets + * @apiDescription Retrieves overall bucket results that summarize the bucket results of multiple anomaly detection jobs. + * + * @apiParam {String} jobId Job ID. + * + * @apiSuccess {Number} count + * @apiSuccess {Object[]} overall_buckets + */ + router.post( + { + path: '/api/ml/anomaly_detectors/{jobId}/results/overall_buckets', + validate: { + params: schema.object({ + jobId: schema.string(), + }), + body: schema.object({ + topN: schema.number(), + bucketSpan: schema.string(), + start: schema.number(), + end: schema.number(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const results = await context.ml!.mlClient.callAsCurrentUser('ml.overallBuckets', { + jobId: request.params.jobId, + top_n: request.body.topN, + bucket_span: request.body.bucketSpan, + start: request.body.start, + end: request.body.end, + }); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); + + /** + * @apiGroup AnomalyDetectors + * + * @api {get} /api/ml/anomaly_detectors/:jobId/results/categories/:categoryId Get results category data by job id and category id + * @apiName GetCategories + * @apiDescription Returns the categories results for the specified job ID and category ID. + * + * @apiParam {String} jobId Job ID. + * @apiParam {String} categoryId Category ID. + */ + router.get( + { + path: '/api/ml/anomaly_detectors/{jobId}/results/categories/{categoryId}', + validate: { + params: schema.object({ + categoryId: schema.string(), + jobId: schema.string(), + }), + }, + }, + licensePreRoutingFactory(xpackMainPlugin, async (context, request, response) => { + try { + const options = { + jobId: request.params.jobId, + categoryId: request.params.categoryId, + }; + const results = await context.ml!.mlClient.callAsCurrentUser('ml.categories', options); + return response.ok({ + body: { ...results }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); +} diff --git a/x-pack/legacy/plugins/ml/server/routes/apidoc.json b/x-pack/legacy/plugins/ml/server/routes/apidoc.json index 4a3b93b9b866f8..f2ed202ae47771 100644 --- a/x-pack/legacy/plugins/ml/server/routes/apidoc.json +++ b/x-pack/legacy/plugins/ml/server/routes/apidoc.json @@ -19,6 +19,20 @@ "GetDataFrameAnalyticsMessages", "DataVisualizer", "GetOverallStats", - "GetStatsForFields" + "GetStatsForFields", + "AnomalyDetectors", + "GetAnomalyDetectors", + "GetAnomalyDetectorsById", + "GetAnomalyDetectorsStats", + "GetAnomalyDetectorsStatsById", + "CreateAnomalyDetectors", + "UpdateAnomalyDetectors", + "OpenAnomalyDetectorsJob", + "CloseAnomalyDetectorsJob", + "DeleteAnomalyDetectorsJob", + "ValidateAnomalyDetector", + "ForecastAnomalyDetector", + "GetOverallBuckets", + "GetCategories" ] }