Skip to content

Commit

Permalink
[8.18] [UA] ML anomaly job indices special handling (#211407) (#211715)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `8.x` to `8.18`:
- [[UA] ML anomaly job indices special handling
(#211407)](#211407)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Jean-Louis
Leysens","email":"jeanlouis.leysens@elastic.co"},"sourceCommit":{"committedDate":"2025-02-18T11:40:27Z","message":"[UA]
ML anomaly job indices special handling (#211407)\n\nClose
https://github.com/elastic/kibana-team/issues/1501\r\n\r\n\r\n<img
width=\"535\" alt=\"Screenshot 2025-02-17 at 11 43
19\"\r\nsrc=\"https://github.com/user-attachments/assets/648cc007-aef8-4959-add8-6aec943e9e41\"\r\n/>","sha":"5d3fb74647d24decd1adca486004244809b79957","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","Feature:Upgrade
Assistant","backport:version","v8.18.0","v8.19.0"],"title":"[UA] ML
anomaly job indices special
handling","number":211407,"url":"https://github.com/elastic/kibana/pull/211407","mergeCommit":{"message":"[UA]
ML anomaly job indices special handling (#211407)\n\nClose
https://github.com/elastic/kibana-team/issues/1501\r\n\r\n\r\n<img
width=\"535\" alt=\"Screenshot 2025-02-17 at 11 43
19\"\r\nsrc=\"https://github.com/user-attachments/assets/648cc007-aef8-4959-add8-6aec943e9e41\"\r\n/>","sha":"5d3fb74647d24decd1adca486004244809b79957"}},"sourceBranch":"8.x","suggestedTargetBranches":["8.18"],"targetPullRequestStates":[{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
  • Loading branch information
jloleysens authored Feb 19, 2025
1 parent f8fc8e7 commit d5437f2
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,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
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
),
},
]}
/>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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',
Expand All @@ -58,22 +57,22 @@ 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(
<ReindexDetailsFlyoutStep
closeFlyout={jest.fn()}
startReindex={jest.fn()}
startReadonly={jest.fn()}
reindexState={defaultReindexState}
updateIndexState={defaultUpdateIndexState}
deprecation={deprecation}
reindexState={defaultReindexState()}
updateIndexState={defaultUpdateIndexState()}
deprecation={defaultDeprecation()}
/>
);

Expand Down Expand Up @@ -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'] },
}}
/>
Expand Down Expand Up @@ -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(
Expand All @@ -313,8 +312,8 @@ describe('ReindexDetailsFlyoutStep', () => {
startReindex={jest.fn()}
startReadonly={jest.fn()}
reindexState={props}
updateIndexState={defaultUpdateIndexState}
deprecation={deprecation}
updateIndexState={defaultUpdateIndexState()}
deprecation={defaultDeprecation()}
/>
);

Expand Down Expand Up @@ -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>
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand All @@ -160,8 +181,7 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
</p>
</Fragment>
)}
{isESTransformTarget && <ESTransformsTargetGuidance deprecation={deprecation} />}
{!meta.isReadonly && !isESTransformTarget && (
{showDefaultGuidance && (
<Fragment>
<p>
<FormattedMessage
Expand Down

0 comments on commit d5437f2

Please sign in to comment.