mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[ML] DF Analytics creation: ensure monitor
cluster privilege not required to create job (#71934)
* add checkIndexExists endpoint wrapping field_caps * replace indexNames with checkIndexExists check * update translations * show error toast on index check fail * add new route to api doc
This commit is contained in:
parent
f75ccd4d8d
commit
d0d271c07d
10 changed files with 87 additions and 38 deletions
|
@ -4,7 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { FC, Fragment, useRef } from 'react';
|
||||
import React, { FC, Fragment, useRef, useEffect } from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
import {
|
||||
EuiFieldText,
|
||||
EuiFormRow,
|
||||
|
@ -21,6 +22,8 @@ import { CreateAnalyticsStepProps } from '../../../analytics_management/hooks/us
|
|||
import { JOB_ID_MAX_LENGTH } from '../../../../../../../common/constants/validation';
|
||||
import { ContinueButton } from '../continue_button';
|
||||
import { ANALYTICS_STEPS } from '../../page';
|
||||
import { ml } from '../../../../../services/ml_api_service';
|
||||
import { extractErrorMessage } from '../../../../../../../common/util/errors';
|
||||
|
||||
export const DetailsStepForm: FC<CreateAnalyticsStepProps> = ({
|
||||
actions,
|
||||
|
@ -28,7 +31,7 @@ export const DetailsStepForm: FC<CreateAnalyticsStepProps> = ({
|
|||
setCurrentStep,
|
||||
}) => {
|
||||
const {
|
||||
services: { docLinks },
|
||||
services: { docLinks, notifications },
|
||||
} = useMlKibana();
|
||||
const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks;
|
||||
|
||||
|
@ -59,6 +62,32 @@ export const DetailsStepForm: FC<CreateAnalyticsStepProps> = ({
|
|||
destinationIndexNameValid === false ||
|
||||
(destinationIndexPatternTitleExists === true && createIndexPattern === true);
|
||||
|
||||
const debouncedIndexCheck = debounce(async () => {
|
||||
try {
|
||||
const { exists } = await ml.checkIndexExists({ index: destinationIndex });
|
||||
setFormState({ destinationIndexNameExists: exists });
|
||||
} catch (e) {
|
||||
notifications.toasts.addDanger(
|
||||
i18n.translate('xpack.ml.dataframe.analytics.create.errorCheckingIndexExists', {
|
||||
defaultMessage: 'The following error occurred getting the existing index names: {error}',
|
||||
values: { error: extractErrorMessage(e) },
|
||||
})
|
||||
);
|
||||
}
|
||||
}, 400);
|
||||
|
||||
useEffect(() => {
|
||||
if (destinationIndexNameValid === true) {
|
||||
debouncedIndexCheck();
|
||||
} else if (destinationIndex.trim() === '' && destinationIndexNameExists === true) {
|
||||
setFormState({ destinationIndexNameExists: false });
|
||||
}
|
||||
|
||||
return () => {
|
||||
debouncedIndexCheck.cancel();
|
||||
};
|
||||
}, [destinationIndex]);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFormRow
|
||||
|
|
|
@ -17,7 +17,6 @@ export enum ACTION {
|
|||
RESET_FORM,
|
||||
SET_ADVANCED_EDITOR_RAW_STRING,
|
||||
SET_FORM_STATE,
|
||||
SET_INDEX_NAMES,
|
||||
SET_INDEX_PATTERN_TITLES,
|
||||
SET_IS_JOB_CREATED,
|
||||
SET_IS_JOB_STARTED,
|
||||
|
@ -48,7 +47,6 @@ export type Action =
|
|||
advancedEditorRawString: State['advancedEditorRawString'];
|
||||
}
|
||||
| { type: ACTION.SET_FORM_STATE; payload: Partial<State['form']> }
|
||||
| { type: ACTION.SET_INDEX_NAMES; indexNames: State['indexNames'] }
|
||||
| {
|
||||
type: ACTION.SET_INDEX_PATTERN_TITLES;
|
||||
payload: {
|
||||
|
|
|
@ -480,9 +480,6 @@ export function reducer(state: State, action: Action): State {
|
|||
|
||||
// update state attributes which are derived from other state attributes.
|
||||
if (action.payload.destinationIndex !== undefined) {
|
||||
newFormState.destinationIndexNameExists = state.indexNames.some(
|
||||
(name) => newFormState.destinationIndex === name
|
||||
);
|
||||
newFormState.destinationIndexNameEmpty = newFormState.destinationIndex === '';
|
||||
newFormState.destinationIndexNameValid = isValidIndexName(newFormState.destinationIndex);
|
||||
newFormState.destinationIndexPatternTitleExists =
|
||||
|
@ -514,14 +511,6 @@ export function reducer(state: State, action: Action): State {
|
|||
? validateAdvancedEditor({ ...state, form: newFormState })
|
||||
: validateForm({ ...state, form: newFormState });
|
||||
|
||||
case ACTION.SET_INDEX_NAMES: {
|
||||
const newState = { ...state, indexNames: action.indexNames };
|
||||
newState.form.destinationIndexNameExists = newState.indexNames.some(
|
||||
(name) => newState.form.destinationIndex === name
|
||||
);
|
||||
return newState;
|
||||
}
|
||||
|
||||
case ACTION.SET_INDEX_PATTERN_TITLES: {
|
||||
const newState = {
|
||||
...state,
|
||||
|
|
|
@ -94,7 +94,6 @@ export interface State {
|
|||
trainingPercent: number;
|
||||
};
|
||||
disabled: boolean;
|
||||
indexNames: EsIndexName[];
|
||||
indexPatternsMap: SourceIndexMap;
|
||||
isAdvancedEditorEnabled: boolean;
|
||||
isAdvancedEditorValidJson: boolean;
|
||||
|
@ -165,7 +164,6 @@ export const getInitialState = (): State => ({
|
|||
!mlNodesAvailable() ||
|
||||
!checkPermission('canCreateDataFrameAnalytics') ||
|
||||
!checkPermission('canStartStopDataFrameAnalytics'),
|
||||
indexNames: [],
|
||||
indexPatternsMap: {},
|
||||
isAdvancedEditorEnabled: false,
|
||||
isAdvancedEditorValidJson: true,
|
||||
|
|
|
@ -25,7 +25,6 @@ import { reducer } from './reducer';
|
|||
import {
|
||||
getInitialState,
|
||||
getJobConfigFromFormState,
|
||||
EsIndexName,
|
||||
FormMessage,
|
||||
State,
|
||||
SourceIndexMap,
|
||||
|
@ -67,9 +66,6 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => {
|
|||
const resetAdvancedEditorMessages = () =>
|
||||
dispatch({ type: ACTION.RESET_ADVANCED_EDITOR_MESSAGES });
|
||||
|
||||
const setIndexNames = (indexNames: EsIndexName[]) =>
|
||||
dispatch({ type: ACTION.SET_INDEX_NAMES, indexNames });
|
||||
|
||||
const setAdvancedEditorRawString = (advancedEditorRawString: string) =>
|
||||
dispatch({ type: ACTION.SET_ADVANCED_EDITOR_RAW_STRING, advancedEditorRawString });
|
||||
|
||||
|
@ -214,21 +210,7 @@ export const useCreateAnalyticsForm = (): CreateAnalyticsFormProps => {
|
|||
}
|
||||
|
||||
try {
|
||||
setIndexNames((await ml.getIndices()).map((index) => index.name));
|
||||
} catch (e) {
|
||||
addRequestMessage({
|
||||
error: getErrorMessage(e),
|
||||
message: i18n.translate(
|
||||
'xpack.ml.dataframe.analytics.create.errorGettingDataFrameIndexNames',
|
||||
{
|
||||
defaultMessage: 'An error occurred getting the existing index names:',
|
||||
}
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Set the index pattern titles which the user can choose as the source.
|
||||
// Set the existing index pattern titles.
|
||||
const indexPatternsMap: SourceIndexMap = {};
|
||||
const savedObjects = (await mlContext.indexPatterns.getCache()) || [];
|
||||
savedObjects.forEach((obj) => {
|
||||
|
|
|
@ -372,6 +372,16 @@ export function mlApiServicesProvider(httpService: HttpService) {
|
|||
});
|
||||
},
|
||||
|
||||
checkIndexExists({ index }: { index: string }) {
|
||||
const body = JSON.stringify({ index });
|
||||
|
||||
return httpService.http<{ exists: boolean }>({
|
||||
path: `${basePath()}/index_exists`,
|
||||
method: 'POST',
|
||||
body,
|
||||
});
|
||||
},
|
||||
|
||||
getFieldCaps({ index, fields }: { index: string; fields: string[] }) {
|
||||
const body = JSON.stringify({
|
||||
...(index !== undefined ? { index } : {}),
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
"MlNodeCount",
|
||||
"MlInfo",
|
||||
"MlEsSearch",
|
||||
"MlIndexExists",
|
||||
|
||||
"JobAuditMessages",
|
||||
"GetJobAuditMessages",
|
||||
|
|
|
@ -226,4 +226,48 @@ export function systemRoutes(
|
|||
}
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @apiGroup SystemRoutes
|
||||
*
|
||||
* @api {post} /api/ml/index_exists ES Field caps wrapper checks if index exists
|
||||
* @apiName MlIndexExists
|
||||
*/
|
||||
router.post(
|
||||
{
|
||||
path: '/api/ml/index_exists',
|
||||
validate: {
|
||||
body: schema.object({ index: schema.string() }),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:ml:canGetJobs'],
|
||||
},
|
||||
},
|
||||
mlLicense.fullLicenseAPIGuard(async (context, request, response) => {
|
||||
try {
|
||||
const { index } = request.body;
|
||||
|
||||
const options = {
|
||||
index: [index],
|
||||
fields: ['*'],
|
||||
ignoreUnavailable: true,
|
||||
allowNoIndices: true,
|
||||
ignore: 404,
|
||||
};
|
||||
|
||||
const fieldsResult = await context.ml!.mlClient.callAsCurrentUser('fieldCaps', options);
|
||||
const result = { exists: false };
|
||||
|
||||
if (Array.isArray(fieldsResult.indices) && fieldsResult.indices.length !== 0) {
|
||||
result.exists = true;
|
||||
}
|
||||
|
||||
return response.ok({
|
||||
body: result,
|
||||
});
|
||||
} catch (error) {
|
||||
return response.customError(wrapError(error));
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9483,7 +9483,6 @@
|
|||
"xpack.ml.dataframe.analytics.create.duplicateIndexPatternErrorMessageError": "インデックスパターン{indexPatternName}はすでに作成されています。",
|
||||
"xpack.ml.dataframe.analytics.create.errorCreatingDataFrameAnalyticsJob": "データフレーム分析ジョブの作成中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingDataFrameAnalyticsList": "既存のデータフレーム分析ジョブIDの取得中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingDataFrameIndexNames": "既存のインデックス名の取得中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingIndexPatternTitles": "既存のインデックスパターンのタイトルの取得中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.create.errorStartingDataFrameAnalyticsJob": "データフレーム分析ジョブの開始中にエラーが発生しました。",
|
||||
"xpack.ml.dataframe.analytics.create.indexPatternAlreadyExistsError": "このタイトルのインデックスパターンが既に存在します。",
|
||||
|
|
|
@ -9488,7 +9488,6 @@
|
|||
"xpack.ml.dataframe.analytics.create.duplicateIndexPatternErrorMessageError": "索引模式 {indexPatternName} 已存在。",
|
||||
"xpack.ml.dataframe.analytics.create.errorCreatingDataFrameAnalyticsJob": "创建数据帧分析作业时发生错误:",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingDataFrameAnalyticsList": "获取现有数据帧分析作业 ID 时发生错误:",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingDataFrameIndexNames": "获取现有索引名称时发生错误:",
|
||||
"xpack.ml.dataframe.analytics.create.errorGettingIndexPatternTitles": "获取现有索引模式标题时发生错误:",
|
||||
"xpack.ml.dataframe.analytics.create.errorStartingDataFrameAnalyticsJob": "启动数据帧分析作业时发生错误:",
|
||||
"xpack.ml.dataframe.analytics.create.indexPatternAlreadyExistsError": "具有此名称的索引模式已存在。",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue