[ML] Versioning all ML APIs (#156949)

Adds versioning to all of the ML kibana APIs.
Versions are added to the server side routes and to the client side
functions which call the routes.
Makes some small refactors to ensure only the functions inside
`ml/public/application/services/ml_api_service/` are where the ML APIs
are called.
Updates external plugins which call ML APIs to add the new versioning.
Updates API tests to add the API version to the request headers.

Our one public API has been given the version `'2023-05-15'`, all of the
internal APIs have been given the version `'1'`.

**Public APIs:**
`/api/ml/saved_objects/sync`

**Internal APIS:**
`/internal/ml/alerting/preview`
`/internal/ml/annotations`
`/internal/ml/annotations/index`
`/internal/ml/annotations/delete/{annotationId}`
`/internal/ml/anomaly_detectors`
`/internal/ml/anomaly_detectors/{jobId}`
`/internal/ml/anomaly_detectors/_stats`
`/internal/ml/anomaly_detectors/{jobId}/_stats`
`/internal/ml/anomaly_detectors/{jobId}`
`/internal/ml/anomaly_detectors/{jobId}/_update`
`/internal/ml/anomaly_detectors/{jobId}/_open`
`/internal/ml/anomaly_detectors/{jobId}/_close`
`/internal/ml/anomaly_detectors/{jobId}/_reset`
`/internal/ml/anomaly_detectors/{jobId}`
`/internal/ml/anomaly_detectors/_validate/detector`
`/internal/ml/anomaly_detectors/{jobId}/_forecast`
`/internal/ml/anomaly_detectors/{jobId}/results/records`
`/internal/ml/anomaly_detectors/{jobId}/results/buckets/{timestamp?}`
`/internal/ml/anomaly_detectors/{jobId}/results/overall_buckets`
`/internal/ml/anomaly_detectors/{jobId}/results/categories/{categoryId}`
`/internal/ml/anomaly_detectors/{jobId}/model_snapshots`
`/internal/ml/anomaly_detectors/{jobId}/model_snapshots/{snapshotId}`

`/internal/ml/anomaly_detectors/{jobId}/model_snapshots/{snapshotId}/_update`
`/internal/ml/anomaly_detectors/{jobId}/model_snapshots/{snapshotId}`
`/internal/ml/calendars`
`/internal/ml/calendars/{calendarIds}`
`/internal/ml/calendars`
`/internal/ml/calendars/{calendarId}`
`/internal/ml/calendars/{calendarId}`
`/internal/ml/data_frame/analytics`
`/internal/ml/data_frame/analytics/{analyticsId}`
`/internal/ml/data_frame/analytics/_stats`
`/internal/ml/data_frame/analytics/{analyticsId}/_stats`
`/internal/ml/data_frame/analytics/{analyticsId}`
`/internal/ml/data_frame/_evaluate`
`/internal/ml/data_frame/analytics/_explain`
`/internal/ml/data_frame/analytics/{analyticsId}`
`/internal/ml/data_frame/analytics/{analyticsId}/_start`
`/internal/ml/data_frame/analytics/{analyticsId}/_stop`
`/internal/ml/data_frame/analytics/{analyticsId}/_update`
`/internal/ml/data_frame/analytics/{analyticsId}/messages`
`/internal/ml/data_frame/analytics/jobs_exist`
`/internal/ml/data_frame/analytics/map/{analyticsId}`
`/internal/ml/data_frame/analytics/new_job_caps/{indexPattern}`
`/internal/ml/data_frame/analytics/validate`
`/internal/ml/data_visualizer/get_field_histograms/{indexPattern}`
`/internal/ml/datafeeds`
`/internal/ml/datafeeds/{datafeedId}`
`/internal/ml/datafeeds/_stats`
`/internal/ml/datafeeds/{datafeedId}/_stats`
`/internal/ml/datafeeds/{datafeedId}`
`/internal/ml/datafeeds/{datafeedId}/_update`
`/internal/ml/datafeeds/{datafeedId}`
`/internal/ml/datafeeds/{datafeedId}/_start`
`/internal/ml/datafeeds/{datafeedId}/_stop`
`/internal/ml/datafeeds/{datafeedId}/_preview`
`/internal/ml/fields_service/field_cardinality`
`/internal/ml/fields_service/time_field_range`
`/internal/ml/filters`
`/internal/ml/filters/{filterId}`
`/internal/ml/filters`
`/internal/ml/filters/{filterId}`
`/internal/ml/filters/{filterId}`
`/internal/ml/filters/_stats`
`/internal/ml/indices/field_caps`
`/internal/ml/job_audit_messages/messages/{jobId}`
`/internal/ml/job_audit_messages/messages`
`/internal/ml/job_audit_messages/clear_messages`
`/internal/ml/jobs/force_start_datafeeds`
`/internal/ml/jobs/stop_datafeeds`
`/internal/ml/jobs/delete_jobs`
`/internal/ml/jobs/close_jobs`
`/internal/ml/jobs/reset_jobs`
`/internal/ml/jobs/force_stop_and_close_job`
`/internal/ml/jobs/jobs_summary`
`/internal/ml/jobs/jobs_with_geo`
`/internal/ml/jobs/jobs_with_time_range`
`/internal/ml/jobs/job_for_cloning`
`/internal/ml/jobs/jobs`
`/internal/ml/jobs/groups`
`/internal/ml/jobs/update_groups`
`/internal/ml/jobs/blocking_jobs_tasks`
`/internal/ml/jobs/jobs_exist`
`/internal/ml/jobs/new_job_caps/{indexPattern}`
`/internal/ml/jobs/new_job_line_chart`
`/internal/ml/jobs/new_job_population_chart`
`/internal/ml/jobs/all_jobs_and_group_ids`
`/internal/ml/jobs/look_back_progress`
`/internal/ml/jobs/categorization_field_examples`
`/internal/ml/jobs/top_categories`
`/internal/ml/jobs/datafeed_preview`
`/internal/ml/jobs/revert_model_snapshot`
`/internal/ml/jobs/bulk_create`
`/internal/ml/validate/estimate_bucket_span`
`/internal/ml/validate/calculate_model_memory_limit`
`/internal/ml/validate/cardinality`
`/internal/ml/validate/job`
`/internal/ml/validate/datafeed_preview`
`/internal/ml/json_schema`
`/internal/ml/management/list/{listType}`
`/internal/ml/model_management/nodes_overview`
`/internal/ml/model_management/memory_usage`
`/internal/ml/modules/recognize/{indexPatternTitle}`
`/internal/ml/modules/get_module/{moduleId?}`
`/internal/ml/modules/setup/{moduleId}`
`/internal/ml/modules/jobs_exist/{moduleId}`
`/internal/ml/notifications`
`/internal/ml/notifications/count`
`/internal/ml/results/anomalies_table_data`
`/internal/ml/results/category_definition`
`/internal/ml/results/max_anomaly_score`
`/internal/ml/results/category_examples`
`/internal/ml/results/partition_fields_values`
`/internal/ml/results/anomaly_search`
`/internal/ml/results/{jobId}/categorizer_stats`
`/internal/ml/results/category_stopped_partitions`
`/internal/ml/results/datafeed_results_chart`
`/internal/ml/results/anomaly_charts`
`/internal/ml/results/anomaly_records`
`/internal/ml/saved_objects/status`
`/internal/ml/saved_objects/initialize`
`/internal/ml/saved_objects/sync_check`
`/internal/ml/saved_objects/update_jobs_spaces`
`/internal/ml/saved_objects/update_trained_models_spaces`
`/internal/ml/saved_objects/remove_item_from_current_space`
`/internal/ml/saved_objects/jobs_spaces`
`/internal/ml/saved_objects/trained_models_spaces`
`/internal/ml/saved_objects/can_delete_ml_space_aware_item/{jobType}`
`/internal/ml/_has_privileges`
`/internal/ml/ml_capabilities`
`/internal/ml/ml_node_count`
`/internal/ml/info`
`/internal/ml/es_search`
`/internal/ml/index_exists`
`/internal/ml/trained_models/{modelId?}`
`/internal/ml/trained_models/_stats`
`/internal/ml/trained_models/{modelId}/_stats`
`/internal/ml/trained_models/{modelId}/pipelines`
`/internal/ml/trained_models/{modelId}`
`/internal/ml/trained_models/{modelId}`
`/internal/ml/trained_models/{modelId}/deployment/_start`

`/internal/ml/trained_models/{modelId}/{deploymentId}/deployment/_update`
`/internal/ml/trained_models/{modelId}/{deploymentId}/deployment/_stop`
`/internal/ml/trained_models/pipeline_simulate`
`/internal/ml/trained_models/infer/{modelId}/{deploymentId}`
This commit is contained in:
James Gowdy 2023-05-23 21:21:22 +01:00 committed by GitHub
parent 46dc7ff1d7
commit 203d3068e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
190 changed files with 5969 additions and 4789 deletions

View file

@ -22,7 +22,7 @@ import type { GetTimeFieldRangeResponse } from './types';
*/
export type SetFullTimeRangeApiPath =
| '/internal/file_upload/time_field_range'
| '/api/ml/fields_service/time_field_range';
| '/internal/ml/fields_service/time_field_range';
/**
* Determines the full available time range of the given Data View and updates

View file

@ -18,7 +18,7 @@ describe('MLModelsApiLogic', () => {
it('calls the ml api', async () => {
http.get.mockResolvedValue(mlModelStats);
const result = await getMLModelsStats();
expect(http.get).toHaveBeenCalledWith('/api/ml/trained_models/_stats');
expect(http.get).toHaveBeenCalledWith('/internal/ml/trained_models/_stats', { version: '1' });
expect(result).toEqual(mlModelStats);
});
});

View file

@ -17,7 +17,10 @@ export interface GetMlModelsStatsResponse {
}
export const getMLModelsStats = async () => {
return await HttpLogic.values.http.get<GetMlModelsStatsResponse>('/api/ml/trained_models/_stats');
return await HttpLogic.values.http.get<GetMlModelsStatsResponse>(
'/internal/ml/trained_models/_stats',
{ version: '1' }
);
};
export const MLModelsStatsApiLogic = createApiLogic(

View file

@ -18,8 +18,9 @@ describe('MLModelsApiLogic', () => {
it('calls the ml api', async () => {
http.get.mockResolvedValue(mlModels);
const result = await getMLModels();
expect(http.get).toHaveBeenCalledWith('/api/ml/trained_models', {
expect(http.get).toHaveBeenCalledWith('/internal/ml/trained_models', {
query: { size: 1000, with_pipelines: true },
version: '1',
});
expect(result).toEqual(mlModels);
});

View file

@ -14,9 +14,13 @@ export type GetMlModelsArgs = number | undefined;
export type GetMlModelsResponse = TrainedModelConfigResponse[];
export const getMLModels = async (size: GetMlModelsArgs = 1000) => {
return await HttpLogic.values.http.get<TrainedModelConfigResponse[]>('/api/ml/trained_models', {
query: { size, with_pipelines: true },
});
return await HttpLogic.values.http.get<TrainedModelConfigResponse[]>(
'/internal/ml/trained_models',
{
query: { size, with_pipelines: true },
version: '1',
}
);
};
export const MLModelsApiLogic = createApiLogic(['ml_models_api_logic'], getMLModels, {

View file

@ -24,8 +24,9 @@ export const callDeleteJobs = async <JobType extends string>(
const { spaceId, logViewId, jobTypes } = requestArgs;
// NOTE: Deleting the jobs via this API will delete the datafeeds at the same time
const deleteJobsResponse = await fetch('/api/ml/jobs/delete_jobs', {
const deleteJobsResponse = await fetch('/internal/ml/jobs/delete_jobs', {
method: 'POST',
version: '1',
body: JSON.stringify(
deleteJobsRequestPayloadRT.encode({
jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, jobType)),
@ -37,7 +38,9 @@ export const callDeleteJobs = async <JobType extends string>(
};
export const callGetJobDeletionTasks = async (fetch: HttpHandler) => {
const jobDeletionTasksResponse = await fetch('/api/ml/jobs/deleting_jobs_tasks');
const jobDeletionTasksResponse = await fetch('/internal/ml/jobs/deleting_jobs_tasks', {
version: '1',
});
return decodeOrThrow(getJobDeletionTasksResponsePayloadRT)(jobDeletionTasksResponse);
};
@ -55,8 +58,9 @@ export const callStopDatafeeds = async <JobType extends string>(
const { spaceId, logViewId, jobTypes } = requestArgs;
// Stop datafeed due to https://github.com/elastic/kibana/issues/44652
const stopDatafeedResponse = await fetch('/api/ml/jobs/stop_datafeeds', {
const stopDatafeedResponse = await fetch('/internal/ml/jobs/stop_datafeeds', {
method: 'POST',
version: '1',
body: JSON.stringify(
stopDatafeedsRequestPayloadRT.encode({
datafeedIds: jobTypes.map((jobType) => getDatafeedId(spaceId, logViewId, jobType)),

View file

@ -22,8 +22,9 @@ export const callJobsSummaryAPI = async <JobType extends string>(
fetch: HttpHandler
) => {
const { spaceId, logViewId, jobTypes } = requestArgs;
const response = await fetch('/api/ml/jobs/jobs_summary', {
const response = await fetch('/internal/ml/jobs/jobs_summary', {
method: 'POST',
version: '1',
body: JSON.stringify(
fetchJobStatusRequestPayloadRT.encode({
jobIds: jobTypes.map((jobType) => getJobId(spaceId, logViewId, jobType)),

View file

@ -12,8 +12,9 @@ import { jobCustomSettingsRT } from '../../../../../common/log_analysis';
import { decodeOrThrow } from '../../../../../common/runtime_types';
export const callGetMlModuleAPI = async (moduleId: string, fetch: HttpHandler) => {
const response = await fetch(`/api/ml/modules/get_module/${moduleId}`, {
const response = await fetch(`/internal/ml/modules/get_module/${moduleId}`, {
method: 'GET',
version: '1',
});
return decodeOrThrow(getMlModuleResponsePayloadRT)(response);

View file

@ -38,8 +38,9 @@ export const callSetupMlModuleAPI = async (requestArgs: RequestArgs, fetch: Http
useDedicatedIndex = false,
} = requestArgs;
const response = await fetch(`/api/ml/modules/setup/${moduleId}`, {
const response = await fetch(`/internal/ml/modules/setup/${moduleId}`, {
method: 'POST',
version: '1',
body: JSON.stringify(
setupMlModuleRequestPayloadRT.encode({
start,

View file

@ -24,7 +24,9 @@ export const useLogAnalysisCapabilities = () => {
{
cancelPreviousOn: 'resolution',
createPromise: async () => {
const rawResponse = await services.http.fetch('/api/ml/ml_capabilities');
const rawResponse = await services.http.fetch('/internal/ml/ml_capabilities', {
version: '1',
});
return decodeOrThrow(getMlCapabilitiesResponsePayloadRT)(rawResponse);
},

View file

@ -23,8 +23,9 @@ export const callDeleteJobs = async <JobType extends string>(
const { spaceId, sourceId, jobTypes } = requestArgs;
// NOTE: Deleting the jobs via this API will delete the datafeeds at the same time
const deleteJobsResponse = await fetch('/api/ml/jobs/delete_jobs', {
const deleteJobsResponse = await fetch('/internal/ml/jobs/delete_jobs', {
method: 'POST',
version: '1',
body: JSON.stringify(
deleteJobsRequestPayloadRT.encode({
jobIds: jobTypes.map((jobType) => getJobId(spaceId, sourceId, jobType)),
@ -36,7 +37,9 @@ export const callDeleteJobs = async <JobType extends string>(
};
export const callGetJobDeletionTasks = async (fetch: HttpHandler) => {
const jobDeletionTasksResponse = await fetch('/api/ml/jobs/deleting_jobs_tasks');
const jobDeletionTasksResponse = await fetch('/internal/ml/jobs/deleting_jobs_tasks', {
version: '1',
});
return decodeOrThrow(getJobDeletionTasksResponsePayloadRT)(jobDeletionTasksResponse);
};
@ -54,8 +57,9 @@ export const callStopDatafeeds = async <JobType extends string>(
const { spaceId, sourceId, jobTypes } = requestArgs;
// Stop datafeed due to https://github.com/elastic/kibana/issues/44652
const stopDatafeedResponse = await fetch('/api/ml/jobs/stop_datafeeds', {
const stopDatafeedResponse = await fetch('/internal/ml/jobs/stop_datafeeds', {
method: 'POST',
version: '1',
body: JSON.stringify(
stopDatafeedsRequestPayloadRT.encode({
datafeedIds: jobTypes.map((jobType) => getDatafeedId(spaceId, sourceId, jobType)),

View file

@ -22,8 +22,9 @@ export const callJobsSummaryAPI = async <JobType extends string>(
fetch: HttpHandler
) => {
const { spaceId, sourceId, jobTypes } = requestArgs;
const response = await fetch('/api/ml/jobs/jobs_summary', {
const response = await fetch('/internal/ml/jobs/jobs_summary', {
method: 'POST',
version: '1',
body: JSON.stringify(
fetchJobStatusRequestPayloadRT.encode({
jobIds: jobTypes.map((jobType) => getJobId(spaceId, sourceId, jobType)),

View file

@ -12,8 +12,9 @@ import { jobCustomSettingsRT } from '../../../../common/log_analysis';
import { decodeOrThrow } from '../../../../common/runtime_types';
export const callGetMlModuleAPI = async (moduleId: string, fetch: HttpHandler) => {
const response = await fetch(`/api/ml/modules/get_module/${moduleId}`, {
const response = await fetch(`/internal/ml/modules/get_module/${moduleId}`, {
method: 'GET',
version: '1',
});
return decodeOrThrow(getMlModuleResponsePayloadRT)(response);

View file

@ -36,8 +36,9 @@ export const callSetupMlModuleAPI = async (requestArgs: RequestArgs, fetch: Http
query,
} = requestArgs;
const response = await fetch(`/api/ml/modules/setup/${moduleId}`, {
const response = await fetch(`/internal/ml/modules/setup/${moduleId}`, {
method: 'POST',
version: '1',
body: JSON.stringify(
setupMlModuleRequestPayloadRT.encode({
start,

View file

@ -27,7 +27,9 @@ export const useInfraMLCapabilities = () => {
{
cancelPreviousOn: 'resolution',
createPromise: async () => {
const rawResponse = await services.http.fetch('/api/ml/ml_capabilities');
const rawResponse = await services.http.fetch('/internal/ml/ml_capabilities', {
version: '1',
});
return pipe(
getMlCapabilitiesResponsePayloadRT.decode(rawResponse),

View file

@ -13,4 +13,5 @@ export const PLUGIN_ICON_SOLUTION = 'logoKibana';
export const ML_APP_NAME = i18n.translate('xpack.ml.navMenu.mlAppNameText', {
defaultMessage: 'Machine Learning',
});
export const ML_BASE_PATH = '/api/ml';
export const ML_INTERNAL_BASE_PATH = '/internal/ml';
export const ML_EXTERNAL_BASE_PATH = '/api/ml';

View file

@ -90,7 +90,7 @@ export interface MlSummaryJob {
/**
* Used in older implementations of the job config, where the datafeed was placed inside the job for convenience.
* This will be populated if the job's id has been passed to the /api/ml/jobs/jobs_summary endpoint.
* This will be populated if the job's id has been passed to the /internal/ml/jobs/jobs_summary endpoint.
*/
fullJob?: CombinedJob;

View file

@ -58,6 +58,14 @@ export interface Module {
kibana: KibanaObjects;
}
export interface RecognizeResult {
id: string;
title: string;
query: any;
description: string;
logo: Logo;
}
export interface FileBasedModule extends Omit<Module, 'jobs' | 'datafeeds' | 'kibana'> {
jobs: Array<{ file: string; id: string }>;
datafeeds: Array<{ file: string; job_id: string; id: string }>;

View file

@ -916,3 +916,20 @@ export function isKnownEmptyQuery(query: QueryDslQueryContainer) {
return false;
}
/**
* Extract unique influencers from the job or collection of jobs
* @param jobs
*/
export function extractInfluencers(jobs: Job | Job[]): string[] {
if (!Array.isArray(jobs)) {
jobs = [jobs];
}
const influencers = new Set<string>();
for (const job of jobs) {
for (const influencer of job.analysis_config.influencers || []) {
influencers.add(influencer);
}
}
return Array.from(influencers);
}

View file

@ -23,26 +23,18 @@ import { mlNodesAvailable, getMlNodeCount } from '../../ml_nodes_check/check_ml_
import { checkPermission } from '../../capabilities/check_capabilities';
import { MlPageHeader } from '../../components/page_header';
interface RecognizerModule {
id: string;
title: string;
query: Record<string, object>;
description: string;
logo: {
icon: string;
};
}
export const IndexDataVisualizerPage: FC = () => {
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
const {
services: {
http,
docLinks,
dataVisualizer,
data: {
dataViews: { get: getDataView },
},
mlServices: {
mlApiServices: { recognizeIndex },
},
},
} = useMlKibana();
const mlLocator = useMlLocator()!;
@ -140,18 +132,14 @@ export const IndexDataVisualizerPage: FC = () => {
const getAsyncRecognizedModuleCards = async (params: GetAdditionalLinksParams) => {
const { dataViewId, dataViewTitle } = params;
try {
const modules = await http.fetch<RecognizerModule[]>(
`/api/ml/modules/recognize/${dataViewTitle}`,
{
method: 'GET',
}
);
const modules = await recognizeIndex({ indexPatternTitle: dataViewTitle! });
return modules?.map(
(m): ResultLink => ({
id: m.id,
title: m.title,
description: m.description,
icon: m.logo.icon,
icon: m.logo?.icon ?? '',
type: 'index',
getUrl: async () => {
return await mlLocator.getUrl({

View file

@ -13,6 +13,7 @@ import moment from 'moment';
import { FullTimeRangeSelector, FROZEN_TIER_PREFERENCE } from '@kbn/ml-date-picker';
import { useTimefilter, type GetTimeFieldRangeResponse } from '@kbn/ml-date-picker';
import { useStorage } from '@kbn/ml-local-storage';
import { ML_INTERNAL_BASE_PATH } from '../../../../../../../common/constants/app';
import { WizardNav } from '../wizard_nav';
import { StepProps, WIZARD_STEPS } from '../step_types';
import { JobCreatorContext } from '../job_creator_context';
@ -135,7 +136,7 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep })
disabled={false}
callback={fullTimeRangeCallback}
timefilter={timefilter}
apiPath="/api/ml/fields_service/time_field_range"
apiPath={`${ML_INTERNAL_BASE_PATH}/fields_service/time_field_range`}
/>
</EuiFlexItem>
<EuiFlexItem />

View file

@ -7,25 +7,23 @@
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Job, JobId } from '../../../common/types/anomaly_detection_jobs';
import { basePath } from './ml_api_service';
import type { Job, JobId } from '../../../common/types/anomaly_detection_jobs';
import { HttpService } from './http_service';
import { type MlApiServices, mlApiServicesProvider } from './ml_api_service';
export class AnomalyDetectorService {
private readonly apiBasePath = basePath() + '/anomaly_detectors';
private mlApiServices: MlApiServices;
constructor(private httpService: HttpService) {}
constructor(httpService: HttpService) {
this.mlApiServices = mlApiServicesProvider(httpService);
}
/**
* Fetches a single job object
* @param jobId
*/
getJobById$(jobId: JobId): Observable<Job> {
return this.httpService
.http$<{ count: number; jobs: Job[] }>({
path: `${this.apiBasePath}/${jobId}`,
})
.pipe(map((response) => response.jobs[0]));
return this.getJobs$([jobId]).pipe(map((jobs) => jobs[0]));
}
/**
@ -33,27 +31,8 @@ export class AnomalyDetectorService {
* @param jobIds
*/
getJobs$(jobIds: JobId[]): Observable<Job[]> {
return this.httpService
.http$<{ count: number; jobs: Job[] }>({
path: `${this.apiBasePath}/${jobIds.join(',')}`,
})
return this.mlApiServices
.getJobs$({ jobId: jobIds.join(',') })
.pipe(map((response) => response.jobs));
}
/**
* Extract unique influencers from the job or collection of jobs
* @param jobs
*/
extractInfluencers(jobs: Job | Job[]): string[] {
if (!Array.isArray(jobs)) {
jobs = [jobs];
}
const influencers = new Set<string>();
for (const job of jobs) {
for (const influencer of job.analysis_config.influencers || []) {
influencers.add(influencer);
}
}
return Array.from(influencers);
}
}

View file

@ -8,7 +8,7 @@
import { useMemo } from 'react';
import { HttpService } from '../http_service';
import { useMlKibana } from '../../contexts/kibana';
import { ML_BASE_PATH } from '../../../../common/constants/app';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import type {
MlAnomalyDetectionAlertParams,
PreviewResponse,
@ -23,9 +23,10 @@ export const alertingApiProvider = (httpService: HttpService) => {
}): Promise<PreviewResponse> {
const body = JSON.stringify(params);
return httpService.http<PreviewResponse>({
path: `${ML_BASE_PATH}/alerting/preview`,
path: `${ML_INTERNAL_BASE_PATH}/alerting/preview`,
method: 'POST',
body,
version: '1',
});
},
};

View file

@ -6,10 +6,10 @@
*/
import { useMemo } from 'react';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { HttpService } from '../http_service';
import { useMlKibana } from '../../contexts/kibana';
import type { Annotation, GetAnnotationsResponse } from '../../../../common/types/annotations';
import { basePath } from '.';
export const annotationsApiProvider = (httpService: HttpService) => ({
getAnnotations$(obj: {
@ -22,9 +22,10 @@ export const annotationsApiProvider = (httpService: HttpService) => ({
}) {
const body = JSON.stringify(obj);
return httpService.http$<GetAnnotationsResponse>({
path: `${basePath()}/annotations`,
path: `${ML_INTERNAL_BASE_PATH}/annotations`,
method: 'POST',
body,
version: '1',
});
},
@ -38,24 +39,27 @@ export const annotationsApiProvider = (httpService: HttpService) => ({
}) {
const body = JSON.stringify(obj);
return httpService.http<GetAnnotationsResponse>({
path: `${basePath()}/annotations`,
path: `${ML_INTERNAL_BASE_PATH}/annotations`,
method: 'POST',
body,
version: '1',
});
},
indexAnnotation(obj: Annotation) {
const body = JSON.stringify(obj);
return httpService.http<any>({
path: `${basePath()}/annotations/index`,
path: `${ML_INTERNAL_BASE_PATH}/annotations/index`,
method: 'PUT',
body,
version: '1',
});
},
deleteAnnotation(id: string) {
return httpService.http<any>({
path: `${basePath()}/annotations/delete/${id}`,
path: `${ML_INTERNAL_BASE_PATH}/annotations/delete/${id}`,
method: 'DELETE',
version: '1',
});
},
});

View file

@ -6,10 +6,10 @@
*/
import { useMemo } from 'react';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { HttpService } from '../http_service';
import { useMlKibana } from '../../contexts/kibana';
import { basePath } from '.';
import type { DataFrameAnalyticsStats } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/common';
import type { ValidateAnalyticsJobResponse } from '../../../../common/constants/validation';
import type { DataFrameAnalyticsConfig } from '../../data_frame_analytics/common';
@ -58,22 +58,25 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({
getDataFrameAnalytics(analyticsId?: string, excludeGenerated?: boolean, size?: number) {
const analyticsIdString = analyticsId !== undefined ? `/${analyticsId}` : '';
return httpService.http<GetDataFrameAnalyticsResponse>({
path: `${basePath()}/data_frame/analytics${analyticsIdString}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics${analyticsIdString}`,
method: 'GET',
...(excludeGenerated ? { query: { excludeGenerated, size } } : {}),
version: '1',
});
},
getDataFrameAnalyticsStats(analyticsId?: string) {
if (analyticsId !== undefined) {
return httpService.http<GetDataFrameAnalyticsStatsResponse>({
path: `${basePath()}/data_frame/analytics/${analyticsId}/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}/_stats`,
method: 'GET',
version: '1',
});
}
return httpService.http<GetDataFrameAnalyticsStatsResponse>({
path: `${basePath()}/data_frame/analytics/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/_stats`,
method: 'GET',
version: '1',
});
},
createDataFrameAnalytics(
@ -82,17 +85,19 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({
) {
const body = JSON.stringify(analyticsConfig);
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/${analyticsId}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}`,
method: 'PUT',
body,
version: '1',
});
},
updateDataFrameAnalytics(analyticsId: string, updateConfig: UpdateDataFrameAnalyticsConfig) {
const body = JSON.stringify(updateConfig);
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/${analyticsId}/_update`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}/_update`,
method: 'POST',
body,
version: '1',
});
},
getDataFrameAnalyticsMap(
@ -102,39 +107,44 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({
): Promise<AnalyticsMapReturnType> {
const idString = id !== undefined ? `/${id}` : '';
return httpService.http({
path: `${basePath()}/data_frame/analytics/map${idString}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/map${idString}`,
method: 'GET',
query: { treatAsRoot, type },
version: '1',
});
},
jobsExist(analyticsIds: string[], allSpaces: boolean = false) {
const body = JSON.stringify({ analyticsIds, allSpaces });
return httpService.http<JobsExistsResponse>({
path: `${basePath()}/data_frame/analytics/jobs_exist`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/jobs_exist`,
method: 'POST',
body,
version: '1',
});
},
evaluateDataFrameAnalytics(evaluateConfig: any) {
const body = JSON.stringify(evaluateConfig);
return httpService.http<any>({
path: `${basePath()}/data_frame/_evaluate`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/_evaluate`,
method: 'POST',
body,
version: '1',
});
},
explainDataFrameAnalytics(jobConfig: DeepPartial<DataFrameAnalyticsConfig>) {
const body = JSON.stringify(jobConfig);
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/_explain`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/_explain`,
method: 'POST',
body,
version: '1',
});
},
deleteDataFrameAnalytics(analyticsId: string) {
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/${analyticsId}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}`,
method: 'DELETE',
version: '1',
});
},
deleteDataFrameAnalyticsAndDestIndex(
@ -143,44 +153,50 @@ export const dataFrameAnalyticsApiProvider = (httpService: HttpService) => ({
deleteDestIndexPattern: boolean
) {
return httpService.http<DeleteDataFrameAnalyticsWithIndexResponse>({
path: `${basePath()}/data_frame/analytics/${analyticsId}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}`,
query: { deleteDestIndex, deleteDestIndexPattern },
method: 'DELETE',
version: '1',
});
},
startDataFrameAnalytics(analyticsId: string) {
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/${analyticsId}/_start`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}/_start`,
method: 'POST',
version: '1',
});
},
stopDataFrameAnalytics(analyticsId: string, force: boolean = false) {
return httpService.http<any>({
path: `${basePath()}/data_frame/analytics/${analyticsId}/_stop`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}/_stop`,
method: 'POST',
query: { force },
version: '1',
});
},
getAnalyticsAuditMessages(analyticsId: string) {
return httpService.http<JobMessage[]>({
path: `${basePath()}/data_frame/analytics/${analyticsId}/messages`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/${analyticsId}/messages`,
method: 'GET',
version: '1',
});
},
validateDataFrameAnalytics(analyticsConfig: DeepPartial<DataFrameAnalyticsConfig>) {
const body = JSON.stringify(analyticsConfig);
return httpService.http<ValidateAnalyticsJobResponse>({
path: `${basePath()}/data_frame/analytics/validate`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/validate`,
method: 'POST',
body,
version: '1',
});
},
newJobCapsAnalytics(indexPatternTitle: string, isRollup: boolean = false) {
const query = isRollup === true ? { rollup: true } : {};
return httpService.http<NewJobCapsResponse>({
path: `${basePath()}/data_frame/analytics/new_job_caps/${indexPatternTitle}`,
path: `${ML_INTERNAL_BASE_PATH}/data_frame/analytics/new_job_caps/${indexPatternTitle}`,
method: 'GET',
query,
version: '1',
});
},
});

View file

@ -8,25 +8,27 @@
// Service for querying filters, which hold lists of entities,
// for example a list of known safe URL domains.
import { useMemo } from 'react';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { HttpService } from '../http_service';
import { useMlKibana } from '../../contexts/kibana';
import { basePath } from '.';
import type { Filter, FilterStats } from '../../../../common/types/filters';
export const filtersApiProvider = (httpService: HttpService) => ({
filters(obj?: { filterId?: string }) {
const filterId = obj && obj.filterId ? `/${obj.filterId}` : '';
return httpService.http<Filter[]>({
path: `${basePath()}/filters${filterId}`,
path: `${ML_INTERNAL_BASE_PATH}/filters${filterId}`,
method: 'GET',
version: '1',
});
},
filtersStats() {
return httpService.http<FilterStats[]>({
path: `${basePath()}/filters/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/filters/_stats`,
method: 'GET',
version: '1',
});
},
@ -37,8 +39,9 @@ export const filtersApiProvider = (httpService: HttpService) => ({
items,
});
return httpService.http<Filter>({
path: `${basePath()}/filters`,
path: `${ML_INTERNAL_BASE_PATH}/filters`,
method: 'PUT',
version: '1',
body,
});
},
@ -51,16 +54,18 @@ export const filtersApiProvider = (httpService: HttpService) => ({
});
return httpService.http<Filter>({
path: `${basePath()}/filters/${filterId}`,
path: `${ML_INTERNAL_BASE_PATH}/filters/${filterId}`,
method: 'PUT',
body,
version: '1',
});
},
deleteFilter(filterId: string) {
return httpService.http<{ acknowledged: boolean }>({
path: `${basePath()}/filters/${filterId}`,
path: `${ML_INTERNAL_BASE_PATH}/filters/${filterId}`,
method: 'DELETE',
version: '1',
});
},
});

View file

@ -8,6 +8,7 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { Observable } from 'rxjs';
import type { HttpStart } from '@kbn/core/public';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { jsonSchemaProvider } from './json_schema';
import { HttpService } from '../http_service';
@ -41,7 +42,11 @@ import type {
IndicesOptions,
} from '../../../../common/types/anomaly_detection_jobs';
import type { FieldHistogramRequestConfig } from '../../datavisualizer/index_based/common/request';
import type { DataRecognizerConfigResponse, Module } from '../../../../common/types/modules';
import type {
DataRecognizerConfigResponse,
Module,
RecognizeResult,
} from '../../../../common/types/modules';
import { getHttp } from '../../util/dependency_cache';
import type { RuntimeMappings } from '../../../../common/types/fields';
import type { DatafeedValidationResponse } from '../../../../common/types/job_validation';
@ -89,10 +94,6 @@ export interface GetModelSnapshotsResponse {
model_snapshots: ModelSnapshot[];
}
export function basePath() {
return '/api/ml';
}
/**
* Temp solution to allow {@link ml} service to use http from
* the dependency_cache.
@ -120,83 +121,102 @@ export function mlApiServicesProvider(httpService: HttpService) {
getJobs(obj?: { jobId?: string }) {
const jobId = obj && obj.jobId ? `/${obj.jobId}` : '';
return httpService.http<{ jobs: Job[]; count: number }>({
path: `${basePath()}/anomaly_detectors${jobId}`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors${jobId}`,
version: '1',
});
},
getJobs$(obj?: { jobId?: string }) {
const jobId = obj && obj.jobId ? `/${obj.jobId}` : '';
return httpService.http$<{ count: number; jobs: Job[] }>({
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors${jobId}`,
version: '1',
});
},
getJobStats(obj: { jobId?: string }) {
const jobId = obj && obj.jobId ? `/${obj.jobId}` : '';
return httpService.http<{ jobs: JobStats[]; count: number }>({
path: `${basePath()}/anomaly_detectors${jobId}/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors${jobId}/_stats`,
version: '1',
});
},
addJob({ jobId, job }: { jobId: string; job: Job }) {
const body = JSON.stringify(job);
return httpService.http<estypes.MlPutJobResponse>({
path: `${basePath()}/anomaly_detectors/${jobId}`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}`,
method: 'PUT',
body,
version: '1',
});
},
openJob({ jobId }: { jobId: string }) {
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/_open`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_open`,
method: 'POST',
version: '1',
});
},
closeJob({ jobId }: { jobId: string }) {
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/_close`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_close`,
method: 'POST',
version: '1',
});
},
forceCloseJob({ jobId }: { jobId: string }) {
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/_close?force=true`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_close?force=true`,
method: 'POST',
version: '1',
});
},
deleteJob({ jobId }: { jobId: string }) {
return httpService.http<estypes.MlDeleteJobResponse>({
path: `${basePath()}/anomaly_detectors/${jobId}`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}`,
method: 'DELETE',
version: '1',
});
},
forceDeleteJob({ jobId }: { jobId: string }) {
return httpService.http<estypes.MlDeleteJobResponse>({
path: `${basePath()}/anomaly_detectors/${jobId}?force=true`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}?force=true`,
method: 'DELETE',
version: '1',
});
},
updateJob({ jobId, job }: { jobId: string; job: Job }) {
const body = JSON.stringify(job);
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/_update`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_update`,
method: 'POST',
body,
version: '1',
});
},
resetJob({ jobId }: { jobId: string }) {
return httpService.http<ResetJobsResponse>({
path: `${basePath()}/anomaly_detectors/${jobId}/_reset`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_reset`,
method: 'POST',
version: '1',
});
},
estimateBucketSpan(obj: BucketSpanEstimatorData) {
const body = JSON.stringify(obj);
return httpService.http<BucketSpanEstimatorResponse>({
path: `${basePath()}/validate/estimate_bucket_span`,
path: `${ML_INTERNAL_BASE_PATH}/validate/estimate_bucket_span`,
method: 'POST',
body,
version: '1',
});
},
@ -210,50 +230,56 @@ export function mlApiServicesProvider(httpService: HttpService) {
}) {
const body = JSON.stringify(payload);
return httpService.http<any>({
path: `${basePath()}/validate/job`,
path: `${ML_INTERNAL_BASE_PATH}/validate/job`,
method: 'POST',
body,
version: '1',
});
},
validateDatafeedPreview(payload: { job: CombinedJob; start?: number; end?: number }) {
const body = JSON.stringify(payload);
return httpService.http<DatafeedValidationResponse>({
path: `${basePath()}/validate/datafeed_preview`,
path: `${ML_INTERNAL_BASE_PATH}/validate/datafeed_preview`,
method: 'POST',
body,
version: '1',
});
},
validateCardinality$(job: CombinedJob): Observable<CardinalityValidationResults> {
const body = JSON.stringify(job);
return httpService.http$({
path: `${basePath()}/validate/cardinality`,
path: `${ML_INTERNAL_BASE_PATH}/validate/cardinality`,
method: 'POST',
body,
version: '1',
});
},
getDatafeeds(obj: { datafeedId: string }) {
const datafeedId = obj && obj.datafeedId ? `/${obj.datafeedId}` : '';
return httpService.http<any>({
path: `${basePath()}/datafeeds${datafeedId}`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds${datafeedId}`,
version: '1',
});
},
getDatafeedStats(obj: { datafeedId: string }) {
const datafeedId = obj && obj.datafeedId ? `/${obj.datafeedId}` : '';
return httpService.http<any>({
path: `${basePath()}/datafeeds${datafeedId}/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds${datafeedId}/_stats`,
version: '1',
});
},
addDatafeed({ datafeedId, datafeedConfig }: { datafeedId: string; datafeedConfig: Datafeed }) {
const body = JSON.stringify(datafeedConfig);
return httpService.http<estypes.MlPutDatafeedResponse>({
path: `${basePath()}/datafeeds/${datafeedId}`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}`,
method: 'PUT',
body,
version: '1',
});
},
@ -266,23 +292,26 @@ export function mlApiServicesProvider(httpService: HttpService) {
}) {
const body = JSON.stringify(datafeedConfig);
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}/_update`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}/_update`,
method: 'POST',
body,
version: '1',
});
},
deleteDatafeed({ datafeedId }: { datafeedId: string }) {
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}`,
method: 'DELETE',
version: '1',
});
},
forceDeleteDatafeed({ datafeedId }: { datafeedId: string }) {
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}?force=true`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}?force=true`,
method: 'DELETE',
version: '1',
});
},
@ -301,37 +330,41 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}/_start`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}/_start`,
method: 'POST',
body,
version: '1',
});
},
stopDatafeed({ datafeedId }: { datafeedId: string }) {
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}/_stop`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}/_stop`,
method: 'POST',
version: '1',
});
},
forceStopDatafeed({ datafeedId }: { datafeedId: string }) {
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}/_stop?force=true`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}/_stop?force=true`,
method: 'POST',
version: '1',
});
},
datafeedPreview({ datafeedId }: { datafeedId: string }) {
return httpService.http<any>({
path: `${basePath()}/datafeeds/${datafeedId}/_preview`,
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/${datafeedId}/_preview`,
method: 'GET',
version: '1',
});
},
validateDetector({ detector }: { detector: Detector }) {
const body = JSON.stringify(detector);
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/_validate/detector`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/_validate/detector`,
method: 'POST',
body,
});
@ -343,9 +376,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/_forecast`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/_forecast`,
method: 'POST',
body,
version: '1',
});
},
@ -372,25 +406,28 @@ export function mlApiServicesProvider(httpService: HttpService) {
...(overallScore ? { overall_score: overallScore } : {}),
});
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/results/overall_buckets`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/results/overall_buckets`,
method: 'POST',
body,
version: '1',
});
},
hasPrivileges(obj: any) {
const body = JSON.stringify(obj);
return httpService.http<any>({
path: `${basePath()}/_has_privileges`,
path: `${ML_INTERNAL_BASE_PATH}/_has_privileges`,
method: 'POST',
body,
version: '1',
});
},
checkMlCapabilities() {
return httpService.http<MlCapabilitiesResponse>({
path: `${basePath()}/ml_capabilities`,
path: `${ML_INTERNAL_BASE_PATH}/ml_capabilities`,
method: 'GET',
version: '1',
});
},
@ -398,9 +435,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
const body = JSON.stringify({ indices });
return httpService.http<Record<string, { exists: boolean }>>({
path: `${basePath()}/index_exists`,
path: `${ML_INTERNAL_BASE_PATH}/index_exists`,
method: 'POST',
body,
version: '1',
});
},
@ -411,37 +449,42 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<any>({
path: `${basePath()}/indices/field_caps`,
path: `${ML_INTERNAL_BASE_PATH}/indices/field_caps`,
method: 'POST',
body,
version: '1',
});
},
recognizeIndex({ indexPatternTitle }: { indexPatternTitle: string }) {
return httpService.http<any>({
path: `${basePath()}/modules/recognize/${indexPatternTitle}`,
return httpService.http<RecognizeResult[]>({
path: `${ML_INTERNAL_BASE_PATH}/modules/recognize/${indexPatternTitle}`,
method: 'GET',
version: '1',
});
},
listDataRecognizerModules() {
return httpService.http<any>({
path: `${basePath()}/modules/get_module`,
path: `${ML_INTERNAL_BASE_PATH}/modules/get_module`,
method: 'GET',
version: '1',
});
},
getDataRecognizerModule({ moduleId }: { moduleId: string }) {
return httpService.http<Module>({
path: `${basePath()}/modules/get_module/${moduleId}`,
path: `${ML_INTERNAL_BASE_PATH}/modules/get_module/${moduleId}`,
method: 'GET',
version: '1',
});
},
dataRecognizerModuleJobsExist({ moduleId }: { moduleId: string }) {
return httpService.http<any>({
path: `${basePath()}/modules/jobs_exist/${moduleId}`,
path: `${ML_INTERNAL_BASE_PATH}/modules/jobs_exist/${moduleId}`,
method: 'GET',
version: '1',
});
},
@ -484,9 +527,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<DataRecognizerConfigResponse>({
path: `${basePath()}/modules/setup/${moduleId}`,
path: `${ML_INTERNAL_BASE_PATH}/modules/setup/${moduleId}`,
method: 'POST',
body,
version: '1',
});
},
@ -511,9 +555,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<any>({
path: `${basePath()}/data_visualizer/get_field_histograms/${indexPattern}`,
path: `${ML_INTERNAL_BASE_PATH}/data_visualizer/get_field_histograms/${indexPattern}`,
method: 'POST',
body,
version: '1',
});
},
@ -531,17 +576,19 @@ export function mlApiServicesProvider(httpService: HttpService) {
calendarIdsPathComponent = `/${calendarIds.join(',')}`;
}
return httpService.http<Calendar[]>({
path: `${basePath()}/calendars${calendarIdsPathComponent}`,
path: `${ML_INTERNAL_BASE_PATH}/calendars${calendarIdsPathComponent}`,
method: 'GET',
version: '1',
});
},
addCalendar(obj: Calendar) {
const body = JSON.stringify(obj);
return httpService.http<any>({
path: `${basePath()}/calendars`,
path: `${ML_INTERNAL_BASE_PATH}/calendars`,
method: 'PUT',
body,
version: '1',
});
},
@ -549,30 +596,34 @@ export function mlApiServicesProvider(httpService: HttpService) {
const calendarId = obj && obj.calendarId ? `/${obj.calendarId}` : '';
const body = JSON.stringify(obj);
return httpService.http<any>({
path: `${basePath()}/calendars${calendarId}`,
path: `${ML_INTERNAL_BASE_PATH}/calendars${calendarId}`,
method: 'PUT',
body,
version: '1',
});
},
deleteCalendar({ calendarId }: { calendarId?: string }) {
return httpService.http<any>({
path: `${basePath()}/calendars/${calendarId}`,
path: `${ML_INTERNAL_BASE_PATH}/calendars/${calendarId}`,
method: 'DELETE',
version: '1',
});
},
mlNodeCount() {
return httpService.http<MlNodeCount>({
path: `${basePath()}/ml_node_count`,
path: `${ML_INTERNAL_BASE_PATH}/ml_node_count`,
method: 'GET',
version: '1',
});
},
mlInfo() {
return httpService.http<MlInfoResponse>({
path: `${basePath()}/info`,
path: `${ML_INTERNAL_BASE_PATH}/info`,
method: 'GET',
version: '1',
});
},
@ -604,9 +655,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http$<{ modelMemoryLimit: string }>({
path: `${basePath()}/validate/calculate_model_memory_limit`,
path: `${ML_INTERNAL_BASE_PATH}/validate/calculate_model_memory_limit`,
method: 'POST',
body,
version: '1',
});
},
@ -635,9 +687,10 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<any>({
path: `${basePath()}/fields_service/field_cardinality`,
path: `${ML_INTERNAL_BASE_PATH}/fields_service/field_cardinality`,
method: 'POST',
body,
version: '1',
});
},
@ -666,27 +719,30 @@ export function mlApiServicesProvider(httpService: HttpService) {
});
return httpService.http<GetTimeFieldRangeResponse>({
path: `${basePath()}/fields_service/time_field_range`,
path: `${ML_INTERNAL_BASE_PATH}/fields_service/time_field_range`,
method: 'POST',
body,
version: '1',
});
},
esSearch(obj: any) {
const body = JSON.stringify(obj);
return httpService.http<any>({
path: `${basePath()}/es_search`,
path: `${ML_INTERNAL_BASE_PATH}/es_search`,
method: 'POST',
body,
version: '1',
});
},
esSearch$(obj: any) {
const body = JSON.stringify(obj);
return httpService.http$<any>({
path: `${basePath()}/es_search`,
path: `${ML_INTERNAL_BASE_PATH}/es_search`,
method: 'POST',
body,
version: '1',
});
},
@ -695,14 +751,16 @@ export function mlApiServicesProvider(httpService: HttpService) {
return httpService.http<Array<{ name: string }>>({
path: `${tempBasePath}/index_management/indices`,
method: 'GET',
version: '1',
});
},
getModelSnapshots(jobId: string, snapshotId?: string) {
return httpService.http<GetModelSnapshotsResponse>({
path: `${basePath()}/anomaly_detectors/${jobId}/model_snapshots${
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/model_snapshots${
snapshotId !== undefined ? `/${snapshotId}` : ''
}`,
version: '1',
});
},
@ -712,16 +770,18 @@ export function mlApiServicesProvider(httpService: HttpService) {
body: { description?: string; retain?: boolean }
) {
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/model_snapshots/${snapshotId}/_update`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/model_snapshots/${snapshotId}/_update`,
method: 'POST',
body: JSON.stringify(body),
version: '1',
});
},
deleteModelSnapshot(jobId: string, snapshotId: string) {
return httpService.http<any>({
path: `${basePath()}/anomaly_detectors/${jobId}/model_snapshots/${snapshotId}`,
path: `${ML_INTERNAL_BASE_PATH}/anomaly_detectors/${jobId}/model_snapshots/${snapshotId}`,
method: 'DELETE',
version: '1',
});
},

View file

@ -36,22 +36,24 @@ import type {
BulkCreateResults,
ResetJobsResponse,
} from '../../../../common/types/job_service';
import { ML_BASE_PATH } from '../../../../common/constants/app';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
export const jobsApiProvider = (httpService: HttpService) => ({
jobsSummary(jobIds: string[]) {
const body = JSON.stringify({ jobIds });
return httpService.http<MlSummaryJobs>({
path: `${ML_BASE_PATH}/jobs/jobs_summary`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_summary`,
method: 'POST',
body,
version: '1',
});
},
jobIdsWithGeo() {
return httpService.http<string[]>({
path: `${ML_BASE_PATH}/jobs/jobs_with_geo`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_with_geo`,
method: 'GET',
version: '1',
});
},
@ -61,43 +63,48 @@ export const jobsApiProvider = (httpService: HttpService) => ({
jobs: MlJobWithTimeRange[];
jobsMap: Dictionary<MlJobWithTimeRange>;
}>({
path: `${ML_BASE_PATH}/jobs/jobs_with_time_range`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_with_time_range`,
method: 'POST',
body,
version: '1',
});
},
jobForCloning(jobId: string) {
const body = JSON.stringify({ jobId });
return httpService.http<{ job?: Job; datafeed?: Datafeed } | undefined>({
path: `${ML_BASE_PATH}/jobs/job_for_cloning`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/job_for_cloning`,
method: 'POST',
body,
version: '1',
});
},
jobs(jobIds: string[]) {
const body = JSON.stringify({ jobIds });
return httpService.http<CombinedJobWithStats[]>({
path: `${ML_BASE_PATH}/jobs/jobs`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs`,
method: 'POST',
body,
version: '1',
});
},
groups() {
return httpService.http<Group[]>({
path: `${ML_BASE_PATH}/jobs/groups`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/groups`,
method: 'GET',
version: '1',
});
},
updateGroups(updatedJobs: Array<{ jobId: string; groups: string[] }>) {
const body = JSON.stringify({ jobs: updatedJobs });
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/update_groups`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/update_groups`,
method: 'POST',
body,
version: '1',
});
},
@ -109,54 +116,60 @@ export const jobsApiProvider = (httpService: HttpService) => ({
});
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/force_start_datafeeds`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/force_start_datafeeds`,
method: 'POST',
body,
version: '1',
});
},
stopDatafeeds(datafeedIds: string[]) {
const body = JSON.stringify({ datafeedIds });
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/stop_datafeeds`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/stop_datafeeds`,
method: 'POST',
body,
version: '1',
});
},
deleteJobs(jobIds: string[], deleteUserAnnotations?: boolean) {
const body = JSON.stringify({ jobIds, deleteUserAnnotations });
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/delete_jobs`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/delete_jobs`,
method: 'POST',
body,
version: '1',
});
},
closeJobs(jobIds: string[]) {
const body = JSON.stringify({ jobIds });
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/close_jobs`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/close_jobs`,
method: 'POST',
body,
version: '1',
});
},
resetJobs(jobIds: string[], deleteUserAnnotations?: boolean) {
const body = JSON.stringify({ jobIds, deleteUserAnnotations });
return httpService.http<ResetJobsResponse>({
path: `${ML_BASE_PATH}/jobs/reset_jobs`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/reset_jobs`,
method: 'POST',
body,
version: '1',
});
},
forceStopAndCloseJob(jobId: string) {
const body = JSON.stringify({ jobId });
return httpService.http<{ success: boolean }>({
path: `${ML_BASE_PATH}/jobs/force_stop_and_close_job`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/force_stop_and_close_job`,
method: 'POST',
body,
version: '1',
});
},
@ -178,52 +191,58 @@ export const jobsApiProvider = (httpService: HttpService) => ({
};
return httpService.http<{ messages: JobMessage[]; notificationIndices: string[] }>({
path: `${ML_BASE_PATH}/job_audit_messages/messages${jobIdString}`,
path: `${ML_INTERNAL_BASE_PATH}/job_audit_messages/messages${jobIdString}`,
method: 'GET',
query,
version: '1',
});
},
clearJobAuditMessages(jobId: string, notificationIndices: string[]) {
const body = JSON.stringify({ jobId, notificationIndices });
return httpService.http<{ success: boolean; latest_cleared: number }>({
path: `${ML_BASE_PATH}/job_audit_messages/clear_messages`,
path: `${ML_INTERNAL_BASE_PATH}/job_audit_messages/clear_messages`,
method: 'PUT',
body,
version: '1',
});
},
blockingJobTasks() {
return httpService.http<Record<string, JobAction>>({
path: `${ML_BASE_PATH}/jobs/blocking_jobs_tasks`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/blocking_jobs_tasks`,
method: 'GET',
version: '1',
});
},
jobsExist(jobIds: string[], allSpaces: boolean = false) {
const body = JSON.stringify({ jobIds, allSpaces });
return httpService.http<JobsExistResponse>({
path: `${ML_BASE_PATH}/jobs/jobs_exist`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_exist`,
method: 'POST',
body,
version: '1',
});
},
jobsExist$(jobIds: string[], allSpaces: boolean = false): Observable<JobsExistResponse> {
const body = JSON.stringify({ jobIds, allSpaces });
return httpService.http$({
path: `${ML_BASE_PATH}/jobs/jobs_exist`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_exist`,
method: 'POST',
body,
version: '1',
});
},
newJobCaps(indexPatternTitle: string, isRollup: boolean = false) {
const query = isRollup === true ? { rollup: true } : {};
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/new_job_caps/${indexPatternTitle}`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/new_job_caps/${indexPatternTitle}`,
method: 'GET',
query,
version: '1',
});
},
@ -254,9 +273,10 @@ export const jobsApiProvider = (httpService: HttpService) => ({
indicesOptions,
});
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/new_job_line_chart`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/new_job_line_chart`,
method: 'POST',
body,
version: '1',
});
},
@ -285,16 +305,18 @@ export const jobsApiProvider = (httpService: HttpService) => ({
indicesOptions,
});
return httpService.http<any>({
path: `${ML_BASE_PATH}/jobs/new_job_population_chart`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/new_job_population_chart`,
method: 'POST',
body,
version: '1',
});
},
getAllJobAndGroupIds() {
return httpService.http<ExistingJobsAndGroups>({
path: `${ML_BASE_PATH}/jobs/all_jobs_and_group_ids`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/all_jobs_and_group_ids`,
method: 'GET',
version: '1',
});
},
@ -305,9 +327,10 @@ export const jobsApiProvider = (httpService: HttpService) => ({
end,
});
return httpService.http<{ progress: number; isRunning: boolean; isJobClosed: boolean }>({
path: `${ML_BASE_PATH}/jobs/look_back_progress`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/look_back_progress`,
method: 'POST',
body,
version: '1',
});
},
@ -341,9 +364,10 @@ export const jobsApiProvider = (httpService: HttpService) => ({
overallValidStatus: CATEGORY_EXAMPLES_VALIDATION_STATUS;
validationChecks: FieldExampleCheck[];
}>({
path: `${ML_BASE_PATH}/jobs/categorization_field_examples`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/categorization_field_examples`,
method: 'POST',
body,
version: '1',
});
},
@ -353,9 +377,10 @@ export const jobsApiProvider = (httpService: HttpService) => ({
total: number;
categories: Array<{ count?: number; category: Category }>;
}>({
path: `${ML_BASE_PATH}/jobs/top_categories`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/top_categories`,
method: 'POST',
body,
version: '1',
});
},
@ -370,27 +395,30 @@ export const jobsApiProvider = (httpService: HttpService) => ({
return httpService.http<{
success: boolean;
}>({
path: `${ML_BASE_PATH}/jobs/revert_model_snapshot`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/revert_model_snapshot`,
method: 'POST',
body,
version: '1',
});
},
datafeedPreview(datafeedId?: string, job?: Job, datafeed?: Datafeed) {
const body = JSON.stringify({ datafeedId, job, datafeed });
return httpService.http<unknown[]>({
path: `${ML_BASE_PATH}/jobs/datafeed_preview`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/datafeed_preview`,
method: 'POST',
body,
version: '1',
});
},
bulkCreateJobs(jobs: { job: Job; datafeed: Datafeed } | Array<{ job: Job; datafeed: Datafeed }>) {
const body = JSON.stringify(jobs);
return httpService.http<BulkCreateResults>({
path: `${ML_BASE_PATH}/jobs/bulk_create`,
path: `${ML_INTERNAL_BASE_PATH}/jobs/bulk_create`,
method: 'POST',
body,
version: '1',
});
},
});

View file

@ -7,9 +7,9 @@
import { omitBy } from 'lodash';
import { isDefined } from '@kbn/ml-is-defined';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { type SupportedPath } from '../../../../common/api_schemas/json_schema_schema';
import { HttpService } from '../http_service';
import { basePath } from '.';
export interface GetSchemaDefinitionParams {
path: SupportedPath;
@ -17,14 +17,13 @@ export interface GetSchemaDefinitionParams {
}
export function jsonSchemaProvider(httpService: HttpService) {
const apiBasePath = basePath();
return {
getSchemaDefinition(params: GetSchemaDefinitionParams) {
return httpService.http<object>({
path: `${apiBasePath}/json_schema`,
path: `${ML_INTERNAL_BASE_PATH}/json_schema`,
method: 'GET',
query: omitBy(params, (v) => !isDefined(v)),
version: '1',
});
},
};

View file

@ -6,8 +6,8 @@
*/
import { useMemo } from 'react';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { HttpService } from '../http_service';
import { basePath } from '.';
import { useMlKibana } from '../../contexts/kibana';
import type { TrainedModelStat } from '../../../../common/types/trained_models';
import type { ManagementListResponse } from '../../../../common/types/management';
@ -47,8 +47,6 @@ export interface InferenceStatsResponse {
* @param httpService
*/
export function managementApiProvider(httpService: HttpService) {
const apiBasePath = basePath();
return {
/**
* Fetches lists of anomaly detection jobs, data frame analytics jobs or trained models
@ -58,8 +56,9 @@ export function managementApiProvider(httpService: HttpService) {
*/
getList(mlSavedObjectType: MlSavedObjectType) {
return httpService.http<ManagementListResponse>({
path: `${apiBasePath}/management/list/${mlSavedObjectType}`,
path: `${ML_INTERNAL_BASE_PATH}/management/list/${mlSavedObjectType}`,
method: 'GET',
version: '1',
});
},
};

View file

@ -7,11 +7,11 @@
import { omitBy } from 'lodash';
import { isDefined } from '@kbn/ml-is-defined';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import type {
NotificationsQueryParams,
NotificationsSearchResponse,
} from '../../../../common/types/notifications';
import { basePath } from '.';
import type { HttpService } from '../http_service';
import type {
NotificationsCountQueryParams,
@ -19,22 +19,22 @@ import type {
} from '../../../../common/types/notifications';
export function notificationsProvider(httpService: HttpService) {
const apiBasePath = basePath();
return {
findMessages(params: NotificationsQueryParams) {
return httpService.http<NotificationsSearchResponse>({
path: `${apiBasePath}/notifications`,
path: `${ML_INTERNAL_BASE_PATH}/notifications`,
method: 'GET',
query: omitBy(params, (v) => !isDefined(v)),
version: '1',
});
},
countMessages$(params: NotificationsCountQueryParams) {
return httpService.http$<NotificationsCountResponse>({
path: `${apiBasePath}/notifications/count`,
path: `${ML_INTERNAL_BASE_PATH}/notifications/count`,
method: 'GET',
query: omitBy(params, (v) => !isDefined(v)),
version: '1',
});
},
};

View file

@ -17,6 +17,7 @@ import {
ML_JOB_ID,
ML_PARTITION_FIELD_VALUE,
} from '@kbn/ml-anomaly-utils';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import type {
GetStoppedPartitionResult,
GetDatafeedResultsChartDataResult,
@ -31,8 +32,6 @@ import type { HttpService } from '../http_service';
import type { CriteriaField } from '../results_service';
import type { PartitionFieldsDefinition } from '../results_service/result_service_rx';
import { basePath } from '.';
export interface CategoryDefinition {
categoryId: number;
terms: string;
@ -71,9 +70,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
});
return httpService.http$<any>({
path: `${basePath()}/results/anomalies_table_data`,
path: `${ML_INTERNAL_BASE_PATH}/results/anomalies_table_data`,
method: 'POST',
body,
version: '1',
});
},
@ -84,18 +84,20 @@ export const resultsApiProvider = (httpService: HttpService) => ({
latestMs,
});
return httpService.http<any>({
path: `${basePath()}/results/max_anomaly_score`,
path: `${ML_INTERNAL_BASE_PATH}/results/max_anomaly_score`,
method: 'POST',
body,
version: '1',
});
},
getCategoryDefinition(jobId: string, categoryId: string) {
const body = JSON.stringify({ jobId, categoryId });
return httpService.http<CategoryDefinition>({
path: `${basePath()}/results/category_definition`,
path: `${ML_INTERNAL_BASE_PATH}/results/category_definition`,
method: 'POST',
body,
version: '1',
});
},
@ -106,9 +108,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
maxExamples,
});
return httpService.http<any>({
path: `${basePath()}/results/category_examples`,
path: `${ML_INTERNAL_BASE_PATH}/results/category_examples`,
method: 'POST',
body,
version: '1',
});
},
@ -129,27 +132,30 @@ export const resultsApiProvider = (httpService: HttpService) => ({
fieldsConfig,
});
return httpService.http$<PartitionFieldsDefinition>({
path: `${basePath()}/results/partition_fields_values`,
path: `${ML_INTERNAL_BASE_PATH}/results/partition_fields_values`,
method: 'POST',
body,
version: '1',
});
},
anomalySearch(query: ESSearchRequest, jobIds: string[]) {
const body = JSON.stringify({ query, jobIds });
return httpService.http<ESSearchResponse<MLAnomalyDoc>>({
path: `${basePath()}/results/anomaly_search`,
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_search`,
method: 'POST',
body,
version: '1',
});
},
anomalySearch$(query: ESSearchRequest, jobIds: string[]) {
const body = JSON.stringify({ query, jobIds });
return httpService.http$<ESSearchResponse<MLAnomalyDoc>>({
path: `${basePath()}/results/anomaly_search`,
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_search`,
method: 'POST',
body,
version: '1',
});
},
@ -162,9 +168,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
fieldToBucket,
});
return httpService.http<GetStoppedPartitionResult>({
path: `${basePath()}/results/category_stopped_partitions`,
path: `${ML_INTERNAL_BASE_PATH}/results/category_stopped_partitions`,
method: 'POST',
body,
version: '1',
});
},
@ -175,9 +182,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
end,
});
return httpService.http<GetDatafeedResultsChartDataResult>({
path: `${basePath()}/results/datafeed_results_chart`,
path: `${ML_INTERNAL_BASE_PATH}/results/datafeed_results_chart`,
method: 'POST',
body,
version: '1',
});
},
@ -204,9 +212,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
timeBounds,
});
return httpService.http$<ExplorerChartsData>({
path: `${basePath()}/results/anomaly_charts`,
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_charts`,
method: 'POST',
body,
version: '1',
});
},
@ -229,9 +238,10 @@ export const resultsApiProvider = (httpService: HttpService) => ({
functionDescription,
});
return httpService.http$<{ success: boolean; records: MlAnomalyRecordDoc[] }>({
path: `${basePath()}/results/anomaly_records`,
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_records`,
method: 'POST',
body,
version: '1',
});
},
});

View file

@ -8,11 +8,11 @@
// Service for managing job saved objects
import { useMemo } from 'react';
import { ML_INTERNAL_BASE_PATH, ML_EXTERNAL_BASE_PATH } from '../../../../common/constants/app';
import { useMlKibana } from '../../contexts/kibana';
import { HttpService } from '../http_service';
import { basePath } from '.';
import type {
JobType,
MlSavedObjectType,
@ -28,8 +28,9 @@ import type {
export const savedObjectsApiProvider = (httpService: HttpService) => ({
jobsSpaces() {
return httpService.http<JobsSpacesResponse>({
path: `${basePath()}/saved_objects/jobs_spaces`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/jobs_spaces`,
method: 'GET',
version: '1',
});
},
updateJobsSpaces(
@ -40,61 +41,69 @@ export const savedObjectsApiProvider = (httpService: HttpService) => ({
) {
const body = JSON.stringify({ jobType, jobIds, spacesToAdd, spacesToRemove });
return httpService.http<SavedObjectResult>({
path: `${basePath()}/saved_objects/update_jobs_spaces`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/update_jobs_spaces`,
method: 'POST',
body,
version: '1',
});
},
removeItemFromCurrentSpace(mlSavedObjectType: MlSavedObjectType, ids: string[]) {
const body = JSON.stringify({ mlSavedObjectType, ids });
return httpService.http<SavedObjectResult>({
path: `${basePath()}/saved_objects/remove_item_from_current_space`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/remove_item_from_current_space`,
method: 'POST',
body,
version: '1',
});
},
syncSavedObjects(simulate: boolean = false) {
return httpService.http<SyncSavedObjectResponse>({
path: `${basePath()}/saved_objects/sync`,
path: `${ML_EXTERNAL_BASE_PATH}/saved_objects/sync`,
method: 'GET',
query: { simulate },
version: '2023-05-15',
});
},
initSavedObjects(simulate: boolean = false) {
return httpService.http<InitializeSavedObjectResponse>({
path: `${basePath()}/saved_objects/initialize`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/initialize`,
method: 'GET',
query: { simulate },
version: '1',
});
},
syncCheck(mlSavedObjectType?: MlSavedObjectType) {
const body = JSON.stringify({ mlSavedObjectType });
return httpService.http<SyncCheckResponse>({
path: `${basePath()}/saved_objects/sync_check`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/sync_check`,
method: 'POST',
body,
version: '1',
});
},
canDeleteMLSpaceAwareItems(mlSavedObjectType: MlSavedObjectType, ids: string[]) {
const body = JSON.stringify({ ids });
return httpService.http<CanDeleteMLSpaceAwareItemsResponse>({
path: `${basePath()}/saved_objects/can_delete_ml_space_aware_item/${mlSavedObjectType}`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/can_delete_ml_space_aware_item/${mlSavedObjectType}`,
method: 'POST',
body,
version: '1',
});
},
trainedModelsSpaces() {
return httpService.http<TrainedModelsSpacesResponse>({
path: `${basePath()}/saved_objects/trained_models_spaces`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/trained_models_spaces`,
method: 'GET',
version: '1',
});
},
updateModelsSpaces(modelIds: string[], spacesToAdd: string[], spacesToRemove: string[]) {
const body = JSON.stringify({ modelIds, spacesToAdd, spacesToRemove });
return httpService.http<SavedObjectResult>({
path: `${basePath()}/saved_objects/update_trained_models_spaces`,
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/update_trained_models_spaces`,
method: 'POST',
body,
version: '1',
});
},
});

View file

@ -10,9 +10,9 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { useMemo } from 'react';
import type { HttpFetchQuery } from '@kbn/core/public';
import type { ErrorType } from '@kbn/ml-error-utils';
import { ML_INTERNAL_BASE_PATH } from '../../../../common/constants/app';
import type { MlSavedObjectType } from '../../../../common/types/saved_objects';
import { HttpService } from '../http_service';
import { basePath } from '.';
import { useMlKibana } from '../../contexts/kibana';
import type {
TrainedModelConfigResponse,
@ -55,8 +55,6 @@ export interface InferenceStatsResponse {
* @param httpService
*/
export function trainedModelsApiProvider(httpService: HttpService) {
const apiBasePath = basePath();
return {
/**
* Fetches configuration information for a trained inference model.
@ -69,9 +67,10 @@ export function trainedModelsApiProvider(httpService: HttpService) {
const model = Array.isArray(modelId) ? modelId.join(',') : modelId;
return httpService.http<TrainedModelConfigResponse[]>({
path: `${apiBasePath}/trained_models${model ? `/${model}` : ''}`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models${model ? `/${model}` : ''}`,
method: 'GET',
...(params ? { query: params as HttpFetchQuery } : {}),
version: '1',
});
},
@ -86,8 +85,9 @@ export function trainedModelsApiProvider(httpService: HttpService) {
const model = Array.isArray(modelId) ? modelId.join(',') : modelId;
return httpService.http<InferenceStatsResponse>({
path: `${apiBasePath}/trained_models${model ? `/${model}` : ''}/_stats`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models${model ? `/${model}` : ''}/_stats`,
method: 'GET',
version: '1',
});
},
@ -103,8 +103,9 @@ export function trainedModelsApiProvider(httpService: HttpService) {
}
return httpService.http<ModelPipelines[]>({
path: `${apiBasePath}/trained_models/${model}/pipelines`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${model}/pipelines`,
method: 'GET',
version: '1',
});
},
@ -115,15 +116,17 @@ export function trainedModelsApiProvider(httpService: HttpService) {
*/
deleteTrainedModel(modelId: string) {
return httpService.http<{ acknowledge: boolean }>({
path: `${apiBasePath}/trained_models/${modelId}`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${modelId}`,
method: 'DELETE',
version: '1',
});
},
getTrainedModelsNodesOverview() {
return httpService.http<NodesOverviewResponse>({
path: `${apiBasePath}/model_management/nodes_overview`,
path: `${ML_INTERNAL_BASE_PATH}/model_management/nodes_overview`,
method: 'GET',
version: '1',
});
},
@ -137,9 +140,10 @@ export function trainedModelsApiProvider(httpService: HttpService) {
}
) {
return httpService.http<{ acknowledge: boolean }>({
path: `${apiBasePath}/trained_models/${modelId}/deployment/_start`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${modelId}/deployment/_start`,
method: 'POST',
query: queryParams,
version: '1',
});
},
@ -151,11 +155,12 @@ export function trainedModelsApiProvider(httpService: HttpService) {
const force = options?.force;
return httpService.http<Record<string, { acknowledge: boolean; error?: ErrorType }>>({
path: `${apiBasePath}/trained_models/${modelId}/${deploymentsIds.join(
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${modelId}/${deploymentsIds.join(
','
)}/deployment/_stop`,
method: 'POST',
query: { force },
version: '1',
});
},
@ -165,9 +170,10 @@ export function trainedModelsApiProvider(httpService: HttpService) {
params: { number_of_allocations: number }
) {
return httpService.http<{ acknowledge: boolean }>({
path: `${apiBasePath}/trained_models/${modelId}/${deploymentId}/deployment/_update`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${modelId}/${deploymentId}/deployment/_update`,
method: 'POST',
body: JSON.stringify(params),
version: '1',
});
},
@ -179,10 +185,11 @@ export function trainedModelsApiProvider(httpService: HttpService) {
) {
const body = JSON.stringify(payload);
return httpService.http<estypes.MlInferTrainedModelResponse>({
path: `${apiBasePath}/trained_models/infer/${modelId}/${deploymentsId}`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/infer/${modelId}/${deploymentsId}`,
method: 'POST',
body,
...(timeout ? { query: { timeout } as HttpFetchQuery } : {}),
version: '1',
});
},
@ -195,25 +202,28 @@ export function trainedModelsApiProvider(httpService: HttpService) {
docs,
});
return httpService.http<estypes.IngestSimulateResponse>({
path: `${apiBasePath}/trained_models/pipeline_simulate`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/pipeline_simulate`,
method: 'POST',
body,
version: '1',
});
},
memoryUsage(type?: MlSavedObjectType, node?: string, showClosedJobs = false) {
return httpService.http<MemoryUsageInfo[]>({
path: `${apiBasePath}/model_management/memory_usage`,
path: `${ML_INTERNAL_BASE_PATH}/model_management/memory_usage`,
method: 'GET',
query: { type, node, showClosedJobs },
version: '1',
});
},
putTrainedModelConfig(modelId: string, config: object) {
return httpService.http<estypes.MlPutTrainedModelResponse>({
path: `${apiBasePath}/trained_models/${modelId}`,
path: `${ML_INTERNAL_BASE_PATH}/trained_models/${modelId}`,
method: 'PUT',
body: JSON.stringify(config),
version: '1',
});
},
};

View file

@ -6,16 +6,16 @@
*/
import React from 'react';
import { CoreStart } from '@kbn/core/public';
import { lastValueFrom } from 'rxjs';
import type { CoreStart } from '@kbn/core/public';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { extractInfluencers } from '../../../common/util/job_utils';
import { VIEW_BY_JOB_LABEL } from '../../application/explorer/explorer_constants';
import { AnomalyDetectorService } from '../../application/services/anomaly_detector_service';
import { getDefaultExplorerChartsPanelTitle } from './anomaly_charts_embeddable';
import { HttpService } from '../../application/services/http_service';
import { AnomalyChartsEmbeddableInput } from '..';
import type { AnomalyChartsEmbeddableInput } from '..';
import { resolveJobSelection } from '../common/resolve_job_selection';
import { AnomalyChartsInitializer } from './anomaly_charts_initializer';
import { mlApiServicesProvider } from '../../application/services/ml_api_service';
export async function resolveEmbeddableAnomalyChartsUserInput(
coreStart: CoreStart,
@ -23,14 +23,14 @@ export async function resolveEmbeddableAnomalyChartsUserInput(
): Promise<Partial<AnomalyChartsEmbeddableInput>> {
const { http, overlays } = coreStart;
const anomalyDetectorService = new AnomalyDetectorService(new HttpService(http));
const { getJobs } = mlApiServicesProvider(new HttpService(http));
return new Promise(async (resolve, reject) => {
try {
const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
const title = input?.title ?? getDefaultExplorerChartsPanelTitle(jobIds);
const jobs = await lastValueFrom(anomalyDetectorService.getJobs$(jobIds));
const influencers = anomalyDetectorService.extractInfluencers(jobs);
const { jobs } = await getJobs({ jobId: jobIds.join(',') });
const influencers = extractInfluencers(jobs);
influencers.push(VIEW_BY_JOB_LABEL);
const { theme$ } = coreStart.theme;
const modalSession = overlays.openModal(

View file

@ -6,16 +6,16 @@
*/
import React from 'react';
import { CoreStart } from '@kbn/core/public';
import { lastValueFrom } from 'rxjs';
import type { CoreStart } from '@kbn/core/public';
import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public';
import { extractInfluencers } from '../../../common/util/job_utils';
import { VIEW_BY_JOB_LABEL } from '../../application/explorer/explorer_constants';
import { AnomalySwimlaneInitializer } from './anomaly_swimlane_initializer';
import { AnomalyDetectorService } from '../../application/services/anomaly_detector_service';
import { getDefaultSwimlanePanelTitle } from './anomaly_swimlane_embeddable';
import { HttpService } from '../../application/services/http_service';
import { AnomalySwimlaneEmbeddableInput } from '..';
import type { AnomalySwimlaneEmbeddableInput } from '..';
import { resolveJobSelection } from '../common/resolve_job_selection';
import { mlApiServicesProvider } from '../../application/services/ml_api_service';
export async function resolveAnomalySwimlaneUserInput(
coreStart: CoreStart,
@ -23,14 +23,14 @@ export async function resolveAnomalySwimlaneUserInput(
): Promise<Partial<AnomalySwimlaneEmbeddableInput>> {
const { http, overlays } = coreStart;
const anomalyDetectorService = new AnomalyDetectorService(new HttpService(http));
const { getJobs } = mlApiServicesProvider(new HttpService(http));
return new Promise(async (resolve, reject) => {
try {
const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds);
const title = input?.title ?? getDefaultSwimlanePanelTitle(jobIds);
const jobs = await lastValueFrom(anomalyDetectorService.getJobs$(jobIds));
const influencers = anomalyDetectorService.extractInfluencers(jobs);
const { jobs } = await getJobs({ jobId: jobIds.join(',') });
const influencers = extractInfluencers(jobs);
influencers.push(VIEW_BY_JOB_LABEL);
const { theme$ } = coreStart.theme;
const modalSession = overlays.openModal(

View file

@ -40,6 +40,7 @@ import type {
DataRecognizerConfigResponse,
GeneralDatafeedsOverride,
JobSpecificOverride,
RecognizeResult,
} from '../../../common/types/modules';
import { isGeneralJobOverride } from '../../../common/types/modules';
import {
@ -80,14 +81,6 @@ interface Config {
isSavedObject: boolean;
}
export interface RecognizeResult {
id: string;
title: string;
query: any;
description: string;
logo: Logo;
}
interface ObjectExistResult {
id: string;
type: string;

View file

@ -5,5 +5,4 @@
* 2.0.
*/
export type { RecognizeResult } from './data_recognizer';
export { DataRecognizer, dataRecognizerFactory } from './data_recognizer';

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { RouteInitialization } from '../types';
import { wrapError } from '../client/error_wrapper';
import { mlAnomalyDetectionAlertPreviewRequest } from './schemas/alerting_schema';
@ -17,37 +18,44 @@ export function alertingRoutes(
/**
* @apiGroup Alerting
*
* @api {post} /api/ml/alerting/preview Preview alerting condition
* @api {post} /internal/ml/alerting/preview Preview alerting condition
* @apiName PreviewAlert
* @apiDescription Returns a preview of the alerting condition
*
* @apiSchema (body) mlAnomalyDetectionAlertPreviewRequest
*/
router.post(
{
path: '/api/ml/alerting/preview',
validate: {
body: mlAnomalyDetectionAlertPreviewRequest,
},
router.versioned
.post({
access: 'internal',
path: `${ML_INTERNAL_BASE_PATH}/alerting/preview`,
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response, client, context }) => {
try {
const alertingService = sharedServicesProviders.alertingServiceProvider(
(await context.core).savedObjects.client,
request
);
const result = await alertingService.preview(request.body);
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: mlAnomalyDetectionAlertPreviewRequest,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response, client, context }) => {
try {
const alertingService = sharedServicesProviders.alertingServiceProvider(
(await context.core).savedObjects.client,
request
);
const result = await alertingService.preview(request.body);
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -9,6 +9,7 @@ import Boom from '@hapi/boom';
import { i18n } from '@kbn/i18n';
import { SecurityPluginSetup } from '@kbn/security-plugin/server';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { isAnnotationsFeatureAvailable } from '../lib/check_annotations';
import { annotationServiceProvider } from '../models/annotation_service';
import { wrapError } from '../client/error_wrapper';
@ -40,7 +41,7 @@ export function annotationRoutes(
/**
* @apiGroup Annotations
*
* @api {post} /api/ml/annotations Gets annotations
* @api {post} /internal/ml/annotations Gets annotations
* @apiName GetAnnotations
* @apiDescription Gets annotations.
*
@ -49,109 +50,124 @@ export function annotationRoutes(
* @apiSuccess {Boolean} success
* @apiSuccess {Object} annotations
*/
router.post(
{
path: '/api/ml/annotations',
validate: {
body: getAnnotationsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/annotations`,
access: 'internal',
options: {
tags: ['access:ml:canGetAnnotations'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { getAnnotations } = annotationServiceProvider(client);
const resp = await getAnnotations(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { body: getAnnotationsSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { getAnnotations } = annotationServiceProvider(client);
const resp = await getAnnotations(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Annotations
*
* @api {put} /api/ml/annotations/index Index annotation
* @api {put} /internal/ml/annotations/index Index annotation
* @apiName IndexAnnotations
* @apiDescription Index the annotation.
*
* @apiSchema (body) indexAnnotationSchema
*/
router.put(
{
path: '/api/ml/annotations/index',
validate: {
body: indexAnnotationSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/annotations/index`,
access: 'internal',
options: {
tags: ['access:ml:canCreateAnnotation'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const annotationsFeatureAvailable = await isAnnotationsFeatureAvailable(client);
if (annotationsFeatureAvailable === false) {
throw getAnnotationsFeatureUnavailableErrorMessage();
}
const { indexAnnotation } = annotationServiceProvider(client);
const currentUser =
securityPlugin !== undefined ? securityPlugin.authc.getCurrentUser(request) : {};
// @ts-expect-error username doesn't exist on {}
const username = currentUser?.username ?? ANNOTATION_USER_UNKNOWN;
const resp = await indexAnnotation(request.body, username);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { body: indexAnnotationSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const annotationsFeatureAvailable = await isAnnotationsFeatureAvailable(client);
if (annotationsFeatureAvailable === false) {
throw getAnnotationsFeatureUnavailableErrorMessage();
}
const { indexAnnotation } = annotationServiceProvider(client);
const currentUser =
securityPlugin !== undefined ? securityPlugin.authc.getCurrentUser(request) : {};
// @ts-expect-error username doesn't exist on {}
const username = currentUser?.username ?? ANNOTATION_USER_UNKNOWN;
const resp = await indexAnnotation(request.body, username);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Annotations
*
* @api {delete} /api/ml/annotations/delete/:annotationId Deletes annotation
* @api {delete} /internal/ml/annotations/delete/:annotationId Deletes annotation
* @apiName DeleteAnnotation
* @apiDescription Deletes specified annotation
*
* @apiSchema (params) deleteAnnotationSchema
*/
router.delete(
{
path: '/api/ml/annotations/delete/{annotationId}',
validate: {
params: deleteAnnotationSchema,
},
router.versioned
.delete({
path: `${ML_INTERNAL_BASE_PATH}/annotations/delete/{annotationId}`,
access: 'internal',
options: {
tags: ['access:ml:canDeleteAnnotation'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const annotationsFeatureAvailable = await isAnnotationsFeatureAvailable(client);
if (annotationsFeatureAvailable === false) {
throw getAnnotationsFeatureUnavailableErrorMessage();
}
const annotationId = request.params.annotationId;
const { deleteAnnotation } = annotationServiceProvider(client);
const resp = await deleteAnnotation(annotationId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { params: deleteAnnotationSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const annotationsFeatureAvailable = await isAnnotationsFeatureAvailable(client);
if (annotationsFeatureAvailable === false) {
throw getAnnotationsFeatureUnavailableErrorMessage();
}
const annotationId = request.params.annotationId;
const { deleteAnnotation } = annotationServiceProvider(client);
const resp = await deleteAnnotation(annotationId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import { calendarSchema, calendarIdSchema, calendarIdsSchema } from './schemas/calendars_schema';
@ -45,171 +46,204 @@ export function calendars({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup Calendars
*
* @api {get} /api/ml/calendars Gets calendars
* @api {get} /internal/ml/calendars Gets calendars
* @apiName GetCalendars
* @apiDescription Gets calendars - size limit has been explicitly set to 1000
*/
router.get(
{
path: '/api/ml/calendars',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/calendars`,
access: 'internal',
options: {
tags: ['access:ml:canGetCalendars'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllCalendars(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllCalendars(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Calendars
*
* @api {get} /api/ml/calendars/:calendarIds Gets a calendar
* @api {get} /internal/ml/calendars/:calendarIds Gets a calendar
* @apiName GetCalendarById
* @apiDescription Gets calendar by id
*
* @apiSchema (params) calendarIdsSchema
*/
router.get(
{
path: '/api/ml/calendars/{calendarIds}',
validate: {
params: calendarIdsSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/calendars/{calendarIds}`,
access: 'internal',
options: {
tags: ['access:ml:canGetCalendars'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
let returnValue;
try {
const calendarIds = request.params.calendarIds.split(',');
if (calendarIds.length === 1) {
returnValue = await getCalendar(mlClient, calendarIds[0]);
} else {
returnValue = await getCalendarsByIds(mlClient, calendarIds);
}
return response.ok({
body: returnValue,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: calendarIdsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
let returnValue;
try {
const calendarIds = request.params.calendarIds.split(',');
if (calendarIds.length === 1) {
returnValue = await getCalendar(mlClient, calendarIds[0]);
} else {
returnValue = await getCalendarsByIds(mlClient, calendarIds);
}
return response.ok({
body: returnValue,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Calendars
*
* @api {put} /api/ml/calendars Creates a calendar
* @api {put} /internal/ml/calendars Creates a calendar
* @apiName PutCalendars
* @apiDescription Creates a calendar
*
* @apiSchema (body) calendarSchema
*/
router.put(
{
path: '/api/ml/calendars',
validate: {
body: calendarSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/calendars`,
access: 'internal',
options: {
tags: ['access:ml:canCreateCalendar'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = request.body;
// @ts-expect-error event interface incorrect
const resp = await newCalendar(mlClient, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: calendarSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = request.body;
// @ts-expect-error event interface incorrect
const resp = await newCalendar(mlClient, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Calendars
*
* @api {put} /api/ml/calendars/:calendarId Updates a calendar
* @api {put} /internal/ml/calendars/:calendarId Updates a calendar
* @apiName UpdateCalendarById
* @apiDescription Updates a calendar
*
* @apiSchema (params) calendarIdSchema
* @apiSchema (body) calendarSchema
*/
router.put(
{
path: '/api/ml/calendars/{calendarId}',
validate: {
params: calendarIdSchema,
body: calendarSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/calendars/{calendarId}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateCalendar'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { calendarId } = request.params;
const body = request.body;
// @ts-expect-error event interface incorrect
const resp = await updateCalendar(mlClient, calendarId, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: calendarIdSchema,
body: calendarSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { calendarId } = request.params;
const body = request.body;
// @ts-expect-error event interface incorrect
const resp = await updateCalendar(mlClient, calendarId, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Calendars
*
* @api {delete} /api/ml/calendars/:calendarId Deletes a calendar
* @api {delete} /internal/ml/calendars/:calendarId Deletes a calendar
* @apiName DeleteCalendarById
* @apiDescription Deletes a calendar
*
* @apiSchema (params) calendarIdSchema
*/
router.delete(
{
path: '/api/ml/calendars/{calendarId}',
validate: {
params: calendarIdSchema,
},
router.versioned
.delete({
path: `${ML_INTERNAL_BASE_PATH}/calendars/{calendarId}`,
access: 'internal',
options: {
tags: ['access:ml:canDeleteCalendar'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { calendarId } = request.params;
const resp = await deleteCalendar(mlClient, calendarId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: calendarIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { calendarId } = request.params;
const resp = await deleteCalendar(mlClient, calendarId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
import { IScopedClusterClient } from '@kbn/core/server';
import { FieldsForHistograms } from '@kbn/ml-agg-utils';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { DataVisualizer } from '../models/data_visualizer';
import {
@ -35,7 +36,7 @@ export function dataVisualizerRoutes({ router, routeGuard }: RouteInitialization
/**
* @apiGroup DataVisualizer
*
* @api {post} /api/ml/data_visualizer/get_field_histograms/:indexPattern Get histograms for fields
* @api {post} /internal/ml/data_visualizer/get_field_histograms/:indexPattern Get histograms for fields
* @apiName GetHistogramsForFields
* @apiDescription Returns the histograms on a list fields in the specified index pattern.
*
@ -44,39 +45,46 @@ export function dataVisualizerRoutes({ router, routeGuard }: RouteInitialization
*
* @apiSuccess {Object} fieldName histograms by field, keyed on the name of the field.
*/
router.post(
{
path: '/api/ml/data_visualizer/get_field_histograms/{indexPattern}',
validate: {
params: indexPatternSchema,
body: dataVisualizerFieldHistogramsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/data_visualizer/get_field_histograms/{indexPattern}`,
access: 'internal',
options: {
tags: ['access:ml:canGetFieldInfo'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const {
params: { indexPattern },
body: { query, fields, samplerShardSize, runtimeMappings },
} = request;
const results = await getHistogramsForFields(
client,
indexPattern,
query,
fields,
samplerShardSize,
runtimeMappings
);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: indexPatternSchema,
body: dataVisualizerFieldHistogramsSchema,
},
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const {
params: { indexPattern },
body: { query, fields, samplerShardSize, runtimeMappings },
} = request;
const results = await getHistogramsForFields(
client,
indexPattern,
query,
fields,
samplerShardSize,
runtimeMappings
);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -6,6 +6,7 @@
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import {
@ -23,365 +24,431 @@ export function dataFeedRoutes({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup DatafeedService
*
* @api {get} /api/ml/datafeeds Get all datafeeds
* @api {get} /internal/ml/datafeeds Get all datafeeds
* @apiName GetDatafeeds
* @apiDescription Retrieves configuration information for datafeeds
*/
router.get(
{
path: '/api/ml/datafeeds',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds`,
access: 'internal',
options: {
tags: ['access:ml:canGetDatafeeds'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.getDatafeeds();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.getDatafeeds();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {get} /api/ml/datafeeds/:datafeedId Get datafeed for given datafeed id
* @api {get} /internal/ml/datafeeds/:datafeedId Get datafeed for given datafeed id
* @apiName GetDatafeed
* @apiDescription Retrieves configuration information for datafeed
*
* @apiSchema (params) datafeedIdSchema
*/
router.get(
{
path: '/api/ml/datafeeds/{datafeedId}',
validate: {
params: datafeedIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}`,
access: 'internal',
options: {
tags: ['access:ml:canGetDatafeeds'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.getDatafeeds({ datafeed_id: datafeedId });
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.getDatafeeds({ datafeed_id: datafeedId });
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {get} /api/ml/datafeeds/_stats Get stats for all datafeeds
* @api {get} /internal/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,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetDatafeeds'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.getDatafeedStats();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.getDatafeedStats();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {get} /api/ml/datafeeds/:datafeedId/_stats Get datafeed stats for given datafeed id
* @api {get} /internal/ml/datafeeds/:datafeedId/_stats Get datafeed stats for given datafeed id
* @apiName GetDatafeedStats
* @apiDescription Retrieves usage information for datafeed
*
* @apiSchema (params) datafeedIdSchema
*/
router.get(
{
path: '/api/ml/datafeeds/{datafeedId}/_stats',
validate: {
params: datafeedIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}/_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetDatafeeds'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.getDatafeedStats({
datafeed_id: datafeedId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.getDatafeedStats({
datafeed_id: datafeedId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {put} /api/ml/datafeeds/:datafeedId Creates datafeed
* @api {put} /internal/ml/datafeeds/:datafeedId Creates datafeed
* @apiName CreateDatafeed
* @apiDescription Instantiates a datafeed
*
* @apiSchema (params) datafeedIdSchema
* @apiSchema (body) datafeedConfigSchema
*/
router.put(
{
path: '/api/ml/datafeeds/{datafeedId}',
validate: {
params: datafeedIdSchema,
body: datafeedConfigSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.putDatafeed(
{
datafeed_id: datafeedId,
// @ts-expect-error type mismatch for `time_span` (string | number versus estypes.Duration)
body: request.body,
},
getAuthorizationHeader(request)
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
body: datafeedConfigSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.putDatafeed(
{
datafeed_id: datafeedId,
// @ts-expect-error type mismatch for `time_span` (string | number versus estypes.Duration)
body: request.body,
},
getAuthorizationHeader(request)
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {post} /api/ml/datafeeds/:datafeedId/_update Updates datafeed for given datafeed id
* @api {post} /internal/ml/datafeeds/:datafeedId/_update Updates datafeed for given datafeed id
* @apiName UpdateDatafeed
* @apiDescription Updates certain properties of a datafeed
*
* @apiSchema (params) datafeedIdSchema
* @apiSchema (body) datafeedConfigSchema
*/
router.post(
{
path: '/api/ml/datafeeds/{datafeedId}/_update',
validate: {
params: datafeedIdSchema,
body: datafeedConfigSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}/_update`,
access: 'internal',
options: {
tags: ['access:ml:canUpdateDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.updateDatafeed(
{
datafeed_id: datafeedId,
// @ts-expect-error type mismatch for `time_span` (string | number versus estypes.Duration)
body: request.body,
},
getAuthorizationHeader(request)
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
body: datafeedConfigSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.updateDatafeed(
{
datafeed_id: datafeedId,
// @ts-expect-error type mismatch for `time_span` (string | number versus estypes.Duration)
body: request.body,
},
getAuthorizationHeader(request)
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {delete} /api/ml/datafeeds/:datafeedId Deletes datafeed
* @api {delete} /internal/ml/datafeeds/:datafeedId Deletes datafeed
* @apiName DeleteDatafeed
* @apiDescription Deletes an existing datafeed
*
* @apiSchema (params) datafeedIdSchema
* @apiSchema (query) deleteDatafeedQuerySchema
*/
router.delete(
{
path: '/api/ml/datafeeds/{datafeedId}',
validate: {
params: datafeedIdSchema,
query: deleteDatafeedQuerySchema,
},
router.versioned
.delete({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}`,
access: 'internal',
options: {
tags: ['access:ml:canDeleteDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const options: estypes.MlDeleteDatafeedRequest = {
datafeed_id: request.params.datafeedId,
};
const force = request.query.force;
if (force !== undefined) {
options.force = force;
}
const body = await mlClient.deleteDatafeed(options);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
query: deleteDatafeedQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const options: estypes.MlDeleteDatafeedRequest = {
datafeed_id: request.params.datafeedId,
};
const force = request.query.force;
if (force !== undefined) {
options.force = force;
}
const body = await mlClient.deleteDatafeed(options);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {post} /api/ml/datafeeds/:datafeedId/_start Starts datafeed for given datafeed id(s)
* @api {post} /internal/ml/datafeeds/:datafeedId/_start Starts datafeed for given datafeed id(s)
* @apiName StartDatafeed
* @apiDescription Starts one or more datafeeds
*
* @apiSchema (params) datafeedIdSchema
* @apiSchema (body) startDatafeedSchema
*/
router.post(
{
path: '/api/ml/datafeeds/{datafeedId}/_start',
validate: {
params: datafeedIdSchema,
body: startDatafeedSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}/_start`,
access: 'internal',
options: {
tags: ['access:ml:canStartStopDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const { start, end } = request.body;
const body = await mlClient.startDatafeed({
datafeed_id: datafeedId,
body: {
start: start !== undefined ? String(start) : undefined,
end: end !== undefined ? String(end) : undefined,
},
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
body: startDatafeedSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const { start, end } = request.body;
const body = await mlClient.startDatafeed({
datafeed_id: datafeedId,
body: {
start: start !== undefined ? String(start) : undefined,
end: end !== undefined ? String(end) : undefined,
},
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {post} /api/ml/datafeeds/:datafeedId/_stop Stops datafeed for given datafeed id(s)
* @api {post} /internal/ml/datafeeds/:datafeedId/_stop Stops datafeed for given datafeed id(s)
* @apiName StopDatafeed
* @apiDescription Stops one or more datafeeds
*
* @apiSchema (params) datafeedIdSchema
*/
router.post(
{
path: '/api/ml/datafeeds/{datafeedId}/_stop',
validate: {
params: datafeedIdSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}/_stop`,
access: 'internal',
options: {
tags: ['access:ml:canStartStopDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.stopDatafeed({
datafeed_id: datafeedId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.stopDatafeed({
datafeed_id: datafeedId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DatafeedService
*
* @api {get} /api/ml/datafeeds/:datafeedId/_preview Preview datafeed for given datafeed id
* @api {get} /internal/ml/datafeeds/:datafeedId/_preview Preview datafeed for given datafeed id
* @apiName PreviewDatafeed
* @apiDescription Previews a datafeed
*
* @apiSchema (params) datafeedIdSchema
*/
router.get(
{
path: '/api/ml/datafeeds/{datafeedId}/_preview',
validate: {
params: datafeedIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/datafeeds/{datafeedId}/_preview`,
access: 'internal',
options: {
tags: ['access:ml:canPreviewDatafeed'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.previewDatafeed(
{
datafeed_id: datafeedId,
},
{ ...getAuthorizationHeader(request), maxRetries: 0 }
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: datafeedIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const datafeedId = request.params.datafeedId;
const body = await mlClient.previewDatafeed(
{
datafeed_id: datafeedId,
},
{ ...getAuthorizationHeader(request), maxRetries: 0 }
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -6,6 +6,7 @@
*/
import { IScopedClusterClient } from '@kbn/core/server';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import {
@ -33,7 +34,7 @@ export function fieldsService({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup FieldsService
*
* @api {post} /api/ml/fields_service/field_cardinality Get cardinality of fields
* @api {post} /internal/ml/fields_service/field_cardinality Get cardinality of fields
* @apiName GetCardinalityOfFields
* @apiDescription Returns the cardinality of one or more fields. Returns an Object whose keys are the names of the fields, with values equal to the cardinality of the field
*
@ -41,33 +42,40 @@ export function fieldsService({ router, routeGuard }: RouteInitialization) {
*
* @apiSuccess {number} fieldName cardinality of the field.
*/
router.post(
{
path: '/api/ml/fields_service/field_cardinality',
validate: {
body: getCardinalityOfFieldsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/fields_service/field_cardinality`,
access: 'internal',
options: {
tags: ['access:ml:canGetFieldInfo'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const resp = await getCardinalityOfFields(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getCardinalityOfFieldsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const resp = await getCardinalityOfFields(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup FieldsService
*
* @api {post} /api/ml/fields_service/time_field_range Get time field range
* @api {post} /internal/ml/fields_service/time_field_range Get time field range
* @apiName GetTimeFieldRange
* @apiDescription Returns the time range for the given index and query using the specified time range.
*
@ -76,26 +84,33 @@ export function fieldsService({ router, routeGuard }: RouteInitialization) {
* @apiSuccess {Object} start start of time range with epoch and string properties.
* @apiSuccess {Object} end end of time range with epoch and string properties.
*/
router.post(
{
path: '/api/ml/fields_service/time_field_range',
validate: {
body: getTimeFieldRangeSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/fields_service/time_field_range`,
access: 'internal',
options: {
tags: ['access:ml:canGetFieldInfo'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const resp = await getTimeFieldRange(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getTimeFieldRangeSchema,
},
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const resp = await getTimeFieldRange(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import { createFilterSchema, filterIdSchema, updateFilterSchema } from './schemas/filters_schema';
@ -47,38 +48,43 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup Filters
*
* @api {get} /api/ml/filters Get filters
* @api {get} /internal/ml/filters Get filters
* @apiName GetFilters
* @apiDescription Retrieves the list of filters which are used for custom rules in anomaly detection. Sets the size limit explicitly to return a maximum of 1000.
*
* @apiSuccess {Boolean} success
* @apiSuccess {Object[]} filters list of filters
*/
router.get(
{
path: '/api/ml/filters',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/filters`,
access: 'internal',
options: {
tags: ['access:ml:canGetFilters'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllFilters(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllFilters(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Filters
*
* @api {get} /api/ml/filters/:filterId Gets filter by ID
* @api {get} /internal/ml/filters/:filterId Gets filter by ID
* @apiName GetFilterById
* @apiDescription Retrieves the filter with the specified ID.
*
@ -87,32 +93,37 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) {
* @apiSuccess {Boolean} success
* @apiSuccess {Object} filter the filter with the specified ID
*/
router.get(
{
path: '/api/ml/filters/{filterId}',
validate: {
params: filterIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/filters/{filterId}`,
access: 'internal',
options: {
tags: ['access:ml:canGetFilters'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getFilter(mlClient, request.params.filterId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { params: filterIdSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getFilter(mlClient, request.params.filterId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Filters
*
* @api {put} /api/ml/filters Creates a filter
* @api {put} /internal/ml/filters Creates a filter
* @apiName CreateFilter
* @apiDescription Instantiates a filter, for use by custom rules in anomaly detection.
*
@ -121,34 +132,39 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) {
* @apiSuccess {Boolean} success
* @apiSuccess {Object} filter created filter
*/
router.put(
{
path: '/api/ml/filters',
validate: {
body: createFilterSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/filters`,
access: 'internal',
options: {
tags: ['access:ml:canCreateFilter'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = request.body;
const resp = await newFilter(mlClient, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { body: createFilterSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = request.body;
const resp = await newFilter(mlClient, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Filters
*
* @api {put} /api/ml/filters/:filterId Updates a filter
* @api {put} /internal/ml/filters/:filterId Updates a filter
* @apiName UpdateFilter
* @apiDescription Updates the description of a filter, adds items or removes items.
*
@ -158,69 +174,83 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) {
* @apiSuccess {Boolean} success
* @apiSuccess {Object} filter updated filter
*/
router.put(
{
path: '/api/ml/filters/{filterId}',
validate: {
params: filterIdSchema,
body: updateFilterSchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/filters/{filterId}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateFilter'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { filterId } = request.params;
const body = request.body;
const resp = await updateFilter(mlClient, filterId, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: filterIdSchema,
body: updateFilterSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { filterId } = request.params;
const body = request.body;
const resp = await updateFilter(mlClient, filterId, body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Filters
*
* @api {delete} /api/ml/filters/:filterId Delete filter
* @api {delete} /internal/ml/filters/:filterId Delete filter
* @apiName DeleteFilter
* @apiDescription Deletes the filter with the specified ID.
*
* @apiSchema (params) filterIdSchema
*/
router.delete(
{
path: '/api/ml/filters/{filterId}',
validate: {
params: filterIdSchema,
},
router.versioned
.delete({
path: `${ML_INTERNAL_BASE_PATH}/filters/{filterId}`,
access: 'internal',
options: {
tags: ['access:ml:canDeleteFilter'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { filterId } = request.params;
const resp = await deleteFilter(mlClient, filterId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: filterIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { filterId } = request.params;
const resp = await deleteFilter(mlClient, filterId);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup Filters
*
* @api {get} /api/ml/filters/_stats Gets filters stats
* @api {get} /internal/ml/filters/_stats Gets filters stats
* @apiName GetFiltersStats
* @apiDescription Retrieves the list of filters which are used for custom rules in anomaly detection,
* with stats on the list of jobs and detectors which are using each filter.
@ -228,24 +258,29 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) {
* @apiSuccess {Boolean} success
* @apiSuccess {Object[]} filters list of filters with stats on usage
*/
router.get(
{
path: '/api/ml/filters/_stats',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/filters/_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetFilters'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllFilterStats(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const resp = await getAllFilterStats(mlClient);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import { indicesSchema } from './schemas/indices_schema';
@ -16,34 +17,41 @@ export function indicesRoutes({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup Indices
*
* @api {post} /api/ml/indices/field_caps Field caps
* @api {post} /internal/ml/indices/field_caps Field caps
* @apiName FieldCaps
* @apiDescription Retrieves the capabilities of fields among multiple indices.
*
* @apiSchema (body) indicesSchema
*/
router.post(
{
path: '/api/ml/indices/field_caps',
validate: {
body: indicesSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/indices/field_caps`,
access: 'internal',
options: {
tags: ['access:ml:canGetFieldInfo'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const {
body: { index, fields: requestFields },
} = request;
const fields =
requestFields !== undefined && Array.isArray(requestFields) ? requestFields : '*';
const body = await client.asCurrentUser.fieldCaps({ index, fields }, { maxRetries: 0 });
return response.ok({ body });
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: indicesSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const {
body: { index, fields: requestFields },
} = request;
const fields =
requestFields !== undefined && Array.isArray(requestFields) ? requestFields : '*';
const body = await client.asCurrentUser.fieldCaps({ index, fields }, { maxRetries: 0 });
return response.ok({ body });
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import { jobAuditMessagesProvider } from '../models/job_audit_messages';
@ -21,116 +22,137 @@ export function jobAuditMessagesRoutes({ router, routeGuard }: RouteInitializati
/**
* @apiGroup JobAuditMessages
*
* @api {get} /api/ml/job_audit_messages/messages/:jobId Get audit messages
* @api {get} /internal/ml/job_audit_messages/messages/:jobId Get audit messages
* @apiName GetJobAuditMessages
* @apiDescription Returns audit messages for specified job ID
*
* @apiSchema (params) jobAuditMessagesJobIdSchema
* @apiSchema (query) jobAuditMessagesQuerySchema
*/
router.get(
{
path: '/api/ml/job_audit_messages/messages/{jobId}',
validate: {
params: jobAuditMessagesJobIdSchema,
query: jobAuditMessagesQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/job_audit_messages/messages/{jobId}`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { getJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { jobId } = request.params;
const { from, start, end } = request.query;
const resp = await getJobAuditMessages(mlSavedObjectService, {
jobId,
from,
start,
end,
});
})
.addVersion(
{
version: '1',
validate: {
request: {
params: jobAuditMessagesJobIdSchema,
query: jobAuditMessagesQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { getJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { jobId } = request.params;
const { from, start, end } = request.query;
const resp = await getJobAuditMessages(mlSavedObjectService, {
jobId,
from,
start,
end,
});
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
/**
* @apiGroup JobAuditMessages
*
* @api {get} /api/ml/job_audit_messages/messages Get all audit messages
* @api {get} /internal/ml/job_audit_messages/messages Get all audit messages
* @apiName GetAllJobAuditMessages
* @apiDescription Returns all audit messages
*
* @apiSchema (query) jobAuditMessagesQuerySchema
*/
router.get(
{
path: '/api/ml/job_audit_messages/messages',
validate: {
query: jobAuditMessagesQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/job_audit_messages/messages`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { getJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { from } = request.query;
const resp = await getJobAuditMessages(mlSavedObjectService, { from });
})
.addVersion(
{
version: '1',
validate: {
request: {
query: jobAuditMessagesQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { getJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { from } = request.query;
const resp = await getJobAuditMessages(mlSavedObjectService, { from });
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
/**
* @apiGroup JobAuditMessages
*
* @api {put} /api/ml/job_audit_messages/clear_messages Clear messages
* @api {put} /internal/ml/job_audit_messages/clear_messages Clear messages
* @apiName ClearJobAuditMessages
* @apiDescription Clear the job audit messages.
*
* @apiSchema (body) clearJobAuditMessagesSchema
*/
router.put(
{
path: '/api/ml/job_audit_messages/clear_messages',
validate: {
body: clearJobAuditMessagesBodySchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/job_audit_messages/clear_messages`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { clearJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { jobId, notificationIndices } = request.body;
const resp = await clearJobAuditMessages(jobId, notificationIndices);
})
.addVersion(
{
version: '1',
validate: {
request: {
body: clearJobAuditMessagesBodySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { clearJobAuditMessages } = jobAuditMessagesProvider(client, mlClient);
const { jobId, notificationIndices } = request.body;
const resp = await clearJobAuditMessages(jobId, notificationIndices);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
}

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
import Boom from '@hapi/boom';
import { IScopedClusterClient } from '@kbn/core/server';
import { TypeOf } from '@kbn/config-schema';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import type { AnalysisConfig, Datafeed } from '../../common/types/anomaly_detection_jobs';
import { wrapError } from '../client/error_wrapper';
import type { RouteInitialization } from '../types';
@ -65,52 +66,58 @@ export function jobValidationRoutes({ router, mlLicense, routeGuard }: RouteInit
/**
* @apiGroup JobValidation
*
* @api {post} /api/ml/validate/estimate_bucket_span Estimate bucket span
* @api {post} /internal/ml/validate/estimate_bucket_span Estimate bucket span
* @apiName EstimateBucketSpan
* @apiDescription Estimates minimum viable bucket span based on the characteristics of a pre-viewed subset of the data
*
* @apiSchema (body) estimateBucketSpanSchema
*/
router.post(
{
path: '/api/ml/validate/estimate_bucket_span',
validate: {
body: estimateBucketSpanSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/validate/estimate_bucket_span`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
let errorResp;
const resp = await estimateBucketSpanFactory(client)(request.body)
// this catch gets triggered when the estimation code runs without error
// but isn't able to come up with a bucket span estimation.
// this doesn't return a HTTP error but an object with an error message a HTTP error would be
// too severe for this case.
.catch((error: any) => {
errorResp = {
error: true,
message: error,
};
});
return response.ok({
body: errorResp !== undefined ? errorResp : resp,
});
} catch (e) {
// this catch gets triggered when an actual error gets thrown when running
// the estimation code, for example when the request payload is malformed
throw Boom.badRequest(e);
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { body: estimateBucketSpanSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
let errorResp;
const resp = await estimateBucketSpanFactory(client)(request.body)
// this catch gets triggered when the estimation code runs without error
// but isn't able to come up with a bucket span estimation.
// this doesn't return a HTTP error but an object with an error message a HTTP error would be
// too severe for this case.
.catch((error: any) => {
errorResp = {
error: true,
message: error,
};
});
return response.ok({
body: errorResp !== undefined ? errorResp : resp,
});
} catch (e) {
// this catch gets triggered when an actual error gets thrown when running
// the estimation code, for example when the request payload is malformed
throw Boom.badRequest(e);
}
})
);
/**
* @apiGroup JobValidation
*
* @api {post} /api/ml/validate/calculate_model_memory_limit Calculates model memory limit
* @api {post} /internal/ml/validate/calculate_model_memory_limit Calculates model memory limit
* @apiName CalculateModelMemoryLimit
* @apiDescription Calls _estimate_model_memory endpoint to retrieve model memory estimation.
*
@ -118,139 +125,167 @@ export function jobValidationRoutes({ router, mlLicense, routeGuard }: RouteInit
*
* @apiSuccess {String} modelMemoryLimit
*/
router.post(
{
path: '/api/ml/validate/calculate_model_memory_limit',
validate: {
body: modelMemoryLimitSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/validate/calculate_model_memory_limit`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const resp = await calculateModelMemoryLimit(client, mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: modelMemoryLimitSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const resp = await calculateModelMemoryLimit(client, mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup JobValidation
*
* @api {post} /api/ml/validate/cardinality Validate cardinality
* @api {post} /internal/ml/validate/cardinality Validate cardinality
* @apiName ValidateCardinality
* @apiDescription Validates cardinality for the given job configuration
*
* @apiSchema (body) validateCardinalitySchema
*/
router.post(
{
path: '/api/ml/validate/cardinality',
validate: {
body: validateCardinalitySchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/validate/cardinality`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
// @ts-expect-error datafeed config is incorrect
const resp = await validateCardinality(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: validateCardinalitySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
// @ts-expect-error datafeed config is incorrect
const resp = await validateCardinality(client, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup JobValidation
*
* @api {post} /api/ml/validate/job Validates job
* @api {post} /internal/ml/validate/job Validates job
* @apiName ValidateJob
* @apiDescription Validates the given job configuration
*
* @apiSchema (body) validateJobSchema
*/
router.post(
{
path: '/api/ml/validate/job',
validate: {
body: validateJobSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/validate/job`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const resp = await validateJob(
client,
mlClient,
request.body,
getAuthorizationHeader(request),
mlLicense.isSecurityEnabled() === false
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: validateJobSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const resp = await validateJob(
client,
mlClient,
request.body,
getAuthorizationHeader(request),
mlLicense.isSecurityEnabled() === false
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup DataFeedPreviewValidation
*
* @api {post} /api/ml/validate/datafeed_preview Validates datafeed preview
* @api {post} /internal/ml/validate/datafeed_preview Validates datafeed preview
* @apiName ValidateDataFeedPreview
* @apiDescription Validates that the datafeed preview runs successfully and produces results
*
* @apiSchema (body) validateDatafeedPreviewSchema
*/
router.post(
{
path: '/api/ml/validate/datafeed_preview',
validate: {
body: validateDatafeedPreviewSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/validate/datafeed_preview`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const {
body: { job, start, end },
} = request;
const resp = await validateDatafeedPreview(
mlClient,
getAuthorizationHeader(request),
job as CombinedJob,
start,
end
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: validateDatafeedPreviewSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const {
body: { job, start, end },
} = request;
const resp = await validateDatafeedPreview(
mlClient,
getAuthorizationHeader(request),
job as CombinedJob,
start,
end
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { getJsonSchemaQuerySchema } from '../../common/api_schemas/json_schema_schema';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
@ -14,35 +15,42 @@ export function jsonSchemaRoutes({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup JsonSchema
*
* @api {get} /api/ml/json_schema Get requested JSON schema
* @api {get} /internal/ml/json_schema Get requested JSON schema
* @apiName GetJsonSchema
* @apiDescription Retrieves the JSON schema
*/
router.get(
{
path: '/api/ml/json_schema',
validate: {
query: getJsonSchemaQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/json_schema`,
access: 'internal',
options: {
tags: ['access:ml:canAccessML'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response }) => {
try {
const jsonSchemaService = new JsonSchemaService();
const result = await jsonSchemaService.extractSchema(
request.query.path,
request.query.method
);
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
query: getJsonSchemaQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response }) => {
try {
const jsonSchemaService = new JsonSchemaService();
const result = await jsonSchemaService.extractSchema(
request.query.path,
request.query.method
);
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -7,6 +7,7 @@
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { BUILT_IN_MODEL_TYPE, BUILT_IN_MODEL_TAG } from '@kbn/ml-trained-models-utils';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import type { RouteInitialization } from '../types';
import { listTypeSchema } from './schemas/management_schema';
@ -26,19 +27,17 @@ export function managementRoutes({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup Management
*
* @api {get} /api/ml/management/list/:listType Management list
* @api {get} /internal/ml/management/list/:listType Management list
* @apiName ManagementList
* @apiDescription Returns a list of anomaly detection jobs, data frame analytics jobs or trained models
*
* @apiSchema (params) listTypeSchema
*
*/
router.get(
{
path: '/api/ml/management/list/{listType}',
validate: {
params: listTypeSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/management/list/{listType}`,
access: 'internal',
options: {
tags: [
'access:ml:canCreateJob',
@ -46,108 +45,117 @@ export function managementRoutes({ router, routeGuard }: RouteInitialization) {
'access:ml:canCreateTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { listType } = request.params;
const { jobsSpaces, trainedModelsSpaces } = checksFactory(client, mlSavedObjectService);
})
.addVersion(
{
version: '1',
validate: {
request: {
params: listTypeSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlClient, request, response, mlSavedObjectService }) => {
try {
const { listType } = request.params;
const { jobsSpaces, trainedModelsSpaces } = checksFactory(client, mlSavedObjectService);
switch (listType) {
case 'anomaly-detector':
const { jobsSummary } = jobServiceProvider(client, mlClient);
const [jobs, adJobStatus] = await Promise.all([jobsSummary(), jobsSpaces()]);
switch (listType) {
case 'anomaly-detector':
const { jobsSummary } = jobServiceProvider(client, mlClient);
const [jobs, adJobStatus] = await Promise.all([jobsSummary(), jobsSpaces()]);
const adJobsWithSpaces: AnomalyDetectionManagementItems[] = jobs.map((job) => {
return {
id: job.id,
description: job.description,
jobState: job.jobState,
datafeedState: job.datafeedState,
spaces: adJobStatus['anomaly-detector'][job.id] ?? [],
};
});
const adJobsWithSpaces: AnomalyDetectionManagementItems[] = jobs.map((job) => {
return {
id: job.id,
description: job.description,
jobState: job.jobState,
datafeedState: job.datafeedState,
spaces: adJobStatus['anomaly-detector'][job.id] ?? [],
};
});
return response.ok({
body: adJobsWithSpaces,
});
case 'data-frame-analytics':
const [
{ data_frame_analytics: dfaJobs },
{ data_frame_analytics: dfaJobsStats },
dfaJobStatus,
] = await Promise.all([
mlClient.getDataFrameAnalytics({
size: 10000,
}),
mlClient.getDataFrameAnalyticsStats({
size: 10000,
}),
jobsSpaces(),
]);
return response.ok({
body: adJobsWithSpaces,
});
case 'data-frame-analytics':
const [
{ data_frame_analytics: dfaJobs },
{ data_frame_analytics: dfaJobsStats },
dfaJobStatus,
] = await Promise.all([
mlClient.getDataFrameAnalytics({
size: 10000,
}),
mlClient.getDataFrameAnalyticsStats({
size: 10000,
}),
jobsSpaces(),
]);
const dfaStatsMapped = dfaJobsStats.reduce((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {} as Record<string, estypes.MlDataframeAnalytics>);
const dfaStatsMapped = dfaJobsStats.reduce((acc, cur) => {
acc[cur.id] = cur;
return acc;
}, {} as Record<string, estypes.MlDataframeAnalytics>);
const dfaJobsWithSpaces: AnalyticsManagementItems[] = dfaJobs.map((j) => {
const id = j.id;
return {
id,
description: j.description ?? '',
source_index: j.source.index as string[], // esclient types are wrong
dest_index: j.dest.index,
job_type: Object.keys(j.analysis)[0] ?? '',
state: dfaStatsMapped[id]?.state ?? '',
spaces: dfaJobStatus['data-frame-analytics'][id] ?? [],
};
});
return response.ok({
body: dfaJobsWithSpaces,
});
const dfaJobsWithSpaces: AnalyticsManagementItems[] = dfaJobs.map((j) => {
const id = j.id;
return {
id,
description: j.description ?? '',
source_index: j.source.index as string[], // esclient types are wrong
dest_index: j.dest.index,
job_type: Object.keys(j.analysis)[0] ?? '',
state: dfaStatsMapped[id]?.state ?? '',
spaces: dfaJobStatus['data-frame-analytics'][id] ?? [],
};
});
return response.ok({
body: dfaJobsWithSpaces,
});
case 'trained-model':
const [
{ trained_model_configs: models },
{ trained_model_stats: modelsStats },
modelSpaces,
] = await Promise.all([
mlClient.getTrainedModels(),
mlClient.getTrainedModelsStats(),
trainedModelsSpaces(),
]);
case 'trained-model':
const [
{ trained_model_configs: models },
{ trained_model_stats: modelsStats },
modelSpaces,
] = await Promise.all([
mlClient.getTrainedModels(),
mlClient.getTrainedModelsStats(),
trainedModelsSpaces(),
]);
const modelStatsMapped = modelsStats.reduce((acc, cur) => {
acc[cur.model_id] = cur;
return acc;
}, {} as Record<string, estypes.MlTrainedModelStats>);
const modelStatsMapped = modelsStats.reduce((acc, cur) => {
acc[cur.model_id] = cur;
return acc;
}, {} as Record<string, estypes.MlTrainedModelStats>);
const modelsWithSpaces: TrainedModelsManagementItems[] = models.map((m) => {
const id = m.model_id;
return {
id,
description: m.description ?? '',
state: modelStatsMapped[id].deployment_stats?.state ?? '',
type: [
m.model_type,
...Object.keys(m.inference_config),
...(m.tags.includes(BUILT_IN_MODEL_TAG) ? [BUILT_IN_MODEL_TYPE] : []),
],
spaces: modelSpaces.trainedModels[id] ?? [],
};
});
return response.ok({
body: modelsWithSpaces,
});
default:
// this should never be hit because of the route's schema checks.
throw Error('Specified listType not supported');
const modelsWithSpaces: TrainedModelsManagementItems[] = models.map((m) => {
const id = m.model_id;
return {
id,
description: m.description ?? '',
state: modelStatsMapped[id].deployment_stats?.state ?? '',
type: [
m.model_type,
...Object.keys(m.inference_config),
...(m.tags.includes(BUILT_IN_MODEL_TAG) ? [BUILT_IN_MODEL_TYPE] : []),
],
spaces: modelSpaces.trainedModels[id] ?? [],
};
});
return response.ok({
body: modelsWithSpaces,
});
default:
// this should never be hit because of the route's schema checks.
throw Error('Specified listType not supported');
}
} catch (e) {
return response.customError(wrapError(e));
}
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
)
);
}

View file

@ -13,6 +13,7 @@
*/
import { schema } from '@kbn/config-schema';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { RouteInitialization } from '../types';
import { wrapError } from '../client/error_wrapper';
@ -23,14 +24,14 @@ export function modelManagementRoutes({ router, routeGuard }: RouteInitializatio
/**
* @apiGroup ModelManagement
*
* @api {get} /api/ml/model_management/nodes_overview Get node overview about the models allocation
* @api {get} /internal/ml/model_management/nodes_overview Get node overview about the models allocation
* @apiName GetModelManagementNodesOverview
* @apiDescription Retrieves the list of ML nodes with memory breakdown and allocated models info
*/
router.get(
{
path: '/api/ml/model_management/nodes_overview',
validate: {},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/model_management/nodes_overview`,
access: 'internal',
options: {
tags: [
'access:ml:canViewMlNodes',
@ -39,37 +40,36 @@ export function modelManagementRoutes({ router, routeGuard }: RouteInitializatio
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response }) => {
try {
const memoryUsageService = new MemoryUsageService(mlClient);
const result = await memoryUsageService.getNodesOverview();
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response }) => {
try {
const memoryUsageService = new MemoryUsageService(mlClient);
const result = await memoryUsageService.getNodesOverview();
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ModelManagement
*
* @api {get} /api/ml/model_management/memory_usage Memory usage for jobs and trained models
* @api {get} /internal/ml/model_management/memory_usage Memory usage for jobs and trained models
* @apiName GetModelManagementMemoryUsage
* @apiDescription Returns the memory usage for jobs and trained models
*/
router.get(
{
path: '/api/ml/model_management/memory_usage',
validate: {
query: schema.object({
type: schema.maybe(itemTypeLiterals),
node: schema.maybe(schema.string()),
showClosedJobs: schema.maybe(schema.boolean()),
}),
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/model_management/memory_usage`,
access: 'internal',
options: {
tags: [
'access:ml:canViewMlNodes',
@ -78,21 +78,34 @@ export function modelManagementRoutes({ router, routeGuard }: RouteInitializatio
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response, request }) => {
try {
const memoryUsageService = new MemoryUsageService(mlClient);
return response.ok({
body: await memoryUsageService.getMemorySizes(
request.query.type,
request.query.node,
request.query.showClosedJobs
),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
query: schema.object({
type: schema.maybe(itemTypeLiterals),
node: schema.maybe(schema.string()),
showClosedJobs: schema.maybe(schema.boolean()),
}),
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, response, request }) => {
try {
const memoryUsageService = new MemoryUsageService(mlClient);
return response.ok({
body: await memoryUsageService.getMemorySizes(
request.query.type,
request.query.node,
request.query.showClosedJobs
),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -13,6 +13,7 @@ import type {
SavedObjectsClientContract,
} from '@kbn/core/server';
import type { DataViewsService } from '@kbn/data-views-plugin/common';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import type { DatafeedOverride, JobOverride } from '../../common/types/modules';
import { wrapError } from '../client/error_wrapper';
import { dataRecognizerFactory } from '../models/data_recognizer';
@ -143,7 +144,7 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) {
/**
* @apiGroup Modules
*
* @api {get} /api/ml/modules/recognize/:indexPatternTitle Recognize index pattern
* @api {get} /internal/ml/modules/recognize/:indexPatternTitle Recognize index pattern
* @apiName RecognizeIndex
* @apiDescription By supplying an index pattern, discover if any of the modules are a match for data in that index.
* @apiSchema (params) modulesIndexPatternTitleSchema
@ -168,52 +169,59 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) {
* }
* }]
*/
router.get(
{
path: '/api/ml/modules/recognize/{indexPatternTitle}',
validate: {
params: modulesIndexPatternTitleSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/modules/recognize/{indexPatternTitle}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { indexPatternTitle } = request.params;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const results = await recognize(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
indexPatternTitle
);
})
.addVersion(
{
version: '1',
validate: {
request: {
params: modulesIndexPatternTitleSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { indexPatternTitle } = request.params;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const results = await recognize(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
indexPatternTitle
);
return response.ok({ body: results });
} catch (e) {
return response.customError(wrapError(e));
return response.ok({ body: results });
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
/**
* @apiGroup Modules
*
* @api {get} /api/ml/modules/get_module/:moduleId Get module
* @api {get} /internal/ml/modules/get_module/:moduleId Get module
* @apiName GetModule
* @apiDescription Retrieve a whole ML module, containing jobs, datafeeds and saved objects. If
* no module ID is supplied, returns all modules.
@ -318,57 +326,64 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) {
* "kibana":{}
* }
*/
router.get(
{
path: '/api/ml/modules/get_module/{moduleId?}',
validate: {
params: optionalModuleIdParamSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/modules/get_module/{moduleId?}`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
let { moduleId } = request.params;
if (moduleId === '') {
// if the endpoint is called with a trailing /
// the moduleId will be an empty string.
moduleId = undefined;
}
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const results = await getModule(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId
);
})
.addVersion(
{
version: '1',
validate: {
request: {
params: optionalModuleIdParamSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
let { moduleId } = request.params;
if (moduleId === '') {
// if the endpoint is called with a trailing /
// the moduleId will be an empty string.
moduleId = undefined;
}
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const results = await getModule(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId
);
return response.ok({ body: results });
} catch (e) {
return response.customError(wrapError(e));
return response.ok({ body: results });
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
/**
* @apiGroup Modules
*
* @api {post} /api/ml/modules/setup/:moduleId Set up module
* @api {post} /internal/ml/modules/setup/:moduleId Set up module
* @apiName SetupModule
* @apiDescription Runs the module setup process.
* This creates jobs, datafeeds and kibana saved objects. It allows for customization of the module,
@ -505,81 +520,88 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) {
* }]
* }
*/
router.post(
{
path: '/api/ml/modules/setup/{moduleId}',
validate: {
params: moduleIdParamSchema,
body: setupModuleBodySchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/modules/setup/{moduleId}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { moduleId } = request.params;
})
.addVersion(
{
version: '1',
validate: {
request: {
params: moduleIdParamSchema,
body: setupModuleBodySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { moduleId } = request.params;
const {
prefix,
groups,
indexPatternName,
query,
useDedicatedIndex,
startDatafeed,
start,
end,
jobOverrides,
datafeedOverrides,
estimateModelMemory,
applyToAllSpaces,
} = request.body as TypeOf<typeof setupModuleBodySchema>;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const {
prefix,
groups,
indexPatternName,
query,
useDedicatedIndex,
startDatafeed,
start,
end,
jobOverrides,
datafeedOverrides,
estimateModelMemory,
applyToAllSpaces,
} = request.body as TypeOf<typeof setupModuleBodySchema>;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const result = await setup(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId,
prefix,
groups,
indexPatternName,
query,
useDedicatedIndex,
startDatafeed,
start,
end,
jobOverrides,
datafeedOverrides,
estimateModelMemory,
applyToAllSpaces
);
const result = await setup(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId,
prefix,
groups,
indexPatternName,
query,
useDedicatedIndex,
startDatafeed,
start,
end,
jobOverrides,
datafeedOverrides,
estimateModelMemory,
applyToAllSpaces
);
return response.ok({ body: result });
} catch (e) {
return response.customError(wrapError(e));
return response.ok({ body: result });
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
/**
* @apiGroup Modules
*
* @api {get} /api/ml/modules/jobs_exist/:moduleId Check if module jobs exist
* @api {get} /internal/ml/modules/jobs_exist/:moduleId Check if module jobs exist
* @apiName CheckExistingModuleJobs
* @apiDescription Check whether the jobs in the module with the specified ID exist in the
* current list of jobs. The check runs a test to see if any of the jobs in existence
@ -628,45 +650,52 @@ export function dataRecognizer({ router, routeGuard }: RouteInitialization) {
* ]
* }
*/
router.get(
{
path: '/api/ml/modules/jobs_exist/{moduleId}',
validate: {
params: moduleIdParamSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/modules/jobs_exist/{moduleId}`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { moduleId } = request.params;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const result = await dataRecognizerJobsExist(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId
);
})
.addVersion(
{
version: '1',
validate: {
request: {
params: moduleIdParamSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({
client,
mlClient,
request,
response,
context,
mlSavedObjectService,
getDataViewsService,
}) => {
try {
const { moduleId } = request.params;
const soClient = (await context.core).savedObjects.client;
const dataViewService = await getDataViewsService();
const result = await dataRecognizerJobsExist(
client,
mlClient,
soClient,
dataViewService,
mlSavedObjectService,
request,
moduleId
);
return response.ok({ body: result });
} catch (e) {
return response.customError(wrapError(e));
return response.ok({ body: result });
} catch (e) {
return response.customError(wrapError(e));
}
}
}
)
);
)
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { NotificationsService } from '../models/notifications_service';
import {
getNotificationsCountQuerySchema,
@ -17,16 +18,14 @@ export function notificationsRoutes({ router, routeGuard }: RouteInitialization)
/**
* @apiGroup Notifications
*
* @api {get} /api/ml/notifications Get notifications
* @api {get} /internal/ml/notifications Get notifications
* @apiName GetNotifications
* @apiDescription Retrieves notifications based on provided criteria.
*/
router.get(
{
path: '/api/ml/notifications',
validate: {
query: getNotificationsQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/notifications`,
access: 'internal',
options: {
tags: [
'access:ml:canGetJobs',
@ -34,35 +33,44 @@ export function notificationsRoutes({ router, routeGuard }: RouteInitialization)
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response, mlSavedObjectService }) => {
try {
const notificationsService = new NotificationsService(client, mlSavedObjectService);
const results = await notificationsService.searchMessages(request.query);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
query: getNotificationsQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, request, response, mlSavedObjectService }) => {
try {
const notificationsService = new NotificationsService(client, mlSavedObjectService);
const results = await notificationsService.searchMessages(request.query);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
/**
* @apiGroup Notifications
*
* @api {get} /api/ml/notifications/count Get notification counts
* @api {get} /internal/ml/notifications/count Get notification counts
* @apiName GetNotificationCounts
* @apiDescription Counts notifications by level.
*/
router.get(
{
path: '/api/ml/notifications/count',
validate: {
query: getNotificationsCountQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/notifications/count`,
access: 'internal',
options: {
tags: [
'access:ml:canGetJobs',
@ -70,19 +78,30 @@ export function notificationsRoutes({ router, routeGuard }: RouteInitialization)
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlSavedObjectService, request, response }) => {
try {
const notificationsService = new NotificationsService(client, mlSavedObjectService);
const results = await notificationsService.countMessages(request.query);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
query: getNotificationsCountQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, mlSavedObjectService, request, response }) => {
try {
const notificationsService = new NotificationsService(client, mlSavedObjectService);
const results = await notificationsService.countMessages(request.query);
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization } from '../types';
import {
@ -108,362 +109,440 @@ export function resultsServiceRoutes({ router, routeGuard }: RouteInitialization
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/anomalies_table_data Get anomalies records for table display
* @api {post} /internal/ml/results/anomalies_table_data Get anomalies records for table display
* @apiName GetAnomaliesTableData
* @apiDescription Retrieves anomaly records for an anomaly detection job and formats them for anomalies table display.
*
* @apiSchema (body) anomaliesTableDataSchema
*/
router.post(
{
path: '/api/ml/results/anomalies_table_data',
validate: {
body: anomaliesTableDataSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/anomalies_table_data`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getAnomaliesTableData(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: anomaliesTableDataSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getAnomaliesTableData(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/category_definition Get category definition
* @api {post} /internal/ml/results/category_definition Get category definition
* @apiName GetCategoryDefinition
* @apiDescription Returns the definition of the category with the specified ID and job ID
*
* @apiSchema (body) categoryDefinitionSchema
*/
router.post(
{
path: '/api/ml/results/category_definition',
validate: {
body: categoryDefinitionSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/category_definition`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryDefinition(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: categoryDefinitionSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryDefinition(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/max_anomaly_score Get the maximum anomaly_score
* @api {post} /internal/ml/results/max_anomaly_score Get the maximum anomaly_score
* @apiName GetMaxAnomalyScore
* @apiDescription Returns the maximum anomaly score of the bucket results for the request job ID(s) and time range
*
* @apiSchema (body) maxAnomalyScoreSchema
*/
router.post(
{
path: '/api/ml/results/max_anomaly_score',
validate: {
body: maxAnomalyScoreSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/max_anomaly_score`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getMaxAnomalyScore(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: maxAnomalyScoreSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getMaxAnomalyScore(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/category_examples Get category examples
* @api {post} /internal/ml/results/category_examples Get category examples
* @apiName GetCategoryExamples
* @apiDescription Returns examples for the categories with the specified IDs from the job with the supplied ID
*
* @apiSchema (body) categoryExamplesSchema
*/
router.post(
{
path: '/api/ml/results/category_examples',
validate: {
body: categoryExamplesSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/category_examples`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryExamples(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: categoryExamplesSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryExamples(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/partition_fields_values Returns partition fields values
* @api {post} /internal/ml/results/partition_fields_values Returns partition fields values
* @apiName GetPartitionFieldsValues
* @apiDescription Returns the partition fields with values that match the provided criteria for the specified job ID.
*
* @apiSchema (body) partitionFieldValuesSchema
*/
router.post(
{
path: '/api/ml/results/partition_fields_values',
validate: {
body: partitionFieldValuesSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/partition_fields_values`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getPartitionFieldsValues(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: partitionFieldValuesSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getPartitionFieldsValues(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/anomaly_search Run a search on the anomaly results index
* @api {post} /internal/ml/results/anomaly_search Run a search on the anomaly results index
* @apiName AnomalySearch
* @apiDescription Runs the supplied query against the anomaly results index for the specified job IDs.
* @apiSchema (body) anomalySearchSchema
*/
router.post(
{
path: '/api/ml/results/anomaly_search',
validate: {
body: anomalySearchSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_search`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { jobIds, query } = request.body;
const body = await mlClient.anomalySearch(query, jobIds);
return response.ok({
body,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: anomalySearchSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { jobIds, query } = request.body;
const body = await mlClient.anomalySearch(query, jobIds);
return response.ok({
body,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {get} /api/ml/results/:jobId/categorizer_stats Return categorizer statistics
* @api {get} /internal/ml/results/:jobId/categorizer_stats Return categorizer statistics
* @apiName GetCategorizerStats
* @apiDescription Returns the categorizer stats for the specified job ID
* @apiSchema (params) jobIdSchema
* @apiSchema (query) getCategorizerStatsSchema
*/
router.get(
{
path: '/api/ml/results/{jobId}/categorizer_stats',
validate: {
params: jobIdSchema,
query: getCategorizerStatsSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/results/{jobId}/categorizer_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategorizerStats(mlClient, request.params, request.query);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: jobIdSchema,
query: getCategorizerStatsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategorizerStats(mlClient, request.params, request.query);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/category_stopped_partitions Get partitions that have stopped being categorized
* @api {post} /internal/ml/results/category_stopped_partitions Get partitions that have stopped being categorized
* @apiName GetCategoryStoppedPartitions
* @apiDescription Returns information on the partitions that have stopped being categorized due to the categorization status changing from ok to warn. Can return either the list of stopped partitions for each job, or just the list of job IDs.
* @apiSchema (body) getCategorizerStoppedPartitionsSchema
*/
router.post(
{
path: '/api/ml/results/category_stopped_partitions',
validate: {
body: getCategorizerStoppedPartitionsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/category_stopped_partitions`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryStoppedPartitions(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getCategorizerStoppedPartitionsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const resp = await getCategoryStoppedPartitions(mlClient, request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/datafeed_results_chart Get datafeed results chart data
* @api {post} /internal/ml/results/datafeed_results_chart Get datafeed results chart data
* @apiName GetDatafeedResultsChartData
* @apiDescription Returns datafeed results chart data
*
* @apiSchema (body) getDatafeedResultsChartDataSchema
*/
router.post(
{
path: '/api/ml/results/datafeed_results_chart',
validate: {
body: getDatafeedResultsChartDataSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/datafeed_results_chart`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getDatafeedResultsChartData } = resultsServiceProvider(mlClient, client);
const resp = await getDatafeedResultsChartData(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getDatafeedResultsChartDataSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getDatafeedResultsChartData } = resultsServiceProvider(mlClient, client);
const resp = await getDatafeedResultsChartData(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/anomaly_charts Get data for anomaly charts
* @api {post} /internal/ml/results/anomaly_charts Get data for anomaly charts
* @apiName GetAnomalyChartsData
* @apiDescription Returns anomaly charts data
*
* @apiSchema (body) getAnomalyChartsSchema
*/
router.post(
{
path: '/api/ml/results/anomaly_charts',
validate: {
body: getAnomalyChartsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_charts`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getAnomalyChartsData } = resultsServiceProvider(mlClient, client);
const resp = await getAnomalyChartsData(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getAnomalyChartsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getAnomalyChartsData } = resultsServiceProvider(mlClient, client);
const resp = await getAnomalyChartsData(request.body);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup ResultsService
*
* @api {post} /api/ml/results/anomaly_records Get anomaly records for criteria
* @api {post} /internal/ml/results/anomaly_records Get anomaly records for criteria
* @apiName GetAnomalyRecords
* @apiDescription Returns anomaly records
*
* @apiSchema (body) getAnomalyRecordsSchema
*/
router.post(
{
path: '/api/ml/results/anomaly_records',
validate: {
body: getAnomalyRecordsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/results/anomaly_records`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getRecordsForCriteria } = resultsServiceProvider(mlClient, client);
const { jobIds, criteriaFields, earliestMs, latestMs, threshold, interval } = request.body;
const resp = await getRecordsForCriteria(
jobIds,
criteriaFields,
threshold,
earliestMs,
latestMs,
interval
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: getAnomalyRecordsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { getRecordsForCriteria } = resultsServiceProvider(mlClient, client);
const { jobIds, criteriaFields, earliestMs, latestMs, threshold, interval } =
request.body;
const resp = await getRecordsForCriteria(
jobIds,
criteriaFields,
threshold,
earliestMs,
latestMs,
interval
);
return response.ok({
body: resp,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { ML_EXTERNAL_BASE_PATH, ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { RouteInitialization, SavedObjectsRouteDeps } from '../types';
import { checksFactory, syncSavedObjectsFactory } from '../saved_objects';
@ -30,32 +31,37 @@ export function savedObjectsRoutes(
/**
* @apiGroup MLSavedObjects
*
* @api {get} /api/ml/saved_objects/status Get job and trained model saved object status
* @api {get} /internal/ml/saved_objects/status Get job and trained model saved object status
* @apiName SavedObjectsStatus
* @apiDescription Lists all jobs, trained models and saved objects to view the relationship status between them
*
*/
router.get(
{
path: '/api/ml/saved_objects/status',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/status`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs', 'access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, response, mlSavedObjectService }) => {
try {
const { checkStatus } = checksFactory(client, mlSavedObjectService);
const status = await checkStatus();
return response.ok({
body: status,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ client, response, mlSavedObjectService }) => {
try {
const { checkStatus } = checksFactory(client, mlSavedObjectService);
const status = await checkStatus();
return response.ok({
body: status,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup MLSavedObjects
@ -68,12 +74,10 @@ export function savedObjectsRoutes(
* removes datafeed IDs for datafeeds which no longer exist.
*
*/
router.get(
{
path: '/api/ml/saved_objects/sync',
validate: {
query: syncJobObjects,
},
router.versioned
.get({
path: `${ML_EXTERNAL_BASE_PATH}/saved_objects/sync`,
access: 'public',
options: {
tags: [
'access:ml:canCreateJob',
@ -81,36 +85,45 @@ export function savedObjectsRoutes(
'access:ml:canCreateTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response, mlSavedObjectService }) => {
try {
const { simulate } = request.query;
const { syncSavedObjects } = syncSavedObjectsFactory(client, mlSavedObjectService);
const savedObjects = await syncSavedObjects(simulate);
return response.ok({
body: savedObjects,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '2023-05-15',
validate: {
request: {
query: syncJobObjects,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, request, response, mlSavedObjectService }) => {
try {
const { simulate } = request.query;
const { syncSavedObjects } = syncSavedObjectsFactory(client, mlSavedObjectService);
const savedObjects = await syncSavedObjects(simulate);
return response.ok({
body: savedObjects,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
/**
* @apiGroup MLSavedObjects
*
* @api {get} /api/ml/saved_objects/initialize Create saved objects for all job and trained models
* @api {get} /internal/ml/saved_objects/initialize Create saved objects for all job and trained models
* @apiName InitializeMLSavedObjects
* @apiDescription Create saved objects for jobs and trained models which are missing them.
*
*/
router.get(
{
path: '/api/ml/saved_objects/initialize',
validate: {
query: syncJobObjects,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/initialize`,
access: 'internal',
options: {
tags: [
'access:ml:canCreateJob',
@ -118,36 +131,45 @@ export function savedObjectsRoutes(
'access:ml:canCreateTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response, mlSavedObjectService }) => {
try {
const { simulate } = request.query;
const { initSavedObjects } = syncSavedObjectsFactory(client, mlSavedObjectService);
const savedObjects = await initSavedObjects(simulate);
return response.ok({
body: savedObjects,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
query: syncJobObjects,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, request, response, mlSavedObjectService }) => {
try {
const { simulate } = request.query;
const { initSavedObjects } = syncSavedObjectsFactory(client, mlSavedObjectService);
const savedObjects = await initSavedObjects(simulate);
return response.ok({
body: savedObjects,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
/**
* @apiGroup MLSavedObjects
*
* @api {get} /api/ml/saved_objects/sync_needed Check whether job and trained model saved objects need synchronizing
* @api {get} /internal/ml/saved_objects/sync_needed Check whether job and trained model saved objects need synchronizing
* @apiName SyncCheck
* @apiDescription Check whether job and trained model saved objects need synchronizing.
*
*/
router.post(
{
path: '/api/ml/saved_objects/sync_check',
validate: {
body: syncCheckSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/sync_check`,
access: 'internal',
options: {
tags: [
'access:ml:canGetJobs',
@ -155,137 +177,181 @@ export function savedObjectsRoutes(
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response, mlSavedObjectService }) => {
try {
const { mlSavedObjectType } = request.body;
const { isSyncNeeded } = syncSavedObjectsFactory(client, mlSavedObjectService);
const result = await isSyncNeeded(mlSavedObjectType as MlSavedObjectType);
return response.ok({
body: { result },
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: syncCheckSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ client, request, response, mlSavedObjectService }) => {
try {
const { mlSavedObjectType } = request.body;
const { isSyncNeeded } = syncSavedObjectsFactory(client, mlSavedObjectService);
const result = await isSyncNeeded(mlSavedObjectType as MlSavedObjectType);
return response.ok({
body: { result },
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
/**
* @apiGroup MLSavedObjects
*
* @api {post} /api/ml/saved_objects/update_jobs_spaces Update what spaces jobs are assigned to
* @api {post} /internal/ml/saved_objects/update_jobs_spaces Update what spaces jobs are assigned to
* @apiName UpdateJobsSpaces
* @apiDescription Update a list of jobs to add and/or remove them from given spaces.
*
* @apiSchema (body) updateJobsSpaces
*/
router.post(
{
path: '/api/ml/saved_objects/update_jobs_spaces',
validate: {
body: updateJobsSpaces,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/update_jobs_spaces`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob', 'access:ml:canCreateDataFrameAnalytics'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { jobType, jobIds, spacesToAdd, spacesToRemove } = request.body;
const body = await mlSavedObjectService.updateJobsSpaces(
jobType,
jobIds,
spacesToAdd,
spacesToRemove
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: updateJobsSpaces,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { jobType, jobIds, spacesToAdd, spacesToRemove } = request.body;
const body = await mlSavedObjectService.updateJobsSpaces(
jobType,
jobIds,
spacesToAdd,
spacesToRemove
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup MLSavedObjects
*
* @api {post} /api/ml/saved_objects/update_trained_models_spaces Update what spaces trained models are assigned to
* @api {post} /internal/ml/saved_objects/update_trained_models_spaces Update what spaces trained models are assigned to
* @apiName UpdateTrainedModelsSpaces
* @apiDescription Update a list of trained models to add and/or remove them from given spaces.
*
* @apiSchema (body) updateTrainedModelsSpaces
*/
router.post(
{
path: '/api/ml/saved_objects/update_trained_models_spaces',
validate: {
body: updateTrainedModelsSpaces,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/update_trained_models_spaces`,
access: 'internal',
options: {
tags: ['access:ml:canCreateTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { modelIds, spacesToAdd, spacesToRemove } = request.body;
const body = await mlSavedObjectService.updateTrainedModelsSpaces(
modelIds,
spacesToAdd,
spacesToRemove
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: updateTrainedModelsSpaces,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { modelIds, spacesToAdd, spacesToRemove } = request.body;
const body = await mlSavedObjectService.updateTrainedModelsSpaces(
modelIds,
spacesToAdd,
spacesToRemove
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup MLSavedObjects
*
* @api {post} /api/ml/saved_objects/remove_item_from_current_space Remove jobs or trained models from the current space
* @api {post} /internal/ml/saved_objects/remove_item_from_current_space Remove jobs or trained models from the current space
* @apiName RemoveMLSpaceAwareItemsFromCurrentSpace
* @apiDescription Remove a list of jobs or trained models from the current space.
*
* @apiSchema (body) itemsAndCurrentSpace
*/
router.post(
{
path: '/api/ml/saved_objects/remove_item_from_current_space',
validate: {
body: itemsAndCurrentSpace,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/remove_item_from_current_space`,
access: 'internal',
options: {
tags: ['access:ml:canCreateJob', 'access:ml:canCreateDataFrameAnalytics'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { mlSavedObjectType, ids } = request.body;
const { getCurrentSpaceId } = spacesUtilsProvider(getSpaces, request);
})
.addVersion(
{
version: '1',
validate: {
request: {
body: itemsAndCurrentSpace,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService }) => {
try {
const { mlSavedObjectType, ids } = request.body;
const { getCurrentSpaceId } = spacesUtilsProvider(getSpaces, request);
const currentSpaceId = await getCurrentSpaceId();
if (currentSpaceId === null) {
return response.ok({
body: ids.map((id) => ({
[id]: {
success: false,
error: 'Cannot remove current space. Spaces plugin is disabled.',
},
})),
});
}
const currentSpaceId = await getCurrentSpaceId();
if (currentSpaceId === null) {
return response.ok({
body: ids.map((id) => ({
[id]: {
success: false,
error: 'Cannot remove current space. Spaces plugin is disabled.',
},
})),
});
}
if (mlSavedObjectType === 'trained-model') {
const body = await mlSavedObjectService.updateTrainedModelsSpaces(
if (mlSavedObjectType === 'trained-model') {
const body = await mlSavedObjectService.updateTrainedModelsSpaces(
ids,
[], // spacesToAdd
[currentSpaceId] // spacesToRemove
);
return response.ok({
body,
});
}
const body = await mlSavedObjectService.updateJobsSpaces(
mlSavedObjectType,
ids,
[], // spacesToAdd
[currentSpaceId] // spacesToRemove
@ -294,88 +360,86 @@ export function savedObjectsRoutes(
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
const body = await mlSavedObjectService.updateJobsSpaces(
mlSavedObjectType,
ids,
[], // spacesToAdd
[currentSpaceId] // spacesToRemove
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
})
);
/**
* @apiGroup MLSavedObjects
*
* @api {get} /api/ml/saved_objects/jobs_spaces Get all jobs and their spaces
* @api {get} /internal/ml/saved_objects/jobs_spaces Get all jobs and their spaces
* @apiName JobsSpaces
* @apiDescription List all jobs and their spaces.
*
*/
router.get(
{
path: '/api/ml/saved_objects/jobs_spaces',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/jobs_spaces`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs', 'access:ml:canGetDataFrameAnalytics'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ response, mlSavedObjectService, client }) => {
try {
const { jobsSpaces } = checksFactory(client, mlSavedObjectService);
const jobsStatus = await jobsSpaces();
return response.ok({
body: jobsStatus,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ response, mlSavedObjectService, client }) => {
try {
const { jobsSpaces } = checksFactory(client, mlSavedObjectService);
const jobsStatus = await jobsSpaces();
return response.ok({
body: jobsStatus,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup MLSavedObjects
*
* @api {get} /api/ml/saved_objects/trained_models_spaces Get all trained models and their spaces
* @api {get} /internal/ml/saved_objects/trained_models_spaces Get all trained models and their spaces
* @apiName TrainedModelsSpaces
* @apiDescription List all trained models and their spaces.
*
*/
router.get(
{
path: '/api/ml/saved_objects/trained_models_spaces',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/trained_models_spaces`,
access: 'internal',
options: {
tags: ['access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ response, mlSavedObjectService, client }) => {
try {
const { trainedModelsSpaces } = checksFactory(client, mlSavedObjectService);
const modelStatus = await trainedModelsSpaces();
return response.ok({
body: modelStatus,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ response, mlSavedObjectService, client }) => {
try {
const { trainedModelsSpaces } = checksFactory(client, mlSavedObjectService);
const modelStatus = await trainedModelsSpaces();
return response.ok({
body: modelStatus,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup MLSavedObjects
*
* @api {post} /api/ml/saved_objects/can_delete_ml_space_aware_item Check whether user can delete a job or trained model
* @api {post} /internal/ml/saved_objects/can_delete_ml_space_aware_item Check whether user can delete a job or trained model
* @apiName CanDeleteMLSpaceAwareItems
* @apiDescription Check the user's ability to delete jobs or trained models. Returns whether they are able
* to fully delete the job or trained model and whether they are able to remove it from
@ -394,13 +458,10 @@ export function savedObjectsRoutes(
* }
*
*/
router.post(
{
path: '/api/ml/saved_objects/can_delete_ml_space_aware_item/{jobType}',
validate: {
params: itemTypeSchema,
body: canDeleteMLSpaceAwareItemsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/saved_objects/can_delete_ml_space_aware_item/{jobType}`,
access: 'internal',
options: {
tags: [
'access:ml:canGetJobs',
@ -408,27 +469,39 @@ export function savedObjectsRoutes(
'access:ml:canGetTrainedModels',
],
},
},
routeGuard.fullLicenseAPIGuard(async ({ request, response, mlSavedObjectService, client }) => {
try {
const { jobType } = request.params;
const { ids } = request.body;
const { canDeleteMLSpaceAwareItems } = checksFactory(client, mlSavedObjectService);
const body = await canDeleteMLSpaceAwareItems(
request,
jobType,
ids,
getSpaces !== undefined,
resolveMlCapabilities
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: itemTypeSchema,
body: canDeleteMLSpaceAwareItemsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(
async ({ request, response, mlSavedObjectService, client }) => {
try {
const { jobType } = request.params;
const { ids } = request.body;
const { canDeleteMLSpaceAwareItems } = checksFactory(client, mlSavedObjectService);
const body = await canDeleteMLSpaceAwareItems(
request,
jobType,
ids,
getSpaces !== undefined,
resolveMlCapabilities
);
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
}
)
);
}

View file

@ -7,6 +7,7 @@
import { schema } from '@kbn/config-schema';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { wrapError } from '../client/error_wrapper';
import { mlLog } from '../lib/log';
import { capabilitiesProvider } from '../lib/capabilities';
@ -24,229 +25,264 @@ export function systemRoutes(
/**
* @apiGroup SystemRoutes
*
* @api {post} /api/ml/_has_privileges Check privileges
* @api {post} /internal/ml/_has_privileges Check privileges
* @apiName HasPrivileges
* @apiDescription Checks if the user has required privileges
*/
router.post(
{
path: '/api/ml/_has_privileges',
validate: {
body: schema.maybe(schema.any()),
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/_has_privileges`,
access: 'internal',
options: {
tags: ['access:ml:canGetMlInfo'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, client, request, response }) => {
try {
const { asCurrentUser } = client;
let upgradeInProgress = false;
try {
const body = await mlClient.info();
// if ml indices are currently being migrated, upgrade_mode will be set to true
// pass this back with the privileges to allow for the disabling of UI controls.
upgradeInProgress = body.upgrade_mode === true;
} catch (error) {
// if the ml.info check fails, it could be due to the user having insufficient privileges
// most likely they do not have the ml_user role and therefore will be blocked from using
// ML at all. However, we need to catch this error so the privilege check doesn't fail.
if (error.status === 403) {
mlLog.info(
'Unable to determine whether upgrade is being performed due to insufficient user privileges'
);
} else {
mlLog.warn('Unable to determine whether upgrade is being performed');
}
}
if (mlLicense.isSecurityEnabled() === false) {
// if xpack.security.enabled has been explicitly set to false
// return that security is disabled and don't call the privilegeCheck endpoint
return response.ok({
body: {
securityDisabled: true,
upgradeInProgress,
},
});
} else {
const body = await asCurrentUser.security.hasPrivileges({ body: request.body });
return response.ok({
body: {
...body,
upgradeInProgress,
},
});
}
} catch (error) {
return response.customError(wrapError(error));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: schema.maybe(schema.any()),
},
},
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, client, request, response }) => {
try {
const { asCurrentUser } = client;
let upgradeInProgress = false;
try {
const body = await mlClient.info();
// if ml indices are currently being migrated, upgrade_mode will be set to true
// pass this back with the privileges to allow for the disabling of UI controls.
upgradeInProgress = body.upgrade_mode === true;
} catch (error) {
// if the ml.info check fails, it could be due to the user having insufficient privileges
// most likely they do not have the ml_user role and therefore will be blocked from using
// ML at all. However, we need to catch this error so the privilege check doesn't fail.
if (error.status === 403) {
mlLog.info(
'Unable to determine whether upgrade is being performed due to insufficient user privileges'
);
} else {
mlLog.warn('Unable to determine whether upgrade is being performed');
}
}
if (mlLicense.isSecurityEnabled() === false) {
// if xpack.security.enabled has been explicitly set to false
// return that security is disabled and don't call the privilegeCheck endpoint
return response.ok({
body: {
securityDisabled: true,
upgradeInProgress,
},
});
} else {
const body = await asCurrentUser.security.hasPrivileges({ body: request.body });
return response.ok({
body: {
...body,
upgradeInProgress,
},
});
}
} catch (error) {
return response.customError(wrapError(error));
}
})
);
/**
* @apiGroup SystemRoutes
*
* @api {get} /api/ml/ml_capabilities Check ML capabilities
* @api {get} /internal/ml/ml_capabilities Check ML capabilities
* @apiName MlCapabilitiesResponse
* @apiDescription Checks ML capabilities
*/
router.get(
{
path: '/api/ml/ml_capabilities',
validate: false,
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { isMlEnabledInSpace } = spacesUtilsProvider(getSpaces, request);
const mlCapabilities = await resolveMlCapabilities(request);
if (mlCapabilities === null) {
return response.customError(wrapError(new Error('resolveMlCapabilities is not defined')));
}
const { getCapabilities } = capabilitiesProvider(
mlClient,
mlCapabilities,
mlLicense,
isMlEnabledInSpace
);
return response.ok({
body: await getCapabilities(),
});
} catch (error) {
return response.customError(wrapError(error));
}
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/ml_capabilities`,
access: 'internal',
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { isMlEnabledInSpace } = spacesUtilsProvider(getSpaces, request);
const mlCapabilities = await resolveMlCapabilities(request);
if (mlCapabilities === null) {
return response.customError(
wrapError(new Error('resolveMlCapabilities is not defined'))
);
}
const { getCapabilities } = capabilitiesProvider(
mlClient,
mlCapabilities,
mlLicense,
isMlEnabledInSpace
);
return response.ok({
body: await getCapabilities(),
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
/**
* @apiGroup SystemRoutes
*
* @api {get} /api/ml/ml_node_count Get the amount of ML nodes
* @api {get} /internal/ml/ml_node_count Get the amount of ML nodes
* @apiName MlNodeCount
* @apiDescription Returns the amount of ML nodes.
*/
router.get(
{
path: '/api/ml/ml_node_count',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/ml_node_count`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs', 'access:ml:canGetDatafeeds'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, response }) => {
try {
return response.ok({
body: await getMlNodeCount(client),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.basicLicenseAPIGuard(async ({ client, response }) => {
try {
return response.ok({
body: await getMlNodeCount(client),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup SystemRoutes
*
* @api {get} /api/ml/info Get ML info
* @api {get} /internal/ml/info Get ML info
* @apiName MlInfo
* @apiDescription Returns defaults and limits used by machine learning.
*/
router.get(
{
path: '/api/ml/info',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/info`,
access: 'internal',
options: {
tags: ['access:ml:canGetMlInfo'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.info();
const cloudId = cloud?.cloudId;
const isCloudTrial = cloud?.trialEndDate && Date.now() < cloud.trialEndDate.getTime();
return response.ok({
body: { ...body, cloudId, isCloudTrial },
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.basicLicenseAPIGuard(async ({ mlClient, response }) => {
try {
const body = await mlClient.info();
const cloudId = cloud?.cloudId;
const isCloudTrial = cloud?.trialEndDate && Date.now() < cloud.trialEndDate.getTime();
return response.ok({
body: { ...body, cloudId, isCloudTrial },
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
/**
* @apiGroup SystemRoutes
*
* @apiDeprecated
*
* @api {post} /api/ml/es_search ES Search wrapper
* @api {post} /internal/ml/es_search ES Search wrapper
* @apiName MlEsSearch
*/
router.post(
{
path: '/api/ml/es_search',
validate: {
body: schema.maybe(schema.any()),
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/es_search`,
access: 'internal',
options: {
tags: ['access:ml:canGetJobs'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const body = await client.asCurrentUser.search(request.body);
return response.ok({
body,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: schema.maybe(schema.any()),
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const body = await client.asCurrentUser.search(request.body);
return response.ok({
body,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
/**
* @apiGroup SystemRoutes
*
* @api {post} /api/ml/index_exists ES Field caps wrapper checks if index exists
* @api {post} /internal/ml/index_exists ES Field caps wrapper checks if index exists
* @apiName MlIndexExists
*/
router.post(
{
path: '/api/ml/index_exists',
validate: {
body: schema.object({ indices: schema.arrayOf(schema.string()) }),
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/index_exists`,
access: 'internal',
options: {
tags: ['access:ml:canGetFieldInfo'],
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { indices } = request.body;
const results = await Promise.all(
indices.map(async (index) =>
client.asCurrentUser.indices.exists({
index,
allow_no_indices: false,
})
)
);
const result = indices.reduce((acc, cur, i) => {
acc[cur] = { exists: results[i] };
return acc;
}, {} as Record<string, { exists: boolean }>);
return response.ok({
body: result,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { body: schema.object({ indices: schema.arrayOf(schema.string()) }) },
},
},
routeGuard.basicLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { indices } = request.body;
const results = await Promise.all(
indices.map(async (index) =>
client.asCurrentUser.indices.exists({
index,
allow_no_indices: false,
})
)
);
const result = indices.reduce((acc, cur, i) => {
acc[cur] = { exists: results[i] };
return acc;
}, {} as Record<string, { exists: boolean }>);
return response.ok({
body: result,
});
} catch (error) {
return response.customError(wrapError(error));
}
})
);
}

View file

@ -7,6 +7,7 @@
import { schema } from '@kbn/config-schema';
import { ErrorType } from '@kbn/ml-error-utils';
import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app';
import { RouteInitialization } from '../types';
import { wrapError } from '../client/error_wrapper';
import {
@ -31,442 +32,514 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization)
/**
* @apiGroup TrainedModels
*
* @api {get} /api/ml/trained_models/:modelId Get info of a trained inference model
* @api {get} /internal/ml/trained_models/:modelId Get info of a trained inference model
* @apiName GetTrainedModel
* @apiDescription Retrieves configuration information for a trained model.
*/
router.get(
{
path: '/api/ml/trained_models/{modelId?}',
validate: {
params: optionalModelIdSchema,
query: getInferenceQuerySchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId?}`,
access: 'internal',
options: {
tags: ['access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { modelId } = request.params;
const { with_pipelines: withPipelines, ...query } = request.query;
const body = await mlClient.getTrainedModels({
// @ts-expect-error @elastic-elasticsearch not sure why this is an error, size is a number
size: 1000,
...query,
...(modelId ? { model_id: modelId } : {}),
});
// model_type is missing
// @ts-ignore
const result = body.trained_model_configs as TrainedModelConfigResponse[];
try {
if (withPipelines) {
// Also need to retrieve the list of deployment IDs from stats
const stats = await mlClient.getTrainedModelsStats({
...(modelId ? { model_id: modelId } : {}),
size: 10000,
});
const modelDeploymentsMap = stats.trained_model_stats.reduce((acc, curr) => {
if (!curr.deployment_stats) return acc;
// @ts-ignore elasticsearch-js client is missing deployment_id
const deploymentId = curr.deployment_stats.deployment_id;
if (acc[curr.model_id]) {
acc[curr.model_id].push(deploymentId);
} else {
acc[curr.model_id] = [deploymentId];
}
return acc;
}, {} as Record<string, string[]>);
const modelIdsAndAliases: string[] = Array.from(
new Set([
...result
.map(({ model_id: id, metadata }) => {
return [id, ...(metadata?.model_aliases ?? [])];
})
.flat(),
...Object.values(modelDeploymentsMap).flat(),
])
);
const pipelinesResponse = await modelsProvider(client).getModelsPipelines(
modelIdsAndAliases
);
for (const model of result) {
model.pipelines = {
...(pipelinesResponse.get(model.model_id) ?? {}),
...(model.metadata?.model_aliases ?? []).reduce((acc, alias) => {
return Object.assign(acc, pipelinesResponse.get(alias) ?? {});
}, {}),
...(modelDeploymentsMap[model.model_id] ?? []).reduce((acc, deploymentId) => {
return Object.assign(acc, pipelinesResponse.get(deploymentId) ?? {});
}, {}),
};
}
}
} catch (e) {
// the user might not have required permissions to fetch pipelines
// log the error to the debug log as this might be a common situation and
// we don't need to fill kibana's log with these messages.
mlLog.debug(e);
}
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: optionalModelIdSchema,
query: getInferenceQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response }) => {
try {
const { modelId } = request.params;
const { with_pipelines: withPipelines, ...query } = request.query;
const body = await mlClient.getTrainedModels({
// @ts-expect-error @elastic-elasticsearch not sure why this is an error, size is a number
size: 1000,
...query,
...(modelId ? { model_id: modelId } : {}),
});
// model_type is missing
// @ts-ignore
const result = body.trained_model_configs as TrainedModelConfigResponse[];
try {
if (withPipelines) {
// Also need to retrieve the list of deployment IDs from stats
const stats = await mlClient.getTrainedModelsStats({
...(modelId ? { model_id: modelId } : {}),
size: 10000,
});
const modelDeploymentsMap = stats.trained_model_stats.reduce((acc, curr) => {
if (!curr.deployment_stats) return acc;
// @ts-ignore elasticsearch-js client is missing deployment_id
const deploymentId = curr.deployment_stats.deployment_id;
if (acc[curr.model_id]) {
acc[curr.model_id].push(deploymentId);
} else {
acc[curr.model_id] = [deploymentId];
}
return acc;
}, {} as Record<string, string[]>);
const modelIdsAndAliases: string[] = Array.from(
new Set([
...result
.map(({ model_id: id, metadata }) => {
return [id, ...(metadata?.model_aliases ?? [])];
})
.flat(),
...Object.values(modelDeploymentsMap).flat(),
])
);
const pipelinesResponse = await modelsProvider(client).getModelsPipelines(
modelIdsAndAliases
);
for (const model of result) {
model.pipelines = {
...(pipelinesResponse.get(model.model_id) ?? {}),
...(model.metadata?.model_aliases ?? []).reduce((acc, alias) => {
return Object.assign(acc, pipelinesResponse.get(alias) ?? {});
}, {}),
...(modelDeploymentsMap[model.model_id] ?? []).reduce((acc, deploymentId) => {
return Object.assign(acc, pipelinesResponse.get(deploymentId) ?? {});
}, {}),
};
}
}
} catch (e) {
// the user might not have required permissions to fetch pipelines
// log the error to the debug log as this might be a common situation and
// we don't need to fill kibana's log with these messages.
mlLog.debug(e);
}
return response.ok({
body: result,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {get} /api/ml/trained_models/_stats Get stats for all trained models
* @api {get} /internal/ml/trained_models/_stats Get stats for all trained models
* @apiName GetTrainedModelStats
* @apiDescription Retrieves usage information for all trained models.
*/
router.get(
{
path: '/api/ml/trained_models/_stats',
validate: false,
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = await mlClient.getTrainedModelsStats();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: false,
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const body = await mlClient.getTrainedModelsStats();
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {get} /api/ml/trained_models/:modelId/_stats Get stats of a trained model
* @api {get} /internal/ml/trained_models/:modelId/_stats Get stats of a trained model
* @apiName GetTrainedModelStatsById
* @apiDescription Retrieves usage information for trained models.
*/
router.get(
{
path: '/api/ml/trained_models/{modelId}/_stats',
validate: {
params: modelIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}/_stats`,
access: 'internal',
options: {
tags: ['access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.getTrainedModelsStats({
...(modelId ? { model_id: modelId } : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.getTrainedModelsStats({
...(modelId ? { model_id: modelId } : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {get} /api/ml/trained_models/:modelId/pipelines Get trained model pipelines
* @api {get} /internal/ml/trained_models/:modelId/pipelines Get trained model pipelines
* @apiName GetTrainedModelPipelines
* @apiDescription Retrieves pipelines associated with a trained model
*/
router.get(
{
path: '/api/ml/trained_models/{modelId}/pipelines',
validate: {
params: modelIdSchema,
},
router.versioned
.get({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}/pipelines`,
access: 'internal',
options: {
tags: ['access:ml:canGetTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, mlClient, response }) => {
try {
const { modelId } = request.params;
const result = await modelsProvider(client).getModelsPipelines(modelId.split(','));
return response.ok({
body: [...result].map(([id, pipelines]) => ({ model_id: id, pipelines })),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, mlClient, response }) => {
try {
const { modelId } = request.params;
const result = await modelsProvider(client).getModelsPipelines(modelId.split(','));
return response.ok({
body: [...result].map(([id, pipelines]) => ({ model_id: id, pipelines })),
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {put} /api/ml/trained_models/:modelId Put a trained model
* @api {put} /internal/ml/trained_models/:modelId Put a trained model
* @apiName PutTrainedModel
* @apiDescription Adds a new trained model
*/
router.put(
{
path: '/api/ml/trained_models/{modelId}',
validate: {
params: modelIdSchema,
body: schema.any(),
query: putTrainedModelQuerySchema,
},
router.versioned
.put({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}`,
access: 'internal',
options: {
tags: ['access:ml:canCreateTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.putTrainedModel({
model_id: modelId,
body: request.body,
...(request.query?.defer_definition_decompression
? { defer_definition_decompression: true }
: {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelIdSchema,
body: schema.any(),
query: putTrainedModelQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.putTrainedModel({
model_id: modelId,
body: request.body,
...(request.query?.defer_definition_decompression
? { defer_definition_decompression: true }
: {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {delete} /api/ml/trained_models/:modelId Delete a trained model
* @api {delete} /internal/ml/trained_models/:modelId Delete a trained model
* @apiName DeleteTrainedModel
* @apiDescription Deletes an existing trained model that is currently not referenced by an ingest pipeline.
*/
router.delete(
{
path: '/api/ml/trained_models/{modelId}',
validate: {
params: modelIdSchema,
},
router.versioned
.delete({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}`,
access: 'internal',
options: {
tags: ['access:ml:canDeleteTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.deleteTrainedModel({
model_id: modelId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelIdSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.deleteTrainedModel({
model_id: modelId,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {post} /api/ml/trained_models/:modelId/deployment/_start Start trained model deployment
* @api {post} /internal/ml/trained_models/:modelId/deployment/_start Start trained model deployment
* @apiName StartTrainedModelDeployment
* @apiDescription Starts trained model deployment.
*/
router.post(
{
path: '/api/ml/trained_models/{modelId}/deployment/_start',
validate: {
params: modelIdSchema,
query: threadingParamsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}/deployment/_start`,
access: 'internal',
options: {
tags: ['access:ml:canStartStopTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.startTrainedModelDeployment({
model_id: modelId,
...(request.query ? request.query : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelIdSchema,
query: threadingParamsSchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId } = request.params;
const body = await mlClient.startTrainedModelDeployment({
model_id: modelId,
...(request.query ? request.query : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {post} /api/ml/trained_models/:modelId/deployment/_update Update trained model deployment
* @api {post} /internal/ml/trained_models/:modelId/deployment/_update Update trained model deployment
* @apiName UpdateTrainedModelDeployment
* @apiDescription Updates trained model deployment.
*/
router.post(
{
path: '/api/ml/trained_models/{modelId}/{deploymentId}/deployment/_update',
validate: {
params: modelAndDeploymentIdSchema,
body: updateDeploymentParamsSchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}/{deploymentId}/deployment/_update`,
access: 'internal',
options: {
tags: ['access:ml:canStartStopTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId, deploymentId } = request.params;
const body = await mlClient.updateTrainedModelDeployment({
model_id: modelId,
deployment_id: deploymentId,
...request.body,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: { params: modelAndDeploymentIdSchema, body: updateDeploymentParamsSchema },
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId, deploymentId } = request.params;
const body = await mlClient.updateTrainedModelDeployment({
model_id: modelId,
deployment_id: deploymentId,
...request.body,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {post} /api/ml/trained_models/:modelId/deployment/_stop Stop trained model deployment
* @api {post} /internal/ml/trained_models/:modelId/deployment/_stop Stop trained model deployment
* @apiName StopTrainedModelDeployment
* @apiDescription Stops trained model deployment.
*/
router.post(
{
path: '/api/ml/trained_models/{modelId}/{deploymentId}/deployment/_stop',
validate: {
params: modelAndDeploymentIdSchema,
query: forceQuerySchema,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/{modelId}/{deploymentId}/deployment/_stop`,
access: 'internal',
options: {
tags: ['access:ml:canStartStopTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { deploymentId, modelId } = request.params;
const results: Record<string, { success: boolean; error?: ErrorType }> = {};
for (const id of deploymentId.split(',')) {
try {
const { stopped: success } = await mlClient.stopTrainedModelDeployment({
model_id: modelId,
deployment_id: id,
force: request.query.force ?? false,
allow_no_match: false,
});
results[id] = { success };
} catch (error) {
results[id] = { success: false, error };
}
}
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelAndDeploymentIdSchema,
query: forceQuerySchema,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { deploymentId, modelId } = request.params;
const results: Record<string, { success: boolean; error?: ErrorType }> = {};
for (const id of deploymentId.split(',')) {
try {
const { stopped: success } = await mlClient.stopTrainedModelDeployment({
model_id: modelId,
deployment_id: id,
force: request.query.force ?? false,
allow_no_match: false,
});
results[id] = { success };
} catch (error) {
results[id] = { success: false, error };
}
}
return response.ok({
body: results,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {post} /api/ml/trained_models/pipeline_simulate Simulates an ingest pipeline
* @api {post} /internal/ml/trained_models/pipeline_simulate Simulates an ingest pipeline
* @apiName SimulateIngestPipeline
* @apiDescription Simulates an ingest pipeline.
*/
router.post(
{
path: '/api/ml/trained_models/pipeline_simulate',
validate: {
body: pipelineSimulateBody,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/pipeline_simulate`,
access: 'internal',
options: {
tags: ['access:ml:canTestTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { pipeline, docs } = request.body;
const body = await client.asInternalUser.ingest.simulate({
pipeline,
docs,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: pipelineSimulateBody,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ client, request, response }) => {
try {
const { pipeline, docs } = request.body;
const body = await client.asInternalUser.ingest.simulate({
pipeline,
docs,
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
/**
* @apiGroup TrainedModels
*
* @api {post} /api/ml/trained_models/infer/:modelId Evaluates a trained model
* @api {post} /internal/ml/trained_models/infer/:modelId Evaluates a trained model
* @apiName InferTrainedModelDeployment
* @apiDescription Evaluates a trained model.
*/
router.post(
{
path: '/api/ml/trained_models/infer/{modelId}/{deploymentId}',
validate: {
params: modelAndDeploymentIdSchema,
query: inferTrainedModelQuery,
body: inferTrainedModelBody,
},
router.versioned
.post({
path: `${ML_INTERNAL_BASE_PATH}/trained_models/infer/{modelId}/{deploymentId}`,
access: 'internal',
options: {
tags: ['access:ml:canTestTrainedModels'],
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId, deploymentId } = request.params;
const body = await mlClient.inferTrainedModel({
model_id: modelId,
deployment_id: deploymentId,
body: {
docs: request.body.docs,
...(request.body.inference_config
? { inference_config: request.body.inference_config }
: {}),
},
...(request.query.timeout ? { timeout: request.query.timeout } : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
.addVersion(
{
version: '1',
validate: {
request: {
params: modelAndDeploymentIdSchema,
query: inferTrainedModelQuery,
body: inferTrainedModelBody,
},
},
},
routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => {
try {
const { modelId, deploymentId } = request.params;
const body = await mlClient.inferTrainedModel({
model_id: modelId,
deployment_id: deploymentId,
body: {
docs: request.body.docs,
...(request.body.inference_config
? { inference_config: request.body.inference_config }
: {}),
},
...(request.query.timeout ? { timeout: request.query.timeout } : {}),
});
return response.ok({
body,
});
} catch (e) {
return response.customError(wrapError(e));
}
})
);
}

View file

@ -28,9 +28,10 @@ export const anomaliesSearch = async (
signal: AbortSignal
): Promise<AnomaliesSearchResponse> => {
return KibanaServices.get().http.fetch<AnomaliesSearchResponse>(
'/api/ml/results/anomaly_search',
'/internal/ml/results/anomaly_search',
{
method: 'POST',
version: '1',
body: JSON.stringify(body),
asSystemRequest: true,
signal,

View file

@ -24,8 +24,9 @@ export interface Body {
}
export const anomaliesTableData = async (body: Body, signal: AbortSignal): Promise<Anomalies> => {
return KibanaServices.get().http.fetch<Anomalies>('/api/ml/results/anomalies_table_data', {
return KibanaServices.get().http.fetch<Anomalies>('/internal/ml/results/anomalies_table_data', {
method: 'POST',
version: '1',
body: JSON.stringify(body),
asSystemRequest: true,
signal,

View file

@ -28,8 +28,9 @@ export const getJobs = async ({
jobIds,
signal,
}: GetJobsArgs): Promise<CombinedJobWithStats[]> =>
http.fetch<CombinedJobWithStats[]>('/api/ml/jobs/jobs', {
http.fetch<CombinedJobWithStats[]>('/internal/ml/jobs/jobs', {
method: 'POST',
version: '1',
body: JSON.stringify({ jobIds }),
asSystemRequest: true,
signal,

View file

@ -25,8 +25,9 @@ export const getJobsSummary = async ({
jobIds,
signal,
}: GetJobsSummaryArgs): Promise<MlSummaryJob[]> =>
KibanaServices.get().http.fetch<MlSummaryJob[]>('/api/ml/jobs/jobs_summary', {
KibanaServices.get().http.fetch<MlSummaryJob[]>('/internal/ml/jobs/jobs_summary', {
method: 'POST',
version: '1',
body: JSON.stringify({ jobIds: jobIds ?? [] }),
asSystemRequest: true,
signal,

View file

@ -29,8 +29,9 @@ export const getMlCapabilities = async ({
http: HttpSetup;
signal: AbortSignal;
}): Promise<MlCapabilitiesResponse> =>
http.fetch<MlCapabilitiesResponse>('/api/ml/ml_capabilities', {
http.fetch<MlCapabilitiesResponse>('/internal/ml/ml_capabilities', {
method: 'GET',
version: '1',
asSystemRequest: true,
signal,
});

View file

@ -33,9 +33,10 @@ export const checkRecognizer = async ({
signal,
}: CheckRecognizerProps): Promise<RecognizerModule[]> =>
KibanaServices.get().http.fetch<RecognizerModule[]>(
`/api/ml/modules/recognize/${indexPatternName}`,
`/internal/ml/modules/recognize/${indexPatternName}`,
{
method: 'GET',
version: '1',
asSystemRequest: true,
signal,
}
@ -50,8 +51,9 @@ export const checkRecognizer = async ({
* @throws An error if response is not OK
*/
export const getModules = async ({ moduleId = '', signal }: GetModulesProps): Promise<Module[]> =>
KibanaServices.get().http.fetch<Module[]>(`/api/ml/modules/get_module/${moduleId}`, {
KibanaServices.get().http.fetch<Module[]>(`/internal/ml/modules/get_module/${moduleId}`, {
method: 'GET',
version: '1',
asSystemRequest: true,
signal,
});
@ -75,9 +77,10 @@ export const setupMlJob = async ({
prefix = '',
}: MlSetupArgs): Promise<SetupMlResponse> => {
const response = await KibanaServices.get().http.fetch<SetupMlResponse>(
`/api/ml/modules/setup/${configTemplate}`,
`/internal/ml/modules/setup/${configTemplate}`,
{
method: 'POST',
version: '1',
body: JSON.stringify({
prefix,
groups,
@ -110,9 +113,10 @@ export const startDatafeeds = async ({
start: number;
}): Promise<StartDatafeedResponse> => {
const response = await KibanaServices.get().http.fetch<StartDatafeedResponse>(
'/api/ml/jobs/force_start_datafeeds',
'/internal/ml/jobs/force_start_datafeeds',
{
method: 'POST',
version: '1',
body: JSON.stringify({
datafeedIds,
...(start !== 0 && { start }),
@ -138,9 +142,10 @@ export const stopDatafeeds = async ({
datafeedIds: string[];
}): Promise<[StopDatafeedResponse | ErrorResponse, CloseJobsResponse]> => {
const stopDatafeedsResponse = await KibanaServices.get().http.fetch<StopDatafeedResponse>(
'/api/ml/jobs/stop_datafeeds',
'/internal/ml/jobs/stop_datafeeds',
{
method: 'POST',
version: '1',
body: JSON.stringify({
datafeedIds,
}),
@ -150,9 +155,10 @@ export const stopDatafeeds = async ({
const datafeedPrefix = 'datafeed-';
const closeJobsResponse = await KibanaServices.get().http.fetch<CloseJobsResponse>(
'/api/ml/jobs/close_jobs',
'/internal/ml/jobs/close_jobs',
{
method: 'POST',
version: '1',
body: JSON.stringify({
jobIds: datafeedIds.map((dataFeedId) =>
dataFeedId.startsWith(datafeedPrefix)

View file

@ -12,7 +12,7 @@ import { getModules } from '../api';
import type { GetModulesProps, Module } from '../types';
const ONE_MINUTE = 60000;
export const GET_MODULES_QUERY_KEY = ['GET', '/api/ml/modules/get_module/:moduleId'];
export const GET_MODULES_QUERY_KEY = ['GET', '/internal/ml/modules/get_module/:moduleId'];
export const useFetchModulesQuery = (
queryArgs: Omit<GetModulesProps, 'signal'>,

View file

@ -12,7 +12,7 @@ import { checkRecognizer } from '../api';
import type { CheckRecognizerProps, RecognizerModule } from '../types';
const ONE_MINUTE = 60000;
export const GET_RECOGNIZER_QUERY_KEY = ['GET', '/api/ml/modules/recognize/:indexPatterns'];
export const GET_RECOGNIZER_QUERY_KEY = ['GET', '/internal/ml/modules/recognize/:indexPatterns'];
export const useFetchRecognizerQuery = (
queryArgs: Omit<CheckRecognizerProps, 'signal'>,

View file

@ -24,11 +24,11 @@ export enum API_URLS {
JOURNEY_SCREENSHOT_BLOCKS = `/internal/uptime/journey/screenshot/block`,
LOG_PAGE_VIEW = `/internal/uptime/log_page_view`,
ML_MODULE_JOBS = `/api/ml/modules/jobs_exist/`,
ML_SETUP_MODULE = '/api/ml/modules/setup/',
ML_DELETE_JOB = `/api/ml/jobs/delete_jobs`,
ML_CAPABILITIES = '/api/ml/ml_capabilities',
ML_ANOMALIES_RESULT = `/api/ml/results/anomalies_table_data`,
ML_MODULE_JOBS = `/internal/ml/modules/jobs_exist/`,
ML_SETUP_MODULE = '/internal/ml/modules/setup/',
ML_DELETE_JOB = `/internal/ml/jobs/delete_jobs`,
ML_CAPABILITIES = '/internal/ml/ml_capabilities',
ML_ANOMALIES_RESULT = `/internal/ml/results/anomalies_table_data`,
RULE_CONNECTORS = '/api/actions/connectors',
CREATE_RULE = '/api/alerting/rule',

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { Annotation } from '@kbn/ml-plugin/common/types/annotations';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
import { createJobConfig, createAnnotationRequestBody } from './common_jobs';
export default ({ getService }: FtrProviderContext) => {
@ -35,9 +35,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should successfully create annotations for anomaly job', async () => {
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(annotationRequestBody);
ml.api.assertResponseStatusCode(200, status, body);
const annotationId = body._id;
@ -57,9 +57,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should successfully create annotation for user with ML read permissions', async () => {
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(annotationRequestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -77,9 +77,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to create annotation for unauthorized user', async () => {
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(annotationRequestBody);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -7,7 +7,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
import { testSetupJobConfigs, jobIds, testSetupAnnotations } from './common_jobs';
@ -42,9 +42,9 @@ export default ({ getService }: FtrProviderContext) => {
const annotationIdToDelete = annotationsForJob[0]._id;
const { body, status } = await supertest
.delete(`/api/ml/annotations/delete/${annotationIdToDelete}`)
.delete(`/internal/ml/annotations/delete/${annotationIdToDelete}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body._id).to.eql(annotationIdToDelete);
@ -60,9 +60,9 @@ export default ({ getService }: FtrProviderContext) => {
const annotationIdToDelete = annotationsForJob[0]._id;
const { body, status } = await supertest
.delete(`/api/ml/annotations/delete/${annotationIdToDelete}`)
.delete(`/internal/ml/annotations/delete/${annotationIdToDelete}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body._id).to.eql(annotationIdToDelete);
@ -78,9 +78,9 @@ export default ({ getService }: FtrProviderContext) => {
const annotationIdToDelete = annotationsForJob[0]._id;
const { body, status } = await supertest
.delete(`/api/ml/annotations/delete/${annotationIdToDelete}`)
.delete(`/internal/ml/annotations/delete/${annotationIdToDelete}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { omit } from 'lodash';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
import { testSetupJobConfigs, jobIds, testSetupAnnotations } from './common_jobs';
@ -44,9 +44,9 @@ export default ({ getService }: FtrProviderContext) => {
maxAnnotations: 500,
};
const { body, status } = await supertest
.post('/api/ml/annotations')
.post('/internal/ml/annotations')
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -69,9 +69,9 @@ export default ({ getService }: FtrProviderContext) => {
maxAnnotations: 500,
};
const { body, status } = await supertest
.post('/api/ml/annotations')
.post('/internal/ml/annotations')
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -94,9 +94,9 @@ export default ({ getService }: FtrProviderContext) => {
maxAnnotations: 500,
};
const { body, status } = await supertest
.post('/api/ml/annotations')
.post('/internal/ml/annotations')
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -119,9 +119,9 @@ export default ({ getService }: FtrProviderContext) => {
maxAnnotations: 500,
};
const { body, status } = await supertest
.post('/api/ml/annotations')
.post('/internal/ml/annotations')
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { ANNOTATION_TYPE } from '@kbn/ml-plugin/common/constants/annotations';
import { Annotation } from '@kbn/ml-plugin/common/types/annotations';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
import { testSetupJobConfigs, jobIds, testSetupAnnotations } from './common_jobs';
@ -60,9 +60,9 @@ export default ({ getService }: FtrProviderContext) => {
};
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader())
.send(annotationUpdateRequestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -91,9 +91,9 @@ export default ({ getService }: FtrProviderContext) => {
};
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader())
.send(annotationUpdateRequestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -122,9 +122,9 @@ export default ({ getService }: FtrProviderContext) => {
};
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader())
.send(annotationUpdateRequestBody);
ml.api.assertResponseStatusCode(403, status, body);
@ -151,9 +151,9 @@ export default ({ getService }: FtrProviderContext) => {
_id: originalAnnotation._id,
};
const { body, status } = await supertest
.put('/api/ml/annotations/index')
.put('/internal/ml/annotations/index')
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader())
.send(annotationUpdateRequestBodyWithMissingFields);
ml.api.assertResponseStatusCode(200, status, body);

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { JOB_STATE } from '@kbn/ml-plugin/common/constants/states';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -22,12 +22,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runRequest(jobId: string, expectedStatusCode: number, space?: string) {
const { body, status } = await supertest
.post(`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors/${jobId}/_close`)
.post(`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors/${jobId}/_close`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -111,9 +111,9 @@ export default ({ getService }: FtrProviderContext) => {
for (const testData of testDataList) {
it(`${testData.testTitle}`, async () => {
const { body, status } = await supertest
.put(`/api/ml/anomaly_detectors/${testData.jobId}`)
.put(`/internal/ml/anomaly_detectors/${testData.jobId}`)
.auth(testData.user, ml.securityCommon.getPasswordForUser(testData.user))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testData.requestBody);
ml.api.assertResponseStatusCode(testData.expected.responseCode, status, body);

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -76,9 +76,9 @@ export default ({ getService }: FtrProviderContext) => {
for (const testData of testDataList) {
it(`${testData.testTitle}`, async () => {
const { body, status } = await supertest
.put(`/api/ml/anomaly_detectors/${testData.jobId}`)
.put(`/internal/ml/anomaly_detectors/${testData.jobId}`)
.auth(testData.user, ml.securityCommon.getPasswordForUser(testData.user))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testData.requestBody);
ml.api.assertResponseStatusCode(testData.expected.responseCode, status, body);

View file

@ -7,7 +7,7 @@
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -38,12 +38,12 @@ export default ({ getService }: FtrProviderContext) => {
await ml.testExecution.logTestStep('should create job');
const { body, status } = await supertest
.put(`/s/${idSpace1}/api/ml/anomaly_detectors/${jobIdSpace1}`)
.put(`/s/${idSpace1}/internal/ml/anomaly_detectors/${jobIdSpace1}`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(jobConfig);
ml.api.assertResponseStatusCode(200, status, body);

View file

@ -7,7 +7,7 @@
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -20,12 +20,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runRequest(jobId: string, expectedStatusCode: number, space?: string) {
const { body, status } = await supertest
.delete(`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors/${jobId}`)
.delete(`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors/${jobId}`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -8,7 +8,7 @@
import { JOB_STATE, DATAFEED_STATE } from '@kbn/ml-plugin/common/constants/states';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -29,9 +29,9 @@ export default ({ getService }: FtrProviderContext) => {
expectedStatusCode: number
) {
const { body, status } = await supertest
.post(`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors/${jobId}/_forecast`)
.post(`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors/${jobId}/_forecast`)
.auth(user, ml.securityCommon.getPasswordForUser(user))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send({ duration });
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -72,9 +72,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetAnomalyDetectors', () => {
it('should fetch all anomaly detector jobs', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors`)
.get(`/internal/ml/anomaly_detectors`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -85,9 +85,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve jobs for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors`)
.get(`/internal/ml/anomaly_detectors`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -98,9 +98,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetAnomalyDetectorsById', () => {
it('should fetch single anomaly detector job by id', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(1);
@ -110,9 +110,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch anomaly detector jobs based on provided ids', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1,${jobId}_2`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -123,9 +123,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve a job for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -136,9 +136,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetAnomalyDetectorsStats', () => {
it('should fetch jobs stats', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/_stats`)
.get(`/internal/ml/anomaly_detectors/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -156,9 +156,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve jobs stats for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/_stats`)
.get(`/internal/ml/anomaly_detectors/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -169,9 +169,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetAnomalyDetectorsStatsById', () => {
it('should fetch single job stats', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(1);
@ -188,9 +188,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch multiple jobs stats based on provided ids', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1,${jobId}_2/_stats`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1,${jobId}_2/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -208,9 +208,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve a job stats for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/anomaly_detectors/${jobId}_1/_stats`)
.get(`/internal/ml/anomaly_detectors/${jobId}_1/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -29,7 +29,7 @@ export default ({ getService }: FtrProviderContext) => {
) {
const { body, status } = await supertest
.get(
`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors${
`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors${
jobOrGroup ? `/${jobOrGroup}` : ''
}/_stats`
)
@ -37,7 +37,7 @@ export default ({ getService }: FtrProviderContext) => {
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -29,7 +29,7 @@ export default ({ getService }: FtrProviderContext) => {
) {
const { body, status } = await supertest
.get(
`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors${
`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors${
jobOrGroup ? `/${jobOrGroup}` : ''
}`
)
@ -37,7 +37,7 @@ export default ({ getService }: FtrProviderContext) => {
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { JOB_STATE } from '@kbn/ml-plugin/common/constants/states';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const ml = getService('ml');
@ -22,12 +22,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runRequest(jobId: string, expectedStatusCode: number, space?: string) {
const { body, status } = await supertest
.post(`${space ? `/s/${space}` : ''}/api/ml/anomaly_detectors/${jobId}/_open`)
.post(`${space ? `/s/${space}` : ''}/internal/ml/anomaly_detectors/${jobId}/_open`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
@ -39,9 +39,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should successfully create calendar by id', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars`)
.put(`/internal/ml/calendars`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -57,9 +57,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not create new calendar for user without required permission', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars`)
.put(`/internal/ml/calendars`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(403, status, body);
@ -70,9 +70,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not create new calendar for unauthorized user', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars`)
.put(`/internal/ml/calendars`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
@ -43,9 +43,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should delete calendar by id', async () => {
const { body, status } = await supertest
.delete(`/api/ml/calendars/${calendarId}`)
.delete(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.acknowledged).to.eql(true);
@ -54,9 +54,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not delete calendar for user without required permission', async () => {
const { body, status } = await supertest
.delete(`/api/ml/calendars/${calendarId}`)
.delete(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -65,9 +65,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not delete calendar for unauthorized user', async () => {
const { body, status } = await supertest
.delete(`/api/ml/calendars/${calendarId}`)
.delete(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -76,9 +76,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should return 404 if invalid calendarId', async () => {
const { body, status } = await supertest
.delete(`/api/ml/calendars/calendar_id_dne`)
.delete(`/internal/ml/calendars/calendar_id_dne`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(404, status, body);
expect(body.error).to.eql('Not Found');

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
@ -47,9 +47,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch all calendars', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars`)
.get(`/internal/ml/calendars`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body).to.have.length(testCalendars.length);
@ -59,9 +59,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch all calendars for user with view permission', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars`)
.get(`/internal/ml/calendars`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body).to.have.length(testCalendars.length);
@ -71,9 +71,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not fetch calendars for unauthorized user', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars`)
.get(`/internal/ml/calendars`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -99,9 +99,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch calendar & associated events by id', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars/${calendarId}`)
.get(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.job_ids).to.eql(testCalendar.job_ids);
@ -112,9 +112,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch calendar & associated events by id for user with view permission', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars/${calendarId}`)
.get(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.job_ids).to.eql(testCalendar.job_ids);
@ -125,9 +125,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not fetch calendars for unauthorized user', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars/${calendarId}`)
.get(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -136,9 +136,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should return 404 if invalid calendar id', async () => {
const { body, status } = await supertest
.get(`/api/ml/calendars/calendar_id_dne`)
.get(`/internal/ml/calendars/calendar_id_dne`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(404, status, body);
expect(body.error).to.eql('Not Found');

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const supertest = getService('supertestWithoutAuth');
@ -51,9 +51,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should update calendar by id with new settings', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars/${calendarId}`)
.put(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(updateCalendarRequestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -76,27 +76,27 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to update calendar for user without required permission', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars/${calendarId}`)
.put(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(updateCalendarRequestBody);
ml.api.assertResponseStatusCode(403, status, body);
});
it('should not allow to update calendar for unauthorized user', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars/${calendarId}`)
.put(`/internal/ml/calendars/${calendarId}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(updateCalendarRequestBody);
ml.api.assertResponseStatusCode(403, status, body);
});
it('should return error if invalid calendarId', async () => {
const { body, status } = await supertest
.put(`/api/ml/calendars/calendar_id_dne`)
.put(`/internal/ml/calendars/calendar_id_dne`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(updateCalendarRequestBody);
ml.api.assertResponseStatusCode(404, status, body);
});

View file

@ -10,7 +10,7 @@ import { DataFrameAnalyticsConfig } from '@kbn/ml-plugin/public/application/data
import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -92,9 +92,9 @@ export default ({ getService }: FtrProviderContext) => {
const requestBody = testConfig.config;
const { body, status } = await supertest
.put(`/api/ml/data_frame/analytics/${analyticsId}`)
.put(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(200, status, body);
@ -114,9 +114,9 @@ export default ({ getService }: FtrProviderContext) => {
const requestBody = testJobConfigs[0].config;
const { body, status } = await supertest
.put(`/api/ml/data_frame/analytics/${analyticsId}`)
.put(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(403, status, body);
@ -129,9 +129,9 @@ export default ({ getService }: FtrProviderContext) => {
const requestBody = testJobConfigs[0].config;
const { body, status } = await supertest
.put(`/api/ml/data_frame/analytics/${analyticsId}`)
.put(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(requestBody);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -10,7 +10,7 @@ import { DataFrameAnalyticsConfig } from '@kbn/ml-plugin/public/application/data
import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -78,9 +78,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should delete analytics jobs by id', async () => {
const analyticsId = `${jobId}_1`;
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.analyticsJobDeleted.success).to.eql(true);
@ -90,9 +90,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve analytics jobs for unauthorized user', async () => {
const analyticsId = `${jobId}_2`;
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -103,9 +103,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve analytics jobs for the user with only view permission', async () => {
const analyticsId = `${jobId}_2`;
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -116,9 +116,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should show 404 error if job does not exist or has already been deleted', async () => {
const id = `${jobId}_invalid`;
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${id}`)
.delete(`/internal/ml/data_frame/analytics/${id}`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(404, status, body);
expect(body.error).to.eql('Not Found');
@ -140,10 +140,10 @@ export default ({ getService }: FtrProviderContext) => {
it('should delete job and destination index by id', async () => {
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.query({ deleteDestIndex: true })
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.analyticsJobDeleted.success).to.eql(true);
@ -169,10 +169,10 @@ export default ({ getService }: FtrProviderContext) => {
it('should delete job and index pattern by id', async () => {
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.query({ deleteDestIndexPattern: true })
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.analyticsJobDeleted.success).to.eql(true);
@ -201,10 +201,10 @@ export default ({ getService }: FtrProviderContext) => {
it('should delete job, target index, and index pattern by id', async () => {
const { body, status } = await supertest
.delete(`/api/ml/data_frame/analytics/${analyticsId}`)
.delete(`/internal/ml/data_frame/analytics/${analyticsId}`)
.query({ deleteDestIndex: true, deleteDestIndexPattern: true })
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.analyticsJobDeleted.success).to.eql(true);

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -23,12 +23,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runRequest(jobId: string, space: string, expectedStatusCode: number) {
const { body, status } = await supertest
.delete(`/s/${space}/api/ml/data_frame/analytics/${jobId}`)
.delete(`/s/${space}/internal/ml/data_frame/analytics/${jobId}`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -10,7 +10,7 @@ import { DataFrameAnalyticsConfig } from '@kbn/ml-plugin/public/application/data
import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -132,9 +132,9 @@ export default ({ getService }: FtrProviderContext) => {
describe(`EvaluateDataFrameAnalytics ${testConfig.jobType}`, async () => {
it(`should evaluate ${testConfig.jobType} analytics job`, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/_evaluate`)
.post(`/internal/ml/data_frame/_evaluate`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.eval);
ml.api.assertResponseStatusCode(200, status, body);
@ -155,9 +155,9 @@ export default ({ getService }: FtrProviderContext) => {
it(`should evaluate ${testConfig.jobType} job for the user with only view permission`, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/_evaluate`)
.post(`/internal/ml/data_frame/_evaluate`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.eval);
ml.api.assertResponseStatusCode(200, status, body);
@ -178,9 +178,9 @@ export default ({ getService }: FtrProviderContext) => {
it(`should not allow unauthorized user to evaluate ${testConfig.jobType} job`, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/_evaluate`)
.post(`/internal/ml/data_frame/_evaluate`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.eval);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -9,7 +9,7 @@ import { DataFrameAnalyticsConfig } from '@kbn/ml-plugin/public/application/data
import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -91,9 +91,9 @@ export default ({ getService }: FtrProviderContext) => {
describe(`ExplainDataFrameAnalytics ${testConfig.jobType}`, async () => {
it(`should explain ${testConfig.jobType} analytics job`, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/_explain`)
.post(`/internal/ml/data_frame/analytics/_explain`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.config);
ml.api.assertResponseStatusCode(200, status, body);
@ -112,9 +112,9 @@ export default ({ getService }: FtrProviderContext) => {
it(`should not allow user with only view permission to use explain endpoint for ${testConfig.jobType} job `, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/_explain`)
.post(`/internal/ml/data_frame/analytics/_explain`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.config);
ml.api.assertResponseStatusCode(403, status, body);
@ -124,9 +124,9 @@ export default ({ getService }: FtrProviderContext) => {
it(`should not allow unauthorized user to use explain endpoint for ${testConfig.jobType} job`, async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/_explain`)
.post(`/internal/ml/data_frame/analytics/_explain`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(testConfig.config);
ml.api.assertResponseStatusCode(403, status, body);

View file

@ -10,7 +10,7 @@ import { DataFrameAnalyticsConfig } from '@kbn/ml-plugin/public/application/data
import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -96,9 +96,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetDataFrameAnalytics', () => {
it('should fetch all analytics jobs', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics`)
.get(`/internal/ml/data_frame/analytics`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -109,9 +109,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve analytics jobs for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics`)
.get(`/internal/ml/data_frame/analytics`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -122,9 +122,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetDataFrameAnalyticsById', () => {
it('should fetch single analytics job by id', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(1);
@ -134,9 +134,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch analytics jobs based on provided ids', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1,${jobId}_2`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1,${jobId}_2`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -147,9 +147,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve a job for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -160,9 +160,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetDataFrameAnalyticsStats', () => {
it('should fetch analytics jobs stats', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/_stats`)
.get(`/internal/ml/data_frame/analytics/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -180,9 +180,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve jobs stats for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/_stats`)
.get(`/internal/ml/data_frame/analytics/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -193,9 +193,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetDataFrameAnalyticsStatsById', () => {
it('should fetch single analytics job stats by id', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1/_stats`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(1);
@ -212,9 +212,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch multiple analytics jobs stats based on provided ids', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1,${jobId}_2/_stats`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1,${jobId}_2/_stats`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.count).to.eql(2);
@ -232,9 +232,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve a job stats for the user without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1/_stats`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1/_stats`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -245,9 +245,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('GetDataFrameAnalyticsIdMap', () => {
it('should return a map of objects leading up to analytics job id', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/map/${jobId}_1`)
.get(`/internal/ml/data_frame/analytics/map/${jobId}_1`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body).to.have.keys('elements', 'details', 'error');
@ -266,9 +266,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should return empty results and an error message if the job does not exist', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/map/${jobId}_fake`)
.get(`/internal/ml/data_frame/analytics/map/${jobId}_fake`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.elements.length).to.eql(0);
@ -283,9 +283,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should fetch single analytics job messages by id', async () => {
await retry.tryForTime(5000, async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1/messages`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1/messages`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body.length).to.eql(1);
@ -303,9 +303,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to retrieve job messages without required permissions', async () => {
const { body, status } = await supertest
.get(`/api/ml/data_frame/analytics/${jobId}_1/messages`)
.get(`/internal/ml/data_frame/analytics/${jobId}_1/messages`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -31,7 +31,7 @@ export default ({ getService }: FtrProviderContext) => {
) {
const { body, status } = await supertest
.get(
`/s/${space}/api/ml/data_frame/analytics${jobId ? `/${jobId}` : ''}${
`/s/${space}/internal/ml/data_frame/analytics${jobId ? `/${jobId}` : ''}${
requestStats ? '/_stats' : ''
}`
)
@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext) => {
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;
@ -47,12 +47,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runMapRequest(space: string, expectedStatusCode: number, jobId: string) {
const { body, status } = await supertest
.get(`/s/${space}/api/ml/data_frame/analytics/map/${jobId}`)
.get(`/s/${space}/internal/ml/data_frame/analytics/map/${jobId}`)
.auth(
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -31,12 +31,12 @@ export default ({ getService }: FtrProviderContext) => {
allSpaces?: boolean
) {
const { body, status } = await supertest
.post(`/s/${space}/api/ml/data_frame/analytics/jobs_exist`)
.post(`/s/${space}/internal/ml/data_frame/analytics/jobs_exist`)
.auth(
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS)
.set(getCommonRequestHeader('1'))
.send(allSpaces ? { analyticsIds, allSpaces } : { analyticsIds });
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);

View file

@ -8,7 +8,7 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -18,7 +18,7 @@ export default ({ getService }: FtrProviderContext) => {
const testIndexPattern = 'ft_bank_marketing';
async function runRequest(indexPattern: string, expectedStatusCode: number, rollup?: boolean) {
let url = `/api/ml/data_frame/analytics/new_job_caps/${indexPattern}`;
let url = `/internal/ml/data_frame/analytics/new_job_caps/${indexPattern}`;
if (rollup !== undefined) {
url += `?rollup=${rollup}`;
}
@ -28,7 +28,7 @@ export default ({ getService }: FtrProviderContext) => {
USER.ML_VIEWER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_VIEWER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -11,7 +11,7 @@ import { DeepPartial } from '@kbn/ml-plugin/common/types/common';
import { DATA_FRAME_TASK_STATE } from '@kbn/ml-plugin/common/constants/data_frame_analytics';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -79,9 +79,9 @@ export default ({ getService }: FtrProviderContext) => {
const analyticsId = `${jobId}_0`;
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_start`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_start`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body).not.to.be(undefined);
@ -97,9 +97,9 @@ export default ({ getService }: FtrProviderContext) => {
const message = `No known job with id '${id}'`;
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${id}/_start`)
.post(`/internal/ml/data_frame/analytics/${id}/_start`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(404, status, body);
expect(body.error).to.eql('Not Found');
@ -110,9 +110,9 @@ export default ({ getService }: FtrProviderContext) => {
const analyticsId = `${jobId}_0`;
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_start`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_start`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -123,9 +123,9 @@ export default ({ getService }: FtrProviderContext) => {
const analyticsId = `${jobId}_0`;
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_start`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_start`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { DATA_FRAME_TASK_STATE } from '@kbn/ml-plugin/common/constants/data_frame_analytics';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -27,12 +27,12 @@ export default ({ getService }: FtrProviderContext) => {
async function runStartRequest(jobId: string, space: string, expectedStatusCode: number) {
const { body, status } = await supertest
.post(`/s/${space}/api/ml/data_frame/analytics/${jobId}/_start`)
.post(`/s/${space}/internal/ml/data_frame/analytics/${jobId}/_start`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { DATA_FRAME_TASK_STATE } from '@kbn/ml-plugin/common/constants/data_frame_analytics';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { USER } from '../../../../functional/services/ml/security_common';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
export default ({ getService }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
@ -41,9 +41,9 @@ export default ({ getService }: FtrProviderContext) => {
describe('StopsDataFrameAnalyticsJob', () => {
it('should stop analytics job for specified id when job exists', async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_stop`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_stop`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(200, status, body);
expect(body).not.to.be(undefined);
@ -56,9 +56,9 @@ export default ({ getService }: FtrProviderContext) => {
const message = `No known job with id '${id}'`;
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${id}/_stop`)
.post(`/internal/ml/data_frame/analytics/${id}/_stop`)
.auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(404, status, body);
expect(body.error).to.eql('Not Found');
@ -67,9 +67,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to stop analytics job for unauthorized user', async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_stop`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_stop`)
.auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');
@ -78,9 +78,9 @@ export default ({ getService }: FtrProviderContext) => {
it('should not allow to stop analytics job for user with view only permission', async () => {
const { body, status } = await supertest
.post(`/api/ml/data_frame/analytics/${analyticsId}/_stop`)
.post(`/internal/ml/data_frame/analytics/${analyticsId}/_stop`)
.auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(403, status, body);
expect(body.error).to.eql('Forbidden');

View file

@ -9,7 +9,7 @@ import expect from '@kbn/expect';
import { DATA_FRAME_TASK_STATE } from '@kbn/ml-plugin/common/constants/data_frame_analytics';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api';
import { USER } from '../../../../functional/services/ml/security_common';
export default ({ getService }: FtrProviderContext) => {
@ -30,12 +30,12 @@ export default ({ getService }: FtrProviderContext) => {
expectedStatusCode: number
) {
const { body, status } = await supertest
.post(`/s/${space}/api/ml/data_frame/analytics/${jobId}/${action}`)
.post(`/s/${space}/internal/ml/data_frame/analytics/${jobId}/${action}`)
.auth(
USER.ML_POWERUSER_ALL_SPACES,
ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER_ALL_SPACES)
)
.set(COMMON_REQUEST_HEADERS);
.set(getCommonRequestHeader('1'));
ml.api.assertResponseStatusCode(expectedStatusCode, status, body);
return body;

Some files were not shown because too many files have changed in this diff Show more