Skip to content

Commit

Permalink
[ILM] Add forcemerge action to hot phase with a rollover enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
yuliacech committed Sep 10, 2020
1 parent 0f249d7 commit f92d335
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,40 @@ describe('edit policy', () => {
save(rendered);
expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
});
test('should show forcemerge input when rollover enabled', () => {
const rendered = mountWithIntl(component);
setPolicyName(rendered, 'mypolicy');
expect(findTestSubject(rendered, 'hot-forceMergeSwitch').exists()).toBeTruthy();
});
test('should hide forcemerge input when rollover is disabled', () => {
const rendered = mountWithIntl(component);
setPolicyName(rendered, 'mypolicy');
noRollover(rendered);
rendered.update();
expect(findTestSubject(rendered, 'hot-forceMergeSwitch').exists()).toBeFalsy();
});
test('should show positive number required above zero error when trying to save hot phase with 0 for force merge', async () => {
const rendered = mountWithIntl(component);
setPolicyName(rendered, 'mypolicy');
findTestSubject(rendered, 'hot-forceMergeSwitch').simulate('click');
rendered.update();
const forcemergeInput = rendered.find('input#hot-selectedForceMergeSegments');
forcemergeInput.simulate('change', { target: { value: '0' } });
rendered.update();
save(rendered);
expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
});
test('should show positive number above 0 required error when trying to save hot phase with -1 for force merge', async () => {
const rendered = mountWithIntl(component);
setPolicyName(rendered, 'mypolicy');
findTestSubject(rendered, 'hot-forceMergeSwitch').simulate('click');
rendered.update();
const forcemergeInput = rendered.find('input#hot-selectedForceMergeSegments');
forcemergeInput.simulate('change', { target: { value: '-1' } });
rendered.update();
save(rendered);
expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
});
test('should show positive number required error when trying to save with -1 for index priority', () => {
const rendered = mountWithIntl(component);
noRollover(rendered);
Expand Down Expand Up @@ -364,10 +398,10 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
setPhaseAfter(rendered, 'warm', '1');
findTestSubject(rendered, 'forceMergeSwitch').simulate('click');
findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
rendered.update();
const shrinkInput = rendered.find('input#warm-selectedForceMergeSegments');
shrinkInput.simulate('change', { target: { value: '0' } });
const forcemergeInput = rendered.find('input#warm-selectedForceMergeSegments');
forcemergeInput.simulate('change', { target: { value: '0' } });
rendered.update();
save(rendered);
expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
Expand All @@ -378,10 +412,10 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
setPhaseAfter(rendered, 'warm', '1');
findTestSubject(rendered, 'forceMergeSwitch').simulate('click');
findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
rendered.update();
const shrinkInput = rendered.find('input#warm-selectedForceMergeSegments');
shrinkInput.simulate('change', { target: { value: '-1' } });
const forcemergeInput = rendered.find('input#warm-selectedForceMergeSegments');
forcemergeInput.simulate('change', { target: { value: '-1' } });
rendered.update();
save(rendered);
expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
Expand Down
18 changes: 14 additions & 4 deletions x-pack/plugins/index_lifecycle_management/common/types/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export interface SerializedHotPhase extends SerializedPhase {
max_age?: string;
max_docs?: number;
};
forcemerge?: {
max_num_segments: number;
};
set_priority?: {
priority: number | null;
};
Expand Down Expand Up @@ -131,7 +134,15 @@ export interface PhaseWithIndexPriority {
phaseIndexPriority: string;
}

export interface HotPhase extends CommonPhaseSettings, PhaseWithIndexPriority {
export interface PhaseWithForcemergeAction {
forceMergeEnabled: boolean;
selectedForceMergeSegments: string;
}

export interface HotPhase
extends CommonPhaseSettings,
PhaseWithIndexPriority,
PhaseWithForcemergeAction {
rolloverEnabled: boolean;
selectedMaxSizeStored: string;
selectedMaxSizeStoredUnits: string;
Expand All @@ -144,12 +155,11 @@ export interface WarmPhase
extends CommonPhaseSettings,
PhaseWithMinAge,
PhaseWithAllocationAction,
PhaseWithIndexPriority {
PhaseWithIndexPriority,
PhaseWithForcemergeAction {
warmPhaseOnRollover: boolean;
shrinkEnabled: boolean;
selectedPrimaryShardCount: string;
forceMergeEnabled: boolean;
selectedForceMergeSegments: string;
}

export interface ColdPhase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const defaultNewHotPhase: HotPhase = {
selectedMaxAgeUnits: 'd',
selectedMaxSizeStored: '50',
selectedMaxSizeStoredUnits: 'gb',
forceMergeEnabled: false,
selectedForceMergeSegments: '',
phaseIndexPriority: '100',
selectedMaxDocuments: '',
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { FormattedMessage } from '@kbn/i18n/react';
import {
EuiDescribedFormGroup,
EuiFieldNumber,
EuiSpacer,
EuiSwitch,
EuiTextColor,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { LearnMoreLink } from './learn_more_link';
import { ErrableFormRow } from './form_errors';
import { Phases, PhaseWithForcemergeAction } from '../../../../../common/types';
import { PhaseValidationErrors, propertyof } from '../../../services/policies/policy_validation';

const forcemergeLabel = i18n.translate('xpack.indexLifecycleMgmt.warmPhase.forceMergeDataLabel', {
defaultMessage: 'Force merge data',
});

interface Props<T extends PhaseWithForcemergeAction> {
errors?: PhaseValidationErrors<T>;
phase: keyof Phases & string;
phaseData: T;
setPhaseData: (dataKey: keyof T & string, value: boolean | string) => void;
isShowingErrors: boolean;
}
export const Forcemerge = <T extends PhaseWithForcemergeAction>({
errors,
phaseData,
phase,
setPhaseData,
isShowingErrors,
}: React.PropsWithChildren<Props<T>>) => {
const phaseForcemergeEnabledProperty = propertyof<T>('forceMergeEnabled');
const phaseForcemergeSegmentsProperty = propertyof<T>('selectedForceMergeSegments');
return (
<EuiDescribedFormGroup
title={
<h3>
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataText"
defaultMessage="Force merge"
/>
</h3>
}
description={
<EuiTextColor color="subdued">
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataExplanationText"
defaultMessage="Reduce the number of segments in your shard by merging smaller files and clearing deleted ones."
/>{' '}
<LearnMoreLink docPath="indices-forcemerge.html" />
</EuiTextColor>
}
titleSize="xs"
fullWidth
>
<EuiSwitch
data-test-subj={`${phase}-forceMergeSwitch`}
label={forcemergeLabel}
aria-label={forcemergeLabel}
checked={phaseData.forceMergeEnabled}
onChange={(e) => {
setPhaseData(phaseForcemergeEnabledProperty, e.target.checked);
}}
aria-controls="forcemergeContent"
/>

<EuiSpacer />
<div id="forcemergeContent" aria-live="polite" role="region">
{phaseData.forceMergeEnabled ? (
<ErrableFormRow
id={`${phase}-${phaseForcemergeSegmentsProperty}`}
label={i18n.translate('xpack.indexLifecycleMgmt.warmPhase.numberOfSegmentsLabel', {
defaultMessage: 'Number of segments',
})}
isShowingErrors={isShowingErrors}
errors={errors?.selectedForceMergeSegments}
>
<EuiFieldNumber
id={`${phase}-${phaseForcemergeSegmentsProperty}`}
value={phaseData.selectedForceMergeSegments}
onChange={(e) => {
setPhaseData(phaseForcemergeSegmentsProperty, e.target.value);
}}
min={1}
/>
</ErrableFormRow>
) : null}
</div>
</EuiDescribedFormGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { PhaseErrorMessage } from './phase_error_message';
export { PolicyJsonFlyout } from './policy_json_flyout';
export { SetPriorityInput } from './set_priority_input';
export { SnapshotPolicies } from './snapshot_policies';
export { Forcemerge } from './forcemerge';
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
PhaseErrorMessage,
ErrableFormRow,
SetPriorityInput,
Forcemerge,
} from '../components';

const maxSizeStoredUnits = [
Expand Down Expand Up @@ -313,6 +314,15 @@ export class HotPhase extends PureComponent<Props> {
</Fragment>
) : null}
</EuiDescribedFormGroup>
{phaseData.rolloverEnabled ? (
<Forcemerge<HotPhaseInterface>
phase={'hot'}
phaseData={phaseData}
setPhaseData={setPhaseData}
isShowingErrors={isShowingErrors}
errors={errors}
/>
) : null}
<SetPriorityInput<HotPhaseInterface>
errors={errors}
phaseData={phaseData}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
SetPriorityInput,
NodeAllocation,
MinAgeInput,
Forcemerge,
} from '../components';

const shrinkLabel = i18n.translate('xpack.indexLifecycleMgmt.warmPhase.shrinkIndexLabel', {
Expand All @@ -42,10 +43,6 @@ const moveToWarmPhaseOnRolloverLabel = i18n.translate(
}
);

const forcemergeLabel = i18n.translate('xpack.indexLifecycleMgmt.warmPhase.forceMergeDataLabel', {
defaultMessage: 'Force merge data',
});

const warmProperty: keyof Phases = 'warm';
const phaseProperty = (propertyName: keyof WarmPhaseInterface) => propertyName;

Expand Down Expand Up @@ -262,64 +259,13 @@ export class WarmPhase extends PureComponent<Props> {
</div>
</Fragment>
</EuiDescribedFormGroup>
<EuiDescribedFormGroup
title={
<h3>
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataText"
defaultMessage="Force merge"
/>
</h3>
}
description={
<EuiTextColor color="subdued">
<FormattedMessage
id="xpack.indexLifecycleMgmt.editPolicy.warmPhase.forceMergeDataExplanationText"
defaultMessage="Reduce the number of segments in your shard by merging smaller files and clearing deleted ones."
/>{' '}
<LearnMoreLink docPath="indices-forcemerge.html" />
</EuiTextColor>
}
titleSize="xs"
fullWidth
>
<EuiSwitch
data-test-subj="forceMergeSwitch"
label={forcemergeLabel}
aria-label={forcemergeLabel}
checked={phaseData.forceMergeEnabled}
onChange={(e) => {
setPhaseData(phaseProperty('forceMergeEnabled'), e.target.checked);
}}
aria-controls="forcemergeContent"
/>

<EuiSpacer />
<div id="forcemergeContent" aria-live="polite" role="region">
{phaseData.forceMergeEnabled ? (
<ErrableFormRow
id={`${warmProperty}-${phaseProperty('selectedForceMergeSegments')}`}
label={i18n.translate(
'xpack.indexLifecycleMgmt.warmPhase.numberOfSegmentsLabel',
{
defaultMessage: 'Number of segments',
}
)}
isShowingErrors={isShowingErrors}
errors={errors?.selectedForceMergeSegments}
>
<EuiFieldNumber
id={`${warmProperty}-${phaseProperty('selectedForceMergeSegments')}`}
value={phaseData.selectedForceMergeSegments}
onChange={(e) => {
setPhaseData(phaseProperty('selectedForceMergeSegments'), e.target.value);
}}
min={1}
/>
</ErrableFormRow>
) : null}
</div>
</EuiDescribedFormGroup>
<Forcemerge<WarmPhaseInterface>
phase={'warm'}
phaseData={phaseData}
setPhaseData={setPhaseData}
isShowingErrors={isShowingErrors}
errors={errors}
/>
<SetPriorityInput<WarmPhaseInterface>
errors={errors}
phaseData={phaseData}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const hotPhaseInitialization: HotPhase = {
selectedMaxAgeUnits: 'd',
selectedMaxSizeStored: '',
selectedMaxSizeStoredUnits: 'gb',
forceMergeEnabled: false,
selectedForceMergeSegments: '',
phaseIndexPriority: '',
selectedMaxDocuments: '',
};
Expand Down Expand Up @@ -58,6 +60,12 @@ export const hotPhaseFromES = (phaseSerialized?: SerializedHotPhase): HotPhase =
}
}

if (actions.forcemerge) {
const forcemerge = actions.forcemerge;
phase.forceMergeEnabled = true;
phase.selectedForceMergeSegments = forcemerge.max_num_segments.toString();
}

if (actions.set_priority) {
phase.phaseIndexPriority = actions.set_priority.priority
? actions.set_priority.priority.toString()
Expand Down Expand Up @@ -93,8 +101,19 @@ export const hotPhaseToES = (
if (isNumber(phase.selectedMaxDocuments)) {
esPhase.actions.rollover.max_docs = parseInt(phase.selectedMaxDocuments, 10);
}
if (phase.forceMergeEnabled && isNumber(phase.selectedForceMergeSegments)) {
esPhase.actions.forcemerge = {
max_num_segments: parseInt(phase.selectedForceMergeSegments, 10),
};
} else {
delete esPhase.actions.forcemerge;
}
} else {
delete esPhase.actions.rollover;
// forcemerge is only allowed if rollover is enabled
if (esPhase.actions.forcemerge) {
delete esPhase.actions.forcemerge;
}
}

if (isNumber(phase.phaseIndexPriority)) {
Expand Down Expand Up @@ -147,6 +166,15 @@ export const validateHotPhase = (phase: HotPhase): PhaseValidationErrors<HotPhas
if (isNumber(phase.selectedMaxDocuments) && parseInt(phase.selectedMaxDocuments, 10) < 1) {
phaseErrors.selectedMaxDocuments = [positiveNumbersAboveZeroErrorMessage];
}

// if forcemerge is enabled, force merge segments needs to be a number above zero
if (phase.forceMergeEnabled) {
if (!isNumber(phase.selectedForceMergeSegments)) {
phaseErrors.selectedForceMergeSegments = [numberRequiredMessage];
} else if (parseInt(phase.selectedForceMergeSegments, 10) < 1) {
phaseErrors.selectedForceMergeSegments = [positiveNumbersAboveZeroErrorMessage];
}
}
}

return {
Expand Down
Loading

0 comments on commit f92d335

Please sign in to comment.