From d844b127773deec3a974d54c69e99b575b9bd2cc Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Tue, 20 Oct 2020 15:01:49 +0200
Subject: [PATCH 01/19] migrate all fields on warm phase except, data alloc,
replicas and shrink
---
.../phases/shared/forcemerge_field.tsx | 7 +-
.../components/phases/shared/index.ts | 2 +
.../shared/min_age_input_field/index.ts | 7 +
.../min_age_input_field.tsx | 211 ++++++++++++++++++
.../phases/shared/min_age_input_field/util.ts | 58 +++++
.../components/phases/warm_phase/index.ts | 7 +
.../phases/{ => warm_phase}/warm_phase.tsx | 138 +++++-------
.../sections/edit_policy/deserializer.ts | 7 +
.../sections/edit_policy/form_schema.ts | 72 +++++-
.../sections/edit_policy/i18n_texts.ts | 25 +++
.../application/sections/edit_policy/types.ts | 7 +
11 files changed, 450 insertions(+), 91 deletions(-)
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/index.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/min_age_input_field.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/util.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/index.ts
rename x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/{ => warm_phase}/warm_phase.tsx (72%)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
index 987133fd652acf..2a43b99e71452d 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
@@ -20,9 +20,8 @@ interface Props {
phase: keyof Phases & string;
}
-const forceMergeEnabledPath = '_meta.hot.forceMergeEnabled';
-
export const Forcemerge: React.FunctionComponent = ({ phase }) => {
+ const forceMergeEnabledPath = `_meta.${phase}.forceMergeEnabled`;
const [{ [forceMergeEnabledPath]: forceMergeEnabled }] = useFormData({
watch: [forceMergeEnabledPath],
});
@@ -77,8 +76,8 @@ export const Forcemerge: React.FunctionComponent = ({ phase }) => {
}}
/>
= ({ phase }): React.ReactElement => {
+ const [{ [useRolloverPath]: rolloverEnabled }] = useFormData({ watch: useRolloverPath });
+
+ let daysOptionLabel;
+ let hoursOptionLabel;
+ let minutesOptionLabel;
+ let secondsOptionLabel;
+ let millisecondsOptionLabel;
+ let microsecondsOptionLabel;
+ let nanosecondsOptionLabel;
+
+ if (rolloverEnabled) {
+ daysOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverDaysOptionLabel',
+ {
+ defaultMessage: 'days from rollover',
+ }
+ );
+
+ hoursOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverHoursOptionLabel',
+ {
+ defaultMessage: 'hours from rollover',
+ }
+ );
+ minutesOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverMinutesOptionLabel',
+ {
+ defaultMessage: 'minutes from rollover',
+ }
+ );
+
+ secondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverSecondsOptionLabel',
+ {
+ defaultMessage: 'seconds from rollover',
+ }
+ );
+ millisecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverMilliSecondsOptionLabel',
+ {
+ defaultMessage: 'milliseconds from rollover',
+ }
+ );
+
+ microsecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverMicroSecondsOptionLabel',
+ {
+ defaultMessage: 'microseconds from rollover',
+ }
+ );
+
+ nanosecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverNanoSecondsOptionLabel',
+ {
+ defaultMessage: 'nanoseconds from rollover',
+ }
+ );
+ } else {
+ daysOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationDaysOptionLabel',
+ {
+ defaultMessage: 'days from index creation',
+ }
+ );
+
+ hoursOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationHoursOptionLabel',
+ {
+ defaultMessage: 'hours from index creation',
+ }
+ );
+
+ minutesOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationMinutesOptionLabel',
+ {
+ defaultMessage: 'minutes from index creation',
+ }
+ );
+
+ secondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationSecondsOptionLabel',
+ {
+ defaultMessage: 'seconds from index creation',
+ }
+ );
+
+ millisecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationMilliSecondsOptionLabel',
+ {
+ defaultMessage: 'milliseconds from index creation',
+ }
+ );
+
+ microsecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationMicroSecondsOptionLabel',
+ {
+ defaultMessage: 'microseconds from index creation',
+ }
+ );
+
+ nanosecondsOptionLabel = i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.creationNanoSecondsOptionLabel',
+ {
+ defaultMessage: 'nanoseconds from index creation',
+ }
+ );
+ }
+
+ return (
+
+
+
+ }
+ />
+ ),
+ euiFieldProps: {
+ 'data-test-subj': `${phase}-selectedMinimumAge`,
+ min: 0,
+ },
+ }}
+ />
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/util.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/util.ts
new file mode 100644
index 00000000000000..181894badba7bf
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/util.ts
@@ -0,0 +1,58 @@
+/*
+ * 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 { i18n } from '@kbn/i18n';
+import { Phases } from '../../../../../../../../common/types';
+
+type PhaseWithMinAgeAction = 'warm' | 'cold' | 'delete';
+
+export function getUnitsAriaLabelForPhase(phase: keyof Phases) {
+ // NOTE: Hot phase isn't necessary, because indices begin in the hot phase.
+ switch (phase) {
+ case 'warm':
+ return i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.phaseWarm.minimumAgeUnitsAriaLabel',
+ {
+ defaultMessage: 'Units for timing of warm phase',
+ }
+ );
+
+ case 'cold':
+ return i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.phaseCold.minimumAgeUnitsAriaLabel',
+ {
+ defaultMessage: 'Units for timing of cold phase',
+ }
+ );
+
+ case 'delete':
+ return i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.phaseDelete.minimumAgeUnitsAriaLabel',
+ {
+ defaultMessage: 'Units for timing of delete phase',
+ }
+ );
+ }
+}
+export function getTimingLabelForPhase(phase: PhaseWithMinAgeAction) {
+ // NOTE: Hot phase isn't necessary, because indices begin in the hot phase.
+ switch (phase) {
+ case 'warm':
+ return i18n.translate('xpack.indexLifecycleMgmt.editPolicy.phaseWarm.minimumAgeLabel', {
+ defaultMessage: 'Timing for warm phase',
+ });
+
+ case 'cold':
+ return i18n.translate('xpack.indexLifecycleMgmt.editPolicy.phaseCold.minimumAgeLabel', {
+ defaultMessage: 'Timing for cold phase',
+ });
+
+ case 'delete':
+ return i18n.translate('xpack.indexLifecycleMgmt.editPolicy.phaseDelete.minimumAgeLabel', {
+ defaultMessage: 'Timing for delete phase',
+ });
+ }
+}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/index.ts
new file mode 100644
index 00000000000000..d0686270ba559b
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/index.ts
@@ -0,0 +1,7 @@
+/*
+ * 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.
+ */
+
+export { WarmPhase } from './warm_phase';
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
similarity index 72%
rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase.tsx
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
index bd0b380bdc172c..a4f1500c350f1a 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
@@ -12,17 +12,22 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
- EuiFormRow,
EuiFieldNumber,
EuiSwitch,
EuiDescribedFormGroup,
} from '@elastic/eui';
-import { useFormData } from '../../../../../shared_imports';
-import { Phases, WarmPhase as WarmPhaseInterface } from '../../../../../../common/types';
-import { PhaseValidationErrors } from '../../../../services/policies/policy_validation';
+import {
+ useFormData,
+ UseField,
+ ToggleField,
+ useFormContext,
+} from '../../../../../../shared_imports';
+
+import { Phases, WarmPhase as WarmPhaseInterface } from '../../../../../../../common/types';
+import { PhaseValidationErrors } from '../../../../../services/policies/policy_validation';
-import { useRolloverPath } from './shared';
+import { useRolloverPath, MinAgeInputField, Forcemerge, SetPriorityInput } from '../shared';
import {
LearnMoreLink,
@@ -30,24 +35,15 @@ import {
PhaseErrorMessage,
OptionalLabel,
ErrableFormRow,
- SetPriorityInput,
- MinAgeInput,
DescribedFormField,
- Forcemerge,
-} from '../';
+} from '../../index';
-import { DataTierAllocationField } from './shared';
+import { DataTierAllocationField } from '../shared';
const i18nTexts = {
shrinkLabel: i18n.translate('xpack.indexLifecycleMgmt.warmPhase.shrinkIndexLabel', {
defaultMessage: 'Shrink index',
}),
- moveToWarmPhaseOnRolloverLabel: i18n.translate(
- 'xpack.indexLifecycleMgmt.warmPhase.moveToWarmPhaseOnRolloverLabel',
- {
- defaultMessage: 'Move to warm phase on rollover',
- }
- ),
dataTierAllocation: {
description: i18n.translate('xpack.indexLifecycleMgmt.warmPhase.dataTier.description', {
defaultMessage: 'Move data to nodes optimized for less-frequent, read-only access.',
@@ -67,15 +63,18 @@ interface Props {
isShowingErrors: boolean;
errors?: PhaseValidationErrors;
}
-export const WarmPhase: FunctionComponent = ({
- setPhaseData,
- phaseData,
- errors,
- isShowingErrors,
-}) => {
- const [{ [useRolloverPath]: hotPhaseRolloverEnabled }] = useFormData({
- watch: [useRolloverPath],
+export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, errors }) => {
+ const form = useFormContext();
+ const [
+ {
+ [useRolloverPath]: hotPhaseRolloverEnabled,
+ '_meta.warm.enabled': enabled,
+ '_meta.warm.warmPhaseOnRollover': warmPhaseOnRollover,
+ },
+ ] = useFormData({
+ watch: [useRolloverPath, '_meta.warm.enabled', '_meta.warm.warmPhaseOnRollover'],
});
+ const isShowingErrors = form.isValid === false;
return (
<>
@@ -88,7 +87,7 @@ export const WarmPhase: FunctionComponent
= ({
defaultMessage="Warm phase"
/>
{' '}
- {phaseData.phaseEnabled && !isShowingErrors ? : null}
+ {enabled && !isShowingErrors ? : null}
}
@@ -103,60 +102,47 @@ export const WarmPhase: FunctionComponent = ({
For faster searches, you can reduce the number of shards and force merge segments."
/>
-
- }
- id={`${warmProperty}-${phaseProperty('phaseEnabled')}`}
- checked={phaseData.phaseEnabled}
- onChange={(e) => {
- setPhaseData(phaseProperty('phaseEnabled'), e.target.checked);
+
}
fullWidth
>
- {phaseData.phaseEnabled ? (
+ {enabled && (
- {hotPhaseRolloverEnabled ? (
-
- {
- setPhaseData(phaseProperty('warmPhaseOnRollover'), e.target.checked);
- }}
- />
-
- ) : null}
- {!phaseData.warmPhaseOnRollover || !hotPhaseRolloverEnabled ? (
-
+ {hotPhaseRolloverEnabled && (
+
+ )}
+ {(!warmPhaseOnRollover || !hotPhaseRolloverEnabled) && (
+ <>
-
- errors={errors}
- phaseData={phaseData}
- phase={warmProperty}
- isShowingErrors={isShowingErrors}
- setPhaseData={setPhaseData}
- rolloverEnabled={hotPhaseRolloverEnabled}
- />
-
- ) : null}
+
+ >
+ )}
- ) : null}
+ )}
- {phaseData.phaseEnabled ? (
+ {enabled && (
{/* Data tier allocation section */}
= ({
-
-
- errors={errors}
- phaseData={phaseData}
- phase={warmProperty}
- isShowingErrors={isShowingErrors}
- setPhaseData={setPhaseData}
- />
+
+
+
+
- ) : null}
+ )}
>
);
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
index bb24eea64ec8cc..8bedcdd1d9f165 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
@@ -23,6 +23,13 @@ export const deserializer = (policy: SerializedPolicy): FormInternal =>
bestCompression:
policy.phases.hot?.actions?.forcemerge?.index_codec === 'best_compression',
},
+ warm: {
+ enabled: Boolean(policy.phases.warm),
+ warmPhaseOnRollover: Boolean(policy.phases.warm?.min_age === '0ms'),
+ forceMergeEnabled: Boolean(policy.phases.warm?.actions?.forcemerge),
+ bestCompression:
+ policy.phases.warm?.actions?.forcemerge?.index_codec === 'best_compression',
+ },
},
},
(draft) => {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index 806164c8b0da12..6d62e0aed2d735 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -46,6 +46,31 @@ export const schema: FormSchema = {
),
},
},
+ warm: {
+ enabled: {
+ defaultValue: false,
+ label: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.warmPhase.activateWarmPhaseSwitchLabel',
+ { defaultMessage: 'Activate warm phase' }
+ ),
+ },
+ warmPhaseOnRollover: {
+ defaultValue: true,
+ label: i18n.translate('xpack.indexLifecycleMgmt.warmPhase.moveToWarmPhaseOnRolloverLabel', {
+ defaultMessage: 'Move to warm phase on rollover',
+ }),
+ },
+ minAgeUnit: {
+ defaultValue: 'd',
+ },
+ forceMergeEnabled: {
+ label: i18nTexts.editPolicy.forceMergeEnabledFieldLabel,
+ },
+ bestCompression: {
+ label: i18nTexts.editPolicy.bestCompressionFieldLabel,
+ helpText: i18nTexts.editPolicy.bestCompressionFieldHelpText,
+ },
+ },
},
phases: {
hot: {
@@ -94,9 +119,7 @@ export const schema: FormSchema = {
},
forcemerge: {
max_num_segments: {
- label: i18n.translate('xpack.indexLifecycleMgmt.forceMerge.numberOfSegmentsLabel', {
- defaultMessage: 'Number of segments',
- }),
+ label: i18nTexts.editPolicy.maxNumSegmentsFieldLabel,
validations: [
{
validator: emptyField(
@@ -116,9 +139,46 @@ export const schema: FormSchema = {
set_priority: {
priority: {
defaultValue: defaultSetPriority as any,
- label: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.indexPriorityLabel', {
- defaultMessage: 'Index priority (optional)',
- }),
+ label: i18nTexts.editPolicy.setPriorityFieldLabel,
+ validations: [{ validator: ifExistsNumberGreaterThanZero }],
+ serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ },
+ },
+ },
+ },
+ warm: {
+ min_age: {
+ defaultValue: '0',
+ validations: [
+ {
+ validator: ifExistsNumberGreaterThanZero,
+ },
+ ],
+ },
+ actions: {
+ forcemerge: {
+ max_num_segments: {
+ label: i18nTexts.editPolicy.maxNumSegmentsFieldLabel,
+ validations: [
+ {
+ validator: emptyField(
+ i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.forcemerge.numberOfSegmentsRequiredError',
+ { defaultMessage: 'A value for number of segments is required.' }
+ )
+ ),
+ },
+ {
+ validator: ifExistsNumberGreaterThanZero,
+ },
+ ],
+ serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ },
+ },
+ set_priority: {
+ priority: {
+ defaultValue: '50' as any,
+ label: i18nTexts.editPolicy.setPriorityFieldLabel,
validations: [{ validator: ifExistsNumberGreaterThanZero }],
serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
},
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
index 31bb10b402d27c..448df90161c93d 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
@@ -11,5 +11,30 @@ export const i18nTexts = {
forceMergeEnabledFieldLabel: i18n.translate('xpack.indexLifecycleMgmt.forcemerge.enableLabel', {
defaultMessage: 'Force merge data',
}),
+ maxNumSegmentsFieldLabel: i18n.translate(
+ 'xpack.indexLifecycleMgmt.forceMerge.numberOfSegmentsLabel',
+ {
+ defaultMessage: 'Number of segments',
+ }
+ ),
+ setPriorityFieldLabel: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.indexPriorityLabel',
+ {
+ defaultMessage: 'Index priority (optional)',
+ }
+ ),
+ bestCompressionFieldLabel: i18n.translate(
+ 'xpack.indexLifecycleMgmt.forcemerge.bestCompressionLabel',
+ {
+ defaultMessage: 'Compress stored fields',
+ }
+ ),
+ bestCompressionFieldHelpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.forceMerge.bestCompressionText',
+ {
+ defaultMessage:
+ 'Use higher compression for stored fields at the cost of slower performance.',
+ }
+ ),
},
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
index dba56eb8ecbf3e..7c8bc7e8080210 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
@@ -22,5 +22,12 @@ export interface FormInternal extends SerializedPolicy {
maxStorageSizeUnit?: string;
maxAgeUnit?: string;
};
+ warm: {
+ enabled: boolean;
+ forceMergeEnabled: boolean;
+ bestCompression: boolean;
+ warmPhaseOnRollover: boolean;
+ minAgeUnit?: string;
+ };
};
}
From e867ffe8e60adea5a5fe88023b30dac60353210a Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Tue, 20 Oct 2020 16:15:49 +0200
Subject: [PATCH 02/19] introduce edit policy context to share original policy
and migrate shrink and replicas fields
---
.../phases/shared/forcemerge_field.tsx | 97 ++--
.../phases/warm_phase/warm_phase.tsx | 140 +++---
.../components/toggleable_field.tsx | 6 +-
.../sections/edit_policy/edit_policy.tsx | 439 +++++++++---------
.../edit_policy/edit_policy_context.tsx | 32 ++
.../sections/edit_policy/form_schema.ts | 49 +-
.../sections/edit_policy/form_validations.ts | 12 +-
.../sections/edit_policy/i18n_texts.ts | 14 +
8 files changed, 413 insertions(+), 376 deletions(-)
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy_context.tsx
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
index 2a43b99e71452d..b410bd0e6b3b03 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/forcemerge_field.tsx
@@ -4,29 +4,31 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
-import { EuiDescribedFormGroup, EuiSpacer, EuiTextColor } from '@elastic/eui';
-import React from 'react';
+import { EuiSpacer, EuiTextColor } from '@elastic/eui';
-import { Phases } from '../../../../../../../common/types';
-
-import { UseField, ToggleField, NumericField, useFormData } from '../../../../../../shared_imports';
+import { UseField, ToggleField, NumericField } from '../../../../../../shared_imports';
import { i18nTexts } from '../../../i18n_texts';
-import { LearnMoreLink } from '../../';
+import { useEditPolicyContext } from '../../../edit_policy_context';
+
+import { LearnMoreLink, DescribedFormField } from '../../';
interface Props {
- phase: keyof Phases & string;
+ phase: 'hot' | 'warm';
}
export const Forcemerge: React.FunctionComponent = ({ phase }) => {
- const forceMergeEnabledPath = `_meta.${phase}.forceMergeEnabled`;
- const [{ [forceMergeEnabledPath]: forceMergeEnabled }] = useFormData({
- watch: [forceMergeEnabledPath],
- });
+ const { originalPolicy } = useEditPolicyContext();
+
+ const initialToggleValue = useMemo(() => {
+ return Boolean(originalPolicy.phases[phase]?.actions?.forcemerge);
+ }, [originalPolicy, phase]);
+
return (
-
= ({ phase }) => {
}
titleSize="xs"
fullWidth
+ switchProps={{
+ 'aria-label': i18nTexts.editPolicy.forceMergeEnabledFieldLabel,
+ 'data-test-subj': `${phase}-forceMergeSwitch`,
+ 'aria-controls': 'forcemergeContent',
+ label: i18nTexts.editPolicy.forceMergeEnabledFieldLabel,
+ initialValue: initialToggleValue,
+ }}
>
-
- {forceMergeEnabled && (
- <>
-
-
- >
- )}
+
+
-
+
);
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
index a4f1500c350f1a..3f149827365bfe 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
@@ -13,7 +13,6 @@ import {
EuiFlexItem,
EuiSpacer,
EuiFieldNumber,
- EuiSwitch,
EuiDescribedFormGroup,
} from '@elastic/eui';
@@ -22,6 +21,7 @@ import {
UseField,
ToggleField,
useFormContext,
+ NumericField,
} from '../../../../../../shared_imports';
import { Phases, WarmPhase as WarmPhaseInterface } from '../../../../../../../common/types';
@@ -29,14 +29,15 @@ import { PhaseValidationErrors } from '../../../../../services/policies/policy_v
import { useRolloverPath, MinAgeInputField, Forcemerge, SetPriorityInput } from '../shared';
+import { useEditPolicyContext } from '../../../edit_policy_context';
+
import {
LearnMoreLink,
ActiveBadge,
PhaseErrorMessage,
- OptionalLabel,
ErrableFormRow,
DescribedFormField,
-} from '../../index';
+} from '../../';
import { DataTierAllocationField } from '../shared';
@@ -64,6 +65,7 @@ interface Props {
errors?: PhaseValidationErrors;
}
export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, errors }) => {
+ const { originalPolicy } = useEditPolicyContext();
const form = useFormContext();
const [
{
@@ -173,40 +175,25 @@ export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, e
'xpack.indexLifecycleMgmt.editPolicy.warmPhase.numberOfReplicas.switchLabel',
{ defaultMessage: 'Set replicas' }
),
- initialValue: Boolean(phaseData.selectedReplicaCount),
- onChange: (v) => {
- if (!v) {
- setPhaseData('selectedReplicaCount', '');
- }
- },
+ initialValue: Boolean(
+ originalPolicy.phases.warm?.actions?.allocate?.number_of_replicas
+ ),
}}
fullWidth
>
-
-
-
-
- }
- isShowingErrors={isShowingErrors}
- errors={errors?.selectedReplicaCount}
- >
- {
- setPhaseData('selectedReplicaCount', e.target.value);
- }}
- min={0}
- />
-
+
-
= ({ setPhaseData, phaseData, e
}
- fullWidth
titleSize="xs"
+ switchProps={{
+ 'aria-controls': 'shrinkContent',
+ 'data-test-subj': 'shrinkSwitch',
+ label: i18nTexts.shrinkLabel,
+ 'aria-label': i18nTexts.shrinkLabel,
+ initialValue: Boolean(originalPolicy.phases.warm?.actions?.shrink),
+ }}
+ fullWidth
>
-
- {
- setPhaseData(phaseProperty('shrinkEnabled'), e.target.checked);
- }}
- label={i18nTexts.shrinkLabel}
- aria-label={i18nTexts.shrinkLabel}
- aria-controls="shrinkContent"
- />
-
-
- {phaseData.shrinkEnabled ? (
-
-
-
-
-
- {
- setPhaseData(
- phaseProperty('selectedPrimaryShardCount'),
- e.target.value
- );
- }}
- min={1}
- />
-
-
-
-
-
- ) : null}
-
-
-
+
+
+
+
+
+ {
+ setPhaseData(phaseProperty('selectedPrimaryShardCount'), e.target.value);
+ }}
+ min={1}
+ />
+
+
+
+
+
+
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/toggleable_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/toggleable_field.tsx
index ff4301808db339..d188a172d746be 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/toggleable_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/toggleable_field.tsx
@@ -9,7 +9,7 @@ import { EuiSpacer, EuiSwitch, EuiSwitchProps } from '@elastic/eui';
export interface Props extends Omit {
initialValue: boolean;
- onChange: (nextValue: boolean) => void;
+ onChange?: (nextValue: boolean) => void;
}
export const ToggleableField: FunctionComponent = ({
@@ -28,7 +28,9 @@ export const ToggleableField: FunctionComponent = ({
onChange={(e) => {
const nextValue = e.target.checked;
setIsContentVisible(nextValue);
- onChange(nextValue);
+ if (onChange) {
+ onChange(nextValue);
+ }
}}
/>
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
index 8f8b0447f378a4..47b04abd535281 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
@@ -67,6 +67,8 @@ import { schema } from './form_schema';
import { deserializer } from './deserializer';
import { createSerializer } from './serializer';
+import { EditPolicyContextProvider } from './edit_policy_context';
+
export interface Props {
policies: PolicyFromES[];
policyName: string;
@@ -113,9 +115,11 @@ export const EditPolicy: React.FunctionComponent = ({
return createSerializer(existingPolicy?.policy);
}, [existingPolicy?.policy]);
+ const originalPolicy = existingPolicy?.policy ?? defaultPolicy;
+
const { form } = useForm({
schema,
- defaultValue: existingPolicy?.policy ?? defaultPolicy,
+ defaultValue: originalPolicy,
deserializer,
serializer,
});
@@ -220,234 +224,243 @@ export const EditPolicy: React.FunctionComponent = ({
);
return (
-
-
-
-
-
- {isNewPolicy
- ? i18n.translate('xpack.indexLifecycleMgmt.editPolicy.createPolicyMessage', {
- defaultMessage: 'Create an index lifecycle policy',
- })
- : i18n.translate('xpack.indexLifecycleMgmt.editPolicy.editPolicyMessage', {
- defaultMessage: 'Edit index lifecycle policy {originalPolicyName}',
- values: { originalPolicyName },
- })}
-
-
-
-
- }
- titleSize="s"
- fullWidth
- >
-
+ {
+ setPolicy({ ...policy, name: e.target.value });
+ }}
/>
- }
- >
- {
- setPolicy({ ...policy, name: e.target.value });
- }}
- />
-
-
- ) : null}
-
-
-
-
-
-
-
- 0}
- setPhaseData={setWarmPhaseData}
- phaseData={policy.phases.warm}
- />
-
-
-
- 0}
- setPhaseData={setColdPhaseData}
- phaseData={policy.phases.cold}
- />
-
-
-
- 0
- }
- getUrlForApp={getUrlForApp}
- setPhaseData={setDeletePhaseData}
- phaseData={policy.phases.delete}
- />
-
-
-
-
-
-
-
-
- {saveAsNew ? (
-
- ) : (
+
+
+ ) : null}
+
+
+
+
+
+
+
+ 0
+ }
+ setPhaseData={setWarmPhaseData}
+ phaseData={policy.phases.warm}
+ />
+
+
+
+ 0
+ }
+ setPhaseData={setColdPhaseData}
+ phaseData={policy.phases.cold}
+ />
+
+
+
+ 0
+ }
+ getUrlForApp={getUrlForApp}
+ setPhaseData={setDeletePhaseData}
+ phaseData={policy.phases.delete}
+ />
+
+
+
+
+
+
+
+
+ {saveAsNew ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
- )}
-
-
-
-
-
+
+
+
+
+
+
+
+ {isShowingPolicyJsonFlyout ? (
-
-
-
-
-
-
-
- {isShowingPolicyJsonFlyout ? (
-
- ) : (
-
- )}
-
-
-
-
- {isShowingPolicyJsonFlyout ? (
- setIsShowingPolicyJsonFlyout(false)}
- />
- ) : null}
-
-
-
-
-
+ ) : (
+
+ )}
+
+
+
+
+ {isShowingPolicyJsonFlyout ? (
+ setIsShowingPolicyJsonFlyout(false)}
+ />
+ ) : null}
+
+
+
+
+
+
);
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy_context.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy_context.tsx
new file mode 100644
index 00000000000000..4748c26d6cec1b
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy_context.tsx
@@ -0,0 +1,32 @@
+/*
+ * 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 React, { createContext, ReactChild, useContext } from 'react';
+import { SerializedPolicy } from '../../../../common/types';
+
+interface EditPolicyContextValue {
+ originalPolicy: SerializedPolicy;
+}
+
+const EditPolicyContext = createContext(null as any);
+
+export const EditPolicyContextProvider = ({
+ value,
+ children,
+}: {
+ value: EditPolicyContextValue;
+ children: ReactChild;
+}) => {
+ return {children};
+};
+
+export const useEditPolicyContext = () => {
+ const ctx = useContext(EditPolicyContext);
+ if (!ctx) {
+ throw new Error('useEditPolicyContext can only be called inside of EditPolicyContext!');
+ }
+ return ctx;
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index 6d62e0aed2d735..8985ee4e6a68c7 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -10,10 +10,12 @@ import { FormSchema, fieldValidators } from '../../../shared_imports';
import { defaultSetPriority } from '../../constants';
import { FormInternal } from './types';
+
import { ifExistsNumberGreaterThanZero, rolloverThresholdsValidator } from './form_validations';
+
import { i18nTexts } from './i18n_texts';
-const { emptyField } = fieldValidators;
+const { emptyField, numberGreaterThanField } = fieldValidators;
export const schema: FormSchema = {
_meta: {
@@ -30,20 +32,9 @@ export const schema: FormSchema = {
maxAgeUnit: {
defaultValue: 'd',
},
- forceMergeEnabled: {
- label: i18nTexts.editPolicy.forceMergeEnabledFieldLabel,
- },
bestCompression: {
- label: i18n.translate('xpack.indexLifecycleMgmt.forcemerge.bestCompressionLabel', {
- defaultMessage: 'Compress stored fields',
- }),
- helpText: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.forceMerge.bestCompressionText',
- {
- defaultMessage:
- 'Use higher compression for stored fields at the cost of slower performance.',
- }
- ),
+ label: i18nTexts.editPolicy.bestCompressionFieldLabel,
+ helpText: i18nTexts.editPolicy.bestCompressionFieldHelpText,
},
},
warm: {
@@ -63,9 +54,6 @@ export const schema: FormSchema = {
minAgeUnit: {
defaultValue: 'd',
},
- forceMergeEnabled: {
- label: i18nTexts.editPolicy.forceMergeEnabledFieldLabel,
- },
bestCompression: {
label: i18nTexts.editPolicy.bestCompressionFieldLabel,
helpText: i18nTexts.editPolicy.bestCompressionFieldHelpText,
@@ -156,6 +144,33 @@ export const schema: FormSchema = {
],
},
actions: {
+ allocate: {
+ number_of_replicas: {
+ label: i18n.translate('xpack.indexLifecycleMgmt.warmPhase.numberOfReplicasLabel', {
+ defaultMessage: 'Number of replicas (optional)',
+ }),
+ validations: [
+ {
+ validator: ifExistsNumberGreaterThanZero,
+ },
+ ],
+ },
+ },
+ shrink: {
+ number_of_shards: {
+ validations: [
+ {
+ validator: emptyField(i18nTexts.editPolicy.errors.numberRequired),
+ },
+ {
+ validator: numberGreaterThanField({
+ message: i18nTexts.editPolicy.errors.numberGreatThan0Required,
+ than: 0,
+ }),
+ },
+ ],
+ },
+ },
forcemerge: {
max_num_segments: {
label: i18nTexts.editPolicy.maxNumSegmentsFieldLabel,
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
index b937ea2043138c..18f62eb066c7ed 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
@@ -4,27 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { i18n } from '@kbn/i18n';
import { fieldValidators, ValidationFunc } from '../../../shared_imports';
import { i18nTexts } from './components/phases/hot_phase/i18n_texts';
import { ROLLOVER_FORM_PATHS } from './constants';
-const { numberGreaterThanField } = fieldValidators;
+import { i18nTexts } from './i18n_texts';
-export const positiveNumberRequiredMessage = i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.numberAboveZeroRequiredError',
- {
- defaultMessage: 'Only numbers above 0 are allowed.',
- }
-);
+const { numberGreaterThanField } = fieldValidators;
export const ifExistsNumberGreaterThanZero: ValidationFunc = (arg) => {
if (arg.value) {
return numberGreaterThanField({
than: 0,
- message: positiveNumberRequiredMessage,
+ message: i18nTexts.editPolicy.errors.numberGreatThan0Required,
})({
...arg,
value: parseInt(arg.value, 10),
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
index 448df90161c93d..ae442091bd9c82 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
@@ -36,5 +36,19 @@ export const i18nTexts = {
'Use higher compression for stored fields at the cost of slower performance.',
}
),
+ errors: {
+ numberRequired: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.numberRequiredErrorMessage',
+ {
+ defaultMessage: 'A number is required.',
+ }
+ ),
+ numberGreatThan0Required: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.numberAboveZeroRequiredError',
+ {
+ defaultMessage: 'Only numbers above 0 are allowed.',
+ }
+ ),
+ },
},
};
From d349eee9b1a8804f352cad60d52f773387d311a2 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Tue, 20 Oct 2020 18:43:00 +0200
Subject: [PATCH 03/19] Refactored biggest field; data allocation
Copied the entire field for now duplicating all of the components
---
.../data_tiers/determine_allocation_type.ts | 22 ++-
.../application/lib/data_tiers/index.ts | 2 +
.../{forcemerge.tsx => forcemerge_legacy.tsx} | 0
.../sections/edit_policy/components/index.ts | 6 +-
...age_input.tsx => min_age_input_legacy.tsx} | 0
.../components/phases/cold_phase.tsx | 4 +-
.../components/phases/hot_phase/hot_phase.tsx | 12 +-
.../components/phases/hot_phase/i18n_texts.ts | 37 ----
.../components/cloud_data_tier_callout.tsx | 26 +++
.../components/data_tier_allocation.scss | 9 +
.../components/data_tier_allocation.tsx | 184 ++++++++++++++++++
.../components/default_allocation_notice.tsx | 106 ++++++++++
.../components/index.ts | 19 ++
.../components/no_node_attributes_warning.tsx | 50 +++++
.../components/node_allocation.tsx | 115 +++++++++++
.../components/node_attrs_details.tsx | 106 ++++++++++
.../components/node_data_provider.tsx | 70 +++++++
.../components/types.ts | 22 +++
.../data_tier_allocation_field.tsx | 43 ++--
.../data_tier_allocation_field/index.ts | 7 +
.../data_tier_allocation_legacy_field.tsx | 137 +++++++++++++
.../components/phases/shared/index.ts | 2 +
.../phases/warm_phase/warm_phase.tsx | 3 -
...nput.tsx => set_priority_input_legacy.tsx} | 0
.../sections/edit_policy/deserializer.ts | 47 +++--
.../sections/edit_policy/form_schema.ts | 7 +
.../sections/edit_policy/form_validations.ts | 14 +-
.../sections/edit_policy/i18n_texts.ts | 43 ++++
.../application/sections/edit_policy/types.ts | 4 +
.../services/policies/cold_phase.ts | 4 +-
.../services/policies/warm_phase.ts | 4 +-
.../public/shared_imports.ts | 1 +
32 files changed, 1000 insertions(+), 106 deletions(-)
rename x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/{forcemerge.tsx => forcemerge_legacy.tsx} (100%)
rename x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/{min_age_input.tsx => min_age_input_legacy.tsx} (100%)
delete mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/i18n_texts.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/cloud_data_tier_callout.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.scss
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/index.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_attrs_details.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_data_provider.tsx
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/types.ts
rename x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/{ => data_tier_allocation_field}/data_tier_allocation_field.tsx (76%)
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/index.ts
create mode 100644 x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_legacy_field.tsx
rename x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/{set_priority_input.tsx => set_priority_input_legacy.tsx} (100%)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
index 4067ad97fc43bc..099893a9f04011 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
@@ -11,7 +11,7 @@ import { DataTierAllocationType, AllocateAction } from '../../../../common/types
*
* See {@DataTierAllocationType} for more information.
*/
-export const determineDataTierAllocationType = (
+export const determineDataTierAllocationTypeLegacy = (
allocateAction?: AllocateAction
): DataTierAllocationType => {
if (!allocateAction) {
@@ -32,3 +32,23 @@ export const determineDataTierAllocationType = (
return 'default';
};
+
+export const determineDataTierAllocationType = (allocateAction?: AllocateAction) => {
+ if (!allocateAction) {
+ return 'node_roles';
+ }
+
+ if (allocateAction.migrate?.enabled === false) {
+ return 'none';
+ }
+
+ if (
+ (allocateAction.require && Object.keys(allocateAction.require).length) ||
+ (allocateAction.include && Object.keys(allocateAction.include).length) ||
+ (allocateAction.exclude && Object.keys(allocateAction.exclude).length)
+ ) {
+ return 'node_attrs';
+ }
+
+ return 'node_roles';
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/index.ts
index 87f2cbc08ecc0b..ac1aae270628d1 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/index.ts
@@ -7,3 +7,5 @@
export * from './determine_allocation_type';
export * from './get_available_node_roles_for_phase';
+
+export * from './is_node_role_first_preference';
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/forcemerge.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/forcemerge_legacy.tsx
similarity index 100%
rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/forcemerge.tsx
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/forcemerge_legacy.tsx
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts
index 04d9a6ef3cf67f..2b774b00b98a9f 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/index.ts
@@ -7,11 +7,11 @@
export { ActiveBadge } from './active_badge';
export { ErrableFormRow } from './form_errors';
export { LearnMoreLink } from './learn_more_link';
-export { MinAgeInput } from './min_age_input';
+export { MinAgeInput } from './min_age_input_legacy';
export { OptionalLabel } from './optional_label';
export { PhaseErrorMessage } from './phase_error_message';
export { PolicyJsonFlyout } from './policy_json_flyout';
-export { SetPriorityInput } from './set_priority_input';
+export { SetPriorityInput } from './set_priority_input_legacy';
export { SnapshotPolicies } from './snapshot_policies';
export {
DataTierAllocation,
@@ -21,6 +21,6 @@ export {
DefaultAllocationNotice,
} from './data_tier_allocation';
export { DescribedFormField } from './described_form_field';
-export { Forcemerge } from './forcemerge';
+export { Forcemerge } from './forcemerge_legacy';
export * from './phases';
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input_legacy.tsx
similarity index 100%
rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input.tsx
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/min_age_input_legacy.tsx
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase.tsx
index 7ed8a94403a9bc..3911925751ceb9 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/cold_phase.tsx
@@ -27,7 +27,7 @@ import {
DescribedFormField,
} from '../';
-import { DataTierAllocationField, useRolloverPath } from './shared';
+import { DataTierAllocationFieldLegacy, useRolloverPath } from './shared';
const i18nTexts = {
freezeLabel: i18n.translate('xpack.indexLifecycleMgmt.coldPhase.freezeIndexLabel', {
@@ -121,7 +121,7 @@ export const ColdPhase: FunctionComponent = ({
{phaseData.phaseEnabled ? (
{/* Data tier allocation section */}
- void }> = ({
@@ -123,11 +121,11 @@ export const HotPhase: FunctionComponent<{ setWarmPhaseOnRollover: (v: boolean)
{showEmptyRolloverFieldsError && (
<>
- {i18nTexts.rollOverConfigurationCallout.body}
+ {i18nTexts.editPolicy.errors.rollOverConfigurationCallout.body}
>
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/i18n_texts.ts
deleted file mode 100644
index 6423b12b86dd24..00000000000000
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/i18n_texts.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 { i18n } from '@kbn/i18n';
-
-export const i18nTexts = {
- maximumAgeRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumAgeMissingError',
- {
- defaultMessage: 'A maximum age is required.',
- }
- ),
- maximumSizeRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError',
- {
- defaultMessage: 'A maximum index size is required.',
- }
- ),
- maximumDocumentsRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError',
- {
- defaultMessage: 'Maximum documents is required.',
- }
- ),
- rollOverConfigurationCallout: {
- title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.title', {
- defaultMessage: 'Invalid rollover configuration',
- }),
- body: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.body', {
- defaultMessage:
- 'A value for one of maximum size, maximum documents, or maximum age is required.',
- }),
- },
-};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/cloud_data_tier_callout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/cloud_data_tier_callout.tsx
new file mode 100644
index 00000000000000..2dff55ac10de18
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/cloud_data_tier_callout.tsx
@@ -0,0 +1,26 @@
+/*
+ * 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 { i18n } from '@kbn/i18n';
+import React, { FunctionComponent } from 'react';
+import { EuiCallOut } from '@elastic/eui';
+
+const i18nTexts = {
+ title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.title', {
+ defaultMessage: 'Create a cold tier',
+ }),
+ body: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.body', {
+ defaultMessage: 'Edit your Elastic Cloud deployment to set up a cold tier.',
+ }),
+};
+
+export const CloudDataTierCallout: FunctionComponent = () => {
+ return (
+
+ {i18nTexts.body}
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.scss b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.scss
new file mode 100644
index 00000000000000..62ec3f303e1e8c
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.scss
@@ -0,0 +1,9 @@
+.indexLifecycleManagement__phase__dataTierAllocation {
+ &__controlSection {
+ background-color: $euiColorLightestShade;
+ padding-top: $euiSizeM;
+ padding-left: $euiSizeM;
+ padding-right: $euiSizeM;
+ padding-bottom: $euiSizeM;
+ }
+}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
new file mode 100644
index 00000000000000..99fa2abac3abe5
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
@@ -0,0 +1,184 @@
+/*
+ * 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 React, { FunctionComponent } from 'react';
+import { i18n } from '@kbn/i18n';
+import { EuiText, EuiSpacer, EuiSuperSelectOption } from '@elastic/eui';
+
+import { UseField, SuperSelectField, useFormData } from '../../../../../../../../shared_imports';
+
+import { DataTierAllocationType } from '../../../../../types';
+
+import { NodeAllocation } from './node_allocation';
+import { SharedProps } from './types';
+
+import './data_tier_allocation.scss';
+
+type SelectOptions = EuiSuperSelectOption;
+
+const i18nTexts = {
+ allocationOptions: {
+ warm: {
+ default: {
+ input: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.defaultOption.input',
+ { defaultMessage: 'Use warm nodes (recommended)' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.defaultOption.helpText',
+ { defaultMessage: 'Move data to nodes in the warm tier.' }
+ ),
+ },
+ none: {
+ inputDisplay: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.noneOption.input',
+ { defaultMessage: 'Off' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.noneOption.helpText',
+ { defaultMessage: 'Do not move data in the warm phase.' }
+ ),
+ },
+ custom: {
+ inputDisplay: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.customOption.input',
+ { defaultMessage: 'Custom' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.warm.customOption.helpText',
+ { defaultMessage: 'Move data based on node attributes.' }
+ ),
+ },
+ },
+ cold: {
+ default: {
+ input: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.defaultOption.input',
+ { defaultMessage: 'Use cold nodes (recommended)' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.defaultOption.helpText',
+ { defaultMessage: 'Move data to nodes in the cold tier.' }
+ ),
+ },
+ none: {
+ inputDisplay: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.noneOption.input',
+ { defaultMessage: 'Off' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.noneOption.helpText',
+ { defaultMessage: 'Do not move data in the cold phase.' }
+ ),
+ },
+ custom: {
+ inputDisplay: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.customOption.input',
+ { defaultMessage: 'Custom' }
+ ),
+ helpText: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.common.dataTierAllocation.cold.customOption.helpText',
+ { defaultMessage: 'Move data based on node attributes.' }
+ ),
+ },
+ },
+ },
+};
+
+export const DataTierAllocation: FunctionComponent = (props) => {
+ const { phase, hasNodeAttributes, disableDataTierOption } = props;
+
+ const dataTierAllocationTypePath = `_meta.${phase}.dataTierAllocationType`;
+
+ const [{ [dataTierAllocationTypePath]: dataTierAllocationType }] = useFormData({
+ watch: [dataTierAllocationTypePath],
+ });
+
+ return (
+
+
+ {(field) => {
+ /**
+ * We reset the value to "custom" if we deserialized to "default".
+ *
+ * It would be better if we had all the information we needed before deserializing and
+ * were able to handle this at the deserialization step instead of patching further down
+ * the component tree - this should be a future refactor.
+ */
+ if (disableDataTierOption && field.value === 'node_roles') {
+ field.setValue('node_attrs');
+ }
+ return (
+
+ {i18nTexts.allocationOptions[phase].default.input}
+
+
+ {i18nTexts.allocationOptions[phase].default.helpText}
+
+
+ >
+ ),
+ },
+ {
+ 'data-test-subj': 'customDataAllocationOption',
+ value: 'node_attrs',
+ inputDisplay: i18nTexts.allocationOptions[phase].custom.inputDisplay,
+ dropdownDisplay: (
+ <>
+ {i18nTexts.allocationOptions[phase].custom.inputDisplay}
+
+
+ {i18nTexts.allocationOptions[phase].custom.helpText}
+
+
+ >
+ ),
+ },
+ {
+ 'data-test-subj': 'noneDataAllocationOption',
+ value: 'none',
+ inputDisplay: i18nTexts.allocationOptions[phase].none.inputDisplay,
+ dropdownDisplay: (
+ <>
+ {i18nTexts.allocationOptions[phase].none.inputDisplay}
+
+
+ {i18nTexts.allocationOptions[phase].none.helpText}
+
+
+ >
+ ),
+ },
+ ].filter(Boolean) as SelectOptions[],
+ }}
+ />
+ );
+ }}
+
+ {dataTierAllocationType === 'node_attrs' && hasNodeAttributes && (
+ <>
+
+
+
+
+ >
+ )}
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
new file mode 100644
index 00000000000000..9f7b37d49594d1
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
@@ -0,0 +1,106 @@
+/*
+ * 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 { i18n } from '@kbn/i18n';
+import React, { FunctionComponent } from 'react';
+import { EuiCallOut } from '@elastic/eui';
+
+import { PhaseWithAllocation, NodeDataRole } from '../../../../../../../../../common/types';
+
+import { AllocationNodeRole } from '../../../../../../../lib';
+
+const i18nTextsNodeRoleToDataTier: Record = {
+ data_hot: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.dataTierHotLabel', {
+ defaultMessage: 'hot',
+ }),
+ data_warm: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.dataTierWarmLabel', {
+ defaultMessage: 'warm',
+ }),
+ data_cold: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.dataTierColdLabel', {
+ defaultMessage: 'cold',
+ }),
+};
+
+const i18nTexts = {
+ notice: {
+ warm: {
+ title: i18n.translate(
+ 'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.warm.title',
+ { defaultMessage: 'No nodes assigned to the warm tier' }
+ ),
+ body: (nodeRole: NodeDataRole) =>
+ i18n.translate('xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.warm', {
+ defaultMessage:
+ 'This policy will move data in the warm phase to {tier} tier nodes instead.',
+ values: { tier: i18nTextsNodeRoleToDataTier[nodeRole] },
+ }),
+ },
+ cold: {
+ title: i18n.translate(
+ 'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.cold.title',
+ { defaultMessage: 'No nodes assigned to the cold tier' }
+ ),
+ body: (nodeRole: NodeDataRole) =>
+ i18n.translate('xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.cold', {
+ defaultMessage:
+ 'This policy will move data in the cold phase to {tier} tier nodes instead.',
+ values: { tier: i18nTextsNodeRoleToDataTier[nodeRole] },
+ }),
+ },
+ },
+ warning: {
+ warm: {
+ title: i18n.translate(
+ 'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotAvailableTitle',
+ { defaultMessage: 'No nodes assigned to the warm tier' }
+ ),
+ body: i18n.translate(
+ 'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotAvailableBody',
+ {
+ defaultMessage:
+ 'Assign at least one node to the warm or hot tier to use role-based allocation. The policy will fail to complete allocation if there are no available nodes.',
+ }
+ ),
+ },
+ cold: {
+ title: i18n.translate(
+ 'xpack.indexLifecycleMgmt.coldPhase.dataTier.defaultAllocationNotAvailableTitle',
+ { defaultMessage: 'No nodes assigned to the cold tier' }
+ ),
+ body: i18n.translate(
+ 'xpack.indexLifecycleMgmt.coldPhase.dataTier.defaultAllocationNotAvailableBody',
+ {
+ defaultMessage:
+ 'Assign at least one node to the cold, warm, or hot tier to use role-based allocation. The policy will fail to complete allocation if there are no available nodes.',
+ }
+ ),
+ },
+ },
+};
+
+interface Props {
+ phase: PhaseWithAllocation;
+ targetNodeRole: AllocationNodeRole;
+}
+
+export const DefaultAllocationNotice: FunctionComponent = ({ phase, targetNodeRole }) => {
+ const content =
+ targetNodeRole === 'none' ? (
+
+ {i18nTexts.warning[phase].body}
+
+ ) : (
+
+ {i18nTexts.notice[phase].body(targetNodeRole)}
+
+ );
+
+ return content;
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/index.ts
new file mode 100644
index 00000000000000..0782782e77fadc
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/index.ts
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+export { NodesDataProvider } from './node_data_provider';
+
+export { NodeAllocation } from './node_allocation';
+
+export { NodeAttrsDetails } from './node_attrs_details';
+
+export { DataTierAllocation } from './data_tier_allocation';
+
+export { DefaultAllocationNotice } from './default_allocation_notice';
+
+export { NoNodeAttributesWarning } from './no_node_attributes_warning';
+
+export { CloudDataTierCallout } from './cloud_data_tier_callout';
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
new file mode 100644
index 00000000000000..69185277f64ce6
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
@@ -0,0 +1,50 @@
+/*
+ * 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 React, { FunctionComponent } from 'react';
+import { EuiCallOut } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+
+import { PhaseWithAllocation } from '../../../../../../common/types';
+
+const i18nTexts = {
+ title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.nodeAttributesMissingLabel', {
+ defaultMessage: 'No custom node attributes configured',
+ }),
+ warm: {
+ body: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.warm.nodeAttributesMissingDescription',
+ {
+ defaultMessage:
+ 'Define custom node attributes in elasticsearch.yml to use attribute-based allocation. Warm nodes will be used instead.',
+ }
+ ),
+ },
+ cold: {
+ body: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.cold.nodeAttributesMissingDescription',
+ {
+ defaultMessage:
+ 'Define custom node attributes in elasticsearch.yml to use attribute-based allocation. Cold nodes will be used instead.',
+ }
+ ),
+ },
+};
+
+export const NoNodeAttributesWarning: FunctionComponent<{ phase: PhaseWithAllocation }> = ({
+ phase,
+}) => {
+ return (
+
+ {i18nTexts[phase].body}
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
new file mode 100644
index 00000000000000..fe74c82d29e7b2
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
@@ -0,0 +1,115 @@
+/*
+ * 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 React, { useState, FunctionComponent } from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { i18n } from '@kbn/i18n';
+import { EuiButtonEmpty, EuiText, EuiSpacer } from '@elastic/eui';
+
+import { PhaseWithAllocationAction } from '../../../../../../../../../common/types';
+
+import { UseField, SelectField, useFormData } from '../../../../../../../../shared_imports';
+
+import { propertyof } from '../../../../../../../services/policies/policy_validation';
+
+import { LearnMoreLink } from '../../../../learn_more_link';
+
+import { NodeAttrsDetails } from './node_attrs_details';
+
+import { SharedProps } from './types';
+
+const learnMoreLink = (
+
+ }
+ docPath="modules-cluster.html#cluster-shard-allocation-settings"
+ />
+);
+
+const i18nTexts = {
+ doNotModifyAllocationOption: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.doNotModifyAllocationOption',
+ { defaultMessage: 'Do not modify allocation configuration' }
+ ),
+};
+
+export const NodeAllocation: FunctionComponent = ({ phase, nodes }) => {
+ const allocationNodeAttributePath = `_meta.${phase}.allocationNodeAttribute`;
+
+ const [{ [allocationNodeAttributePath]: selectedAllocationNodeAttribute }] = useFormData({
+ watch: [allocationNodeAttributePath],
+ });
+
+ const [selectedNodeAttrsForDetails, setSelectedNodeAttrsForDetails] = useState(
+ null
+ );
+
+ const nodeOptions = Object.keys(nodes).map((attrs) => ({
+ text: `${attrs} (${nodes[attrs].length})`,
+ value: attrs,
+ }));
+
+ nodeOptions.sort((a, b) => a.value.localeCompare(b.value));
+
+ // check that this string is a valid property
+ const nodeAttrsProperty = propertyof('selectedNodeAttrs');
+
+ return (
+ <>
+
+
+
+
+
+
+
+ {/*
+ TODO: this field component must be revisited to support setting multiple require values and to support
+ setting `include and exclude values on ILM policies. See https://github.com/elastic/kibana/issues/77344
+ */}
+ setSelectedNodeAttrsForDetails(selectedAllocationNodeAttribute)}
+ >
+
+
+ ) : undefined,
+ euiFieldProps: {
+ 'data-test-subj': `${phase}-${nodeAttrsProperty}`,
+ options: [{ text: i18nTexts.doNotModifyAllocationOption, value: 'none' }].concat(
+ nodeOptions
+ ),
+ },
+ }}
+ />
+ {selectedNodeAttrsForDetails ? (
+ setSelectedNodeAttrsForDetails(null)}
+ />
+ ) : null}
+ >
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_attrs_details.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_attrs_details.tsx
new file mode 100644
index 00000000000000..61de977b1cb121
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_attrs_details.tsx
@@ -0,0 +1,106 @@
+/*
+ * 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 React from 'react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import {
+ EuiFlyoutBody,
+ EuiFlyout,
+ EuiTitle,
+ EuiInMemoryTable,
+ EuiSpacer,
+ EuiPortal,
+ EuiLoadingContent,
+ EuiCallOut,
+ EuiButton,
+} from '@elastic/eui';
+
+import { useLoadNodeDetails } from '../../../../../../../services/api';
+
+interface Props {
+ close: () => void;
+ selectedNodeAttrs: string;
+}
+
+export const NodeAttrsDetails: React.FunctionComponent = ({ close, selectedNodeAttrs }) => {
+ const { data, isLoading, error, resendRequest } = useLoadNodeDetails(selectedNodeAttrs);
+ let content;
+ if (isLoading) {
+ content = ;
+ } else if (error) {
+ const { statusCode, message } = error;
+ content = (
+
+ }
+ color="danger"
+ >
+
+ {message} ({statusCode})
+
+
+
+
+
+ );
+ } else {
+ content = (
+
+ );
+ }
+ return (
+
+
+
+
+
+
+
+
+
+ {content}
+
+
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_data_provider.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_data_provider.tsx
new file mode 100644
index 00000000000000..bb01a42e378faa
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_data_provider.tsx
@@ -0,0 +1,70 @@
+/*
+ * 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 React from 'react';
+import { EuiButton, EuiCallOut, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import { ListNodesRouteResponse } from '../../../../../../../../../common/types';
+import { useLoadNodes } from '../../../../../../../services/api';
+
+interface Props {
+ children: (data: ListNodesRouteResponse) => JSX.Element;
+}
+
+export const NodesDataProvider = ({ children }: Props): JSX.Element => {
+ const { isLoading, data, error, resendRequest } = useLoadNodes();
+
+ if (isLoading) {
+ return (
+ <>
+
+
+ >
+ );
+ }
+
+ const renderError = () => {
+ if (error) {
+ const { statusCode, message } = error;
+ return (
+ <>
+
+ }
+ color="danger"
+ >
+
+ {message} ({statusCode})
+
+
+
+
+
+
+
+ >
+ );
+ }
+ return null;
+ };
+
+ return (
+ <>
+ {renderError()}
+ {/* `data` will always be defined because we use an initial value when loading */}
+ {children(data!)}
+ >
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/types.ts
new file mode 100644
index 00000000000000..7bd620757a8ac5
--- /dev/null
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/types.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 {
+ ListNodesRouteResponse,
+ PhaseWithAllocation,
+} from '../../../../../../../../../common/types';
+
+export interface SharedProps {
+ phase: PhaseWithAllocation;
+ nodes: ListNodesRouteResponse['nodesByAttributes'];
+ hasNodeAttributes: boolean;
+ /**
+ * When on Cloud we want to disable the data tier allocation option when we detect that we are not
+ * using node roles in our Node config yet. See {@link ListNodesRouteResponse} for information about how this is
+ * detected.
+ */
+ disableDataTierOption: boolean;
+}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
similarity index 76%
rename from x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field.tsx
rename to x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
index de7f321e5f15d6..b7b9a1e9f3dad9 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
@@ -6,13 +6,16 @@
import React, { FunctionComponent } from 'react';
import { i18n } from '@kbn/i18n';
+
import { EuiDescribedFormGroup, EuiFormRow, EuiSpacer } from '@elastic/eui';
-import { useKibana } from '../../../../../../shared_imports';
-import { PhaseWithAllocationAction, PhaseWithAllocation } from '../../../../../../../common/types';
-import { PhaseValidationErrors } from '../../../../../services/policies/policy_validation';
-import { getAvailableNodeRoleForPhase } from '../../../../../lib/data_tiers';
-import { isNodeRoleFirstPreference } from '../../../../../lib/data_tiers/is_node_role_first_preference';
+import { useKibana, useFormData } from '../../../../../../../shared_imports';
+
+import { PhaseWithAllocation } from '../../../../../../../../common/types';
+
+import { getAvailableNodeRoleForPhase } from '../../../../../../lib/data_tiers';
+
+import { isNodeRoleFirstPreference } from '../../../../../../lib';
import {
DataTierAllocation,
@@ -20,7 +23,7 @@ import {
NoNodeAttributesWarning,
NodesDataProvider,
CloudDataTierCallout,
-} from '../../data_tier_allocation';
+} from './components';
const i18nTexts = {
title: i18n.translate('xpack.indexLifecycleMgmt.common.dataTier.title', {
@@ -29,37 +32,29 @@ const i18nTexts = {
};
interface Props {
- description: React.ReactNode;
phase: PhaseWithAllocation;
- setPhaseData: (dataKey: keyof PhaseWithAllocationAction, value: string) => void;
- isShowingErrors: boolean;
- errors?: PhaseValidationErrors;
- phaseData: PhaseWithAllocationAction;
+ description: React.ReactNode;
}
/**
* Top-level layout control for the data tier allocation field.
*/
-export const DataTierAllocationField: FunctionComponent = ({
- description,
- phase,
- phaseData,
- setPhaseData,
- isShowingErrors,
- errors,
-}) => {
+export const DataTierAllocationField: FunctionComponent = ({ phase, description }) => {
const {
services: { cloud },
} = useKibana();
+ const allocationTypePath = `_meta.${phase}.dataTierAllocationType`;
+ const [{ [allocationTypePath]: allocationType }] = useFormData({ watch: [allocationTypePath] });
+
return (
{({ nodesByRoles, nodesByAttributes, isUsingDeprecatedDataRoleConfig }) => {
const hasNodeAttrs = Boolean(Object.keys(nodesByAttributes ?? {}).length);
const renderNotice = () => {
- switch (phaseData.dataTierAllocationType) {
- case 'default':
+ switch (allocationType) {
+ case 'node_roles':
const isCloudEnabled = cloud?.isCloudEnabled ?? false;
const isUsingNodeRoles = !isUsingDeprecatedDataRoleConfig;
if (
@@ -90,7 +85,7 @@ export const DataTierAllocationField: FunctionComponent = ({
);
}
break;
- case 'custom':
+ case 'node_attrs':
if (!hasNodeAttrs) {
return (
<>
@@ -116,10 +111,6 @@ export const DataTierAllocationField: FunctionComponent = ({
void;
+ isShowingErrors: boolean;
+ errors?: PhaseValidationErrors;
+ phaseData: PhaseWithAllocationAction;
+}
+
+/**
+ * Top-level layout control for the data tier allocation field.
+ */
+export const DataTierAllocationFieldLegacy: FunctionComponent = ({
+ description,
+ phase,
+ phaseData,
+ setPhaseData,
+ isShowingErrors,
+ errors,
+}) => {
+ const {
+ services: { cloud },
+ } = useKibana();
+
+ return (
+
+ {({ nodesByRoles, nodesByAttributes, isUsingDeprecatedDataRoleConfig }) => {
+ const hasNodeAttrs = Boolean(Object.keys(nodesByAttributes ?? {}).length);
+
+ const renderNotice = () => {
+ switch (phaseData.dataTierAllocationType) {
+ case 'default':
+ const isCloudEnabled = cloud?.isCloudEnabled ?? false;
+ const isUsingNodeRoles = !isUsingDeprecatedDataRoleConfig;
+ if (
+ isCloudEnabled &&
+ isUsingNodeRoles &&
+ phase === 'cold' &&
+ !nodesByRoles.data_cold?.length
+ ) {
+ // Tell cloud users they can deploy cold tier nodes.
+ return (
+ <>
+
+
+ >
+ );
+ }
+
+ const allocationNodeRole = getAvailableNodeRoleForPhase(phase, nodesByRoles);
+ if (
+ allocationNodeRole === 'none' ||
+ !isNodeRoleFirstPreference(phase, allocationNodeRole)
+ ) {
+ return (
+ <>
+
+
+ >
+ );
+ }
+ break;
+ case 'custom':
+ if (!hasNodeAttrs) {
+ return (
+ <>
+
+
+ >
+ );
+ }
+ break;
+ default:
+ return null;
+ }
+ };
+
+ return (
+ {i18nTexts.title}}
+ description={description}
+ fullWidth
+ >
+
+ <>
+
+
+ {/* Data tier related warnings and call-to-action notices */}
+ {renderNotice()}
+ >
+
+
+ );
+ }}
+
+ );
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/index.ts
index 6355dab89771d7..0cae3eea6316b9 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/index.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/index.ts
@@ -6,6 +6,8 @@
export { useRolloverPath } from '../../../constants';
+export { DataTierAllocationFieldLegacy } from './data_tier_allocation_legacy_field';
+
export { DataTierAllocationField } from './data_tier_allocation_field';
export { Forcemerge } from './forcemerge_field';
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
index 3f149827365bfe..a3450c0482460b 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
@@ -150,9 +150,6 @@ export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, e
- produce(
+export const deserializer = (policy: SerializedPolicy): FormInternal => {
+ const _meta: FormInternal['_meta'] = {
+ hot: {
+ useRollover: Boolean(policy.phases.hot?.actions?.rollover),
+ forceMergeEnabled: Boolean(policy.phases.hot?.actions?.forcemerge),
+ bestCompression: policy.phases.hot?.actions?.forcemerge?.index_codec === 'best_compression',
+ },
+ warm: {
+ enabled: Boolean(policy.phases.warm),
+ warmPhaseOnRollover: Boolean(policy.phases.warm?.min_age === '0ms'),
+ forceMergeEnabled: Boolean(policy.phases.warm?.actions?.forcemerge),
+ bestCompression: policy.phases.warm?.actions?.forcemerge?.index_codec === 'best_compression',
+ dataTierAllocationType: determineDataTierAllocationType(policy.phases.warm?.actions.allocate),
+ },
+ };
+
+ return produce(
{
...policy,
- _meta: {
- hot: {
- useRollover: Boolean(policy.phases.hot?.actions?.rollover),
- forceMergeEnabled: Boolean(policy.phases.hot?.actions?.forcemerge),
- bestCompression:
- policy.phases.hot?.actions?.forcemerge?.index_codec === 'best_compression',
- },
- warm: {
- enabled: Boolean(policy.phases.warm),
- warmPhaseOnRollover: Boolean(policy.phases.warm?.min_age === '0ms'),
- forceMergeEnabled: Boolean(policy.phases.warm?.actions?.forcemerge),
- bestCompression:
- policy.phases.warm?.actions?.forcemerge?.index_codec === 'best_compression',
- },
- },
+ _meta,
},
- (draft) => {
+ (draft: FormInternal) => {
if (draft.phases.hot?.actions?.rollover) {
if (draft.phases.hot.actions.rollover.max_size) {
const maxSize = splitSizeAndUnits(draft.phases.hot.actions.rollover.max_size);
@@ -46,5 +50,12 @@ export const deserializer = (policy: SerializedPolicy): FormInternal =>
draft._meta.hot.maxAgeUnit = maxAge.units;
}
}
+
+ if (draft.phases.warm?.actions?.allocate?.require) {
+ Object.entries(draft.phases.warm.actions.allocate.require).forEach((entry) => {
+ draft._meta.warm.allocationNodeAttribute = entry.join(':');
+ });
+ }
}
);
+};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index 8985ee4e6a68c7..32897d7be0ed06 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -58,6 +58,13 @@ export const schema: FormSchema = {
label: i18nTexts.editPolicy.bestCompressionFieldLabel,
helpText: i18nTexts.editPolicy.bestCompressionFieldHelpText,
},
+ dataTierAllocationType: {
+ label: i18nTexts.editPolicy.allocationTypeOptionsFieldLabel,
+ },
+ allocationNodeAttribute: {
+ defaultValue: 'none',
+ label: i18nTexts.editPolicy.allocationNodeAttributeFieldLabel,
+ },
},
},
phases: {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
index 18f62eb066c7ed..37ca4e9def340f 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_validations.ts
@@ -6,8 +6,6 @@
import { fieldValidators, ValidationFunc } from '../../../shared_imports';
-import { i18nTexts } from './components/phases/hot_phase/i18n_texts';
-
import { ROLLOVER_FORM_PATHS } from './constants';
import { i18nTexts } from './i18n_texts';
@@ -48,16 +46,22 @@ export const rolloverThresholdsValidator: ValidationFunc = ({ form }) => {
)
) {
fields[ROLLOVER_FORM_PATHS.maxAge].setErrors([
- { validationType: ROLLOVER_EMPTY_VALIDATION, message: i18nTexts.maximumAgeRequiredMessage },
+ {
+ validationType: ROLLOVER_EMPTY_VALIDATION,
+ message: i18nTexts.editPolicy.errors.maximumAgeRequiredMessage,
+ },
]);
fields[ROLLOVER_FORM_PATHS.maxDocs].setErrors([
{
validationType: ROLLOVER_EMPTY_VALIDATION,
- message: i18nTexts.maximumDocumentsRequiredMessage,
+ message: i18nTexts.editPolicy.errors.maximumDocumentsRequiredMessage,
},
]);
fields[ROLLOVER_FORM_PATHS.maxSize].setErrors([
- { validationType: ROLLOVER_EMPTY_VALIDATION, message: i18nTexts.maximumSizeRequiredMessage },
+ {
+ validationType: ROLLOVER_EMPTY_VALIDATION,
+ message: i18nTexts.editPolicy.errors.maximumSizeRequiredMessage,
+ },
]);
} else {
fields[ROLLOVER_FORM_PATHS.maxAge].clearErrors(ROLLOVER_EMPTY_VALIDATION);
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
index ae442091bd9c82..71031d1801ee6a 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
@@ -36,6 +36,16 @@ export const i18nTexts = {
'Use higher compression for stored fields at the cost of slower performance.',
}
),
+ allocationTypeOptionsFieldLabel: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.dataTierAllocation.allocationFieldLabel',
+ { defaultMessage: 'Data tier options' }
+ ),
+ allocationNodeAttributeFieldLabel: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.dataTierAllocation.nodeAllocationFieldLabel',
+ {
+ defaultMessage: 'Select a node attribute',
+ }
+ ),
errors: {
numberRequired: i18n.translate(
'xpack.indexLifecycleMgmt.editPolicy.numberRequiredErrorMessage',
@@ -49,6 +59,39 @@ export const i18nTexts = {
defaultMessage: 'Only numbers above 0 are allowed.',
}
),
+ maximumAgeRequiredMessage: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.maximumAgeMissingError',
+ {
+ defaultMessage: 'A maximum age is required.',
+ }
+ ),
+ maximumSizeRequiredMessage: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError',
+ {
+ defaultMessage: 'A maximum index size is required.',
+ }
+ ),
+ maximumDocumentsRequiredMessage: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError',
+ {
+ defaultMessage: 'Maximum documents is required.',
+ }
+ ),
+ rollOverConfigurationCallout: {
+ title: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.title',
+ {
+ defaultMessage: 'Invalid rollover configuration',
+ }
+ ),
+ body: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.body',
+ {
+ defaultMessage:
+ 'A value for one of maximum size, maximum documents, or maximum age is required.',
+ }
+ ),
+ },
},
},
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
index 7c8bc7e8080210..98333b5973dc2f 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
@@ -6,6 +6,8 @@
import { SerializedPolicy } from '../../../../common/types';
+export type DataTierAllocationType = 'node_roles' | 'node_attrs' | 'none';
+
/**
* Describes the shape of data after deserialization.
*/
@@ -27,6 +29,8 @@ export interface FormInternal extends SerializedPolicy {
forceMergeEnabled: boolean;
bestCompression: boolean;
warmPhaseOnRollover: boolean;
+ dataTierAllocationType: DataTierAllocationType;
+ allocationNodeAttribute?: string;
minAgeUnit?: string;
};
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
index 9f5f603fbc5640..89b4743a995694 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
@@ -13,7 +13,7 @@ import {
PhaseValidationErrors,
positiveNumberRequiredMessage,
} from './policy_validation';
-import { determineDataTierAllocationType } from '../../lib';
+import { determineDataTierAllocationTypeLegacy } from '../../lib';
import { serializePhaseWithAllocation } from './shared';
export const coldPhaseInitialization: ColdPhase = {
@@ -36,7 +36,7 @@ export const coldPhaseFromES = (phaseSerialized?: SerializedColdPhase): ColdPhas
phase.phaseEnabled = true;
if (phaseSerialized.actions.allocate) {
- phase.dataTierAllocationType = determineDataTierAllocationType(
+ phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(
phaseSerialized.actions.allocate
);
}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
index 436e5a222f86d4..a5a6fa6abe47b0 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
@@ -16,7 +16,7 @@ import {
positiveNumbersAboveZeroErrorMessage,
} from './policy_validation';
-import { determineDataTierAllocationType } from '../../lib';
+import { determineDataTierAllocationTypeLegacy } from '../../lib';
import { serializePhaseWithAllocation } from './shared';
const warmPhaseInitialization: WarmPhase = {
@@ -45,7 +45,7 @@ export const warmPhaseFromES = (phaseSerialized?: SerializedWarmPhase): WarmPhas
phase.phaseEnabled = true;
if (phaseSerialized.actions.allocate) {
- phase.dataTierAllocationType = determineDataTierAllocationType(
+ phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(
phaseSerialized.actions.allocate
);
}
diff --git a/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts
index dc3e1b1d1b62da..023aeba57aa7a6 100644
--- a/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts
@@ -26,6 +26,7 @@ export {
ToggleField,
NumericField,
SelectField,
+ SuperSelectField,
} from '../../../../src/plugins/es_ui_shared/static/forms/components';
export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public';
From 779534e7bba5bca93fce2d1b3da76c56327b9c30 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Tue, 20 Oct 2020 18:49:47 +0200
Subject: [PATCH 04/19] remove unused import
---
.../public/application/sections/edit_policy/deserializer.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
index a29971fafcbdb9..996b64b5940fcc 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
@@ -11,7 +11,6 @@ import { SerializedPolicy } from '../../../../common/types';
import { splitSizeAndUnits } from '../../services/policies/policy_serialization';
import { determineDataTierAllocationType } from '../../lib';
-import {} from '../../services/policies/policy_serialization';
import { FormInternal } from './types';
From 5bb0be91829b84c45a0c80cbc877ba622bd98d2d Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 12:35:09 +0200
Subject: [PATCH 05/19] complete migration of new serialization
---
.../common/types/policies.ts | 4 +-
.../components/phases/hot_phase/hot_phase.tsx | 10 +-
.../phases/warm_phase/warm_phase.tsx | 54 +++------
.../components/policy_json_flyout.tsx | 4 +-
.../sections/edit_policy/deserializer.ts | 16 ++-
.../sections/edit_policy/edit_policy.tsx | 32 +----
.../sections/edit_policy/form_schema.ts | 25 +++-
.../sections/edit_policy/i18n_texts.ts | 6 +
.../sections/edit_policy/serializer.ts | 111 +++++++++++++++---
.../application/sections/edit_policy/types.ts | 39 +++---
10 files changed, 179 insertions(+), 122 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
index 152c5e4e9e0d70..c2d2c22424666d 100644
--- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
+++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
@@ -87,8 +87,8 @@ export interface SerializedDeletePhase extends SerializedPhase {
export interface AllocateAction {
number_of_replicas?: number;
- include: {};
- exclude: {};
+ include?: {};
+ exclude?: {};
require?: {
[attribute: string]: string;
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx
index 232277e9f762d1..d8a95cd8c9c2f2 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { Fragment, FunctionComponent, useEffect, useState } from 'react';
+import React, { Fragment, FunctionComponent, useState } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import {
@@ -40,19 +40,13 @@ import { maxSizeStoredUnits, maxAgeUnits } from './constants';
const hotProperty: keyof Phases = 'hot';
-export const HotPhase: FunctionComponent<{ setWarmPhaseOnRollover: (v: boolean) => void }> = ({
- setWarmPhaseOnRollover,
-}) => {
+export const HotPhase: FunctionComponent = () => {
const [{ [useRolloverPath]: isRolloverEnabled }] = useFormData({ watch: [useRolloverPath] });
const form = useFormContext();
const isShowingErrors = form.isValid === false;
const [showEmptyRolloverFieldsError, setShowEmptyRolloverFieldsError] = useState(false);
- useEffect(() => {
- setWarmPhaseOnRollover(isRolloverEnabled ?? false);
- }, [setWarmPhaseOnRollover, isRolloverEnabled]);
-
return (
<>
propertyName;
-interface Props {
- setPhaseData: (
- key: keyof WarmPhaseInterface & string,
- value: boolean | string | undefined
- ) => void;
- phaseData: WarmPhaseInterface;
- isShowingErrors: boolean;
- errors?: PhaseValidationErrors;
-}
-export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, errors }) => {
+export const WarmPhase: FunctionComponent = () => {
const { originalPolicy } = useEditPolicyContext();
const form = useFormContext();
const [
@@ -222,26 +206,18 @@ export const WarmPhase: FunctionComponent = ({ setPhaseData, phaseData, e
-
- {
- setPhaseData(phaseProperty('selectedPrimaryShardCount'), e.target.value);
- }}
- min={1}
- />
-
+
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
index e9ce193118b35b..9693733eb61508 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
@@ -25,6 +25,7 @@ import {
import { SerializedPolicy } from '../../../../../common/types';
import { useFormContext, useFormData } from '../../../../shared_imports';
+import { FormInternal } from '../types';
interface Props {
legacyPolicy: SerializedPolicy;
@@ -45,7 +46,7 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({
const [policy, setPolicy] = useState(undefined);
const form = useFormContext();
- const [formData, getFormData] = useFormData();
+ const [formData, getFormData] = useFormData();
useEffect(() => {
(async function checkPolicy() {
@@ -57,6 +58,7 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({
phases: {
...legacyPolicy.phases,
hot: p.phases.hot,
+ warm: p.phases.warm,
},
});
} else {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
index 996b64b5940fcc..9337b87d995e6d 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
@@ -50,10 +50,18 @@ export const deserializer = (policy: SerializedPolicy): FormInternal => {
}
}
- if (draft.phases.warm?.actions?.allocate?.require) {
- Object.entries(draft.phases.warm.actions.allocate.require).forEach((entry) => {
- draft._meta.warm.allocationNodeAttribute = entry.join(':');
- });
+ if (draft.phases.warm) {
+ if (draft.phases.warm.actions?.allocate?.require) {
+ Object.entries(draft.phases.warm.actions.allocate.require).forEach((entry) => {
+ draft._meta.warm.allocationNodeAttribute = entry.join(':');
+ });
+ }
+
+ if (draft.phases.warm.min_age) {
+ const minAge = splitSizeAndUnits(draft.phases.warm.min_age);
+ draft.phases.warm.min_age = minAge.size;
+ draft._meta.warm.minAgeUnit = minAge.units;
+ }
}
}
);
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
index 47b04abd535281..eecdfb4871a676 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
@@ -91,6 +91,7 @@ const mergeAllSerializedPolicies = (
phases: {
...legacySerializedPolicy.phases,
hot: serializedPolicy.phases.hot,
+ warm: serializedPolicy.phases.warm,
},
};
};
@@ -136,22 +137,6 @@ export const EditPolicy: React.FunctionComponent = ({
history.push('/policies');
};
- const setWarmPhaseOnRollover = useCallback(
- (value: boolean) => {
- setPolicy((p) => ({
- ...p,
- phases: {
- ...p.phases,
- warm: {
- ...p.phases.warm,
- warmPhaseOnRollover: value,
- },
- },
- }));
- },
- [setPolicy]
- );
-
const submit = async () => {
setIsShowingErrors(true);
const { data: formLibPolicy, isValid: newIsValid } = await form.submit();
@@ -210,10 +195,6 @@ export const EditPolicy: React.FunctionComponent = ({
[setPolicy]
);
- const setWarmPhaseData = useCallback(
- (key: string, value: any) => setPhaseData('warm', key, value),
- [setPhaseData]
- );
const setColdPhaseData = useCallback(
(key: string, value: any) => setPhaseData('cold', key, value),
[setPhaseData]
@@ -353,18 +334,11 @@ export const EditPolicy: React.FunctionComponent = ({
-
+
- 0
- }
- setPhaseData={setWarmPhaseData}
- phaseData={policy.phases.warm}
- />
+
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index 32897d7be0ed06..440d67ed571ad8 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -17,6 +17,10 @@ import { i18nTexts } from './i18n_texts';
const { emptyField, numberGreaterThanField } = fieldValidators;
+const serializers = {
+ stringToNumber: (v: string): any => (v ? parseInt(v, 10) : undefined),
+};
+
export const schema: FormSchema = {
_meta: {
hot: {
@@ -96,7 +100,7 @@ export const schema: FormSchema = {
validator: ifExistsNumberGreaterThanZero,
},
],
- serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ serializer: serializers.stringToNumber,
},
max_size: {
label: i18n.translate('xpack.indexLifecycleMgmt.hotPhase.maximumIndexSizeLabel', {
@@ -128,7 +132,7 @@ export const schema: FormSchema = {
validator: ifExistsNumberGreaterThanZero,
},
],
- serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ serializer: serializers.stringToNumber,
},
},
set_priority: {
@@ -136,7 +140,7 @@ export const schema: FormSchema = {
defaultValue: defaultSetPriority as any,
label: i18nTexts.editPolicy.setPriorityFieldLabel,
validations: [{ validator: ifExistsNumberGreaterThanZero }],
- serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ serializer: serializers.stringToNumber,
},
},
},
@@ -146,7 +150,11 @@ export const schema: FormSchema = {
defaultValue: '0',
validations: [
{
- validator: ifExistsNumberGreaterThanZero,
+ validator: numberGreaterThanField({
+ than: 0,
+ allowEquality: true,
+ message: i18nTexts.editPolicy.errors.positiveNumberRequired,
+ }),
},
],
},
@@ -161,10 +169,14 @@ export const schema: FormSchema = {
validator: ifExistsNumberGreaterThanZero,
},
],
+ serializer: serializers.stringToNumber,
},
},
shrink: {
number_of_shards: {
+ label: i18n.translate('xpack.indexLifecycleMgmt.warmPhase.numberOfPrimaryShardsLabel', {
+ defaultMessage: 'Number of primary shards',
+ }),
validations: [
{
validator: emptyField(i18nTexts.editPolicy.errors.numberRequired),
@@ -176,6 +188,7 @@ export const schema: FormSchema = {
}),
},
],
+ serializer: serializers.stringToNumber,
},
},
forcemerge: {
@@ -194,7 +207,7 @@ export const schema: FormSchema = {
validator: ifExistsNumberGreaterThanZero,
},
],
- serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ serializer: serializers.stringToNumber,
},
},
set_priority: {
@@ -202,7 +215,7 @@ export const schema: FormSchema = {
defaultValue: '50' as any,
label: i18nTexts.editPolicy.setPriorityFieldLabel,
validations: [{ validator: ifExistsNumberGreaterThanZero }],
- serializer: (v: string): any => (v ? parseInt(v, 10) : undefined),
+ serializer: serializers.stringToNumber,
},
},
},
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
index 71031d1801ee6a..245c129db47433 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
@@ -92,6 +92,12 @@ export const i18nTexts = {
}
),
},
+ positiveNumberRequired: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.positiveNumberRequiredError',
+ {
+ defaultMessage: 'Only positive numbers are allowed.',
+ }
+ ),
},
},
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
index e0e1ad44f15571..4ebb33be7647ec 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
@@ -4,40 +4,117 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { SerializedPolicy } from '../../../../common/types';
+import { isEmpty } from 'lodash';
-import { FormInternal } from './types';
+import { AllocateAction, SerializedPhase, SerializedPolicy } from '../../../../common/types';
+
+import { FormInternal, DataAllocationMetaFields } from './types';
+import { isNumber } from '../../services/policies/policy_serialization';
+
+const unsafeSerializePhaseWithAllocation = (
+ dataAllocationMetaFields: DataAllocationMetaFields,
+ actions: SerializedPhase['actions'] = {},
+ originalAllocation: AllocateAction = {}
+) => {
+ if (
+ dataAllocationMetaFields.dataTierAllocationType === 'node_attrs' &&
+ dataAllocationMetaFields.allocationNodeAttribute &&
+ dataAllocationMetaFields.allocationNodeAttribute !== 'none'
+ ) {
+ const [name, value] = dataAllocationMetaFields.allocationNodeAttribute.split(':');
+ actions.allocate = {
+ require: {
+ [name]: value,
+ },
+ // copy over the original include and exclude values until we can set them in the form.
+ include: !isEmpty(originalAllocation.include) ? { ...originalAllocation.include } : undefined,
+ exclude: !isEmpty(originalAllocation.exclude) ? { ...originalAllocation.exclude } : undefined,
+ };
+ } else if (dataAllocationMetaFields.dataTierAllocationType === 'none') {
+ actions.migrate = { enabled: false };
+ delete actions.allocate;
+ } else if (dataAllocationMetaFields.dataTierAllocationType === 'node_roles') {
+ if (actions.allocate) {
+ delete actions.allocate.require;
+ delete actions.allocate.include;
+ delete actions.allocate.exclude;
+ }
+ delete actions.migrate;
+ }
+};
export const createSerializer = (originalPolicy?: SerializedPolicy) => (
data: FormInternal
): SerializedPolicy => {
- const { _meta, ...rest } = data;
+ const { _meta, ...policy } = data;
- if (!rest.phases || !rest.phases.hot) {
- rest.phases = { hot: { actions: {} } };
+ if (!policy.phases || !policy.phases.hot) {
+ policy.phases = { hot: { actions: {} } };
}
- if (rest.phases.hot) {
- rest.phases.hot.min_age = originalPolicy?.phases.hot?.min_age ?? '0ms';
+ /**
+ * HOT PHASE SERIALIZATION
+ */
+ if (policy.phases.hot) {
+ policy.phases.hot.min_age = originalPolicy?.phases.hot?.min_age ?? '0ms';
}
- if (rest.phases.hot?.actions) {
- if (rest.phases.hot.actions?.rollover && _meta.hot.useRollover) {
- if (rest.phases.hot.actions.rollover.max_age) {
- rest.phases.hot.actions.rollover.max_age = `${rest.phases.hot.actions.rollover.max_age}${_meta.hot.maxAgeUnit}`;
+ if (policy.phases.hot?.actions) {
+ if (policy.phases.hot.actions?.rollover && _meta.hot.useRollover) {
+ if (policy.phases.hot.actions.rollover.max_age) {
+ policy.phases.hot.actions.rollover.max_age = `${policy.phases.hot.actions.rollover.max_age}${_meta.hot.maxAgeUnit}`;
}
- if (rest.phases.hot.actions.rollover.max_size) {
- rest.phases.hot.actions.rollover.max_size = `${rest.phases.hot.actions.rollover.max_size}${_meta.hot.maxStorageSizeUnit}`;
+ if (policy.phases.hot.actions.rollover.max_size) {
+ policy.phases.hot.actions.rollover.max_size = `${policy.phases.hot.actions.rollover.max_size}${_meta.hot.maxStorageSizeUnit}`;
}
- if (_meta.hot.bestCompression && rest.phases.hot.actions?.forcemerge) {
- rest.phases.hot.actions.forcemerge.index_codec = 'best_compression';
+ if (_meta.hot.bestCompression && policy.phases.hot.actions?.forcemerge) {
+ policy.phases.hot.actions.forcemerge.index_codec = 'best_compression';
}
} else {
- delete rest.phases.hot.actions?.rollover;
+ delete policy.phases.hot.actions?.rollover;
+ }
+ }
+
+ /**
+ * WARM PHASE SERIALIZATION
+ */
+ if (policy.phases.warm) {
+ // If warm phase on rollover is enabled, delete min age field
+ // An index lifecycle switches to warm phase when rollover occurs, so you cannot specify a warm phase time
+ // They are mutually exclusive
+ if (_meta.hot.useRollover && _meta.warm.warmPhaseOnRollover) {
+ delete policy.phases.warm.min_age;
+ } else if (
+ (!_meta.hot.useRollover || !_meta.warm.warmPhaseOnRollover) &&
+ policy.phases.warm.min_age
+ ) {
+ policy.phases.warm.min_age = `${policy.phases.warm.min_age}${_meta.warm.minAgeUnit}`;
+ }
+
+ unsafeSerializePhaseWithAllocation(
+ _meta.warm,
+ policy.phases.warm.actions,
+ originalPolicy?.phases.warm?.actions.allocate
+ );
+
+ if (
+ policy.phases.warm.actions.allocate &&
+ !policy.phases.warm.actions.allocate.require &&
+ !isNumber(policy.phases.warm.actions.allocate.number_of_replicas) &&
+ isEmpty(policy.phases.warm.actions.allocate.include) &&
+ isEmpty(policy.phases.warm.actions.allocate.exclude)
+ ) {
+ // remove allocate action if it does not define require or number of nodes
+ // and both include and exclude are empty objects (ES will fail to parse if we don't)
+ delete policy.phases.warm.actions.allocate;
+ }
+
+ if (_meta.warm.bestCompression && policy.phases.warm.actions?.forcemerge) {
+ policy.phases.warm.actions.forcemerge.index_codec = 'best_compression';
}
}
- return rest;
+ return policy;
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
index 98333b5973dc2f..6fcfbd050c69d0 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/types.ts
@@ -8,6 +8,27 @@ import { SerializedPolicy } from '../../../../common/types';
export type DataTierAllocationType = 'node_roles' | 'node_attrs' | 'none';
+export interface DataAllocationMetaFields {
+ dataTierAllocationType: DataTierAllocationType;
+ allocationNodeAttribute?: string;
+}
+
+interface HotPhaseMetaFields {
+ useRollover: boolean;
+ forceMergeEnabled: boolean;
+ bestCompression: boolean;
+ maxStorageSizeUnit?: string;
+ maxAgeUnit?: string;
+}
+
+interface WarmPhaseMetaFields extends DataAllocationMetaFields {
+ enabled: boolean;
+ forceMergeEnabled: boolean;
+ bestCompression: boolean;
+ warmPhaseOnRollover: boolean;
+ minAgeUnit?: string;
+}
+
/**
* Describes the shape of data after deserialization.
*/
@@ -17,21 +38,7 @@ export interface FormInternal extends SerializedPolicy {
* certain form fields which affects what is ultimately serialized.
*/
_meta: {
- hot: {
- useRollover: boolean;
- forceMergeEnabled: boolean;
- bestCompression: boolean;
- maxStorageSizeUnit?: string;
- maxAgeUnit?: string;
- };
- warm: {
- enabled: boolean;
- forceMergeEnabled: boolean;
- bestCompression: boolean;
- warmPhaseOnRollover: boolean;
- dataTierAllocationType: DataTierAllocationType;
- allocationNodeAttribute?: string;
- minAgeUnit?: string;
- };
+ hot: HotPhaseMetaFields;
+ warm: WarmPhaseMetaFields;
};
}
From 98bf14b2790dc155081ac9b06df540e69ec44c3e Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 12:45:36 +0200
Subject: [PATCH 06/19] Remove last vestiges of legacy warm phase
- also removed policy serialization tests for warm phase
---
.../common/types/policies.ts | 12 -
.../public/application/constants/policy.ts | 24 +-
.../phases/warm_phase/warm_phase.tsx | 11 +-
.../policies/policy_serialization.test.ts | 168 +------------
.../services/policies/policy_serialization.ts | 7 -
.../services/policies/policy_validation.ts | 16 +-
.../services/policies/warm_phase.ts | 230 ------------------
.../public/application/services/ui_metric.ts | 1 -
8 files changed, 10 insertions(+), 459 deletions(-)
delete mode 100644 x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
index c2d2c22424666d..9e97f982e87b9a 100644
--- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
+++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
@@ -110,7 +110,6 @@ export interface ForcemergeAction {
export interface LegacyPolicy {
name: string;
phases: {
- warm: WarmPhase;
cold: ColdPhase;
delete: DeletePhase;
};
@@ -154,17 +153,6 @@ export interface PhaseWithForcemergeAction {
bestCompressionEnabled: boolean;
}
-export interface WarmPhase
- extends CommonPhaseSettings,
- PhaseWithMinAge,
- PhaseWithAllocationAction,
- PhaseWithIndexPriority,
- PhaseWithForcemergeAction {
- warmPhaseOnRollover: boolean;
- shrinkEnabled: boolean;
- selectedPrimaryShardCount: string;
-}
-
export interface ColdPhase
extends CommonPhaseSettings,
PhaseWithMinAge,
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts b/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
index c919331082ec34..473e6307f2a633 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
@@ -4,13 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import {
- SerializedPhase,
- ColdPhase,
- DeletePhase,
- WarmPhase,
- SerializedPolicy,
-} from '../../../common/types';
+import { SerializedPhase, ColdPhase, DeletePhase, SerializedPolicy } from '../../../common/types';
export const defaultSetPriority: string = '100';
@@ -28,22 +22,6 @@ export const defaultPolicy: SerializedPolicy = {
},
};
-export const defaultNewWarmPhase: WarmPhase = {
- phaseEnabled: false,
- forceMergeEnabled: false,
- selectedForceMergeSegments: '',
- bestCompressionEnabled: false,
- selectedMinimumAge: '0',
- selectedMinimumAgeUnits: 'd',
- selectedNodeAttrs: '',
- shrinkEnabled: false,
- selectedPrimaryShardCount: '',
- selectedReplicaCount: '',
- warmPhaseOnRollover: true,
- phaseIndexPriority: '50',
- dataTierAllocationType: 'default',
-};
-
export const defaultNewColdPhase: ColdPhase = {
phaseEnabled: false,
selectedMinimumAge: '0',
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
index 3c028c7be87887..b13e867a0b1faf 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
@@ -24,7 +24,7 @@ import {
NumericField,
} from '../../../../../../shared_imports';
-import { Phases, WarmPhase as WarmPhaseInterface } from '../../../../../../../common/types';
+import { Phases } from '../../../../../../../common/types';
import { useRolloverPath, MinAgeInputField, Forcemerge, SetPriorityInput } from '../shared';
@@ -46,7 +46,6 @@ const i18nTexts = {
};
const warmProperty: keyof Phases = 'warm';
-const phaseProperty = (propertyName: keyof WarmPhaseInterface) => propertyName;
export const WarmPhase: FunctionComponent = () => {
const { originalPolicy } = useEditPolicyContext();
@@ -112,7 +111,7 @@ export const WarmPhase: FunctionComponent = () => {
componentProps={{
fullWidth: false,
euiFieldProps: {
- 'data-test-subj': `${warmProperty}-${phaseProperty('warmPhaseOnRollover')}`,
+ 'data-test-subj': `${warmProperty}-warmPhaseOnRollover`,
},
}}
/>
@@ -168,7 +167,7 @@ export const WarmPhase: FunctionComponent = () => {
componentProps={{
fullWidth: false,
euiFieldProps: {
- 'data-test-subj': `${warmProperty}-${phaseProperty('selectedReplicaCount')}`,
+ 'data-test-subj': `${warmProperty}-selectedReplicaCount}`,
min: 0,
},
}}
@@ -211,9 +210,7 @@ export const WarmPhase: FunctionComponent = () => {
component={NumericField}
componentProps={{
euiFieldProps: {
- 'data-test-subj': `${warmProperty}-${phaseProperty(
- 'selectedPrimaryShardCount'
- )}`,
+ 'data-test-subj': `${warmProperty}-selectedPrimaryShardCount`,
min: 1,
},
}}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.test.ts
index 5c7f04986827b4..0be6ab35217360 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.test.ts
@@ -7,7 +7,7 @@
// eslint-disable-next-line no-restricted-imports
import cloneDeep from 'lodash/cloneDeep';
import { deserializePolicy, legacySerializePolicy } from './policy_serialization';
-import { defaultNewColdPhase, defaultNewDeletePhase, defaultNewWarmPhase } from '../../constants';
+import { defaultNewColdPhase, defaultNewDeletePhase } from '../../constants';
import { DataTierAllocationType } from '../../../../common/types';
import { coldPhaseInitialization } from './cold_phase';
@@ -18,13 +18,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- dataTierAllocationType: 'default',
- // These selected attrs should be ignored
- selectedNodeAttrs: 'another:thing',
- phaseEnabled: true,
- },
cold: {
...defaultNewColdPhase,
dataTierAllocationType: 'default',
@@ -38,9 +31,6 @@ describe('Policy serialization', () => {
name: 'test',
phases: {
hot: { actions: {} },
- warm: {
- actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
- },
cold: {
actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
},
@@ -50,13 +40,6 @@ describe('Policy serialization', () => {
).toEqual({
name: 'test',
phases: {
- warm: {
- actions: {
- set_priority: {
- priority: 50,
- },
- },
- },
cold: {
actions: {
set_priority: {
@@ -75,12 +58,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- dataTierAllocationType: 'custom',
- selectedNodeAttrs: 'another:thing',
- phaseEnabled: true,
- },
cold: {
...defaultNewColdPhase,
dataTierAllocationType: 'custom',
@@ -94,15 +71,6 @@ describe('Policy serialization', () => {
name: 'test',
phases: {
hot: { actions: {} },
- warm: {
- actions: {
- allocate: {
- include: { keep: 'this' },
- exclude: { keep: 'this' },
- require: { something: 'here' },
- },
- },
- },
cold: {
actions: {
allocate: {
@@ -118,20 +86,6 @@ describe('Policy serialization', () => {
).toEqual({
name: 'test',
phases: {
- warm: {
- actions: {
- allocate: {
- include: { keep: 'this' },
- exclude: { keep: 'this' },
- require: {
- another: 'thing',
- },
- },
- set_priority: {
- priority: 50,
- },
- },
- },
cold: {
actions: {
allocate: {
@@ -157,12 +111,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- dataTierAllocationType: 'custom',
- selectedNodeAttrs: '',
- phaseEnabled: true,
- },
cold: {
...defaultNewColdPhase,
dataTierAllocationType: 'custom',
@@ -176,9 +124,6 @@ describe('Policy serialization', () => {
name: 'test',
phases: {
hot: { actions: {} },
- warm: {
- actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
- },
cold: {
actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
},
@@ -189,14 +134,6 @@ describe('Policy serialization', () => {
// There should be no allocation action in any phases...
name: 'test',
phases: {
- warm: {
- actions: {
- allocate: { include: {}, exclude: {}, require: { something: 'here' } },
- set_priority: {
- priority: 50,
- },
- },
- },
cold: {
actions: {
allocate: { include: {}, exclude: {}, require: { something: 'here' } },
@@ -216,12 +153,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- dataTierAllocationType: 'none',
- selectedNodeAttrs: 'ignore:this',
- phaseEnabled: true,
- },
cold: {
...defaultNewColdPhase,
dataTierAllocationType: 'none',
@@ -235,9 +166,6 @@ describe('Policy serialization', () => {
name: 'test',
phases: {
hot: { actions: {} },
- warm: {
- actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
- },
cold: {
actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
},
@@ -248,16 +176,6 @@ describe('Policy serialization', () => {
// There should be no allocation action in any phases...
name: 'test',
phases: {
- warm: {
- actions: {
- migrate: {
- enabled: false,
- },
- set_priority: {
- priority: 50,
- },
- },
- },
cold: {
actions: {
migrate: {
@@ -277,9 +195,6 @@ describe('Policy serialization', () => {
const originalPolicy = {
name: 'test',
phases: {
- warm: {
- actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
- },
cold: {
actions: { allocate: { include: {}, exclude: {}, require: { something: 'here' } } },
},
@@ -291,12 +206,6 @@ describe('Policy serialization', () => {
const deserializedPolicy = {
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- dataTierAllocationType: 'none' as DataTierAllocationType,
- selectedNodeAttrs: 'ignore:this',
- phaseEnabled: true,
- },
cold: {
...defaultNewColdPhase,
dataTierAllocationType: 'none' as DataTierAllocationType,
@@ -308,10 +217,6 @@ describe('Policy serialization', () => {
},
};
- legacySerializePolicy(deserializedPolicy, originalPolicy);
- deserializedPolicy.phases.warm.dataTierAllocationType = 'custom';
- legacySerializePolicy(deserializedPolicy, originalPolicy);
- deserializedPolicy.phases.warm.dataTierAllocationType = 'default';
legacySerializePolicy(deserializedPolicy, originalPolicy);
expect(originalPolicy).toEqual(originalClone);
});
@@ -322,13 +227,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- phaseEnabled: true,
- forceMergeEnabled: true,
- selectedForceMergeSegments: '1',
- bestCompressionEnabled: true,
- },
cold: {
...defaultNewColdPhase,
},
@@ -344,19 +242,7 @@ describe('Policy serialization', () => {
)
).toEqual({
name: 'test',
- phases: {
- warm: {
- actions: {
- forcemerge: {
- max_num_segments: 1,
- index_codec: 'best_compression',
- },
- set_priority: {
- priority: 50,
- },
- },
- },
- },
+ phases: {},
});
});
@@ -384,31 +270,12 @@ describe('Policy serialization', () => {
},
},
},
- warm: {
- actions: {
- forcemerge: {
- max_num_segments: 1,
- index_codec: 'best_compression',
- },
- set_priority: {
- priority: 50,
- },
- },
- },
},
},
})
).toEqual({
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- warmPhaseOnRollover: false,
- phaseEnabled: true,
- forceMergeEnabled: true,
- selectedForceMergeSegments: '1',
- bestCompressionEnabled: true,
- },
cold: {
...coldPhaseInitialization,
},
@@ -423,13 +290,6 @@ describe('Policy serialization', () => {
{
name: 'test',
phases: {
- warm: {
- ...defaultNewWarmPhase,
- phaseEnabled: true,
- forceMergeEnabled: true,
- selectedForceMergeSegments: '1',
- bestCompressionEnabled: false,
- },
cold: {
...defaultNewColdPhase,
},
@@ -438,32 +298,12 @@ describe('Policy serialization', () => {
},
{
name: 'test',
- phases: {
- warm: {
- actions: {
- forcemerge: {
- max_num_segments: 1,
- index_codec: 'best_compression',
- },
- },
- },
- },
+ phases: {},
}
)
).toEqual({
name: 'test',
- phases: {
- warm: {
- actions: {
- forcemerge: {
- max_num_segments: 1,
- },
- set_priority: {
- priority: 50,
- },
- },
- },
- },
+ phases: {},
});
});
});
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.ts
index 0dce7efce46236..32c7e698b09203 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_serialization.ts
@@ -9,11 +9,9 @@ import { LegacyPolicy, PolicyFromES, SerializedPolicy } from '../../../../common
import {
defaultNewColdPhase,
defaultNewDeletePhase,
- defaultNewWarmPhase,
serializedPhaseInitialization,
} from '../../constants';
-import { warmPhaseFromES, warmPhaseToES } from './warm_phase';
import { coldPhaseFromES, coldPhaseToES } from './cold_phase';
import { deletePhaseFromES, deletePhaseToES } from './delete_phase';
@@ -48,7 +46,6 @@ export const initializeNewPolicy = (newPolicyName: string = ''): LegacyPolicy =>
return {
name: newPolicyName,
phases: {
- warm: { ...defaultNewWarmPhase },
cold: { ...defaultNewColdPhase },
delete: { ...defaultNewDeletePhase },
},
@@ -64,7 +61,6 @@ export const deserializePolicy = (policy: PolicyFromES): LegacyPolicy => {
return {
name,
phases: {
- warm: warmPhaseFromES(phases.warm),
cold: coldPhaseFromES(phases.cold),
delete: deletePhaseFromES(phases.delete),
},
@@ -82,9 +78,6 @@ export const legacySerializePolicy = (
name: policy.name,
phases: {},
} as SerializedPolicy;
- if (policy.phases.warm.phaseEnabled) {
- serializedPolicy.phases.warm = warmPhaseToES(policy.phases.warm, originalEsPolicy.phases.warm);
- }
if (policy.phases.cold.phaseEnabled) {
serializedPolicy.phases.cold = coldPhaseToES(policy.phases.cold, originalEsPolicy.phases.cold);
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_validation.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_validation.ts
index eeceb97c409f55..a113cb68a23496 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_validation.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/policy_validation.ts
@@ -5,14 +5,7 @@
*/
import { i18n } from '@kbn/i18n';
-import {
- ColdPhase,
- DeletePhase,
- LegacyPolicy,
- PolicyFromES,
- WarmPhase,
-} from '../../../../common/types';
-import { validateWarmPhase } from './warm_phase';
+import { ColdPhase, DeletePhase, LegacyPolicy, PolicyFromES } from '../../../../common/types';
import { validateColdPhase } from './cold_phase';
import { validateDeletePhase } from './delete_phase';
@@ -89,7 +82,6 @@ export type PhaseValidationErrors = {
};
export interface ValidationErrors {
- warm: PhaseValidationErrors;
cold: PhaseValidationErrors;
delete: PhaseValidationErrors;
policyName: string[];
@@ -128,19 +120,16 @@ export const validatePolicy = (
}
}
- const warmPhaseErrors = validateWarmPhase(policy.phases.warm);
const coldPhaseErrors = validateColdPhase(policy.phases.cold);
const deletePhaseErrors = validateDeletePhase(policy.phases.delete);
const isValid =
policyNameErrors.length === 0 &&
- Object.keys(warmPhaseErrors).length === 0 &&
Object.keys(coldPhaseErrors).length === 0 &&
Object.keys(deletePhaseErrors).length === 0;
return [
isValid,
{
policyName: [...policyNameErrors],
- warm: warmPhaseErrors,
cold: coldPhaseErrors,
delete: deletePhaseErrors,
},
@@ -156,9 +145,6 @@ export const findFirstError = (errors?: ValidationErrors): string | undefined =>
return propertyof('policyName');
}
- if (Object.keys(errors.warm).length > 0) {
- return `${propertyof('warm')}.${Object.keys(errors.warm)[0]}`;
- }
if (Object.keys(errors.cold).length > 0) {
return `${propertyof('cold')}.${Object.keys(errors.cold)[0]}`;
}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
deleted file mode 100644
index a5a6fa6abe47b0..00000000000000
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/warm_phase.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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 { isEmpty } from 'lodash';
-import { AllocateAction, WarmPhase, SerializedWarmPhase } from '../../../../common/types';
-import { serializedPhaseInitialization } from '../../constants';
-import { isNumber, splitSizeAndUnits } from './policy_serialization';
-
-import {
- numberRequiredMessage,
- PhaseValidationErrors,
- positiveNumberRequiredMessage,
- positiveNumbersAboveZeroErrorMessage,
-} from './policy_validation';
-
-import { determineDataTierAllocationTypeLegacy } from '../../lib';
-import { serializePhaseWithAllocation } from './shared';
-
-const warmPhaseInitialization: WarmPhase = {
- phaseEnabled: false,
- warmPhaseOnRollover: false,
- selectedMinimumAge: '0',
- selectedMinimumAgeUnits: 'd',
- selectedNodeAttrs: '',
- selectedReplicaCount: '',
- shrinkEnabled: false,
- selectedPrimaryShardCount: '',
- forceMergeEnabled: false,
- selectedForceMergeSegments: '',
- bestCompressionEnabled: false,
- phaseIndexPriority: '',
- dataTierAllocationType: 'default',
-};
-
-export const warmPhaseFromES = (phaseSerialized?: SerializedWarmPhase): WarmPhase => {
- const phase: WarmPhase = { ...warmPhaseInitialization };
-
- if (phaseSerialized === undefined || phaseSerialized === null) {
- return phase;
- }
-
- phase.phaseEnabled = true;
-
- if (phaseSerialized.actions.allocate) {
- phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(
- phaseSerialized.actions.allocate
- );
- }
-
- if (phaseSerialized.min_age) {
- if (phaseSerialized.min_age === '0ms') {
- phase.warmPhaseOnRollover = true;
- } else {
- const { size: minAge, units: minAgeUnits } = splitSizeAndUnits(phaseSerialized.min_age);
- phase.selectedMinimumAge = minAge;
- phase.selectedMinimumAgeUnits = minAgeUnits;
- }
- }
- if (phaseSerialized.actions) {
- const actions = phaseSerialized.actions;
- if (actions.allocate) {
- const allocate = actions.allocate;
- if (allocate.require) {
- Object.entries(allocate.require).forEach((entry) => {
- phase.selectedNodeAttrs = entry.join(':');
- });
- if (allocate.number_of_replicas) {
- phase.selectedReplicaCount = allocate.number_of_replicas.toString();
- }
- }
- }
-
- if (actions.forcemerge) {
- const forcemerge = actions.forcemerge;
- phase.forceMergeEnabled = true;
- phase.selectedForceMergeSegments = forcemerge.max_num_segments.toString();
- // only accepted value for index_codec
- phase.bestCompressionEnabled = forcemerge.index_codec === 'best_compression';
- }
-
- if (actions.shrink) {
- phase.shrinkEnabled = true;
- phase.selectedPrimaryShardCount = actions.shrink.number_of_shards
- ? actions.shrink.number_of_shards.toString()
- : '';
- }
-
- if (actions.set_priority) {
- phase.phaseIndexPriority = actions.set_priority.priority
- ? actions.set_priority.priority.toString()
- : '';
- }
- }
- return phase;
-};
-
-export const warmPhaseToES = (
- phase: WarmPhase,
- originalEsPhase?: SerializedWarmPhase
-): SerializedWarmPhase => {
- if (!originalEsPhase) {
- originalEsPhase = { ...serializedPhaseInitialization };
- }
-
- const esPhase = { ...originalEsPhase };
-
- if (isNumber(phase.selectedMinimumAge)) {
- esPhase.min_age = `${phase.selectedMinimumAge}${phase.selectedMinimumAgeUnits}`;
- }
-
- // If warm phase on rollover is enabled, delete min age field
- // An index lifecycle switches to warm phase when rollover occurs, so you cannot specify a warm phase time
- // They are mutually exclusive
- if (phase.warmPhaseOnRollover) {
- delete esPhase.min_age;
- }
-
- esPhase.actions = serializePhaseWithAllocation(phase, esPhase.actions);
-
- if (isNumber(phase.selectedReplicaCount)) {
- esPhase.actions.allocate = esPhase.actions.allocate || ({} as AllocateAction);
- esPhase.actions.allocate.number_of_replicas = parseInt(phase.selectedReplicaCount, 10);
- } else {
- if (esPhase.actions.allocate) {
- delete esPhase.actions.allocate.number_of_replicas;
- }
- }
-
- if (
- esPhase.actions.allocate &&
- !esPhase.actions.allocate.require &&
- !isNumber(esPhase.actions.allocate.number_of_replicas) &&
- isEmpty(esPhase.actions.allocate.include) &&
- isEmpty(esPhase.actions.allocate.exclude)
- ) {
- // remove allocate action if it does not define require or number of nodes
- // and both include and exclude are empty objects (ES will fail to parse if we don't)
- delete esPhase.actions.allocate;
- }
-
- if (phase.forceMergeEnabled) {
- esPhase.actions.forcemerge = {
- max_num_segments: parseInt(phase.selectedForceMergeSegments, 10),
- };
- if (phase.bestCompressionEnabled) {
- // only accepted value for index_codec
- esPhase.actions.forcemerge.index_codec = 'best_compression';
- }
- } else {
- delete esPhase.actions.forcemerge;
- }
-
- if (phase.shrinkEnabled && isNumber(phase.selectedPrimaryShardCount)) {
- esPhase.actions.shrink = {
- number_of_shards: parseInt(phase.selectedPrimaryShardCount, 10),
- };
- } else {
- delete esPhase.actions.shrink;
- }
-
- if (isNumber(phase.phaseIndexPriority)) {
- esPhase.actions.set_priority = {
- priority: parseInt(phase.phaseIndexPriority, 10),
- };
- } else {
- delete esPhase.actions.set_priority;
- }
-
- return esPhase;
-};
-
-export const validateWarmPhase = (phase: WarmPhase): PhaseValidationErrors => {
- if (!phase.phaseEnabled) {
- return {};
- }
-
- const phaseErrors = {} as PhaseValidationErrors;
-
- // index priority is optional, but if it's set, it needs to be a positive number
- if (phase.phaseIndexPriority) {
- if (!isNumber(phase.phaseIndexPriority)) {
- phaseErrors.phaseIndexPriority = [numberRequiredMessage];
- } else if (parseInt(phase.phaseIndexPriority, 10) < 0) {
- phaseErrors.phaseIndexPriority = [positiveNumberRequiredMessage];
- }
- }
-
- // if warm phase on rollover is disabled, min age needs to be a positive number
- if (!phase.warmPhaseOnRollover) {
- if (!isNumber(phase.selectedMinimumAge)) {
- phaseErrors.selectedMinimumAge = [numberRequiredMessage];
- } else if (parseInt(phase.selectedMinimumAge, 10) < 0) {
- phaseErrors.selectedMinimumAge = [positiveNumberRequiredMessage];
- }
- }
-
- // 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];
- }
- }
-
- // if shrink is enabled, primary shard count needs to be a number above zero
- if (phase.shrinkEnabled) {
- if (!isNumber(phase.selectedPrimaryShardCount)) {
- phaseErrors.selectedPrimaryShardCount = [numberRequiredMessage];
- } else if (parseInt(phase.selectedPrimaryShardCount, 10) < 1) {
- phaseErrors.selectedPrimaryShardCount = [positiveNumbersAboveZeroErrorMessage];
- }
- }
-
- // replica count is optional, but if it's set, it needs to be a positive number
- if (phase.selectedReplicaCount) {
- if (!isNumber(phase.selectedReplicaCount)) {
- phaseErrors.selectedReplicaCount = [numberRequiredMessage];
- } else if (parseInt(phase.selectedReplicaCount, 10) < 0) {
- phaseErrors.selectedReplicaCount = [numberRequiredMessage];
- }
- }
-
- return {
- ...phaseErrors,
- };
-};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
index ea5c5619da5899..ec811e29839045 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
@@ -14,7 +14,6 @@ import {
UIM_CONFIG_SET_PRIORITY,
UIM_CONFIG_WARM_PHASE,
defaultNewColdPhase,
- defaultNewWarmPhase,
defaultSetPriority,
} from '../constants';
From 01214116b099557ac921114964ae2b9a63354e71 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 13:52:18 +0200
Subject: [PATCH 07/19] fix existing test coverage and remove use of "none" for
node attribute
---
.../__jest__/components/edit_policy.test.tsx | 195 ++++++++++--------
.../public/application/constants/policy.ts | 2 +
.../components/node_allocation.tsx | 3 +-
.../sections/edit_policy/form_schema.ts | 19 +-
.../sections/edit_policy/i18n_texts.ts | 20 +-
.../sections/edit_policy/serializer.ts | 3 +-
.../application/services/ui_metric.test.ts | 6 +-
.../public/application/services/ui_metric.ts | 4 +-
8 files changed, 137 insertions(+), 115 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx
index d9af20763657b3..9d31480fb42c7c 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx
@@ -30,9 +30,7 @@ import { init as initUiMetric } from '../../public/application/services/ui_metri
import { init as initNotification } from '../../public/application/services/notification';
import { PolicyFromES } from '../../common/types';
import {
- positiveNumbersAboveZeroErrorMessage,
positiveNumberRequiredMessage,
- numberRequiredMessage,
policyNameRequiredMessage,
policyNameStartsWithUnderscoreErrorMessage,
policyNameContainsCommaErrorMessage,
@@ -40,6 +38,8 @@ import {
policyNameMustBeDifferentErrorMessage,
policyNameAlreadyUsedErrorMessage,
} from '../../public/application/services/policies/policy_validation';
+
+import { i18nTexts } from '../../public/application/sections/edit_policy/i18n_texts';
import { editPolicyHelpers } from './helpers';
// @ts-ignore
@@ -89,13 +89,13 @@ const activatePhase = async (rendered: ReactWrapper, phase: string) => {
});
rendered.update();
};
-const openNodeAttributesSection = (rendered: ReactWrapper, phase: string) => {
+const openNodeAttributesSection = async (rendered: ReactWrapper, phase: string) => {
const getControls = () => findTestSubject(rendered, `${phase}-dataTierAllocationControls`);
- act(() => {
+ await act(async () => {
findTestSubject(getControls(), 'dataTierSelect').simulate('click');
});
rendered.update();
- act(() => {
+ await act(async () => {
findTestSubject(getControls(), 'customDataAllocationOption').simulate('click');
});
rendered.update();
@@ -119,19 +119,29 @@ const noRollover = async (rendered: ReactWrapper) => {
});
rendered.update();
};
-const getNodeAttributeSelect = (rendered: ReactWrapper, phase: string) => {
+const getNodeAttributeSelectLegacy = (rendered: ReactWrapper, phase: string) => {
return rendered.find(`select#${phase}-selectedNodeAttrs`);
};
+const getNodeAttributeSelect = (rendered: ReactWrapper, phase: string) => {
+ return findTestSubject(rendered, `${phase}-selectedNodeAttrs`);
+};
const setPolicyName = (rendered: ReactWrapper, policyName: string) => {
const policyNameField = findTestSubject(rendered, 'policyNameField');
policyNameField.simulate('change', { target: { value: policyName } });
rendered.update();
};
-const setPhaseAfter = (rendered: ReactWrapper, phase: string, after: string | number) => {
+const setPhaseAfterLegacy = (rendered: ReactWrapper, phase: string, after: string | number) => {
const afterInput = rendered.find(`input#${phase}-selectedMinimumAge`);
afterInput.simulate('change', { target: { value: after } });
rendered.update();
};
+const setPhaseAfter = async (rendered: ReactWrapper, phase: string, after: string | number) => {
+ const afterInput = findTestSubject(rendered, `${phase}-selectedMinimumAge`);
+ await act(async () => {
+ afterInput.simulate('change', { target: { value: after } });
+ });
+ rendered.update();
+};
const setPhaseIndexPriorityLegacy = (
rendered: ReactWrapper,
phase: string,
@@ -172,10 +182,11 @@ describe('edit policy', () => {
* any validation errors. This helper advances timers and can trigger component
* state changes.
*/
- const waitForFormLibValidation = () => {
+ const waitForFormLibValidation = (rendered: ReactWrapper) => {
act(() => {
jest.advanceTimersByTime(1000);
});
+ rendered.update();
};
beforeEach(() => {
@@ -288,13 +299,12 @@ describe('edit policy', () => {
await act(async () => {
maxSizeInput.simulate('change', { target: { value: '' } });
});
- waitForFormLibValidation();
+ waitForFormLibValidation(rendered);
const maxAgeInput = findTestSubject(rendered, 'hot-selectedMaxAge');
await act(async () => {
maxAgeInput.simulate('change', { target: { value: '' } });
});
- waitForFormLibValidation();
- rendered.update();
+ waitForFormLibValidation(rendered);
await save(rendered);
expect(findTestSubject(rendered, 'rolloverSettingsRequired').exists()).toBeTruthy();
});
@@ -305,9 +315,9 @@ describe('edit policy', () => {
await act(async () => {
maxSizeInput.simulate('change', { target: { value: '-1' } });
});
- waitForFormLibValidation();
+ waitForFormLibValidation(rendered);
rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show number above 0 required error when trying to save with 0 for max size', async () => {
const rendered = mountWithIntl(component);
@@ -316,9 +326,8 @@ describe('edit policy', () => {
await act(async () => {
maxSizeInput.simulate('change', { target: { value: '-1' } });
});
- waitForFormLibValidation();
- rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show number above 0 required error when trying to save with -1 for max age', async () => {
const rendered = mountWithIntl(component);
@@ -327,9 +336,8 @@ describe('edit policy', () => {
await act(async () => {
maxAgeInput.simulate('change', { target: { value: '-1' } });
});
- waitForFormLibValidation();
- rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show number above 0 required error when trying to save with 0 for max age', async () => {
const rendered = mountWithIntl(component);
@@ -338,9 +346,8 @@ describe('edit policy', () => {
await act(async () => {
maxAgeInput.simulate('change', { target: { value: '0' } });
});
- waitForFormLibValidation();
- rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show forcemerge input when rollover enabled', () => {
const rendered = mountWithIntl(component);
@@ -351,8 +358,7 @@ describe('edit policy', () => {
const rendered = mountWithIntl(component);
setPolicyName(rendered, 'mypolicy');
await noRollover(rendered);
- waitForFormLibValidation();
- rendered.update();
+ waitForFormLibValidation(rendered);
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 () => {
@@ -366,9 +372,8 @@ describe('edit policy', () => {
await act(async () => {
forcemergeInput.simulate('change', { target: { value: '0' } });
});
- waitForFormLibValidation();
- rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
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);
@@ -379,19 +384,17 @@ describe('edit policy', () => {
await act(async () => {
forcemergeInput.simulate('change', { target: { value: '-1' } });
});
- waitForFormLibValidation();
- rendered.update();
+ waitForFormLibValidation(rendered);
await save(rendered);
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show positive number required error when trying to save with -1 for index priority', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await setPhaseIndexPriority(rendered, 'hot', '-1');
- waitForFormLibValidation();
- rendered.update();
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
});
describe('warm phase', () => {
@@ -408,17 +411,17 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '');
- await save(rendered);
- expectedErrorMessages(rendered, [numberRequiredMessage]);
+ await setPhaseAfter(rendered, 'warm', '');
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.nonNegativeNumberRequired]);
});
test('should allow 0 for phase timing', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '0');
- await save(rendered);
+ await setPhaseAfter(rendered, 'warm', '0');
+ waitForFormLibValidation(rendered);
expectedErrorMessages(rendered, []);
});
test('should show positive number required error when trying to save warm phase with -1 for after', async () => {
@@ -426,75 +429,87 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '-1');
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumberRequiredMessage]);
+ await setPhaseAfter(rendered, 'warm', '-1');
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.nonNegativeNumberRequired]);
});
test('should show positive number required error when trying to save warm phase with -1 for index priority', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '1');
- setPhaseIndexPriorityLegacy(rendered, 'warm', '-1');
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumberRequiredMessage]);
+ await setPhaseAfter(rendered, 'warm', '1');
+ await setPhaseAfter(rendered, 'warm', '-1');
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.nonNegativeNumberRequired]);
});
test('should show positive number required above zero error when trying to save warm phase with 0 for shrink', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- findTestSubject(rendered, 'shrinkSwitch').simulate('click');
- rendered.update();
- setPhaseAfter(rendered, 'warm', '1');
- const shrinkInput = rendered.find('input#warm-selectedPrimaryShardCount');
- shrinkInput.simulate('change', { target: { value: '0' } });
+ act(() => {
+ findTestSubject(rendered, 'shrinkSwitch').simulate('click');
+ });
rendered.update();
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ await setPhaseAfter(rendered, 'warm', '1');
+ const shrinkInput = findTestSubject(rendered, 'warm-selectedPrimaryShardCount');
+ await act(async () => {
+ shrinkInput.simulate('change', { target: { value: '0' } });
+ });
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show positive number above 0 required error when trying to save warm phase with -1 for shrink', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '1');
- findTestSubject(rendered, 'shrinkSwitch').simulate('click');
- rendered.update();
- const shrinkInput = rendered.find('input#warm-selectedPrimaryShardCount');
- shrinkInput.simulate('change', { target: { value: '-1' } });
+ await setPhaseAfter(rendered, 'warm', '1');
+ act(() => {
+ findTestSubject(rendered, 'shrinkSwitch').simulate('click');
+ });
rendered.update();
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ const shrinkInput = findTestSubject(rendered, 'warm-selectedPrimaryShardCount');
+ await act(async () => {
+ shrinkInput.simulate('change', { target: { value: '-1' } });
+ });
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show positive number required above zero error when trying to save warm phase with 0 for force merge', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '1');
- findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
+ await setPhaseAfter(rendered, 'warm', '1');
+ act(() => {
+ findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
+ });
rendered.update();
const forcemergeInput = findTestSubject(rendered, 'warm-selectedForceMergeSegments');
- forcemergeInput.simulate('change', { target: { value: '0' } });
- rendered.update();
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ await act(async () => {
+ forcemergeInput.simulate('change', { target: { value: '0' } });
+ });
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show positive number above 0 required error when trying to save warm phase with -1 for force merge', async () => {
const rendered = mountWithIntl(component);
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
- setPhaseAfter(rendered, 'warm', '1');
- findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
+ await setPhaseAfter(rendered, 'warm', '1');
+ await act(async () => {
+ findTestSubject(rendered, 'warm-forceMergeSwitch').simulate('click');
+ });
rendered.update();
const forcemergeInput = findTestSubject(rendered, 'warm-selectedForceMergeSegments');
- forcemergeInput.simulate('change', { target: { value: '-1' } });
- rendered.update();
- await save(rendered);
- expectedErrorMessages(rendered, [positiveNumbersAboveZeroErrorMessage]);
+ await act(async () => {
+ forcemergeInput.simulate('change', { target: { value: '-1' } });
+ });
+ waitForFormLibValidation(rendered);
+ expectedErrorMessages(rendered, [i18nTexts.editPolicy.errors.numberGreatThan0Required]);
});
test('should show spinner for node attributes input when loading', async () => {
server.respondImmediately = false;
@@ -504,7 +519,7 @@ describe('edit policy', () => {
await activatePhase(rendered, 'warm');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeTruthy();
expect(rendered.find('.euiCallOut--warning').exists()).toBeFalsy();
- expect(getNodeAttributeSelect(rendered, 'warm').exists()).toBeFalsy();
+ expect(getNodeAttributeSelectLegacy(rendered, 'warm').exists()).toBeFalsy();
});
test('should show warning instead of node attributes input when none exist', async () => {
http.setupNodeListResponse({
@@ -517,9 +532,9 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'warm');
+ await openNodeAttributesSection(rendered, 'warm');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeTruthy();
- expect(getNodeAttributeSelect(rendered, 'warm').exists()).toBeFalsy();
+ expect(getNodeAttributeSelectLegacy(rendered, 'warm').exists()).toBeFalsy();
});
test('should show node attributes input when attributes exist', async () => {
const rendered = mountWithIntl(component);
@@ -527,7 +542,7 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'warm');
+ await openNodeAttributesSection(rendered, 'warm');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeFalsy();
const nodeAttributesSelect = getNodeAttributeSelect(rendered, 'warm');
expect(nodeAttributesSelect.exists()).toBeTruthy();
@@ -539,13 +554,15 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'warm');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'warm');
+ await openNodeAttributesSection(rendered, 'warm');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeFalsy();
const nodeAttributesSelect = getNodeAttributeSelect(rendered, 'warm');
expect(nodeAttributesSelect.exists()).toBeTruthy();
expect(findTestSubject(rendered, 'warm-viewNodeDetailsFlyoutButton').exists()).toBeFalsy();
expect(nodeAttributesSelect.find('option').length).toBe(2);
- nodeAttributesSelect.simulate('change', { target: { value: 'attribute:true' } });
+ await act(async () => {
+ nodeAttributesSelect.simulate('change', { target: { value: 'attribute:true' } });
+ });
rendered.update();
const flyoutButton = findTestSubject(rendered, 'warm-viewNodeDetailsFlyoutButton');
expect(flyoutButton.exists()).toBeTruthy();
@@ -608,7 +625,7 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
- setPhaseAfter(rendered, 'cold', '0');
+ setPhaseAfterLegacy(rendered, 'cold', '0');
await save(rendered);
expectedErrorMessages(rendered, []);
});
@@ -617,7 +634,7 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
- setPhaseAfter(rendered, 'cold', '-1');
+ setPhaseAfterLegacy(rendered, 'cold', '-1');
await save(rendered);
expectedErrorMessages(rendered, [positiveNumberRequiredMessage]);
});
@@ -629,7 +646,7 @@ describe('edit policy', () => {
await activatePhase(rendered, 'cold');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeTruthy();
expect(rendered.find('.euiCallOut--warning').exists()).toBeFalsy();
- expect(getNodeAttributeSelect(rendered, 'cold').exists()).toBeFalsy();
+ expect(getNodeAttributeSelectLegacy(rendered, 'cold').exists()).toBeFalsy();
});
test('should show warning instead of node attributes input when none exist', async () => {
http.setupNodeListResponse({
@@ -642,9 +659,9 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'cold');
+ await openNodeAttributesSection(rendered, 'cold');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeTruthy();
- expect(getNodeAttributeSelect(rendered, 'cold').exists()).toBeFalsy();
+ expect(getNodeAttributeSelectLegacy(rendered, 'cold').exists()).toBeFalsy();
});
test('should show node attributes input when attributes exist', async () => {
const rendered = mountWithIntl(component);
@@ -652,9 +669,9 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'cold');
+ await openNodeAttributesSection(rendered, 'cold');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeFalsy();
- const nodeAttributesSelect = getNodeAttributeSelect(rendered, 'cold');
+ const nodeAttributesSelect = getNodeAttributeSelectLegacy(rendered, 'cold');
expect(nodeAttributesSelect.exists()).toBeTruthy();
expect(nodeAttributesSelect.find('option').length).toBe(2);
});
@@ -664,9 +681,9 @@ describe('edit policy', () => {
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy();
- openNodeAttributesSection(rendered, 'cold');
+ await openNodeAttributesSection(rendered, 'cold');
expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeFalsy();
- const nodeAttributesSelect = getNodeAttributeSelect(rendered, 'cold');
+ const nodeAttributesSelect = getNodeAttributeSelectLegacy(rendered, 'cold');
expect(nodeAttributesSelect.exists()).toBeTruthy();
expect(findTestSubject(rendered, 'cold-viewNodeDetailsFlyoutButton').exists()).toBeFalsy();
expect(nodeAttributesSelect.find('option').length).toBe(2);
@@ -685,7 +702,7 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'cold');
- setPhaseAfter(rendered, 'cold', '1');
+ setPhaseAfterLegacy(rendered, 'cold', '1');
setPhaseIndexPriorityLegacy(rendered, 'cold', '-1');
await save(rendered);
expectedErrorMessages(rendered, [positiveNumberRequiredMessage]);
@@ -736,7 +753,7 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'delete');
- setPhaseAfter(rendered, 'delete', '0');
+ setPhaseAfterLegacy(rendered, 'delete', '0');
await save(rendered);
expectedErrorMessages(rendered, []);
});
@@ -745,7 +762,7 @@ describe('edit policy', () => {
await noRollover(rendered);
setPolicyName(rendered, 'mypolicy');
await activatePhase(rendered, 'delete');
- setPhaseAfter(rendered, 'delete', '-1');
+ setPhaseAfterLegacy(rendered, 'delete', '-1');
await save(rendered);
expectedErrorMessages(rendered, [positiveNumberRequiredMessage]);
});
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts b/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
index 473e6307f2a633..136b68727672aa 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/constants/policy.ts
@@ -8,6 +8,8 @@ import { SerializedPhase, ColdPhase, DeletePhase, SerializedPolicy } from '../..
export const defaultSetPriority: string = '100';
+export const defaultPhaseIndexPriority: string = '50';
+
export const defaultPolicy: SerializedPolicy = {
name: '',
phases: {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
index fe74c82d29e7b2..d866fcd417671b 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
@@ -98,9 +98,10 @@ export const NodeAllocation: FunctionComponent = ({ phase, nodes })
) : undefined,
euiFieldProps: {
'data-test-subj': `${phase}-${nodeAttrsProperty}`,
- options: [{ text: i18nTexts.doNotModifyAllocationOption, value: 'none' }].concat(
+ options: [{ text: i18nTexts.doNotModifyAllocationOption, value: '' }].concat(
nodeOptions
),
+ hasNoInitialSelection: false,
},
}}
/>
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index 440d67ed571ad8..fc7723598c2a62 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -7,7 +7,7 @@
import { i18n } from '@kbn/i18n';
import { FormSchema, fieldValidators } from '../../../shared_imports';
-import { defaultSetPriority } from '../../constants';
+import { defaultSetPriority, defaultPhaseIndexPriority } from '../../constants';
import { FormInternal } from './types';
@@ -66,7 +66,6 @@ export const schema: FormSchema = {
label: i18nTexts.editPolicy.allocationTypeOptionsFieldLabel,
},
allocationNodeAttribute: {
- defaultValue: 'none',
label: i18nTexts.editPolicy.allocationNodeAttributeFieldLabel,
},
},
@@ -150,11 +149,15 @@ export const schema: FormSchema = {
defaultValue: '0',
validations: [
{
- validator: numberGreaterThanField({
- than: 0,
- allowEquality: true,
- message: i18nTexts.editPolicy.errors.positiveNumberRequired,
- }),
+ validator: (arg) =>
+ numberGreaterThanField({
+ than: 0,
+ allowEquality: true,
+ message: i18nTexts.editPolicy.errors.nonNegativeNumberRequired,
+ })({
+ ...arg,
+ value: arg.value === '' ? -Infinity : parseInt(arg.value, 10),
+ }),
},
],
},
@@ -212,7 +215,7 @@ export const schema: FormSchema = {
},
set_priority: {
priority: {
- defaultValue: '50' as any,
+ defaultValue: defaultPhaseIndexPriority as any,
label: i18nTexts.editPolicy.setPriorityFieldLabel,
validations: [{ validator: ifExistsNumberGreaterThanZero }],
serializer: serializers.stringToNumber,
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
index 245c129db47433..1fba69b7634aea 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
@@ -48,54 +48,54 @@ export const i18nTexts = {
),
errors: {
numberRequired: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.numberRequiredErrorMessage',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.numberRequiredErrorMessage',
{
defaultMessage: 'A number is required.',
}
),
numberGreatThan0Required: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.numberAboveZeroRequiredError',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.numberAboveZeroRequiredError',
{
defaultMessage: 'Only numbers above 0 are allowed.',
}
),
maximumAgeRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumAgeMissingError',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.maximumAgeMissingError',
{
defaultMessage: 'A maximum age is required.',
}
),
maximumSizeRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.maximumIndexSizeMissingError',
{
defaultMessage: 'A maximum index size is required.',
}
),
maximumDocumentsRequiredMessage: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.maximumDocumentsMissingError',
{
defaultMessage: 'Maximum documents is required.',
}
),
rollOverConfigurationCallout: {
title: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.title',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.rolloverConfigurationError.title',
{
defaultMessage: 'Invalid rollover configuration',
}
),
body: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.rolloverConfigurationError.body',
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.rolloverConfigurationError.body',
{
defaultMessage:
'A value for one of maximum size, maximum documents, or maximum age is required.',
}
),
},
- positiveNumberRequired: i18n.translate(
- 'xpack.indexLifecycleMgmt.editPolicy.errors.positiveNumberRequiredError',
+ nonNegativeNumberRequired: i18n.translate(
+ 'xpack.indexLifecycleMgmt.editPolicy.errors.nonNegativeNumberRequiredError',
{
- defaultMessage: 'Only positive numbers are allowed.',
+ defaultMessage: 'Only non-negative numbers are allowed.',
}
),
},
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
index 4ebb33be7647ec..463ed0a201251b 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
@@ -18,8 +18,7 @@ const unsafeSerializePhaseWithAllocation = (
) => {
if (
dataAllocationMetaFields.dataTierAllocationType === 'node_attrs' &&
- dataAllocationMetaFields.allocationNodeAttribute &&
- dataAllocationMetaFields.allocationNodeAttribute !== 'none'
+ dataAllocationMetaFields.allocationNodeAttribute
) {
const [name, value] = dataAllocationMetaFields.allocationNodeAttribute.split(':');
actions.allocate = {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts
index 81eb1c8cad1358..c77e3d22f0e37c 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.test.ts
@@ -9,8 +9,8 @@ import {
UIM_CONFIG_WARM_PHASE,
UIM_CONFIG_SET_PRIORITY,
UIM_CONFIG_FREEZE_INDEX,
- defaultNewWarmPhase,
defaultNewColdPhase,
+ defaultPhaseIndexPriority,
} from '../constants/';
import { getUiMetricsForPhases } from './ui_metric';
@@ -38,7 +38,7 @@ describe('getUiMetricsForPhases', () => {
min_age: '0ms',
actions: {
set_priority: {
- priority: parseInt(defaultNewWarmPhase.phaseIndexPriority, 10),
+ priority: parseInt(defaultPhaseIndexPriority, 10),
},
},
},
@@ -53,7 +53,7 @@ describe('getUiMetricsForPhases', () => {
min_age: '0ms',
actions: {
set_priority: {
- priority: parseInt(defaultNewWarmPhase.phaseIndexPriority, 10) + 1,
+ priority: parseInt(defaultPhaseIndexPriority, 10) + 1,
},
},
},
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
index ec811e29839045..305b35b23e4d8b 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/ui_metric.ts
@@ -15,6 +15,7 @@ import {
UIM_CONFIG_WARM_PHASE,
defaultNewColdPhase,
defaultSetPriority,
+ defaultPhaseIndexPriority,
} from '../constants';
import { Phases } from '../../../common/types';
@@ -49,8 +50,7 @@ export function getUiMetricsForPhases(phases: Phases): string[] {
const isWarmPhasePriorityChanged =
phases.warm &&
phases.warm.actions.set_priority &&
- phases.warm.actions.set_priority.priority !==
- parseInt(defaultNewWarmPhase.phaseIndexPriority, 10);
+ phases.warm.actions.set_priority.priority !== parseInt(defaultPhaseIndexPriority, 10);
const isColdPhasePriorityChanged =
phases.cold &&
From d7896d7685fc742c39a3d5ca5ecfa4c98feda891 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 16:18:15 +0200
Subject: [PATCH 08/19] added policy serialization tests
---
.../edit_policy/constants.ts | 41 ++-
.../edit_policy/edit_policy.helpers.tsx | 103 +++++--
.../edit_policy/edit_policy.test.ts | 253 +++++++++++++++++-
.../helpers/http_requests.ts | 10 +
.../phases/warm_phase/warm_phase.tsx | 3 +-
.../sections/edit_policy/form_schema.ts | 2 +-
.../sections/edit_policy/serializer.ts | 45 +++-
7 files changed, 406 insertions(+), 51 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
index bd845b0a7d9a76..bcc5ff53315d72 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
@@ -14,17 +14,52 @@ export const DEFAULT_POLICY: PolicyFromES = {
version: 1,
modified_date: Date.now().toString(),
policy: {
- name: '',
+ name: 'my_policy',
+ phases: {
+ hot: {
+ min_age: '0ms',
+ actions: {
+ rollover: {
+ max_age: '30d',
+ max_size: '50gb',
+ },
+ },
+ },
+ },
+ },
+ name: 'my_policy',
+};
+
+export const POLICY_WITH_INCLUDE_EXCLUDE: PolicyFromES = {
+ version: 1,
+ modified_date: Date.now().toString(),
+ policy: {
+ name: 'my_policy',
phases: {
hot: {
min_age: '123ms',
actions: {
- rollover: {},
+ rollover: {
+ max_age: '30d',
+ max_size: '50gb',
+ },
+ },
+ },
+ warm: {
+ actions: {
+ allocate: {
+ include: {
+ abc: '123',
+ },
+ exclude: {
+ def: '456',
+ },
+ },
},
},
},
},
- name: '',
+ name: 'my_policy',
};
export const DELETE_PHASE_POLICY: PolicyFromES = {
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
index 0cfccba7613094..37a79d45c432e4 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
@@ -13,6 +13,7 @@ import { POLICY_NAME } from './constants';
import { TestSubjects } from '../helpers';
import { EditPolicy } from '../../../public/application/sections/edit_policy';
+import { DataTierAllocationType } from '../../../public/application/sections/edit_policy/types';
jest.mock('@elastic/eui', () => {
const original = jest.requireActual('@elastic/eui');
@@ -54,6 +55,22 @@ export const setup = async () => {
const { find, component } = testBed;
+ const createFormClickAction = (dataTestSubject: string) => async () => {
+ await act(async () => {
+ find(dataTestSubject).simulate('click');
+ });
+ component.update();
+ };
+
+ function createFormSetValueAction(dataTestSubject: string) {
+ return async (value: V) => {
+ await act(async () => {
+ find(dataTestSubject).simulate('change', { target: { value } });
+ });
+ component.update();
+ };
+ }
+
const setWaitForSnapshotPolicy = async (snapshotPolicyName: string) => {
act(() => {
find('snapshotPolicyCombobox').simulate('change', [{ label: snapshotPolicyName }]);
@@ -68,12 +85,7 @@ export const setup = async () => {
component.update();
};
- const toggleRollover = async (checked: boolean) => {
- await act(async () => {
- find('rolloverSwitch').simulate('click', { target: { checked } });
- });
- component.update();
- };
+ const toggleRollover = createFormClickAction('rolloverSwitch');
const setMaxSize = async (value: string, units?: string) => {
await act(async () => {
@@ -87,12 +99,7 @@ export const setup = async () => {
component.update();
};
- const setMaxDocs = async (value: string) => {
- await act(async () => {
- find('hot-selectedMaxDocuments').simulate('change', { target: { value } });
- });
- component.update();
- };
+ const setMaxDocs = createFormSetValueAction('hot-selectedMaxDocuments');
const setMaxAge = async (value: string, units?: string) => {
await act(async () => {
@@ -104,32 +111,56 @@ export const setup = async () => {
component.update();
};
- const toggleForceMerge = (phase: string) => async (checked: boolean) => {
- await act(async () => {
- find(`${phase}-forceMergeSwitch`).simulate('click', { target: { checked } });
+ const toggleForceMerge = (phase: string) => createFormClickAction(`${phase}-forceMergeSwitch`);
+
+ const setForcemergeSegmentsCount = (phase: string) =>
+ createFormSetValueAction(`${phase}-selectedForceMergeSegments`);
+
+ const setBestCompression = (phase: string) => createFormClickAction(`${phase}-bestCompression`);
+
+ const setIndexPriority = (phase: string) =>
+ createFormSetValueAction(`${phase}-phaseIndexPriority`);
+
+ const enable = (phase: string) => createFormClickAction(`enablePhaseSwitch-${phase}`);
+
+ const warmPhaseOnRollover = createFormClickAction(`warm-warmPhaseOnRollover`);
+
+ const setMinAgeValue = (phase: string) => createFormSetValueAction(`${phase}-selectedMinimumAge`);
+
+ const setMinAgeUnits = (phase: string) =>
+ createFormSetValueAction(`${phase}-selectedMinimumAgeUnits`);
+
+ const setDataAllocation = (phase: string) => async (value: DataTierAllocationType) => {
+ act(() => {
+ find(`${phase}-dataTierAllocationControls.dataTierSelect`).simulate('click');
});
component.update();
- };
-
- const setForcemergeSegmentsCount = (phase: string) => async (value: string) => {
await act(async () => {
- find(`${phase}-selectedForceMergeSegments`).simulate('change', { target: { value } });
+ switch (value) {
+ case 'node_roles':
+ find(`${phase}-dataTierAllocationControls.defaultDataAllocationOption`).simulate('click');
+ break;
+ case 'node_attrs':
+ find(`${phase}-dataTierAllocationControls.customDataAllocationOption`).simulate('click');
+ break;
+ default:
+ find(`${phase}-dataTierAllocationControls.noneDataAllocationOption`).simulate('click');
+ }
});
component.update();
};
- const setBestCompression = (phase: string) => async (checked: boolean) => {
- await act(async () => {
- find(`${phase}-bestCompression`).simulate('click', { target: { checked } });
- });
- component.update();
+ const setSelectedNodeAttribute = (phase: string) =>
+ createFormSetValueAction(`${phase}-selectedNodeAttrs`);
+
+ const setReplicas = async (value: string) => {
+ await createFormClickAction('warm-setReplicasSwitch')();
+ await createFormSetValueAction('warm-selectedReplicaCount')(value);
};
- const setIndexPriority = (phase: string) => async (value: string) => {
- await act(async () => {
- find(`${phase}-phaseIndexPriority`).simulate('change', { target: { value } });
- });
- component.update();
+ const setShrink = async (value: string) => {
+ await createFormClickAction('shrinkSwitch')();
+ await createFormSetValueAction('warm-selectedPrimaryShardCount')(value);
};
return {
@@ -147,6 +178,20 @@ export const setup = async () => {
setBestCompression: setBestCompression('hot'),
setIndexPriority: setIndexPriority('hot'),
},
+ warm: {
+ enable: enable('warm'),
+ warmPhaseOnRollover,
+ setMinAgeValue: setMinAgeValue('warm'),
+ setMinAgeUnits: setMinAgeUnits('warm'),
+ setDataAllocation: setDataAllocation('warm'),
+ setSelectedNodeAttribute: setSelectedNodeAttribute('warm'),
+ setReplicas,
+ setShrink,
+ toggleForceMerge: toggleForceMerge('warm'),
+ setForcemergeSegments: setForcemergeSegmentsCount('warm'),
+ setBestCompression: setBestCompression('warm'),
+ setIndexPriority: setIndexPriority('warm'),
+ },
},
};
};
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
index 3cbc2d982566e6..9f1b990705776c 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
@@ -15,6 +15,7 @@ import {
NEW_SNAPSHOT_POLICY_NAME,
SNAPSHOT_POLICY_NAME,
DEFAULT_POLICY,
+ POLICY_WITH_INCLUDE_EXCLUDE,
} from './constants';
window.scrollTo = jest.fn();
@@ -46,9 +47,9 @@ describe('', () => {
await actions.hot.setMaxSize('123', 'mb');
await actions.hot.setMaxDocs('123');
await actions.hot.setMaxAge('123', 'h');
- await actions.hot.toggleForceMerge(true);
+ await actions.hot.toggleForceMerge();
await actions.hot.setForcemergeSegments('123');
- await actions.hot.setBestCompression(true);
+ await actions.hot.setBestCompression();
await actions.hot.setIndexPriority('123');
await actions.savePolicy();
@@ -81,7 +82,7 @@ describe('', () => {
test('disabling rollover', async () => {
const { actions } = testBed;
- await actions.hot.toggleRollover(false);
+ await actions.hot.toggleRollover();
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
@@ -103,8 +104,254 @@ describe('', () => {
});
});
+ describe('warm phase', () => {
+ describe('serialization', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([DEFAULT_POLICY]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('default values', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable();
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ "set_priority": Object {
+ "priority": 100,
+ },
+ },
+ "min_age": "0ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "set_priority": Object {
+ "priority": 50,
+ },
+ },
+ "min_age": "0ms",
+ },
+ },
+ }
+ `);
+ });
+
+ test('setting all values', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable();
+ await actions.warm.setMinAgeValue('123');
+ await actions.warm.setMinAgeUnits('d');
+ await actions.warm.setDataAllocation('node_attrs');
+ await actions.warm.setSelectedNodeAttribute('test:123');
+ await actions.warm.setReplicas('123');
+ await actions.warm.setShrink('123');
+ await actions.warm.toggleForceMerge();
+ await actions.warm.setForcemergeSegments('123');
+ await actions.warm.setBestCompression();
+ await actions.warm.setIndexPriority('123');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ "set_priority": Object {
+ "priority": 100,
+ },
+ },
+ "min_age": "0ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "allocate": Object {
+ "number_of_replicas": 123,
+ "require": Object {
+ "test": "123",
+ },
+ },
+ "forcemerge": Object {
+ "index_codec": "best_compression",
+ "max_num_segments": 123,
+ },
+ "set_priority": Object {
+ "priority": 123,
+ },
+ "shrink": Object {
+ "number_of_shards": 123,
+ },
+ },
+ "min_age": "123d",
+ },
+ },
+ }
+ `);
+ });
+
+ test('default allocation with replicas set', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable();
+ await actions.warm.setReplicas('123');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ "set_priority": Object {
+ "priority": 100,
+ },
+ },
+ "min_age": "0ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "allocate": Object {
+ "number_of_replicas": 123,
+ },
+ "set_priority": Object {
+ "priority": 50,
+ },
+ },
+ "min_age": "0ms",
+ },
+ },
+ }
+ `);
+ });
+
+ test('setting warm phase on rollover to "true"', async () => {
+ const { actions } = testBed;
+ await actions.warm.enable();
+ await actions.warm.warmPhaseOnRollover();
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ "set_priority": Object {
+ "priority": 100,
+ },
+ },
+ "min_age": "0ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "set_priority": Object {
+ "priority": 50,
+ },
+ },
+ },
+ },
+ }
+ `);
+ });
+ });
+
+ describe('policy with include and exclude', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_INCLUDE_EXCLUDE]);
+ httpRequestsMockHelpers.setListNodes({
+ nodesByRoles: {},
+ nodesByAttributes: { test: ['123'] },
+ isUsingDeprecatedDataRoleConfig: false,
+ });
+ httpRequestsMockHelpers.setLoadSnapshotPolicies([]);
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('preserves include, exclude allocation settings', async () => {
+ const { actions } = testBed;
+ await actions.warm.setDataAllocation('node_attrs');
+ await actions.savePolicy();
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ Object {
+ "name": "my_policy",
+ "phases": Object {
+ "hot": Object {
+ "actions": Object {
+ "rollover": Object {
+ "max_age": "30d",
+ "max_size": "50gb",
+ },
+ "set_priority": Object {
+ "priority": 100,
+ },
+ },
+ "min_age": "123ms",
+ },
+ "warm": Object {
+ "actions": Object {
+ "allocate": Object {
+ "exclude": Object {
+ "def": "456",
+ },
+ "include": Object {
+ "abc": "123",
+ },
+ },
+ "set_priority": Object {
+ "priority": 50,
+ },
+ },
+ "min_age": "0ms",
+ },
+ },
+ }
+ `);
+ });
+ });
+ });
+
describe('delete phase', () => {
beforeEach(async () => {
+ server.respondImmediately = true;
httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]);
httpRequestsMockHelpers.setLoadSnapshotPolicies([
SNAPSHOT_POLICY_NAME,
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/http_requests.ts
index 04f58f93939ca3..c7a493ce80d96b 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/http_requests.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/helpers/http_requests.ts
@@ -6,6 +6,7 @@
import { fakeServer, SinonFakeServer } from 'sinon';
import { API_BASE_PATH } from '../../../common/constants';
+import { ListNodesRouteResponse } from '../../../common/types';
export const init = () => {
const server = fakeServer.create();
@@ -38,8 +39,17 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
]);
};
+ const setListNodes = (body: ListNodesRouteResponse) => {
+ server.respondWith('GET', `${API_BASE_PATH}/nodes/list`, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(body),
+ ]);
+ };
+
return {
setLoadPolicies,
setLoadSnapshotPolicies,
+ setListNodes,
};
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
index b13e867a0b1faf..d03b36fceefdd0 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
@@ -151,6 +151,7 @@ export const WarmPhase: FunctionComponent = () => {
}
)}
switchProps={{
+ 'data-test-subj': 'warm-setReplicasSwitch',
label: i18n.translate(
'xpack.indexLifecycleMgmt.editPolicy.warmPhase.numberOfReplicas.switchLabel',
{ defaultMessage: 'Set replicas' }
@@ -167,7 +168,7 @@ export const WarmPhase: FunctionComponent = () => {
componentProps={{
fullWidth: false,
euiFieldProps: {
- 'data-test-subj': `${warmProperty}-selectedReplicaCount}`,
+ 'data-test-subj': `${warmProperty}-selectedReplicaCount`,
min: 0,
},
}}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
index fc7723598c2a62..a80382e87539c2 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form_schema.ts
@@ -56,7 +56,7 @@ export const schema: FormSchema = {
}),
},
minAgeUnit: {
- defaultValue: 'd',
+ defaultValue: 'ms',
},
bestCompression: {
label: i18nTexts.editPolicy.bestCompressionFieldLabel,
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
index 463ed0a201251b..415de1707dd18f 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
@@ -16,22 +16,39 @@ const unsafeSerializePhaseWithAllocation = (
actions: SerializedPhase['actions'] = {},
originalAllocation: AllocateAction = {}
) => {
- if (
- dataAllocationMetaFields.dataTierAllocationType === 'node_attrs' &&
- dataAllocationMetaFields.allocationNodeAttribute
- ) {
- const [name, value] = dataAllocationMetaFields.allocationNodeAttribute.split(':');
- actions.allocate = {
- require: {
- [name]: value,
- },
- // copy over the original include and exclude values until we can set them in the form.
- include: !isEmpty(originalAllocation.include) ? { ...originalAllocation.include } : undefined,
- exclude: !isEmpty(originalAllocation.exclude) ? { ...originalAllocation.exclude } : undefined,
- };
+ if (dataAllocationMetaFields.dataTierAllocationType === 'node_attrs') {
+ if (dataAllocationMetaFields.allocationNodeAttribute) {
+ const [name, value] = dataAllocationMetaFields.allocationNodeAttribute.split(':');
+ actions.allocate = {
+ // copy over any other allocate details like "number_of_replicas"
+ ...actions.allocate,
+ require: {
+ [name]: value,
+ },
+ };
+ }
+
+ // copy over the original include and exclude values until we can set them in the form.
+ if (!isEmpty(originalAllocation.include)) {
+ actions.allocate = {
+ ...actions.allocate,
+ include: { ...originalAllocation.include },
+ };
+ }
+
+ if (!isEmpty(originalAllocation.exclude)) {
+ actions.allocate = {
+ ...actions.allocate,
+ exclude: { ...originalAllocation.exclude },
+ };
+ }
} else if (dataAllocationMetaFields.dataTierAllocationType === 'none') {
actions.migrate = { enabled: false };
- delete actions.allocate;
+ if (actions.allocate) {
+ delete actions.allocate.require;
+ delete actions.allocate.include;
+ delete actions.allocate.exclude;
+ }
} else if (dataAllocationMetaFields.dataTierAllocationType === 'node_roles') {
if (actions.allocate) {
delete actions.allocate.require;
From 4f2a615cd52834f26da85dde3e1a182a0e6c3f8f Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 17:22:37 +0200
Subject: [PATCH 09/19] remove unused translations
---
x-pack/plugins/translations/translations/ja-JP.json | 3 ---
x-pack/plugins/translations/translations/zh-CN.json | 3 ---
2 files changed, 6 deletions(-)
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index e645ae32abbd18..4d2295091addda 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -8570,9 +8570,6 @@
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePoliciesLoadingFailedTitle": "既存のライフサイクルポリシーを読み込めません",
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePoliciesReloadButton": "再試行",
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePolicyDescriptionText": "インデックスへのアクティブな書き込みから削除までの、インデックスライフサイクルの 4 つのフェーズを自動化するには、インデックスポリシーを使用します。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumAgeMissingError": "最高年齢が必要です。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError": "最高ドキュメント数が必要です。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError": "最大インデックスサイズが必要です。",
"xpack.indexLifecycleMgmt.editPolicy.nameLabel": "名前",
"xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.customOption.description": "ノード属性を使用して、シャード割り当てを制御します。{learnMoreLink}。",
"xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.doNotModifyAllocationOption": "割り当て構成を修正しない",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 2f701d0cde284b..a9a48363250cc4 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -8577,9 +8577,6 @@
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePoliciesLoadingFailedTitle": "无法加载现有生命周期策略",
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePoliciesReloadButton": "重试",
"xpack.indexLifecycleMgmt.editPolicy.lifecyclePolicyDescriptionText": "使用索引策略自动化索引生命周期的四个阶段,从频繁地写入到索引到删除索引。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumAgeMissingError": "最大存在时间必填。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumDocumentsMissingError": "最大文档数必填。",
- "xpack.indexLifecycleMgmt.editPolicy.maximumIndexSizeMissingError": "最大索引大小必填。",
"xpack.indexLifecycleMgmt.editPolicy.nameLabel": "名称",
"xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.customOption.description": "使用节点属性控制分片分配。{learnMoreLink}。",
"xpack.indexLifecycleMgmt.editPolicy.nodeAllocation.doNotModifyAllocationOption": "不要修改分配配置",
From 2ed016f87804a46dab32b3ee15cc289acd555f5d Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Wed, 21 Oct 2020 18:05:00 +0200
Subject: [PATCH 10/19] Fix use of useFormData after update
- also minor refactor to use useCallback in policy flyout now
that getFormData changes when the form data changes.
---
.../components/data_tier_allocation.tsx | 7 +++-
.../components/node_allocation.tsx | 5 ++-
.../data_tier_allocation_field.tsx | 6 ++-
.../min_age_input_field.tsx | 5 ++-
.../components/policy_json_flyout.tsx | 41 ++++++++++---------
5 files changed, 37 insertions(+), 27 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
index 99fa2abac3abe5..2aa7e75a48b1b4 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
@@ -5,6 +5,7 @@
*/
import React, { FunctionComponent } from 'react';
+import { get } from 'lodash';
import { i18n } from '@kbn/i18n';
import { EuiText, EuiSpacer, EuiSuperSelectOption } from '@elastic/eui';
@@ -93,10 +94,12 @@ export const DataTierAllocation: FunctionComponent = (props) => {
const dataTierAllocationTypePath = `_meta.${phase}.dataTierAllocationType`;
- const [{ [dataTierAllocationTypePath]: dataTierAllocationType }] = useFormData({
- watch: [dataTierAllocationTypePath],
+ const [formData] = useFormData({
+ watch: dataTierAllocationTypePath,
});
+ const dataTierAllocationType = get(formData, dataTierAllocationTypePath);
+
return (
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
index d866fcd417671b..407bb9ea92e855 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/node_allocation.tsx
@@ -5,6 +5,7 @@
*/
import React, { useState, FunctionComponent } from 'react';
+import { get } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty, EuiText, EuiSpacer } from '@elastic/eui';
@@ -43,10 +44,12 @@ const i18nTexts = {
export const NodeAllocation: FunctionComponent = ({ phase, nodes }) => {
const allocationNodeAttributePath = `_meta.${phase}.allocationNodeAttribute`;
- const [{ [allocationNodeAttributePath]: selectedAllocationNodeAttribute }] = useFormData({
+ const [formData] = useFormData({
watch: [allocationNodeAttributePath],
});
+ const selectedAllocationNodeAttribute = get(formData, allocationNodeAttributePath);
+
const [selectedNodeAttrsForDetails, setSelectedNodeAttrsForDetails] = useState(
null
);
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
index b7b9a1e9f3dad9..bafc48e6e4eeed 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
@@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import { get } from 'lodash';
import React, { FunctionComponent } from 'react';
import { i18n } from '@kbn/i18n';
@@ -44,8 +45,9 @@ export const DataTierAllocationField: FunctionComponent = ({ phase, descr
services: { cloud },
} = useKibana();
- const allocationTypePath = `_meta.${phase}.dataTierAllocationType`;
- const [{ [allocationTypePath]: allocationType }] = useFormData({ watch: [allocationTypePath] });
+ const dataTierAllocationTypePath = `_meta.${phase}.dataTierAllocationType`;
+ const [formData] = useFormData({ watch: dataTierAllocationTypePath });
+ const allocationType = get(formData, dataTierAllocationTypePath);
return (
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/min_age_input_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/min_age_input_field.tsx
index 181f2e6c2a29e4..f37c3873544182 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/min_age_input_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/min_age_input_field/min_age_input_field.tsx
@@ -3,8 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-
import React, { FunctionComponent } from 'react';
+import { get } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
@@ -29,7 +29,8 @@ interface Props {
}
export const MinAgeInputField: FunctionComponent = ({ phase }): React.ReactElement => {
- const [{ [useRolloverPath]: rolloverEnabled }] = useFormData({ watch: useRolloverPath });
+ const [formData] = useFormData({ watch: useRolloverPath });
+ const rolloverEnabled = get(formData, useRolloverPath);
let daysOptionLabel;
let hoursOptionLabel;
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
index 9693733eb61508..4852aecf621f76 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useEffect, useState } from 'react';
+import React, { useCallback, useEffect, useState } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -46,27 +46,28 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({
const [policy, setPolicy] = useState(undefined);
const form = useFormContext();
- const [formData, getFormData] = useFormData();
+ const [, getFormData] = useFormData();
+
+ const getPolicy = useCallback(async () => {
+ setPolicy(undefined);
+ if (await form.validate()) {
+ const p = getFormData() as SerializedPolicy;
+ setPolicy({
+ ...legacyPolicy,
+ phases: {
+ ...legacyPolicy.phases,
+ hot: p.phases.hot,
+ warm: p.phases.warm,
+ },
+ });
+ } else {
+ setPolicy(null);
+ }
+ }, [setPolicy, getFormData, legacyPolicy, form]);
useEffect(() => {
- (async function checkPolicy() {
- setPolicy(undefined);
- if (await form.validate()) {
- const p = getFormData() as SerializedPolicy;
- setPolicy({
- ...legacyPolicy,
- phases: {
- ...legacyPolicy.phases,
- hot: p.phases.hot,
- warm: p.phases.warm,
- },
- });
- } else {
- setPolicy(null);
- }
- })();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [form, legacyPolicy, formData]);
+ getPolicy();
+ }, [getPolicy]);
let content: React.ReactNode;
switch (policy) {
From 5aed5cf4058a6a32b90d464e89eb8abfe6623473 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Thu, 22 Oct 2020 09:49:55 +0200
Subject: [PATCH 11/19] fix import path
---
.../components/no_node_attributes_warning.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
index 69185277f64ce6..338e5367a1d0df 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/no_node_attributes_warning.tsx
@@ -8,7 +8,7 @@ import React, { FunctionComponent } from 'react';
import { EuiCallOut } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { PhaseWithAllocation } from '../../../../../../common/types';
+import { PhaseWithAllocation } from '../../../../../../../../../common/types';
const i18nTexts = {
title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.nodeAttributesMissingLabel', {
From 1affb8ea2ad8a0ba081f9ad42d466c7811b5c023 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 15:16:00 +0100
Subject: [PATCH 12/19] simplify serialization snapshot tests
---
.../edit_policy/edit_policy.test.ts | 155 +++++-------------
1 file changed, 37 insertions(+), 118 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
index 9f1b990705776c..43fe008117b906 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
@@ -54,7 +54,8 @@ describe('', () => {
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ expect(entirePolicy).toMatchInlineSnapshot(`
Object {
"name": "my_policy",
"phases": Object {
@@ -85,18 +86,14 @@ describe('', () => {
await actions.hot.toggleRollover();
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ const hotActions = policy.phases.hot.actions;
+ const rolloverAction = hotActions.rollover;
+ expect(rolloverAction).toBe(undefined);
+ expect(hotActions).toMatchInlineSnapshot(`
Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "set_priority": Object {
- "priority": 100,
- },
- },
- "min_age": "0ms",
- },
+ "set_priority": Object {
+ "priority": 100,
},
}
`);
@@ -128,31 +125,15 @@ describe('', () => {
await actions.warm.enable();
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
+ expect(warmPhase).toMatchInlineSnapshot(`
Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- "set_priority": Object {
- "priority": 100,
- },
- },
- "min_age": "0ms",
- },
- "warm": Object {
- "actions": Object {
- "set_priority": Object {
- "priority": 50,
- },
- },
- "min_age": "0ms",
+ "actions": Object {
+ "set_priority": Object {
+ "priority": 50,
},
},
+ "min_age": "0ms",
}
`);
});
@@ -172,7 +153,9 @@ describe('', () => {
await actions.warm.setIndexPriority('123');
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const entirePolicy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
+ // Check shape of entire policy
+ expect(entirePolicy).toMatchInlineSnapshot(`
Object {
"name": "my_policy",
"phases": Object {
@@ -220,33 +203,15 @@ describe('', () => {
await actions.warm.setReplicas('123');
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const warmPhaseActions = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
+ .actions;
+ expect(warmPhaseActions).toMatchInlineSnapshot(`
Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- "set_priority": Object {
- "priority": 100,
- },
- },
- "min_age": "0ms",
- },
- "warm": Object {
- "actions": Object {
- "allocate": Object {
- "number_of_replicas": 123,
- },
- "set_priority": Object {
- "priority": 50,
- },
- },
- "min_age": "0ms",
- },
+ "allocate": Object {
+ "number_of_replicas": 123,
+ },
+ "set_priority": Object {
+ "priority": 50,
},
}
`);
@@ -258,32 +223,9 @@ describe('', () => {
await actions.warm.warmPhaseOnRollover();
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
- Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- "set_priority": Object {
- "priority": 100,
- },
- },
- "min_age": "0ms",
- },
- "warm": Object {
- "actions": Object {
- "set_priority": Object {
- "priority": 50,
- },
- },
- },
- },
- }
- `);
+ const warmPhaseMinAge = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
+ .min_age;
+ expect(warmPhaseMinAge).toBe(undefined);
});
});
@@ -310,38 +252,15 @@ describe('', () => {
await actions.warm.setDataAllocation('node_attrs');
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
- expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toMatchInlineSnapshot(`
+ const warmPhaseAllocate = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
+ .actions.allocate;
+ expect(warmPhaseAllocate).toMatchInlineSnapshot(`
Object {
- "name": "my_policy",
- "phases": Object {
- "hot": Object {
- "actions": Object {
- "rollover": Object {
- "max_age": "30d",
- "max_size": "50gb",
- },
- "set_priority": Object {
- "priority": 100,
- },
- },
- "min_age": "123ms",
- },
- "warm": Object {
- "actions": Object {
- "allocate": Object {
- "exclude": Object {
- "def": "456",
- },
- "include": Object {
- "abc": "123",
- },
- },
- "set_priority": Object {
- "priority": 50,
- },
- },
- "min_age": "0ms",
- },
+ "exclude": Object {
+ "def": "456",
+ },
+ "include": Object {
+ "abc": "123",
},
}
`);
From 97da20ede660037f527fd8c6cc63f216317289e3 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 15:19:28 +0100
Subject: [PATCH 13/19] type phases: string -> phases: Phases
---
.../edit_policy/edit_policy.helpers.tsx | 26 +++++++++++--------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
index 37a79d45c432e4..d6d79d290c43b6 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
@@ -9,12 +9,16 @@ import { act } from 'react-dom/test-utils';
import { registerTestBed, TestBedConfig } from '../../../../../test_utils';
-import { POLICY_NAME } from './constants';
-import { TestSubjects } from '../helpers';
-
import { EditPolicy } from '../../../public/application/sections/edit_policy';
import { DataTierAllocationType } from '../../../public/application/sections/edit_policy/types';
+import { Phases as PolicyPhases } from '../../../common/types';
+
+type Phases = keyof PolicyPhases;
+
+import { POLICY_NAME } from './constants';
+import { TestSubjects } from '../helpers';
+
jest.mock('@elastic/eui', () => {
const original = jest.requireActual('@elastic/eui');
@@ -111,26 +115,26 @@ export const setup = async () => {
component.update();
};
- const toggleForceMerge = (phase: string) => createFormClickAction(`${phase}-forceMergeSwitch`);
+ const toggleForceMerge = (phase: Phases) => createFormClickAction(`${phase}-forceMergeSwitch`);
- const setForcemergeSegmentsCount = (phase: string) =>
+ const setForcemergeSegmentsCount = (phase: Phases) =>
createFormSetValueAction(`${phase}-selectedForceMergeSegments`);
- const setBestCompression = (phase: string) => createFormClickAction(`${phase}-bestCompression`);
+ const setBestCompression = (phase: Phases) => createFormClickAction(`${phase}-bestCompression`);
- const setIndexPriority = (phase: string) =>
+ const setIndexPriority = (phase: Phases) =>
createFormSetValueAction(`${phase}-phaseIndexPriority`);
- const enable = (phase: string) => createFormClickAction(`enablePhaseSwitch-${phase}`);
+ const enable = (phase: Phases) => createFormClickAction(`enablePhaseSwitch-${phase}`);
const warmPhaseOnRollover = createFormClickAction(`warm-warmPhaseOnRollover`);
- const setMinAgeValue = (phase: string) => createFormSetValueAction(`${phase}-selectedMinimumAge`);
+ const setMinAgeValue = (phase: Phases) => createFormSetValueAction(`${phase}-selectedMinimumAge`);
- const setMinAgeUnits = (phase: string) =>
+ const setMinAgeUnits = (phase: Phases) =>
createFormSetValueAction(`${phase}-selectedMinimumAgeUnits`);
- const setDataAllocation = (phase: string) => async (value: DataTierAllocationType) => {
+ const setDataAllocation = (phase: Phases) => async (value: DataTierAllocationType) => {
act(() => {
find(`${phase}-dataTierAllocationControls.dataTierSelect`).simulate('click');
});
From 2befd672b7b74433d8434f6a09e7e5300a47a772 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 15:33:29 +0100
Subject: [PATCH 14/19] Addressed some PR review items
- refactor toggle click to take a boolean arg
- refactor selection options in data tier component to use a func
to get select options.
---
.../edit_policy/edit_policy.helpers.tsx | 24 ++---
.../edit_policy/edit_policy.test.ts | 21 ++--
.../components/data_tier_allocation.tsx | 102 +++++++++---------
3 files changed, 75 insertions(+), 72 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
index d6d79d290c43b6..1716f124b0c83a 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
@@ -57,19 +57,19 @@ export type EditPolicyTestBed = SetupReturn extends Promise ? U : Setup
export const setup = async () => {
const testBed = await initTestBed();
- const { find, component } = testBed;
+ const { find, component, form } = testBed;
- const createFormClickAction = (dataTestSubject: string) => async () => {
+ const createFormToggleAction = (dataTestSubject: string) => async (checked: boolean) => {
await act(async () => {
- find(dataTestSubject).simulate('click');
+ form.toggleEuiSwitch(dataTestSubject, checked);
});
component.update();
};
- function createFormSetValueAction(dataTestSubject: string) {
+ function createFormSetValueAction(dataTestSubject: string) {
return async (value: V) => {
await act(async () => {
- find(dataTestSubject).simulate('change', { target: { value } });
+ form.setInputValue(dataTestSubject, value);
});
component.update();
};
@@ -89,7 +89,7 @@ export const setup = async () => {
component.update();
};
- const toggleRollover = createFormClickAction('rolloverSwitch');
+ const toggleRollover = createFormToggleAction('rolloverSwitch');
const setMaxSize = async (value: string, units?: string) => {
await act(async () => {
@@ -115,19 +115,19 @@ export const setup = async () => {
component.update();
};
- const toggleForceMerge = (phase: Phases) => createFormClickAction(`${phase}-forceMergeSwitch`);
+ const toggleForceMerge = (phase: Phases) => createFormToggleAction(`${phase}-forceMergeSwitch`);
const setForcemergeSegmentsCount = (phase: Phases) =>
createFormSetValueAction(`${phase}-selectedForceMergeSegments`);
- const setBestCompression = (phase: Phases) => createFormClickAction(`${phase}-bestCompression`);
+ const setBestCompression = (phase: Phases) => createFormToggleAction(`${phase}-bestCompression`);
const setIndexPriority = (phase: Phases) =>
createFormSetValueAction(`${phase}-phaseIndexPriority`);
- const enable = (phase: Phases) => createFormClickAction(`enablePhaseSwitch-${phase}`);
+ const enable = (phase: Phases) => createFormToggleAction(`enablePhaseSwitch-${phase}`);
- const warmPhaseOnRollover = createFormClickAction(`warm-warmPhaseOnRollover`);
+ const warmPhaseOnRollover = createFormToggleAction(`warm-warmPhaseOnRollover`);
const setMinAgeValue = (phase: Phases) => createFormSetValueAction(`${phase}-selectedMinimumAge`);
@@ -158,12 +158,12 @@ export const setup = async () => {
createFormSetValueAction(`${phase}-selectedNodeAttrs`);
const setReplicas = async (value: string) => {
- await createFormClickAction('warm-setReplicasSwitch')();
+ await createFormToggleAction('warm-setReplicasSwitch')(true);
await createFormSetValueAction('warm-selectedReplicaCount')(value);
};
const setShrink = async (value: string) => {
- await createFormClickAction('shrinkSwitch')();
+ await createFormToggleAction('shrinkSwitch')(true);
await createFormSetValueAction('warm-selectedPrimaryShardCount')(value);
};
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
index 43fe008117b906..d7fcbc6fe1ad21 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
@@ -47,9 +47,9 @@ describe('', () => {
await actions.hot.setMaxSize('123', 'mb');
await actions.hot.setMaxDocs('123');
await actions.hot.setMaxAge('123', 'h');
- await actions.hot.toggleForceMerge();
+ await actions.hot.toggleForceMerge(true);
await actions.hot.setForcemergeSegments('123');
- await actions.hot.setBestCompression();
+ await actions.hot.setBestCompression(true);
await actions.hot.setIndexPriority('123');
await actions.savePolicy();
@@ -83,7 +83,7 @@ describe('', () => {
test('disabling rollover', async () => {
const { actions } = testBed;
- await actions.hot.toggleRollover();
+ await actions.hot.toggleRollover(true);
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
const policy = JSON.parse(JSON.parse(latestRequest.requestBody).body);
@@ -122,7 +122,7 @@ describe('', () => {
test('default values', async () => {
const { actions } = testBed;
- await actions.warm.enable();
+ await actions.warm.enable(true);
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
const warmPhase = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm;
@@ -140,16 +140,16 @@ describe('', () => {
test('setting all values', async () => {
const { actions } = testBed;
- await actions.warm.enable();
+ await actions.warm.enable(true);
await actions.warm.setMinAgeValue('123');
await actions.warm.setMinAgeUnits('d');
await actions.warm.setDataAllocation('node_attrs');
await actions.warm.setSelectedNodeAttribute('test:123');
await actions.warm.setReplicas('123');
await actions.warm.setShrink('123');
- await actions.warm.toggleForceMerge();
+ await actions.warm.toggleForceMerge(true);
await actions.warm.setForcemergeSegments('123');
- await actions.warm.setBestCompression();
+ await actions.warm.setBestCompression(true);
await actions.warm.setIndexPriority('123');
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
@@ -199,7 +199,7 @@ describe('', () => {
test('default allocation with replicas set', async () => {
const { actions } = testBed;
- await actions.warm.enable();
+ await actions.warm.enable(true);
await actions.warm.setReplicas('123');
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
@@ -219,8 +219,8 @@ describe('', () => {
test('setting warm phase on rollover to "true"', async () => {
const { actions } = testBed;
- await actions.warm.enable();
- await actions.warm.warmPhaseOnRollover();
+ await actions.warm.enable(true);
+ await actions.warm.warmPhaseOnRollover(true);
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
const warmPhaseMinAge = JSON.parse(JSON.parse(latestRequest.requestBody).body).phases.warm
@@ -270,7 +270,6 @@ describe('', () => {
describe('delete phase', () => {
beforeEach(async () => {
- server.respondImmediately = true;
httpRequestsMockHelpers.setLoadPolicies([DELETE_PHASE_POLICY]);
httpRequestsMockHelpers.setLoadSnapshotPolicies([
SNAPSHOT_POLICY_NAME,
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
index 2aa7e75a48b1b4..56af4bbac7a261 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/data_tier_allocation.tsx
@@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
import { EuiText, EuiSpacer, EuiSuperSelectOption } from '@elastic/eui';
import { UseField, SuperSelectField, useFormData } from '../../../../../../../../shared_imports';
+import { PhaseWithAllocation } from '../../../../../../../../../common/types';
import { DataTierAllocationType } from '../../../../../types';
@@ -89,6 +90,57 @@ const i18nTexts = {
},
};
+const getSelectOptions = (phase: PhaseWithAllocation, disableDataTierOption: boolean) =>
+ [
+ disableDataTierOption
+ ? undefined
+ : {
+ 'data-test-subj': 'defaultDataAllocationOption',
+ value: 'node_roles',
+ inputDisplay: i18nTexts.allocationOptions[phase].default.input,
+ dropdownDisplay: (
+ <>
+ {i18nTexts.allocationOptions[phase].default.input}
+
+
+ {i18nTexts.allocationOptions[phase].default.helpText}
+
+
+ >
+ ),
+ },
+ {
+ 'data-test-subj': 'customDataAllocationOption',
+ value: 'node_attrs',
+ inputDisplay: i18nTexts.allocationOptions[phase].custom.inputDisplay,
+ dropdownDisplay: (
+ <>
+ {i18nTexts.allocationOptions[phase].custom.inputDisplay}
+
+
+ {i18nTexts.allocationOptions[phase].custom.helpText}
+
+
+ >
+ ),
+ },
+ {
+ 'data-test-subj': 'noneDataAllocationOption',
+ value: 'none',
+ inputDisplay: i18nTexts.allocationOptions[phase].none.inputDisplay,
+ dropdownDisplay: (
+ <>
+ {i18nTexts.allocationOptions[phase].none.inputDisplay}
+
+
+ {i18nTexts.allocationOptions[phase].none.helpText}
+
+
+ >
+ ),
+ },
+ ].filter(Boolean) as SelectOptions[];
+
export const DataTierAllocation: FunctionComponent = (props) => {
const { phase, hasNodeAttributes, disableDataTierOption } = props;
@@ -120,55 +172,7 @@ export const DataTierAllocation: FunctionComponent = (props) => {
euiFieldProps={{
hasDividers: true,
'data-test-subj': 'dataTierSelect',
- options: [
- disableDataTierOption
- ? undefined
- : {
- 'data-test-subj': 'defaultDataAllocationOption',
- value: 'node_roles',
- inputDisplay: i18nTexts.allocationOptions[phase].default.input,
- dropdownDisplay: (
- <>
- {i18nTexts.allocationOptions[phase].default.input}
-
-
- {i18nTexts.allocationOptions[phase].default.helpText}
-
-
- >
- ),
- },
- {
- 'data-test-subj': 'customDataAllocationOption',
- value: 'node_attrs',
- inputDisplay: i18nTexts.allocationOptions[phase].custom.inputDisplay,
- dropdownDisplay: (
- <>
- {i18nTexts.allocationOptions[phase].custom.inputDisplay}
-
-
- {i18nTexts.allocationOptions[phase].custom.helpText}
-
-
- >
- ),
- },
- {
- 'data-test-subj': 'noneDataAllocationOption',
- value: 'none',
- inputDisplay: i18nTexts.allocationOptions[phase].none.inputDisplay,
- dropdownDisplay: (
- <>
- {i18nTexts.allocationOptions[phase].none.inputDisplay}
-
-
- {i18nTexts.allocationOptions[phase].none.helpText}
-
-
- >
- ),
- },
- ].filter(Boolean) as SelectOptions[],
+ options: getSelectOptions(phase, disableDataTierOption),
}}
/>
);
From 96e45ae3acc33ed794a03c8ca99a5940aab1cadf Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 15:45:01 +0100
Subject: [PATCH 15/19] updated data tier callout logic after new changes
---
.../data_tier_allocation_field.tsx | 44 +++++++++++--------
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
index bafc48e6e4eeed..73814537ff2764 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/data_tier_allocation_field.tsx
@@ -18,6 +18,8 @@ import { getAvailableNodeRoleForPhase } from '../../../../../../lib/data_tiers';
import { isNodeRoleFirstPreference } from '../../../../../../lib';
+import { DataTierAllocationType } from '../../../../types';
+
import {
DataTierAllocation,
DefaultAllocationNotice,
@@ -47,31 +49,35 @@ export const DataTierAllocationField: FunctionComponent = ({ phase, descr
const dataTierAllocationTypePath = `_meta.${phase}.dataTierAllocationType`;
const [formData] = useFormData({ watch: dataTierAllocationTypePath });
- const allocationType = get(formData, dataTierAllocationTypePath);
+ const allocationType: DataTierAllocationType = get(formData, dataTierAllocationTypePath);
return (
{({ nodesByRoles, nodesByAttributes, isUsingDeprecatedDataRoleConfig }) => {
+ const hasDataNodeRoles = Object.keys(nodesByRoles).some((nodeRole) =>
+ // match any of the "data_" roles, including data_content.
+ nodeRole.trim().startsWith('data_')
+ );
const hasNodeAttrs = Boolean(Object.keys(nodesByAttributes ?? {}).length);
+ const isCloudEnabled = cloud?.isCloudEnabled ?? false;
const renderNotice = () => {
switch (allocationType) {
case 'node_roles':
- const isCloudEnabled = cloud?.isCloudEnabled ?? false;
- const isUsingNodeRoles = !isUsingDeprecatedDataRoleConfig;
- if (
- isCloudEnabled &&
- isUsingNodeRoles &&
- phase === 'cold' &&
- !nodesByRoles.data_cold?.length
- ) {
- // Tell cloud users they can deploy cold tier nodes.
- return (
- <>
-
-
- >
- );
+ if (isCloudEnabled && phase === 'cold') {
+ const isUsingNodeRolesAllocation =
+ !isUsingDeprecatedDataRoleConfig && hasDataNodeRoles;
+ const hasNoNodesWithNodeRole = !nodesByRoles.data_cold?.length;
+
+ if (isUsingNodeRolesAllocation && hasNoNodesWithNodeRole) {
+ // Tell cloud users they can deploy nodes on cloud.
+ return (
+ <>
+
+
+ >
+ );
+ }
}
const allocationNodeRole = getAvailableNodeRoleForPhase(phase, nodesByRoles);
@@ -114,9 +120,9 @@ export const DataTierAllocationField: FunctionComponent = ({ phase, descr
hasNodeAttributes={hasNodeAttrs}
phase={phase}
nodes={nodesByAttributes}
- disableDataTierOption={
- !!(isUsingDeprecatedDataRoleConfig && cloud?.isCloudEnabled)
- }
+ disableDataTierOption={Boolean(
+ isCloudEnabled && !hasDataNodeRoles && isUsingDeprecatedDataRoleConfig
+ )}
/>
{/* Data tier related warnings and call-to-action notices */}
From cb03877d27fc9fb3943cdf9165cc364d6db07105 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 15:47:14 +0100
Subject: [PATCH 16/19] getPolicy -> updatePolicy
Also rather deconstruct the validate fn from the form object
---
.../edit_policy/components/policy_json_flyout.tsx | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
index 4852aecf621f76..9ed24355ce7b36 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/policy_json_flyout.tsx
@@ -45,12 +45,12 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({
*/
const [policy, setPolicy] = useState(undefined);
- const form = useFormContext();
+ const { validate: validateForm } = useFormContext();
const [, getFormData] = useFormData();
- const getPolicy = useCallback(async () => {
+ const updatePolicy = useCallback(async () => {
setPolicy(undefined);
- if (await form.validate()) {
+ if (await validateForm()) {
const p = getFormData() as SerializedPolicy;
setPolicy({
...legacyPolicy,
@@ -63,11 +63,11 @@ export const PolicyJsonFlyout: React.FunctionComponent = ({
} else {
setPolicy(null);
}
- }, [setPolicy, getFormData, legacyPolicy, form]);
+ }, [setPolicy, getFormData, legacyPolicy, validateForm]);
useEffect(() => {
- getPolicy();
- }, [getPolicy]);
+ updatePolicy();
+ }, [updatePolicy]);
let content: React.ReactNode;
switch (policy) {
From 6109d3a1707df74ea9dd9e44c2e5f7a3f0b8fe19 Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 16:29:07 +0100
Subject: [PATCH 17/19] fix detection of migrate false and refactor
serialization to pure function
---
.../common/types/policies.ts | 24 +++--
.../data_tiers/determine_allocation_type.ts | 46 ++++++----
.../sections/edit_policy/serializer.ts | 89 +++++++++----------
.../services/policies/cold_phase.ts | 4 +-
4 files changed, 88 insertions(+), 75 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
index 9e97f982e87b9a..813fcd9c253f1f 100644
--- a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
+++ b/x-pack/plugins/index_lifecycle_management/common/types/policies.ts
@@ -35,6 +35,19 @@ export interface SerializedPhase {
};
}
+export interface MigrateAction {
+ /**
+ * If enabled is ever set it will probably only be set to `false` because the default value
+ * for this is `true`. Rather leave unspecified for true when serialising.
+ */
+ enabled: boolean;
+}
+
+export interface SerializedActionWithAllocation {
+ allocate?: AllocateAction;
+ migrate?: MigrateAction;
+}
+
export interface SerializedHotPhase extends SerializedPhase {
actions: {
rollover?: {
@@ -59,7 +72,7 @@ export interface SerializedWarmPhase extends SerializedPhase {
set_priority?: {
priority: number | null;
};
- migrate?: { enabled: boolean };
+ migrate?: MigrateAction;
};
}
@@ -70,7 +83,7 @@ export interface SerializedColdPhase extends SerializedPhase {
set_priority?: {
priority: number | null;
};
- migrate?: { enabled: boolean };
+ migrate?: MigrateAction;
};
}
@@ -92,13 +105,6 @@ export interface AllocateAction {
require?: {
[attribute: string]: string;
};
- migrate?: {
- /**
- * If enabled is ever set it will only be set to `false` because the default value
- * for this is `true`. Rather leave unspecified for true.
- */
- enabled: false;
- };
}
export interface ForcemergeAction {
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
index 099893a9f04011..20ac439e9964f5 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/lib/data_tiers/determine_allocation_type.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { DataTierAllocationType, AllocateAction } from '../../../../common/types';
+import { DataTierAllocationType, AllocateAction, MigrateAction } from '../../../../common/types';
/**
* Determine what deserialized state the policy config represents.
@@ -12,20 +12,25 @@ import { DataTierAllocationType, AllocateAction } from '../../../../common/types
* See {@DataTierAllocationType} for more information.
*/
export const determineDataTierAllocationTypeLegacy = (
- allocateAction?: AllocateAction
+ actions: {
+ allocate?: AllocateAction;
+ migrate?: MigrateAction;
+ } = {}
): DataTierAllocationType => {
- if (!allocateAction) {
- return 'default';
- }
+ const { allocate, migrate } = actions;
- if (allocateAction.migrate?.enabled === false) {
+ if (migrate?.enabled === false) {
return 'none';
}
+ if (!allocate) {
+ return 'default';
+ }
+
if (
- (allocateAction.require && Object.keys(allocateAction.require).length) ||
- (allocateAction.include && Object.keys(allocateAction.include).length) ||
- (allocateAction.exclude && Object.keys(allocateAction.exclude).length)
+ (allocate.require && Object.keys(allocate.require).length) ||
+ (allocate.include && Object.keys(allocate.include).length) ||
+ (allocate.exclude && Object.keys(allocate.exclude).length)
) {
return 'custom';
}
@@ -33,19 +38,26 @@ export const determineDataTierAllocationTypeLegacy = (
return 'default';
};
-export const determineDataTierAllocationType = (allocateAction?: AllocateAction) => {
- if (!allocateAction) {
- return 'node_roles';
- }
+export const determineDataTierAllocationType = (
+ actions: {
+ allocate?: AllocateAction;
+ migrate?: MigrateAction;
+ } = {}
+) => {
+ const { allocate, migrate } = actions;
- if (allocateAction.migrate?.enabled === false) {
+ if (migrate?.enabled === false) {
return 'none';
}
+ if (!allocate) {
+ return 'node_roles';
+ }
+
if (
- (allocateAction.require && Object.keys(allocateAction.require).length) ||
- (allocateAction.include && Object.keys(allocateAction.include).length) ||
- (allocateAction.exclude && Object.keys(allocateAction.exclude).length)
+ (allocate.require && Object.keys(allocate.require).length) ||
+ (allocate.include && Object.keys(allocate.include).length) ||
+ (allocate.exclude && Object.keys(allocate.exclude).length)
) {
return 'node_attrs';
}
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
index 415de1707dd18f..90e81528f5afe6 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/serializer.ts
@@ -6,57 +6,54 @@
import { isEmpty } from 'lodash';
-import { AllocateAction, SerializedPhase, SerializedPolicy } from '../../../../common/types';
+import { SerializedPolicy, SerializedActionWithAllocation } from '../../../../common/types';
import { FormInternal, DataAllocationMetaFields } from './types';
import { isNumber } from '../../services/policies/policy_serialization';
-const unsafeSerializePhaseWithAllocation = (
- dataAllocationMetaFields: DataAllocationMetaFields,
- actions: SerializedPhase['actions'] = {},
- originalAllocation: AllocateAction = {}
-) => {
- if (dataAllocationMetaFields.dataTierAllocationType === 'node_attrs') {
- if (dataAllocationMetaFields.allocationNodeAttribute) {
- const [name, value] = dataAllocationMetaFields.allocationNodeAttribute.split(':');
- actions.allocate = {
- // copy over any other allocate details like "number_of_replicas"
- ...actions.allocate,
- require: {
- [name]: value,
- },
- };
- }
+const serializeAllocateAction = (
+ { dataTierAllocationType, allocationNodeAttribute }: DataAllocationMetaFields,
+ newActions: SerializedActionWithAllocation = {},
+ originalActions: SerializedActionWithAllocation = {}
+): SerializedActionWithAllocation => {
+ const { allocate, migrate, ...rest } = newActions;
+ // First copy over all non-allocate and migrate actions.
+ const actions: SerializedActionWithAllocation = { allocate, migrate, ...rest };
+
+ switch (dataTierAllocationType) {
+ case 'node_attrs':
+ if (allocationNodeAttribute) {
+ const [name, value] = allocationNodeAttribute.split(':');
+ actions.allocate = {
+ // copy over any other allocate details like "number_of_replicas"
+ ...actions.allocate,
+ require: {
+ [name]: value,
+ },
+ };
+ }
- // copy over the original include and exclude values until we can set them in the form.
- if (!isEmpty(originalAllocation.include)) {
- actions.allocate = {
- ...actions.allocate,
- include: { ...originalAllocation.include },
- };
- }
+ // copy over the original include and exclude values until we can set them in the form.
+ if (!isEmpty(originalActions?.allocate?.include)) {
+ actions.allocate = {
+ ...actions.allocate,
+ include: { ...originalActions?.allocate?.include },
+ };
+ }
- if (!isEmpty(originalAllocation.exclude)) {
- actions.allocate = {
- ...actions.allocate,
- exclude: { ...originalAllocation.exclude },
- };
- }
- } else if (dataAllocationMetaFields.dataTierAllocationType === 'none') {
- actions.migrate = { enabled: false };
- if (actions.allocate) {
- delete actions.allocate.require;
- delete actions.allocate.include;
- delete actions.allocate.exclude;
- }
- } else if (dataAllocationMetaFields.dataTierAllocationType === 'node_roles') {
- if (actions.allocate) {
- delete actions.allocate.require;
- delete actions.allocate.include;
- delete actions.allocate.exclude;
- }
- delete actions.migrate;
+ if (!isEmpty(originalActions?.allocate?.exclude)) {
+ actions.allocate = {
+ ...actions.allocate,
+ exclude: { ...originalActions?.allocate?.exclude },
+ };
+ }
+ break;
+ case 'none':
+ actions.migrate = { enabled: false };
+ break;
+ default:
}
+ return actions;
};
export const createSerializer = (originalPolicy?: SerializedPolicy) => (
@@ -109,10 +106,10 @@ export const createSerializer = (originalPolicy?: SerializedPolicy) => (
policy.phases.warm.min_age = `${policy.phases.warm.min_age}${_meta.warm.minAgeUnit}`;
}
- unsafeSerializePhaseWithAllocation(
+ policy.phases.warm.actions = serializeAllocateAction(
_meta.warm,
policy.phases.warm.actions,
- originalPolicy?.phases.warm?.actions.allocate
+ originalPolicy?.phases.warm?.actions
);
if (
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
index 89b4743a995694..e19107e7c9307d 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
@@ -36,9 +36,7 @@ export const coldPhaseFromES = (phaseSerialized?: SerializedColdPhase): ColdPhas
phase.phaseEnabled = true;
if (phaseSerialized.actions.allocate) {
- phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(
- phaseSerialized.actions.allocate
- );
+ phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(phaseSerialized.actions);
}
if (phaseSerialized.min_age) {
From 750992e3c4577b3229a9d8f8a43afed9acfbbbee Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 16:32:25 +0100
Subject: [PATCH 18/19] fix type issue
---
.../components/default_allocation_notice.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
index 9f7b37d49594d1..f1f8fef62f1f87 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared/data_tier_allocation_field/components/default_allocation_notice.tsx
@@ -8,11 +8,11 @@ import { i18n } from '@kbn/i18n';
import React, { FunctionComponent } from 'react';
import { EuiCallOut } from '@elastic/eui';
-import { PhaseWithAllocation, NodeDataRole } from '../../../../../../../../../common/types';
+import { PhaseWithAllocation, DataTierRole } from '../../../../../../../../../common/types';
import { AllocationNodeRole } from '../../../../../../../lib';
-const i18nTextsNodeRoleToDataTier: Record = {
+const i18nTextsNodeRoleToDataTier: Record = {
data_hot: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.dataTierHotLabel', {
defaultMessage: 'hot',
}),
@@ -31,7 +31,7 @@ const i18nTexts = {
'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.warm.title',
{ defaultMessage: 'No nodes assigned to the warm tier' }
),
- body: (nodeRole: NodeDataRole) =>
+ body: (nodeRole: DataTierRole) =>
i18n.translate('xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.warm', {
defaultMessage:
'This policy will move data in the warm phase to {tier} tier nodes instead.',
@@ -43,7 +43,7 @@ const i18nTexts = {
'xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.cold.title',
{ defaultMessage: 'No nodes assigned to the cold tier' }
),
- body: (nodeRole: NodeDataRole) =>
+ body: (nodeRole: DataTierRole) =>
i18n.translate('xpack.indexLifecycleMgmt.warmPhase.dataTier.defaultAllocationNotice.cold', {
defaultMessage:
'This policy will move data in the cold phase to {tier} tier nodes instead.',
From b85f49234817cda9d008a56fe0c671f3b176874c Mon Sep 17 00:00:00 2001
From: Jean-Louis Leysens
Date: Mon, 26 Oct 2020 17:54:35 +0100
Subject: [PATCH 19/19] fix for correctly detecting policy data tier type
- with jest tests see origin here:
https://github.com/elastic/kibana/pull/81642
---
.../edit_policy/constants.ts | 55 +++++++++++++++++++
.../edit_policy/edit_policy.test.ts | 55 +++++++++++++++++++
.../sections/edit_policy/deserializer.ts | 2 +-
.../services/policies/cold_phase.ts | 2 +-
4 files changed, 112 insertions(+), 2 deletions(-)
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
index bcc5ff53315d72..0a96146339a58b 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/constants.ts
@@ -95,3 +95,58 @@ export const DELETE_PHASE_POLICY: PolicyFromES = {
},
name: POLICY_NAME,
};
+
+export const POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION: PolicyFromES = {
+ version: 1,
+ modified_date: Date.now().toString(),
+ policy: {
+ phases: {
+ hot: {
+ min_age: '0ms',
+ actions: {
+ rollover: {
+ max_size: '50gb',
+ },
+ },
+ },
+ warm: {
+ actions: {
+ allocate: {
+ require: {},
+ include: { test: '123' },
+ exclude: {},
+ },
+ },
+ },
+ cold: {
+ actions: {
+ migrate: { enabled: false },
+ },
+ },
+ },
+ name: POLICY_NAME,
+ },
+ name: POLICY_NAME,
+};
+
+export const POLICY_WITH_NODE_ROLE_ALLOCATION: PolicyFromES = {
+ version: 1,
+ modified_date: Date.now().toString(),
+ policy: {
+ phases: {
+ hot: {
+ min_age: '0ms',
+ actions: {
+ rollover: {
+ max_size: '50gb',
+ },
+ },
+ },
+ warm: {
+ actions: {},
+ },
+ },
+ name: POLICY_NAME,
+ },
+ name: POLICY_NAME,
+};
diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
index d7fcbc6fe1ad21..fccffde3f793f2 100644
--- a/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
+++ b/x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.test.ts
@@ -16,6 +16,8 @@ import {
SNAPSHOT_POLICY_NAME,
DEFAULT_POLICY,
POLICY_WITH_INCLUDE_EXCLUDE,
+ POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION,
+ POLICY_WITH_NODE_ROLE_ALLOCATION,
} from './constants';
window.scrollTo = jest.fn();
@@ -381,4 +383,57 @@ describe('', () => {
expect(testBed.find('policiesErrorCallout').exists()).toBeTruthy();
});
});
+
+ describe('data allocation', () => {
+ describe('node roles', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ROLE_ALLOCATION]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+ test('showing "default" type', () => {
+ const { find } = testBed;
+ expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toContain(
+ 'recommended'
+ );
+ expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).not.toContain(
+ 'Custom'
+ );
+ expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).not.toContain('Off');
+ });
+ });
+ describe('node attr and none', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setLoadPolicies([POLICY_WITH_NODE_ATTR_AND_OFF_ALLOCATION]);
+ httpRequestsMockHelpers.setListNodes({
+ isUsingDeprecatedDataRoleConfig: false,
+ nodesByAttributes: { test: ['123'] },
+ nodesByRoles: { data: ['123'] },
+ });
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ const { component } = testBed;
+ component.update();
+ });
+
+ test('showing "custom" and "off" types', () => {
+ const { find } = testBed;
+ expect(find('warm-dataTierAllocationControls.dataTierSelect').text()).toContain('Custom');
+ expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off');
+ });
+ });
+ });
});
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
index 9337b87d995e6d..760c6ad713ea04 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/deserializer.ts
@@ -26,7 +26,7 @@ export const deserializer = (policy: SerializedPolicy): FormInternal => {
warmPhaseOnRollover: Boolean(policy.phases.warm?.min_age === '0ms'),
forceMergeEnabled: Boolean(policy.phases.warm?.actions?.forcemerge),
bestCompression: policy.phases.warm?.actions?.forcemerge?.index_codec === 'best_compression',
- dataTierAllocationType: determineDataTierAllocationType(policy.phases.warm?.actions.allocate),
+ dataTierAllocationType: determineDataTierAllocationType(policy.phases.warm?.actions),
},
};
diff --git a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
index e19107e7c9307d..faf3954f93fd8c 100644
--- a/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
+++ b/x-pack/plugins/index_lifecycle_management/public/application/services/policies/cold_phase.ts
@@ -35,7 +35,7 @@ export const coldPhaseFromES = (phaseSerialized?: SerializedColdPhase): ColdPhas
phase.phaseEnabled = true;
- if (phaseSerialized.actions.allocate) {
+ if (phaseSerialized.actions) {
phase.dataTierAllocationType = determineDataTierAllocationTypeLegacy(phaseSerialized.actions);
}