Skip to content

Commit a8c7e46

Browse files
committed
[UA] Special handling of ES transforms (elastic#211418)
Close elastic/kibana-team#1293 Related elastic/elasticsearch#122192 <img width="503" alt="Screenshot 2025-02-17 at 14 38 53" src="https://github.com/user-attachments/assets/06131482-8547-4296-bd7e-e1c7c879fb89" /> (cherry picked from commit c6e0eeb)
1 parent b1ff675 commit a8c7e46

File tree

8 files changed

+260
-18
lines changed

8 files changed

+260
-18
lines changed

x-pack/platform/plugins/private/upgrade_assistant/common/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ export interface ReindexAction {
203203
* In future this could be an array of blockers.
204204
*/
205205
blockerForReindexing?: 'index-closed'; // 'index-closed' can be handled automatically, but requires more resources, user should be warned
206+
207+
/**
208+
* The transform IDs that are currently targeting this index
209+
*/
210+
transformIds?: string[];
206211
}
207212

208213
export interface UnfreezeAction {

x-pack/platform/plugins/private/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/indices/flyout/container.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export const IndexFlyout: React.FunctionComponent<IndexFlyoutProps> = ({
154154
startReadonly={() => {
155155
setFlyoutStep('confirmReadonly');
156156
}}
157+
deprecation={deprecation}
157158
updateIndexState={updateIndexState}
158159
reindexState={reindexState}
159160
/>
@@ -214,6 +215,7 @@ export const IndexFlyout: React.FunctionComponent<IndexFlyoutProps> = ({
214215
}, [
215216
flyoutStep,
216217
correctiveAction?.type,
218+
deprecation,
217219
closeFlyout,
218220
updateIndexState,
219221
reindexState,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import { i18n } from '@kbn/i18n';
9+
import { EuiCallOut, EuiLink, EuiText, EuiSpacer } from '@elastic/eui';
10+
import React from 'react';
11+
import { FormattedMessage } from '@kbn/i18n-react';
12+
import type { EnrichedDeprecationInfo } from '../../../../../../../../../common/types';
13+
import { useAppContext } from '../../../../../../../app_context';
14+
15+
interface Props {
16+
deprecation: EnrichedDeprecationInfo;
17+
}
18+
19+
/**
20+
* We get copy directly from ES. This contains information that applies to indices
21+
* that are read-only or not.
22+
*/
23+
export const ESTransformsTargetGuidance = ({ deprecation }: Props) => {
24+
const {
25+
services: {
26+
core: { http },
27+
},
28+
} = useAppContext();
29+
return (
30+
<>
31+
<EuiCallOut
32+
title={i18n.translate(
33+
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.esTransform.calloutTitle',
34+
{ defaultMessage: 'Transforms detected' }
35+
)}
36+
data-test-subj="esTransformsGuidance"
37+
color="warning"
38+
>
39+
{deprecation.details}
40+
</EuiCallOut>
41+
<EuiSpacer size="s" />
42+
<EuiText size="m">
43+
<p>
44+
<FormattedMessage
45+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.esTransform.description1"
46+
defaultMessage="The reindex operation will copy all of the existing documents into a new index and remove the old one. During the reindex operation your data will be in a read-only state and transforms writing to this index will be paused."
47+
/>
48+
</p>
49+
<p>
50+
<FormattedMessage
51+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.esTransform.description2"
52+
defaultMessage="Depending on size and resources, reindexing may take an extended time. For indices with more than 10GB of data or to avoid transform downtime refer to the {migrationGuideLink} or {transformsLink} to manage transforms writing to this index."
53+
values={{
54+
migrationGuideLink: (
55+
<EuiLink target="_blank" href={deprecation.url}>
56+
{i18n.translate(
57+
'xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.esTransform.migrationGuideLink',
58+
{ defaultMessage: 'migration guide' }
59+
)}
60+
</EuiLink>
61+
),
62+
transformsLink: (
63+
<EuiLink
64+
target="_blank"
65+
href={`${http.basePath.prepend('/app/management/data/transform')}`}
66+
>
67+
<FormattedMessage
68+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.esTransform.transfromsLink"
69+
defaultMessage="go to transforms"
70+
/>
71+
</EuiLink>
72+
),
73+
}}
74+
/>
75+
</p>
76+
</EuiText>
77+
</>
78+
);
79+
};

x-pack/platform/plugins/private/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/indices/flyout/steps/details/reindex_details_step.test.tsx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { ReindexState } from '../../../use_reindex';
1212
import type { UpdateIndexState } from '../../../use_update_index';
1313
import { LoadingState } from '../../../../../../types';
1414
import { cloneDeep } from 'lodash';
15+
import { EnrichedDeprecationInfo } from '../../../../../../../../../common/types';
1516

1617
jest.mock('../../../../../../../app_context', () => {
1718
const { docLinksServiceMock } = jest.requireActual('@kbn/core-doc-links-browser-mocks');
@@ -38,6 +39,13 @@ jest.mock('../../../../../../../app_context', () => {
3839
});
3940

4041
describe('ReindexDetailsFlyoutStep', () => {
42+
const deprecation: EnrichedDeprecationInfo = {
43+
isCritical: true,
44+
message: 'foo',
45+
resolveDuringUpgrade: false,
46+
type: 'index_settings',
47+
url: 'https://te.st',
48+
};
4149
const defaultReindexState: ReindexState = {
4250
loadingState: LoadingState.Success,
4351
meta: {
@@ -65,6 +73,7 @@ describe('ReindexDetailsFlyoutStep', () => {
6573
startReadonly={jest.fn()}
6674
reindexState={defaultReindexState}
6775
updateIndexState={defaultUpdateIndexState}
76+
deprecation={deprecation}
6877
/>
6978
);
7079

@@ -206,6 +215,94 @@ describe('ReindexDetailsFlyoutStep', () => {
206215
`);
207216
});
208217

218+
it('renders correct guidance for indices with transforms', () => {
219+
const wrapper = shallow(
220+
<ReindexDetailsFlyoutStep
221+
closeFlyout={jest.fn()}
222+
startReindex={jest.fn()}
223+
startReadonly={jest.fn()}
224+
reindexState={defaultReindexState}
225+
updateIndexState={defaultUpdateIndexState}
226+
deprecation={{
227+
...deprecation,
228+
correctiveAction: { type: 'reindex', transformIds: ['abc', 'def'] },
229+
}}
230+
/>
231+
);
232+
expect(wrapper).toMatchInlineSnapshot(`
233+
<Fragment>
234+
<EuiFlyoutBody>
235+
<EuiText>
236+
<ESTransformsTargetGuidance
237+
deprecation={
238+
Object {
239+
"correctiveAction": Object {
240+
"transformIds": Array [
241+
"abc",
242+
"def",
243+
],
244+
"type": "reindex",
245+
},
246+
"isCritical": true,
247+
"message": "foo",
248+
"resolveDuringUpgrade": false,
249+
"type": "index_settings",
250+
"url": "https://te.st",
251+
}
252+
}
253+
/>
254+
</EuiText>
255+
<EuiSpacer />
256+
</EuiFlyoutBody>
257+
<EuiFlyoutFooter>
258+
<EuiFlexGroup
259+
justifyContent="spaceBetween"
260+
>
261+
<EuiFlexItem
262+
grow={false}
263+
>
264+
<EuiButtonEmpty
265+
flush="left"
266+
iconType="cross"
267+
onClick={[MockFunction]}
268+
>
269+
<MemoizedFormattedMessage
270+
defaultMessage="Close"
271+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.closeButtonLabel"
272+
/>
273+
</EuiButtonEmpty>
274+
</EuiFlexItem>
275+
<EuiFlexItem
276+
grow={false}
277+
>
278+
<EuiFlexGroup
279+
gutterSize="s"
280+
>
281+
<EuiFlexItem
282+
grow={false}
283+
>
284+
<EuiButton
285+
color="primary"
286+
data-test-subj="startReindexingButton"
287+
disabled={false}
288+
fill={true}
289+
isLoading={false}
290+
onClick={[MockFunction]}
291+
>
292+
<MemoizedFormattedMessage
293+
defaultMessage="Start reindexing"
294+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.reindexButton.runReindexLabel"
295+
/>
296+
</EuiButton>
297+
</EuiFlexItem>
298+
</EuiFlexGroup>
299+
</EuiFlexItem>
300+
</EuiFlexGroup>
301+
</EuiFlyoutFooter>
302+
</Fragment>
303+
`);
304+
});
305+
209306
it('renders for readonly indices (warning deprecation)', () => {
210307
const props = cloneDeep(defaultReindexState);
211308
props.meta.isReadonly = true;
@@ -217,6 +314,7 @@ describe('ReindexDetailsFlyoutStep', () => {
217314
startReadonly={jest.fn()}
218315
reindexState={props}
219316
updateIndexState={defaultUpdateIndexState}
317+
deprecation={deprecation}
220318
/>
221319
);
222320

x-pack/platform/plugins/private/upgrade_assistant/public/application/components/es_deprecations/deprecation_types/indices/flyout/steps/details/reindex_details_step.tsx

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import {
2323
import { FormattedMessage } from '@kbn/i18n-react';
2424
import { i18n } from '@kbn/i18n';
2525

26-
import { ReindexStatus } from '../../../../../../../../../common/types';
26+
import {
27+
EnrichedDeprecationInfo,
28+
ReindexAction,
29+
ReindexStatus,
30+
} from '../../../../../../../../../common/types';
2731
import { LoadingState } from '../../../../../../types';
2832
import type { ReindexState } from '../../../use_reindex';
2933
import { useAppContext } from '../../../../../../../app_context';
@@ -32,17 +36,26 @@ import { FrozenCallOut } from '../frozen_callout';
3236
import type { UpdateIndexState } from '../../../use_update_index';
3337
import { FetchFailedCallOut } from '../fetch_failed_callout';
3438
import { ReindexingFailedCallOut } from '../reindexing_failed_callout';
39+
import { ESTransformsTargetGuidance } from './es_transform_target_guidance';
3540

3641
/**
3742
* Displays a flyout that shows the details / corrective action for a "reindex" deprecation for a given index.
3843
*/
3944
export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
4045
reindexState: ReindexState;
4146
updateIndexState: UpdateIndexState;
47+
deprecation: EnrichedDeprecationInfo;
4248
startReindex: () => void;
4349
startReadonly: () => void;
4450
closeFlyout: () => void;
45-
}> = ({ reindexState, updateIndexState, startReindex, startReadonly, closeFlyout }) => {
51+
}> = ({
52+
reindexState,
53+
updateIndexState,
54+
deprecation,
55+
startReindex,
56+
startReadonly,
57+
closeFlyout,
58+
}) => {
4659
const {
4760
services: {
4861
api,
@@ -57,6 +70,8 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
5770
const isCompleted = reindexStatus === ReindexStatus.completed || updateIndexStatus === 'complete';
5871
const hasFetchFailed = reindexStatus === ReindexStatus.fetchFailed;
5972
const hasReindexingFailed = reindexStatus === ReindexStatus.failed;
73+
const correctiveAction = deprecation.correctiveAction as ReindexAction | undefined;
74+
const isESTransformTarget = !!correctiveAction?.transformIds?.length;
6075

6176
const { data: nodes } = api.useLoadNodeDiskSpace();
6277

@@ -145,7 +160,8 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
145160
</p>
146161
</Fragment>
147162
)}
148-
{!meta.isReadonly && (
163+
{isESTransformTarget && <ESTransformsTargetGuidance deprecation={deprecation} />}
164+
{!meta.isReadonly && !isESTransformTarget && (
149165
<Fragment>
150166
<p>
151167
<FormattedMessage
@@ -252,20 +268,24 @@ export const ReindexDetailsFlyoutStep: React.FunctionComponent<{
252268
</EuiFlexItem>
253269
<EuiFlexItem grow={false}>
254270
<EuiFlexGroup gutterSize="s">
255-
{!meta.isReadonly && !hasFetchFailed && !isCompleted && hasRequiredPrivileges && (
256-
<EuiFlexItem grow={false}>
257-
<EuiButton
258-
onClick={startReadonly}
259-
disabled={loading}
260-
data-test-subj="startIndexReadonlyButton"
261-
>
262-
<FormattedMessage
263-
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
264-
defaultMessage="Mark as read-only"
265-
/>
266-
</EuiButton>
267-
</EuiFlexItem>
268-
)}
271+
{!meta.isReadonly &&
272+
!hasFetchFailed &&
273+
!isCompleted &&
274+
hasRequiredPrivileges &&
275+
!isESTransformTarget && (
276+
<EuiFlexItem grow={false}>
277+
<EuiButton
278+
onClick={startReadonly}
279+
disabled={loading}
280+
data-test-subj="startIndexReadonlyButton"
281+
>
282+
<FormattedMessage
283+
id="xpack.upgradeAssistant.esDeprecations.indices.indexFlyout.detailsStep.startIndexReadonlyButton"
284+
defaultMessage="Mark as read-only"
285+
/>
286+
</EuiButton>
287+
</EuiFlexItem>
288+
)}
269289
{!hasFetchFailed && !isCompleted && hasRequiredPrivileges && (
270290
<EuiFlexItem grow={false}>
271291
<EuiButton

x-pack/platform/plugins/private/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,19 @@
164164
"resolve_during_rolling_upgrade": false
165165
}
166166
],
167+
"transforms_index": [
168+
{
169+
"level": "critical",
170+
"message": "Old index with a compatibility version < 8.0",
171+
"url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html",
172+
"details": "This index has version: 7.17.25",
173+
"resolve_during_rolling_upgrade": false,
174+
"_meta": {
175+
"reindex_required": true,
176+
"transform_ids": ["abc"]
177+
}
178+
}
179+
],
167180
"myindex": [
168181
{
169182
"level": "critical",

x-pack/platform/plugins/private/upgrade_assistant/server/lib/es_deprecations_status/__snapshots__/index.test.ts.snap

Lines changed: 17 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)