mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[UA] ML anomaly job indices special handling (#211407)
Close https://github.com/elastic/kibana-team/issues/1501 <img width="535" alt="Screenshot 2025-02-17 at 11 43 19" src="https://github.com/user-attachments/assets/648cc007-aef8-4959-add8-6aec943e9e41" />
This commit is contained in:
parent
9c7c4da7c9
commit
5d3fb74647
4 changed files with 224 additions and 19 deletions
|
@ -596,6 +596,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
|
|||
nlpElser: `${MACHINE_LEARNING_DOCS}ml-nlp-elser.html`,
|
||||
nlpE5: `${MACHINE_LEARNING_DOCS}ml-nlp-e5.html`,
|
||||
nlpImportModel: `${MACHINE_LEARNING_DOCS}ml-nlp-import-model.html`,
|
||||
anomalyMigrationGuide: `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/master/migrating-9.0.html#breaking_90_anomaly_detection_results`,
|
||||
},
|
||||
transforms: {
|
||||
guide: isServerless
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FunctionComponent } from 'react';
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EuiCallOut, EuiDescriptionList, EuiLink, EuiText } from '@elastic/eui';
|
||||
import { useAppContext } from '../../../../../../../app_context';
|
||||
|
||||
export const MlAnomalyGuidance: FunctionComponent = () => {
|
||||
const {
|
||||
services: {
|
||||
core: { docLinks },
|
||||
},
|
||||
} = useAppContext();
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<EuiCallOut
|
||||
title={i18n.translate(
|
||||
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleMlAnomalyIndexTitle',
|
||||
{ defaultMessage: 'ML anomaly index detected' }
|
||||
)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleMlAnomalyIndexText"
|
||||
defaultMessage="Anomaly result indices that were created in 7.x must be either reindexed, marked as read-only, or deleted before upgrading to 9.x. {learnMore}."
|
||||
values={{
|
||||
learnMore: (
|
||||
<EuiLink target="_blank" href={docLinks.links.ml.anomalyMigrationGuide}>
|
||||
{i18n.translate(
|
||||
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.notCompatibleMlAnomalyIndexText.learnMore',
|
||||
{ defaultMessage: 'Learn more' }
|
||||
)}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
</p>
|
||||
<EuiDescriptionList
|
||||
rowGutterSize="m"
|
||||
listItems={[
|
||||
{
|
||||
title: 'Option 1: Reindex data',
|
||||
description: (
|
||||
<EuiText size="m">
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexMlAnomalyIndexText"
|
||||
defaultMessage="While anomaly detection results are being reindexed, jobs continue to run and process new data. However, you cannot completely delete an anomaly detection job that stores results in this index until the reindexing is complete."
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Option 2: Mark as read-only',
|
||||
description: (
|
||||
<EuiText size="m">
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.readOnlyMlAnomalyIndexText"
|
||||
defaultMessage="This skips reindexing and will mark the result index as read-only. It is useful for large indices that contain the results of only one or a few anomaly detection jobs. If you delete these jobs later, you will not be able to create a new job with the same name. {learnMore} about write blocks."
|
||||
values={{
|
||||
learnMore: (
|
||||
<EuiLink target="_blank" href={docLinks.links.upgradeAssistant.indexBlocks}>
|
||||
{i18n.translate(
|
||||
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.learnMoreLinkLabel',
|
||||
{
|
||||
defaultMessage: 'Learn more',
|
||||
}
|
||||
)}
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Option 3: Delete this index',
|
||||
description: (
|
||||
<EuiText size="m">
|
||||
<FormattedMessage
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.deleteMlAnomalyIndexText"
|
||||
defaultMessage="Use the ML UI to delete jobs that are no longer needed. The result index is deleted when all jobs that store results in it have been deleted."
|
||||
/>
|
||||
</EuiText>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -11,7 +11,6 @@ import { ReindexDetailsFlyoutStep } from './reindex_details_step';
|
|||
import type { ReindexState } from '../../../use_reindex';
|
||||
import type { UpdateIndexState } from '../../../use_update_index';
|
||||
import { LoadingState } from '../../../../../../types';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { EnrichedDeprecationInfo } from '../../../../../../../../../common/types';
|
||||
|
||||
jest.mock('../../../../../../../app_context', () => {
|
||||
|
@ -39,14 +38,14 @@ jest.mock('../../../../../../../app_context', () => {
|
|||
});
|
||||
|
||||
describe('ReindexDetailsFlyoutStep', () => {
|
||||
const deprecation: EnrichedDeprecationInfo = {
|
||||
const defaultDeprecation: () => EnrichedDeprecationInfo = () => ({
|
||||
isCritical: true,
|
||||
message: 'foo',
|
||||
resolveDuringUpgrade: false,
|
||||
type: 'index_settings',
|
||||
url: 'https://te.st',
|
||||
};
|
||||
const defaultReindexState: ReindexState = {
|
||||
});
|
||||
const defaultReindexState: () => ReindexState = () => ({
|
||||
loadingState: LoadingState.Success,
|
||||
meta: {
|
||||
indexName: 'some_index',
|
||||
|
@ -58,12 +57,12 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
hasRequiredPrivileges: true,
|
||||
reindexTaskPercComplete: null,
|
||||
errorMessage: null,
|
||||
};
|
||||
});
|
||||
|
||||
const defaultUpdateIndexState: UpdateIndexState = {
|
||||
const defaultUpdateIndexState: () => UpdateIndexState = () => ({
|
||||
status: 'incomplete',
|
||||
failedBefore: false,
|
||||
};
|
||||
});
|
||||
|
||||
it('renders for non-readonly indices', () => {
|
||||
const wrapper = shallow(
|
||||
|
@ -71,9 +70,9 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
closeFlyout={jest.fn()}
|
||||
startReindex={jest.fn()}
|
||||
startReadonly={jest.fn()}
|
||||
reindexState={defaultReindexState}
|
||||
updateIndexState={defaultUpdateIndexState}
|
||||
deprecation={deprecation}
|
||||
reindexState={defaultReindexState()}
|
||||
updateIndexState={defaultUpdateIndexState()}
|
||||
deprecation={defaultDeprecation()}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -221,10 +220,10 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
closeFlyout={jest.fn()}
|
||||
startReindex={jest.fn()}
|
||||
startReadonly={jest.fn()}
|
||||
reindexState={defaultReindexState}
|
||||
updateIndexState={defaultUpdateIndexState}
|
||||
reindexState={defaultReindexState()}
|
||||
updateIndexState={defaultUpdateIndexState()}
|
||||
deprecation={{
|
||||
...deprecation,
|
||||
...defaultDeprecation(),
|
||||
correctiveAction: { type: 'reindex', transformIds: ['abc', 'def'] },
|
||||
}}
|
||||
/>
|
||||
|
@ -304,7 +303,7 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
});
|
||||
|
||||
it('renders for readonly indices (warning deprecation)', () => {
|
||||
const props = cloneDeep(defaultReindexState);
|
||||
const props = defaultReindexState();
|
||||
props.meta.isReadonly = true;
|
||||
|
||||
const wrapper = shallow(
|
||||
|
@ -313,8 +312,8 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
startReindex={jest.fn()}
|
||||
startReadonly={jest.fn()}
|
||||
reindexState={props}
|
||||
updateIndexState={defaultUpdateIndexState}
|
||||
deprecation={deprecation}
|
||||
updateIndexState={defaultUpdateIndexState()}
|
||||
deprecation={defaultDeprecation()}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -385,4 +384,91 @@ describe('ReindexDetailsFlyoutStep', () => {
|
|||
</Fragment>
|
||||
`);
|
||||
});
|
||||
|
||||
it('renders ML anomaly index guidance', () => {
|
||||
const reindexState = defaultReindexState();
|
||||
reindexState.meta.indexName = '.ml-anomalies-1';
|
||||
const deprecation = defaultDeprecation();
|
||||
deprecation.index = '.ml-anomalies-1';
|
||||
const wrapper = shallow(
|
||||
<ReindexDetailsFlyoutStep
|
||||
closeFlyout={jest.fn()}
|
||||
startReindex={jest.fn()}
|
||||
startReadonly={jest.fn()}
|
||||
reindexState={reindexState}
|
||||
updateIndexState={defaultUpdateIndexState()}
|
||||
deprecation={deprecation}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchInlineSnapshot(`
|
||||
<Fragment>
|
||||
<EuiFlyoutBody>
|
||||
<EuiText>
|
||||
<MlAnomalyGuidance />
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
</EuiFlyoutBody>
|
||||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup
|
||||
justifyContent="spaceBetween"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButtonEmpty
|
||||
flush="left"
|
||||
iconType="cross"
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Close"
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiFlexGroup
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButton
|
||||
data-test-subj="startIndexReadonlyButton"
|
||||
disabled={false}
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Mark as read-only"
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<EuiButton
|
||||
color="primary"
|
||||
data-test-subj="startReindexingButton"
|
||||
disabled={false}
|
||||
fill={true}
|
||||
isLoading={false}
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
<MemoizedFormattedMessage
|
||||
defaultMessage="Start reindexing"
|
||||
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.runReindexLabel"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
</Fragment>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -36,8 +36,11 @@ import { FrozenCallOut } from '../frozen_callout';
|
|||
import type { UpdateIndexState } from '../../../use_update_index';
|
||||
import { FetchFailedCallOut } from '../fetch_failed_callout';
|
||||
import { ReindexingFailedCallOut } from '../reindexing_failed_callout';
|
||||
import { MlAnomalyGuidance } from './ml_anomaly_guidance';
|
||||
import { ESTransformsTargetGuidance } from './es_transform_target_guidance';
|
||||
|
||||
const ML_ANOMALIES_PREFIX = '.ml-anomalies-';
|
||||
|
||||
/**
|
||||
* Displays a flyout that shows the details / corrective action for a "reindex" deprecation for a given index.
|
||||
*/
|
||||
|
@ -72,9 +75,25 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
|
|||
const hasReindexingFailed = reindexStatus === ReindexStatus.failed;
|
||||
const correctiveAction = deprecation.correctiveAction as ReindexAction | undefined;
|
||||
const isESTransformTarget = !!correctiveAction?.transformIds?.length;
|
||||
const isMLAnomalyIndex = Boolean(indexName?.startsWith(ML_ANOMALIES_PREFIX));
|
||||
|
||||
const { data: nodes } = api.useLoadNodeDiskSpace();
|
||||
|
||||
let showEsTransformsGuidance = false;
|
||||
let showMlAnomalyReindexingGuidance = false;
|
||||
let showReadOnlyGuidance = false;
|
||||
let showDefaultGuidance = false;
|
||||
|
||||
if (isESTransformTarget) {
|
||||
showEsTransformsGuidance = true;
|
||||
} else if (meta.isReadonly) {
|
||||
showReadOnlyGuidance = true;
|
||||
} else if (isMLAnomalyIndex) {
|
||||
showMlAnomalyReindexingGuidance = true;
|
||||
} else {
|
||||
showDefaultGuidance = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiFlyoutBody>
|
||||
|
@ -144,7 +163,9 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
|
|||
{meta.isFrozen && <FrozenCallOut />}
|
||||
|
||||
<EuiText>
|
||||
{meta.isReadonly && (
|
||||
{showEsTransformsGuidance && <ESTransformsTargetGuidance deprecation={deprecation} />}
|
||||
{showMlAnomalyReindexingGuidance && <MlAnomalyGuidance />}
|
||||
{showReadOnlyGuidance && (
|
||||
<Fragment>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
|
@ -160,8 +181,7 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
|
|||
</p>
|
||||
</Fragment>
|
||||
)}
|
||||
{isESTransformTarget && <ESTransformsTargetGuidance deprecation={deprecation} />}
|
||||
{!meta.isReadonly && !isESTransformTarget && (
|
||||
{showDefaultGuidance && (
|
||||
<Fragment>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue