[7.x] Refactor IndexLifecycleRunner to split state modificatio… (#49936)

This commit refactors the `IndexLifecycleRunner` to split out and
consolidate the number of methods that change state from within ILM. It
adds a new class `IndexLifecycleTransition` that contains a number of
static methods used to modify ILM's state. These methods all return new
cluster states rather than making changes themselves (they can be
thought of as helpers for modifying ILM state).

Rather than having multiple ways to move an index to a particular step
(like `moveClusterStateToStep`, `moveClusterStateToNextStep`,
`moveClusterStateToPreviouslyFailedStep`, etc (there are others)) this
now consolidates those into three with (hopefully) useful names:

- `moveClusterStateToStep`
- `moveClusterStateToErrorStep`
- `moveClusterStateToPreviouslyFailedStep`

In the move, I was also able to consolidate duplicate or redundant
arguments to these functions. Prior to this commit there were many calls
that provided duplicate information (both `IndexMetaData` and
`LifecycleExecutionState` for example) where the duplicate argument
could be derived from a previous argument with no problems.

With this split, `IndexLifecycleRunner` now contains the methods used to
actually run steps as well as the methods that kick off cluster state
updates for state transitions. `IndexLifecycleTransition` contains only
the helpers for constructing new states from given scenarios.

This also adds Javadocs to all methods in both `IndexLifecycleRunner`
and `IndexLifecycleTransition` (this accounts for almost all of the
increase in code lines for this commit). It also makes all methods be as
restrictive in visibility, to limit the scope of where they are used.

This refactoring is part of work towards capturing actions and
transitions that ILM makes, by consolidating and simplifying the places
we make state changes, it will make adding operation auditing easier.
This commit is contained in:
Lee Hinman 2019-12-06 12:55:16 -07:00 committed by GitHub
parent 1c5a139968
commit 8205cdd423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1446 additions and 1223 deletions

View File

@ -8,6 +8,8 @@ package org.elasticsearch.xpack.core.ilm;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import java.util.Collections;
import java.util.HashMap;
@ -78,6 +80,31 @@ public class LifecycleExecutionState {
return fromCustomMetadata(customData);
}
/**
* Retrieves the current {@link Step.StepKey} from the lifecycle state. Note that
* it is illegal for the step to be set with the phase and/or action unset,
* or for the step to be unset with the phase and/or action set. All three
* settings must be either present or missing.
*
* @param lifecycleState the index custom data to extract the {@link Step.StepKey} from.
*/
@Nullable
public static Step.StepKey getCurrentStepKey(LifecycleExecutionState lifecycleState) {
Objects.requireNonNull(lifecycleState, "cannot determine current step key as lifecycle state is null");
String currentPhase = lifecycleState.getPhase();
String currentAction = lifecycleState.getAction();
String currentStep = lifecycleState.getStep();
if (Strings.isNullOrEmpty(currentStep)) {
assert Strings.isNullOrEmpty(currentPhase) : "Current phase is not empty: " + currentPhase;
assert Strings.isNullOrEmpty(currentAction) : "Current action is not empty: " + currentAction;
return null;
} else {
assert Strings.isNullOrEmpty(currentPhase) == false;
assert Strings.isNullOrEmpty(currentAction) == false;
return new Step.StepKey(currentPhase, currentAction, currentStep);
}
}
public static Builder builder() {
return new Builder();
}
@ -278,6 +305,11 @@ public class LifecycleExecutionState {
getStepInfo(), getPhaseDefinition(), getLifecycleDate(), getPhaseTime(), getActionTime(), getStepTime());
}
@Override
public String toString() {
return asMap().toString();
}
public static class Builder {
private String phase;
private String action;

View File

@ -71,6 +71,69 @@ public class LifecycleExecutionStateTests extends ESTestCase {
LifecycleExecutionStateTests::mutate);
}
public void testGetCurrentStepKey() {
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
Step.StepKey stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState.build());
assertNull(stepKey);
String phase = randomAlphaOfLength(20);
String action = randomAlphaOfLength(20);
String step = randomAlphaOfLength(20);
LifecycleExecutionState.Builder lifecycleState2 = LifecycleExecutionState.builder();
lifecycleState2.setPhase(phase);
lifecycleState2.setAction(action);
lifecycleState2.setStep(step);
stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState2.build());
assertNotNull(stepKey);
assertEquals(phase, stepKey.getPhase());
assertEquals(action, stepKey.getAction());
assertEquals(step, stepKey.getName());
phase = randomAlphaOfLength(20);
action = randomAlphaOfLength(20);
step = null;
LifecycleExecutionState.Builder lifecycleState3 = LifecycleExecutionState.builder();
lifecycleState3.setPhase(phase);
lifecycleState3.setAction(action);
lifecycleState3.setStep(step);
AssertionError error3 = expectThrows(AssertionError.class,
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState3.build()));
assertEquals("Current phase is not empty: " + phase, error3.getMessage());
phase = null;
action = randomAlphaOfLength(20);
step = null;
LifecycleExecutionState.Builder lifecycleState4 = LifecycleExecutionState.builder();
lifecycleState4.setPhase(phase);
lifecycleState4.setAction(action);
lifecycleState4.setStep(step);
AssertionError error4 = expectThrows(AssertionError.class,
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState4.build()));
assertEquals("Current action is not empty: " + action, error4.getMessage());
phase = null;
action = randomAlphaOfLength(20);
step = randomAlphaOfLength(20);
LifecycleExecutionState.Builder lifecycleState5 = LifecycleExecutionState.builder();
lifecycleState5.setPhase(phase);
lifecycleState5.setAction(action);
lifecycleState5.setStep(step);
AssertionError error5 = expectThrows(AssertionError.class,
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState5.build()));
assertNull(error5.getMessage());
phase = null;
action = null;
step = randomAlphaOfLength(20);
LifecycleExecutionState.Builder lifecycleState6 = LifecycleExecutionState.builder();
lifecycleState6.setPhase(phase);
lifecycleState6.setAction(action);
lifecycleState6.setStep(step);
AssertionError error6 = expectThrows(AssertionError.class,
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState6.build()));
assertNull(error6.getMessage());
}
private static LifecycleExecutionState mutate(LifecycleExecutionState toMutate) {
LifecycleExecutionState.Builder newState = LifecycleExecutionState.builder(toMutate);
boolean changed = false;

View File

@ -115,9 +115,9 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_true: indices.my_index.phase_time_millis
- is_true: indices.my_index.age
- is_true: indices.my_index.phase_execution
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_false: indices.my_index2
- is_false: indices.another_index
@ -139,9 +139,9 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_true: indices.my_index.phase_time_millis
- is_true: indices.my_index.age
- is_true: indices.my_index.phase_execution
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_true: indices.my_index2.managed
- match: { indices.my_index2.index: "my_index2" }
@ -151,9 +151,9 @@ teardown:
- match: { indices.my_index2.step: "complete" }
- is_true: indices.my_index2.phase_time_millis
- is_true: indices.my_index2.age
- is_true: indices.my_index2.phase_execution
- is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info
- is_false: indices.my_index2.phase_execution
- is_false: indices.another_index
- is_false: indices.unmanaged_index
@ -178,9 +178,9 @@ teardown:
- match: { indices.my_index.step: "complete" }
- is_true: indices.my_index.phase_time_millis
- is_true: indices.my_index.age
- is_true: indices.my_index.phase_execution
- is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info
- is_false: indices.my_index.phase_execution
- is_true: indices.my_index2.managed
- match: { indices.my_index2.index: "my_index2" }
@ -190,9 +190,9 @@ teardown:
- match: { indices.my_index2.step: "complete" }
- is_true: indices.my_index2.phase_time_millis
- is_true: indices.my_index2.age
- is_true: indices.my_index2.phase_execution
- is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info
- is_false: indices.my_index2.phase_execution
- is_true: indices.another_index.managed
- match: { indices.another_index.index: "another_index" }
@ -202,9 +202,9 @@ teardown:
- match: { indices.another_index.step: "complete" }
- is_true: indices.another_index.phase_time_millis
- is_true: indices.another_index.age
- is_true: indices.another_index.phase_execution
- is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info
- is_false: indices.another_index.phase_execution
- match: { indices.unmanaged_index.index: "unmanaged_index" }
- is_false: indices.unmanaged_index.managed

View File

@ -16,7 +16,6 @@ import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.ilm.ClusterStateActionStep;
import org.elasticsearch.xpack.core.ilm.ClusterStateWaitStep;
import org.elasticsearch.xpack.core.ilm.LifecycleExecutionState;
import org.elasticsearch.xpack.core.ilm.Step;
import org.elasticsearch.xpack.core.ilm.TerminalPolicyStep;
@ -78,8 +77,7 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
// This index doesn't exist any more, there's nothing to execute currently
return currentState;
}
Step registeredCurrentStep = IndexLifecycleRunner.getCurrentStep(policyStepsRegistry, policy, indexMetaData,
LifecycleExecutionState.fromIndexMetadata(indexMetaData));
Step registeredCurrentStep = IndexLifecycleRunner.getCurrentStep(policyStepsRegistry, policy, indexMetaData);
if (currentStep.equals(registeredCurrentStep)) {
ClusterState state = currentState;
// We can do cluster state steps all together until we
@ -103,8 +101,8 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
return state;
} else {
logger.trace("[{}] moving cluster state to next step [{}]", index.getName(), nextStepKey);
state = IndexLifecycleRunner.moveClusterStateToNextStep(index, state, currentStep.getKey(),
nextStepKey, nowSupplier, false);
state = IndexLifecycleTransition.moveClusterStateToStep(index, state, nextStepKey, nowSupplier,
policyStepsRegistry, false);
}
} else {
// set here to make sure that the clusterProcessed knows to execute the
@ -130,8 +128,8 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
if (currentStep.getNextStepKey() == null) {
return state;
} else {
state = IndexLifecycleRunner.moveClusterStateToNextStep(index, state, currentStep.getKey(),
currentStep.getNextStepKey(), nowSupplier, false);
state = IndexLifecycleTransition.moveClusterStateToStep(index, state,
currentStep.getNextStepKey(), nowSupplier, policyStepsRegistry,false);
}
} else {
logger.trace("[{}] condition not met ({}) [{}], returning existing state",
@ -145,7 +143,7 @@ public class ExecuteStepsUpdateTask extends ClusterStateUpdateTask {
if (stepInfo == null) {
return state;
} else {
return IndexLifecycleRunner.addStepInfoToClusterState(index, state, stepInfo);
return IndexLifecycleTransition.addStepInfoToClusterState(index, state, stepInfo);
}
}
}

View File

@ -8,22 +8,13 @@ package org.elasticsearch.xpack.ilm;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.support.TransportAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateObserver;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.Index;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.ilm.AsyncActionStep;
@ -31,46 +22,45 @@ import org.elasticsearch.xpack.core.ilm.AsyncWaitStep;
import org.elasticsearch.xpack.core.ilm.ClusterStateActionStep;
import org.elasticsearch.xpack.core.ilm.ClusterStateWaitStep;
import org.elasticsearch.xpack.core.ilm.ErrorStep;
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.ilm.InitializePolicyContextStep;
import org.elasticsearch.xpack.core.ilm.LifecycleExecutionState;
import org.elasticsearch.xpack.core.ilm.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.ilm.LifecycleSettings;
import org.elasticsearch.xpack.core.ilm.Phase;
import org.elasticsearch.xpack.core.ilm.PhaseCompleteStep;
import org.elasticsearch.xpack.core.ilm.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.ilm.RolloverAction;
import org.elasticsearch.xpack.core.ilm.Step;
import org.elasticsearch.xpack.core.ilm.Step.StepKey;
import org.elasticsearch.xpack.core.ilm.TerminalPolicyStep;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.LongSupplier;
import static org.elasticsearch.ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE;
import static org.elasticsearch.xpack.core.ilm.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY;
import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_ORIGINATION_DATE;
public class IndexLifecycleRunner {
class IndexLifecycleRunner {
private static final Logger logger = LogManager.getLogger(IndexLifecycleRunner.class);
private static final ToXContent.Params STACKTRACE_PARAMS =
new ToXContent.MapParams(Collections.singletonMap(REST_EXCEPTION_SKIP_STACK_TRACE, "false"));
private final ThreadPool threadPool;
private PolicyStepsRegistry stepRegistry;
private ClusterService clusterService;
private LongSupplier nowSupplier;
public IndexLifecycleRunner(PolicyStepsRegistry stepRegistry, ClusterService clusterService,
ThreadPool threadPool, LongSupplier nowSupplier) {
IndexLifecycleRunner(PolicyStepsRegistry stepRegistry, ClusterService clusterService,
ThreadPool threadPool, LongSupplier nowSupplier) {
this.stepRegistry = stepRegistry;
this.clusterService = clusterService;
this.nowSupplier = nowSupplier;
this.threadPool = threadPool;
}
/**
* Retrieve the index's current step.
*/
static Step getCurrentStep(PolicyStepsRegistry stepRegistry, String policy, IndexMetaData indexMetaData) {
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
logger.trace("[{}] retrieved current step key: {}", indexMetaData.getIndex().getName(), currentStepKey);
if (currentStepKey == null) {
return stepRegistry.getFirstStep(policy);
} else {
return stepRegistry.getStep(indexMetaData, currentStepKey);
}
}
/**
* Return true or false depending on whether the index is ready to be in {@code phase}
*/
@ -101,12 +91,12 @@ public class IndexLifecycleRunner {
* Run the current step, only if it is an asynchronous wait step. These
* wait criteria are checked periodically from the ILM scheduler
*/
public void runPeriodicStep(String policy, IndexMetaData indexMetaData) {
void runPeriodicStep(String policy, IndexMetaData indexMetaData) {
String index = indexMetaData.getIndex().getName();
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
final Step currentStep;
try {
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData);
} catch (Exception e) {
markPolicyRetrievalError(policy, indexMetaData.getIndex(), lifecycleState, e);
return;
@ -118,7 +108,7 @@ public class IndexLifecycleRunner {
return;
} else {
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
LifecycleExecutionState.getCurrentStepKey(lifecycleState), index, policy);
return;
}
}
@ -163,6 +153,11 @@ public class IndexLifecycleRunner {
}
}
/**
* Given the policy and index metadata for an index, this moves the index's
* execution state to the previously failed step, incrementing the retry
* counter.
*/
private void onErrorMaybeRetryFailedStep(String policy, IndexMetaData indexMetaData) {
String index = indexMetaData.getIndex().getName();
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
@ -181,7 +176,8 @@ public class IndexLifecycleRunner {
clusterService.submitStateUpdateTask("ilm-retry-failed-step", new ClusterStateUpdateTask() {
@Override
public ClusterState execute(ClusterState currentState) {
return moveClusterStateToPreviouslyFailedStep(currentState, index, true);
return IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(currentState, index,
nowSupplier, stepRegistry, true);
}
@Override
@ -198,19 +194,19 @@ public class IndexLifecycleRunner {
/**
* If the current step (matching the expected step key) is an asynchronous action step, run it
*/
public void maybeRunAsyncAction(ClusterState currentState, IndexMetaData indexMetaData, String policy, StepKey expectedStepKey) {
void maybeRunAsyncAction(ClusterState currentState, IndexMetaData indexMetaData, String policy, StepKey expectedStepKey) {
String index = indexMetaData.getIndex().getName();
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
final Step currentStep;
try {
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData);
} catch (Exception e) {
markPolicyRetrievalError(policy, indexMetaData.getIndex(), lifecycleState, e);
return;
}
if (currentStep == null) {
logger.warn("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
LifecycleExecutionState.getCurrentStepKey(lifecycleState), index, policy);
return;
}
@ -247,12 +243,12 @@ public class IndexLifecycleRunner {
* Run the current step that either waits for index age, or updates/waits-on cluster state.
* Invoked after the cluster state has been changed
*/
public void runPolicyAfterStateChange(String policy, IndexMetaData indexMetaData) {
void runPolicyAfterStateChange(String policy, IndexMetaData indexMetaData) {
String index = indexMetaData.getIndex().getName();
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
final Step currentStep;
try {
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
currentStep = getCurrentStep(stepRegistry, policy, indexMetaData);
} catch (Exception e) {
markPolicyRetrievalError(policy, indexMetaData.getIndex(), lifecycleState, e);
return;
@ -263,7 +259,7 @@ public class IndexLifecycleRunner {
return;
} else {
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
LifecycleExecutionState.getCurrentStepKey(lifecycleState), index, policy);
return;
}
}
@ -293,336 +289,58 @@ public class IndexLifecycleRunner {
}
/**
* Retrieves the current {@link StepKey} from the index settings. Note that
* it is illegal for the step to be set with the phase and/or action unset,
* or for the step to be unset with the phase and/or action set. All three
* settings must be either present or missing.
*
* @param lifecycleState the index custom data to extract the {@link StepKey} from.
* Move the index to the given {@code newStepKey}, always checks to ensure that the index's
* current step matches the {@code currentStepKey} prior to changing the state.
*/
public static StepKey getCurrentStepKey(LifecycleExecutionState lifecycleState) {
String currentPhase = lifecycleState.getPhase();
String currentAction = lifecycleState.getAction();
String currentStep = lifecycleState.getStep();
if (Strings.isNullOrEmpty(currentStep)) {
assert Strings.isNullOrEmpty(currentPhase) : "Current phase is not empty: " + currentPhase;
assert Strings.isNullOrEmpty(currentAction) : "Current action is not empty: " + currentAction;
return null;
} else {
assert Strings.isNullOrEmpty(currentPhase) == false;
assert Strings.isNullOrEmpty(currentAction) == false;
return new StepKey(currentPhase, currentAction, currentStep);
}
}
static Step getCurrentStep(PolicyStepsRegistry stepRegistry, String policy, IndexMetaData indexMetaData,
LifecycleExecutionState lifecycleState) {
StepKey currentStepKey = getCurrentStepKey(lifecycleState);
logger.trace("[{}] retrieved current step key: {}", indexMetaData.getIndex().getName(), currentStepKey);
if (currentStepKey == null) {
return stepRegistry.getFirstStep(policy);
} else {
return stepRegistry.getStep(indexMetaData, currentStepKey);
}
}
/**
* This method is intended for handling moving to different steps from {@link TransportAction} executions.
* For this reason, it is reasonable to throw {@link IllegalArgumentException} when state is not as expected.
*
* @param indexName The index whose step is to change
* @param currentState The current {@link ClusterState}
* @param currentStepKey The current {@link StepKey} found for the index in the current cluster state
* @param nextStepKey The next step to move the index into
* @param nowSupplier The current-time supplier for updating when steps changed
* @param stepRegistry The steps registry to check a step-key's existence in the index's current policy
* @return The updated cluster state where the index moved to <code>nextStepKey</code>
*/
static ClusterState moveClusterStateToStep(String indexName, ClusterState currentState, StepKey currentStepKey,
StepKey nextStepKey, LongSupplier nowSupplier,
PolicyStepsRegistry stepRegistry) {
IndexMetaData idxMeta = currentState.getMetaData().index(indexName);
validateTransition(idxMeta, currentStepKey, nextStepKey, stepRegistry);
Settings indexSettings = idxMeta.getSettings();
String policy = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings);
logger.info("moving index [{}] from [{}] to [{}] in policy [{}]",
indexName, currentStepKey, nextStepKey, policy);
return IndexLifecycleRunner.moveClusterStateToNextStep(idxMeta.getIndex(), currentState, currentStepKey,
nextStepKey, nowSupplier, true);
}
static void validateTransition(IndexMetaData idxMeta, StepKey currentStepKey, StepKey nextStepKey, PolicyStepsRegistry stepRegistry) {
String indexName = idxMeta.getIndex().getName();
Settings indexSettings = idxMeta.getSettings();
String indexPolicySetting = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings);
// policy could be updated in-between execution
if (Strings.isNullOrEmpty(indexPolicySetting)) {
throw new IllegalArgumentException("index [" + indexName + "] is not associated with an Index Lifecycle Policy");
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
if (currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(lifecycleState)) == false) {
throw new IllegalArgumentException("index [" + indexName + "] is not on current step [" + currentStepKey + "]");
}
if (stepRegistry.stepExists(indexPolicySetting, nextStepKey) == false) {
throw new IllegalArgumentException("step [" + nextStepKey + "] for index [" + idxMeta.getIndex().getName() +
"] with policy [" + indexPolicySetting + "] does not exist");
}
}
static ClusterState moveClusterStateToNextStep(Index index, ClusterState clusterState, StepKey currentStep, StepKey nextStep,
LongSupplier nowSupplier, boolean forcePhaseDefinitionRefresh) {
IndexMetaData idxMeta = clusterState.getMetaData().index(index);
IndexLifecycleMetadata ilmMeta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
LifecycleExecutionState newLifecycleState = moveExecutionStateToNextStep(policyMetadata,
lifecycleState, currentStep, nextStep, nowSupplier, forcePhaseDefinitionRefresh);
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, clusterState, newLifecycleState);
return newClusterStateBuilder.build();
}
static ClusterState moveClusterStateToErrorStep(Index index, ClusterState clusterState, StepKey currentStep, Exception cause,
LongSupplier nowSupplier,
BiFunction<IndexMetaData, StepKey, Step> stepLookupFunction) throws IOException {
IndexMetaData idxMeta = clusterState.getMetaData().index(index);
IndexLifecycleMetadata ilmMeta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
XContentBuilder causeXContentBuilder = JsonXContent.contentBuilder();
causeXContentBuilder.startObject();
ElasticsearchException.generateThrowableXContent(causeXContentBuilder, STACKTRACE_PARAMS, cause);
causeXContentBuilder.endObject();
LifecycleExecutionState currentState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
LifecycleExecutionState nextStepState = moveExecutionStateToNextStep(policyMetadata, currentState, currentStep,
new StepKey(currentStep.getPhase(), currentStep.getAction(), ErrorStep.NAME), nowSupplier, false);
LifecycleExecutionState.Builder failedState = LifecycleExecutionState.builder(nextStepState);
failedState.setFailedStep(currentStep.getName());
failedState.setStepInfo(BytesReference.bytes(causeXContentBuilder).utf8ToString());
Step failedStep = stepLookupFunction.apply(idxMeta, currentStep);
if (failedStep != null) {
// as an initial step we'll mark the failed step as auto retryable without actually looking at the cause to determine
// if the error is transient/recoverable from
failedState.setIsAutoRetryableError(failedStep.isRetryable());
// maintain the retry count of the failed step as it will be cleared after a successful execution
failedState.setFailedStepRetryCount(currentState.getFailedStepRetryCount());
} else {
logger.warn("failed step [{}] for index [{}] is not part of policy [{}] anymore, or it is invalid",
currentStep.getName(), index, policyMetadata.getName());
}
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, clusterState, failedState.build());
return newClusterStateBuilder.build();
}
ClusterState moveClusterStateToPreviouslyFailedStep(ClusterState currentState, String index, boolean isAutomaticRetry) {
ClusterState newState;
IndexMetaData indexMetaData = currentState.metaData().index(index);
if (indexMetaData == null) {
throw new IllegalArgumentException("index [" + index + "] does not exist");
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
String failedStep = lifecycleState.getFailedStep();
if (currentStepKey != null && ErrorStep.NAME.equals(currentStepKey.getName()) && Strings.isNullOrEmpty(failedStep) == false) {
StepKey nextStepKey = new StepKey(currentStepKey.getPhase(), currentStepKey.getAction(), failedStep);
validateTransition(indexMetaData, currentStepKey, nextStepKey, stepRegistry);
IndexLifecycleMetadata ilmMeta = currentState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexMetaData.getSettings()));
LifecycleExecutionState nextStepState = moveExecutionStateToNextStep(policyMetadata,
lifecycleState, currentStepKey, nextStepKey, nowSupplier, true);
LifecycleExecutionState.Builder retryStepState = LifecycleExecutionState.builder(nextStepState);
retryStepState.setIsAutoRetryableError(lifecycleState.isAutoRetryableError());
Integer currentRetryCount = lifecycleState.getFailedStepRetryCount();
if (isAutomaticRetry) {
retryStepState.setFailedStepRetryCount(currentRetryCount == null ? 1 : ++currentRetryCount);
} else {
// manual retries don't update the retry count
retryStepState.setFailedStepRetryCount(lifecycleState.getFailedStepRetryCount());
}
newState = newClusterStateWithLifecycleState(indexMetaData.getIndex(), currentState, retryStepState.build()).build();
} else {
throw new IllegalArgumentException("cannot retry an action for an index ["
+ index + "] that has not encountered an error when running a Lifecycle Policy");
}
return newState;
}
ClusterState moveClusterStateToPreviouslyFailedStep(ClusterState currentState, String[] indices) {
ClusterState newState = currentState;
for (String index : indices) {
newState = moveClusterStateToPreviouslyFailedStep(newState, index, false);
}
return newState;
}
private static LifecycleExecutionState moveExecutionStateToNextStep(LifecyclePolicyMetadata policyMetadata,
LifecycleExecutionState existingState,
StepKey currentStep, StepKey nextStep,
LongSupplier nowSupplier,
boolean forcePhaseDefinitionRefresh) {
long nowAsMillis = nowSupplier.getAsLong();
LifecycleExecutionState.Builder updatedState = LifecycleExecutionState.builder(existingState);
updatedState.setPhase(nextStep.getPhase());
updatedState.setAction(nextStep.getAction());
updatedState.setStep(nextStep.getName());
updatedState.setStepTime(nowAsMillis);
// clear any step info or error-related settings from the current step
updatedState.setFailedStep(null);
updatedState.setStepInfo(null);
updatedState.setIsAutoRetryableError(null);
updatedState.setFailedStepRetryCount(null);
if (currentStep.getPhase().equals(nextStep.getPhase()) == false || forcePhaseDefinitionRefresh) {
final String newPhaseDefinition;
final Phase nextPhase;
if ("new".equals(nextStep.getPhase()) || TerminalPolicyStep.KEY.equals(nextStep)) {
nextPhase = null;
} else {
nextPhase = policyMetadata.getPolicy().getPhases().get(nextStep.getPhase());
}
PhaseExecutionInfo phaseExecutionInfo = new PhaseExecutionInfo(policyMetadata.getName(), nextPhase,
policyMetadata.getVersion(), policyMetadata.getModifiedDate());
newPhaseDefinition = Strings.toString(phaseExecutionInfo, false, false);
updatedState.setPhaseDefinition(newPhaseDefinition);
updatedState.setPhaseTime(nowAsMillis);
} else if (currentStep.getPhase().equals(InitializePolicyContextStep.INITIALIZATION_PHASE)) {
// The "new" phase is the initialization phase, usually the phase
// time would be set on phase transition, but since there is no
// transition into the "new" phase, we set it any time in the "new"
// phase
updatedState.setPhaseTime(nowAsMillis);
}
if (currentStep.getAction().equals(nextStep.getAction()) == false) {
updatedState.setActionTime(nowAsMillis);
}
return updatedState.build();
}
static ClusterState.Builder newClusterStateWithLifecycleState(Index index, ClusterState clusterState,
LifecycleExecutionState lifecycleState) {
ClusterState.Builder newClusterStateBuilder = ClusterState.builder(clusterState);
newClusterStateBuilder.metaData(MetaData.builder(clusterState.getMetaData())
.put(IndexMetaData.builder(clusterState.getMetaData().index(index))
.putCustom(ILM_CUSTOM_METADATA_KEY, lifecycleState.asMap())));
return newClusterStateBuilder;
}
/**
* Conditionally updates cluster state with new step info. The new cluster state is only
* built if the step info has changed, otherwise the same old <code>clusterState</code> is
* returned
*
* @param index the index to modify
* @param clusterState the cluster state to modify
* @param stepInfo the new step info to update
* @return Updated cluster state with <code>stepInfo</code> if changed, otherwise the same cluster state
* if no changes to step info exist
* @throws IOException if parsing step info fails
*/
static ClusterState addStepInfoToClusterState(Index index, ClusterState clusterState, ToXContentObject stepInfo) throws IOException {
IndexMetaData indexMetaData = clusterState.getMetaData().index(index);
if (indexMetaData == null) {
// This index doesn't exist anymore, we can't do anything
return clusterState;
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
final String stepInfoString;
try (XContentBuilder infoXContentBuilder = JsonXContent.contentBuilder()) {
stepInfo.toXContent(infoXContentBuilder, ToXContent.EMPTY_PARAMS);
stepInfoString = BytesReference.bytes(infoXContentBuilder).utf8ToString();
}
if (stepInfoString.equals(lifecycleState.getStepInfo())) {
return clusterState;
}
LifecycleExecutionState.Builder newState = LifecycleExecutionState.builder(lifecycleState);
newState.setStepInfo(stepInfoString);
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, clusterState, newState.build());
return newClusterStateBuilder.build();
}
private void moveToStep(Index index, String policy, StepKey currentStepKey, StepKey nextStepKey) {
logger.debug("[{}] moving to step [{}] {} -> {}", index.getName(), policy, currentStepKey, nextStepKey);
private void moveToStep(Index index, String policy, Step.StepKey currentStepKey, Step.StepKey newStepKey) {
logger.debug("[{}] moving to step [{}] {} -> {}", index.getName(), policy, currentStepKey, newStepKey);
clusterService.submitStateUpdateTask("ilm-move-to-step",
new MoveToNextStepUpdateTask(index, policy, currentStepKey, nextStepKey, nowSupplier, clusterState ->
new MoveToNextStepUpdateTask(index, policy, currentStepKey, newStepKey, nowSupplier, stepRegistry, clusterState ->
{
IndexMetaData indexMetaData = clusterState.metaData().index(index);
if (nextStepKey != null && nextStepKey != TerminalPolicyStep.KEY && indexMetaData != null) {
maybeRunAsyncAction(clusterState, indexMetaData, policy, nextStepKey);
if (newStepKey != null && newStepKey != TerminalPolicyStep.KEY && indexMetaData != null) {
maybeRunAsyncAction(clusterState, indexMetaData, policy, newStepKey);
}
}));
}
private void moveToErrorStep(Index index, String policy, StepKey currentStepKey, Exception e) {
/**
* Move the index to the ERROR step.
*/
private void moveToErrorStep(Index index, String policy, Step.StepKey currentStepKey, Exception e) {
logger.error(new ParameterizedMessage("policy [{}] for index [{}] failed on step [{}]. Moving to ERROR step",
policy, index.getName(), currentStepKey), e);
policy, index.getName(), currentStepKey), e);
clusterService.submitStateUpdateTask("ilm-move-to-error-step",
new MoveToErrorStepUpdateTask(index, policy, currentStepKey, e, nowSupplier, stepRegistry::getStep));
}
private void setStepInfo(Index index, String policy, StepKey currentStepKey, ToXContentObject stepInfo) {
/**
* Set step info for the given index inside of its {@link LifecycleExecutionState} without
* changing other execution state.
*/
private void setStepInfo(Index index, String policy, Step.StepKey currentStepKey, ToXContentObject stepInfo) {
clusterService.submitStateUpdateTask("ilm-set-step-info", new SetStepInfoUpdateTask(index, policy, currentStepKey, stepInfo));
}
public static ClusterState removePolicyForIndexes(final Index[] indices, ClusterState currentState, List<String> failedIndexes) {
MetaData.Builder newMetadata = MetaData.builder(currentState.getMetaData());
boolean clusterStateChanged = false;
for (Index index : indices) {
IndexMetaData indexMetadata = currentState.getMetaData().index(index);
if (indexMetadata == null) {
// Index doesn't exist so fail it
failedIndexes.add(index.getName());
} else {
IndexMetaData.Builder newIdxMetadata = IndexLifecycleRunner.removePolicyForIndex(indexMetadata);
if (newIdxMetadata != null) {
newMetadata.put(newIdxMetadata);
clusterStateChanged = true;
}
}
}
if (clusterStateChanged) {
ClusterState.Builder newClusterState = ClusterState.builder(currentState);
newClusterState.metaData(newMetadata);
return newClusterState.build();
} else {
return currentState;
}
}
private static IndexMetaData.Builder removePolicyForIndex(IndexMetaData indexMetadata) {
Settings idxSettings = indexMetadata.getSettings();
Settings.Builder newSettings = Settings.builder().put(idxSettings);
boolean notChanged = true;
notChanged &= Strings.isNullOrEmpty(newSettings.remove(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey()));
notChanged &= Strings.isNullOrEmpty(newSettings.remove(LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING.getKey()));
notChanged &= Strings.isNullOrEmpty(newSettings.remove(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.getKey()));
long newSettingsVersion = notChanged ? indexMetadata.getSettingsVersion() : 1 + indexMetadata.getSettingsVersion();
IndexMetaData.Builder builder = IndexMetaData.builder(indexMetadata);
builder.removeCustom(ILM_CUSTOM_METADATA_KEY);
return builder.settings(newSettings).settingsVersion(newSettingsVersion);
}
/**
* Mark the index with step info explaining that the policy doesn't exist.
*/
private void markPolicyDoesNotExist(String policyName, Index index, LifecycleExecutionState executionState) {
markPolicyRetrievalError(policyName, index, executionState,
new IllegalArgumentException("policy [" + policyName + "] does not exist"));
}
/**
* Mark the index with step info for a given error encountered while retrieving policy
* information. This is opposed to lifecycle execution errors, which would cause a transition to
* the ERROR step, however, the policy may be unparseable in which case there is no way to move
* to the ERROR step, so this is the best effort at capturing the error retrieving the policy.
*/
private void markPolicyRetrievalError(String policyName, Index index, LifecycleExecutionState executionState, Exception e) {
logger.debug(
new ParameterizedMessage("unable to retrieve policy [{}] for index [{}], recording this in step_info for this index",
policyName, index.getName()), e);
setStepInfo(index, policyName, getCurrentStepKey(executionState), new SetStepInfoUpdateTask.ExceptionWrapper(e));
policyName, index.getName()), e);
setStepInfo(index, policyName, LifecycleExecutionState.getCurrentStepKey(executionState),
new SetStepInfoUpdateTask.ExceptionWrapper(e));
}
}

View File

@ -87,13 +87,33 @@ public class IndexLifecycleService
lifecycleRunner.maybeRunAsyncAction(clusterState, indexMetaData, policyName, nextStepKey);
}
public ClusterState moveClusterStateToStep(ClusterState currentState, String indexName, StepKey currentStepKey, StepKey nextStepKey) {
return IndexLifecycleRunner.moveClusterStateToStep(indexName, currentState, currentStepKey, nextStepKey,
nowSupplier, policyRegistry);
/**
* Move the cluster state to an arbitrary step for the provided index.
*
* In order to avoid a check-then-set race condition, the current step key
* is required in order to validate that the index is currently on the
* provided step. If it is not, an {@link IllegalArgumentException} is
* thrown.
* @throws IllegalArgumentException if the step movement cannot be validated
*/
public ClusterState moveClusterStateToStep(ClusterState currentState, Index index, StepKey currentStepKey, StepKey newStepKey) {
// We manually validate here, because any API must correctly specify the current step key
// when moving to an arbitrary step key (to avoid race conditions between the
// check-and-set). moveClusterStateToStep also does its own validation, but doesn't take
// the user-input for the current step (which is why we validate here for a passed in step)
IndexLifecycleTransition.validateTransition(currentState.getMetaData().index(index),
currentStepKey, newStepKey, policyRegistry);
return IndexLifecycleTransition.moveClusterStateToStep(index, currentState, newStepKey,
nowSupplier, policyRegistry, true);
}
public ClusterState moveClusterStateToPreviouslyFailedStep(ClusterState currentState, String[] indices) {
return lifecycleRunner.moveClusterStateToPreviouslyFailedStep(currentState, indices);
ClusterState newState = currentState;
for (String index : indices) {
newState = IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(newState, index,
nowSupplier, policyRegistry, false);
}
return newState;
}
@Override
@ -118,7 +138,7 @@ public class IndexLifecycleService
String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings());
if (Strings.isNullOrEmpty(policyName) == false) {
final LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
StepKey stepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
try {
if (OperationMode.STOPPING == currentMode) {
@ -279,7 +299,7 @@ public class IndexLifecycleService
String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings());
if (Strings.isNullOrEmpty(policyName) == false) {
final LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
StepKey stepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
try {
if (OperationMode.STOPPING == currentMode) {

View File

@ -0,0 +1,342 @@
/*
* 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.
*/
package org.elasticsearch.xpack.ilm;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.support.TransportAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.ilm.ErrorStep;
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.ilm.InitializePolicyContextStep;
import org.elasticsearch.xpack.core.ilm.LifecycleExecutionState;
import org.elasticsearch.xpack.core.ilm.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.ilm.LifecycleSettings;
import org.elasticsearch.xpack.core.ilm.Phase;
import org.elasticsearch.xpack.core.ilm.PhaseExecutionInfo;
import org.elasticsearch.xpack.core.ilm.RolloverAction;
import org.elasticsearch.xpack.core.ilm.Step;
import org.elasticsearch.xpack.core.ilm.TerminalPolicyStep;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.LongSupplier;
import static org.elasticsearch.ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE;
import static org.elasticsearch.xpack.core.ilm.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY;
/**
* The {@link IndexLifecycleTransition} class handles cluster state transitions
* related to ILM operations. These operations are all at the index level
* (inside of {@link IndexMetaData}) for the index in question.
*
* Each method is static and only changes a given state, no actions are
* performed by methods in this class.
*/
public final class IndexLifecycleTransition {
private static final Logger logger = LogManager.getLogger(IndexLifecycleTransition.class);
private static final ToXContent.Params STACKTRACE_PARAMS =
new ToXContent.MapParams(Collections.singletonMap(REST_EXCEPTION_SKIP_STACK_TRACE, "false"));
/**
* Validates that the given transition from {@code currentStepKey} to {@code newStepKey} can be accomplished
* @throws IllegalArgumentException when the transition is not valid
*/
public static void validateTransition(IndexMetaData idxMeta, Step.StepKey currentStepKey,
Step.StepKey newStepKey, PolicyStepsRegistry stepRegistry) {
String indexName = idxMeta.getIndex().getName();
Settings indexSettings = idxMeta.getSettings();
String indexPolicySetting = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings);
// policy could be updated in-between execution
if (Strings.isNullOrEmpty(indexPolicySetting)) {
throw new IllegalArgumentException("index [" + indexName + "] is not associated with an Index Lifecycle Policy");
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
if (currentStepKey != null && currentStepKey.equals(LifecycleExecutionState.getCurrentStepKey(lifecycleState)) == false) {
throw new IllegalArgumentException("index [" + indexName + "] is not on current step [" + currentStepKey + "]");
}
if (stepRegistry.stepExists(indexPolicySetting, newStepKey) == false) {
throw new IllegalArgumentException("step [" + newStepKey + "] for index [" + idxMeta.getIndex().getName() +
"] with policy [" + indexPolicySetting + "] does not exist");
}
}
/**
* This method is intended for handling moving to different steps from {@link TransportAction} executions.
* For this reason, it is reasonable to throw {@link IllegalArgumentException} when state is not as expected.
*
* @param index The index whose step is to change
* @param state The current {@link ClusterState}
* @param newStepKey The new step to move the index into
* @param nowSupplier The current-time supplier for updating when steps changed
* @param stepRegistry The steps registry to check a step-key's existence in the index's current policy
* @param forcePhaseDefinitionRefresh Whether to force the phase JSON to be reread or not
* @return The updated cluster state where the index moved to <code>newStepKey</code>
*/
static ClusterState moveClusterStateToStep(Index index, ClusterState state, Step.StepKey newStepKey, LongSupplier nowSupplier,
PolicyStepsRegistry stepRegistry, boolean forcePhaseDefinitionRefresh) {
IndexMetaData idxMeta = state.getMetaData().index(index);
Step.StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(LifecycleExecutionState.fromIndexMetadata(idxMeta));
validateTransition(idxMeta, currentStepKey, newStepKey, stepRegistry);
Settings indexSettings = idxMeta.getSettings();
String policy = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings);
logger.info("moving index [{}] from [{}] to [{}] in policy [{}]", index.getName(), currentStepKey, newStepKey, policy);
IndexLifecycleMetadata ilmMeta = state.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
LifecycleExecutionState newLifecycleState = updateExecutionStateToStep(policyMetadata,
lifecycleState, newStepKey, nowSupplier, forcePhaseDefinitionRefresh);
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, state, newLifecycleState);
return newClusterStateBuilder.build();
}
/**
* Moves the given index into the ERROR step. The ERROR step will have the same phase and
* action, but use the {@link ErrorStep#NAME} as the name in the lifecycle execution state.
*/
static ClusterState moveClusterStateToErrorStep(Index index, ClusterState clusterState, Exception cause, LongSupplier nowSupplier,
BiFunction<IndexMetaData, Step.StepKey, Step> stepLookupFunction) throws IOException {
IndexMetaData idxMeta = clusterState.getMetaData().index(index);
IndexLifecycleMetadata ilmMeta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(idxMeta.getSettings()));
XContentBuilder causeXContentBuilder = JsonXContent.contentBuilder();
causeXContentBuilder.startObject();
ElasticsearchException.generateThrowableXContent(causeXContentBuilder, STACKTRACE_PARAMS, cause);
causeXContentBuilder.endObject();
LifecycleExecutionState currentState = LifecycleExecutionState.fromIndexMetadata(idxMeta);
Step.StepKey currentStep = Objects.requireNonNull(LifecycleExecutionState.getCurrentStepKey(currentState),
"unable to move to an error step where there is no current step, state: " + currentState);
LifecycleExecutionState nextStepState = updateExecutionStateToStep(policyMetadata, currentState,
new Step.StepKey(currentStep.getPhase(), currentStep.getAction(), ErrorStep.NAME), nowSupplier, false);
LifecycleExecutionState.Builder failedState = LifecycleExecutionState.builder(nextStepState);
failedState.setFailedStep(currentStep.getName());
failedState.setStepInfo(BytesReference.bytes(causeXContentBuilder).utf8ToString());
Step failedStep = stepLookupFunction.apply(idxMeta, currentStep);
if (failedStep != null) {
// as an initial step we'll mark the failed step as auto retryable without actually looking at the cause to determine
// if the error is transient/recoverable from
failedState.setIsAutoRetryableError(failedStep.isRetryable());
// maintain the retry count of the failed step as it will be cleared after a successful execution
failedState.setFailedStepRetryCount(currentState.getFailedStepRetryCount());
} else {
logger.warn("failed step [{}] for index [{}] is not part of policy [{}] anymore, or it is invalid",
currentStep.getName(), index, policyMetadata.getName());
}
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, clusterState, failedState.build());
return newClusterStateBuilder.build();
}
/**
* Move the given index's execution state back to a step that had previously failed. If this is
* an automatic retry ({@code isAutomaticRetry}), the retry count is incremented.
*/
static ClusterState moveClusterStateToPreviouslyFailedStep(ClusterState currentState, String index, LongSupplier nowSupplier,
PolicyStepsRegistry stepRegistry, boolean isAutomaticRetry) {
ClusterState newState;
IndexMetaData indexMetaData = currentState.metaData().index(index);
if (indexMetaData == null) {
throw new IllegalArgumentException("index [" + index + "] does not exist");
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
Step.StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
String failedStep = lifecycleState.getFailedStep();
if (currentStepKey != null && ErrorStep.NAME.equals(currentStepKey.getName()) && Strings.isNullOrEmpty(failedStep) == false) {
Step.StepKey nextStepKey = new Step.StepKey(currentStepKey.getPhase(), currentStepKey.getAction(), failedStep);
IndexLifecycleTransition.validateTransition(indexMetaData, currentStepKey, nextStepKey, stepRegistry);
IndexLifecycleMetadata ilmMeta = currentState.metaData().custom(IndexLifecycleMetadata.TYPE);
LifecyclePolicyMetadata policyMetadata = ilmMeta.getPolicyMetadatas()
.get(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexMetaData.getSettings()));
LifecycleExecutionState nextStepState = IndexLifecycleTransition.updateExecutionStateToStep(policyMetadata,
lifecycleState, nextStepKey, nowSupplier, true);
LifecycleExecutionState.Builder retryStepState = LifecycleExecutionState.builder(nextStepState);
retryStepState.setIsAutoRetryableError(lifecycleState.isAutoRetryableError());
Integer currentRetryCount = lifecycleState.getFailedStepRetryCount();
if (isAutomaticRetry) {
retryStepState.setFailedStepRetryCount(currentRetryCount == null ? 1 : ++currentRetryCount);
} else {
// manual retries don't update the retry count
retryStepState.setFailedStepRetryCount(lifecycleState.getFailedStepRetryCount());
}
newState = IndexLifecycleTransition.newClusterStateWithLifecycleState(indexMetaData.getIndex(),
currentState, retryStepState.build()).build();
} else {
throw new IllegalArgumentException("cannot retry an action for an index ["
+ index + "] that has not encountered an error when running a Lifecycle Policy");
}
return newState;
}
/**
* Given the existing execution state for an index, this updates pieces of the state with new
* timings and optionally the phase JSON (when transitioning to a different phase).
*/
private static LifecycleExecutionState updateExecutionStateToStep(LifecyclePolicyMetadata policyMetadata,
LifecycleExecutionState existingState,
Step.StepKey newStep,
LongSupplier nowSupplier,
boolean forcePhaseDefinitionRefresh) {
Step.StepKey currentStep = LifecycleExecutionState.getCurrentStepKey(existingState);
long nowAsMillis = nowSupplier.getAsLong();
LifecycleExecutionState.Builder updatedState = LifecycleExecutionState.builder(existingState);
updatedState.setPhase(newStep.getPhase());
updatedState.setAction(newStep.getAction());
updatedState.setStep(newStep.getName());
updatedState.setStepTime(nowAsMillis);
// clear any step info or error-related settings from the current step
updatedState.setFailedStep(null);
updatedState.setStepInfo(null);
updatedState.setIsAutoRetryableError(null);
updatedState.setFailedStepRetryCount(null);
if (currentStep == null ||
currentStep.getPhase().equals(newStep.getPhase()) == false ||
forcePhaseDefinitionRefresh) {
final String newPhaseDefinition;
final Phase nextPhase;
if ("new".equals(newStep.getPhase()) || TerminalPolicyStep.KEY.equals(newStep)) {
nextPhase = null;
} else {
nextPhase = policyMetadata.getPolicy().getPhases().get(newStep.getPhase());
}
PhaseExecutionInfo phaseExecutionInfo = new PhaseExecutionInfo(policyMetadata.getName(), nextPhase,
policyMetadata.getVersion(), policyMetadata.getModifiedDate());
newPhaseDefinition = Strings.toString(phaseExecutionInfo, false, false);
updatedState.setPhaseDefinition(newPhaseDefinition);
updatedState.setPhaseTime(nowAsMillis);
} else if (currentStep.getPhase().equals(InitializePolicyContextStep.INITIALIZATION_PHASE)) {
// The "new" phase is the initialization phase, usually the phase
// time would be set on phase transition, but since there is no
// transition into the "new" phase, we set it any time in the "new"
// phase
updatedState.setPhaseTime(nowAsMillis);
}
if (currentStep == null || currentStep.getAction().equals(newStep.getAction()) == false) {
updatedState.setActionTime(nowAsMillis);
}
return updatedState.build();
}
/**
* Given a cluster state and lifecycle state, return a new state using the new lifecycle state for the given index.
*/
private static ClusterState.Builder newClusterStateWithLifecycleState(Index index, ClusterState clusterState,
LifecycleExecutionState lifecycleState) {
ClusterState.Builder newClusterStateBuilder = ClusterState.builder(clusterState);
newClusterStateBuilder.metaData(MetaData.builder(clusterState.getMetaData())
.put(IndexMetaData.builder(clusterState.getMetaData().index(index))
.putCustom(ILM_CUSTOM_METADATA_KEY, lifecycleState.asMap())));
return newClusterStateBuilder;
}
/**
* Conditionally updates cluster state with new step info. The new cluster state is only
* built if the step info has changed, otherwise the same old <code>clusterState</code> is
* returned
*
* @param index the index to modify
* @param clusterState the cluster state to modify
* @param stepInfo the new step info to update
* @return Updated cluster state with <code>stepInfo</code> if changed, otherwise the same cluster state
* if no changes to step info exist
* @throws IOException if parsing step info fails
*/
static ClusterState addStepInfoToClusterState(Index index, ClusterState clusterState, ToXContentObject stepInfo) throws IOException {
IndexMetaData indexMetaData = clusterState.getMetaData().index(index);
if (indexMetaData == null) {
// This index doesn't exist anymore, we can't do anything
return clusterState;
}
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData);
final String stepInfoString;
try (XContentBuilder infoXContentBuilder = JsonXContent.contentBuilder()) {
stepInfo.toXContent(infoXContentBuilder, ToXContent.EMPTY_PARAMS);
stepInfoString = BytesReference.bytes(infoXContentBuilder).utf8ToString();
}
if (stepInfoString.equals(lifecycleState.getStepInfo())) {
return clusterState;
}
LifecycleExecutionState.Builder newState = LifecycleExecutionState.builder(lifecycleState);
newState.setStepInfo(stepInfoString);
ClusterState.Builder newClusterStateBuilder = newClusterStateWithLifecycleState(index, clusterState, newState.build());
return newClusterStateBuilder.build();
}
/**
* Remove the ILM policy from the given indices, this removes the lifecycle setting as well as
* any lifecycle execution state that may be present in the index metadata
*/
public static ClusterState removePolicyForIndexes(final Index[] indices, ClusterState currentState, List<String> failedIndexes) {
MetaData.Builder newMetadata = MetaData.builder(currentState.getMetaData());
boolean clusterStateChanged = false;
for (Index index : indices) {
IndexMetaData indexMetadata = currentState.getMetaData().index(index);
if (indexMetadata == null) {
// Index doesn't exist so fail it
failedIndexes.add(index.getName());
} else {
IndexMetaData.Builder newIdxMetadata = removePolicyForIndex(indexMetadata);
if (newIdxMetadata != null) {
newMetadata.put(newIdxMetadata);
clusterStateChanged = true;
}
}
}
if (clusterStateChanged) {
ClusterState.Builder newClusterState = ClusterState.builder(currentState);
newClusterState.metaData(newMetadata);
return newClusterState.build();
} else {
return currentState;
}
}
/**
* Remove ILM-related metadata from an index's {@link IndexMetaData}
*/
private static IndexMetaData.Builder removePolicyForIndex(IndexMetaData indexMetadata) {
Settings idxSettings = indexMetadata.getSettings();
Settings.Builder newSettings = Settings.builder().put(idxSettings);
boolean notChanged = true;
notChanged &= Strings.isNullOrEmpty(newSettings.remove(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey()));
notChanged &= Strings.isNullOrEmpty(newSettings.remove(LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING.getKey()));
notChanged &= Strings.isNullOrEmpty(newSettings.remove(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.getKey()));
long newSettingsVersion = notChanged ? indexMetadata.getSettingsVersion() : 1 + indexMetadata.getSettingsVersion();
IndexMetaData.Builder builder = IndexMetaData.builder(indexMetadata);
builder.removeCustom(ILM_CUSTOM_METADATA_KEY);
return builder.settings(newSettings).settingsVersion(newSettingsVersion);
}
}

View File

@ -63,9 +63,8 @@ public class MoveToErrorStepUpdateTask extends ClusterStateUpdateTask {
Settings indexSettings = idxMeta.getSettings();
LifecycleExecutionState indexILMData = LifecycleExecutionState.fromIndexMetadata(idxMeta);
if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings))
&& currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
return IndexLifecycleRunner.moveClusterStateToErrorStep(index, currentState, currentStepKey, cause, nowSupplier,
stepLookupFunction);
&& currentStepKey.equals(LifecycleExecutionState.getCurrentStepKey(indexILMData))) {
return IndexLifecycleTransition.moveClusterStateToErrorStep(index, currentState, cause, nowSupplier, stepLookupFunction);
} else {
// either the policy has changed or the step is now
// not the same as when we submitted the update task. In

View File

@ -28,15 +28,18 @@ public class MoveToNextStepUpdateTask extends ClusterStateUpdateTask {
private final Step.StepKey currentStepKey;
private final Step.StepKey nextStepKey;
private final LongSupplier nowSupplier;
private final PolicyStepsRegistry stepRegistry;
private final Consumer<ClusterState> stateChangeConsumer;
public MoveToNextStepUpdateTask(Index index, String policy, Step.StepKey currentStepKey, Step.StepKey nextStepKey,
LongSupplier nowSupplier, Consumer<ClusterState> stateChangeConsumer) {
LongSupplier nowSupplier, PolicyStepsRegistry stepRegistry,
Consumer<ClusterState> stateChangeConsumer) {
this.index = index;
this.policy = policy;
this.currentStepKey = currentStepKey;
this.nextStepKey = nextStepKey;
this.nowSupplier = nowSupplier;
this.stepRegistry = stepRegistry;
this.stateChangeConsumer = stateChangeConsumer;
}
@ -66,9 +69,9 @@ public class MoveToNextStepUpdateTask extends ClusterStateUpdateTask {
Settings indexSettings = indexMetaData.getSettings();
LifecycleExecutionState indexILMData = LifecycleExecutionState.fromIndexMetadata(currentState.getMetaData().index(index));
if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings))
&& currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
&& currentStepKey.equals(LifecycleExecutionState.getCurrentStepKey(indexILMData))) {
logger.trace("moving [{}] to next step ({})", index.getName(), nextStepKey);
return IndexLifecycleRunner.moveClusterStateToNextStep(index, currentState, currentStepKey, nextStepKey, nowSupplier, false);
return IndexLifecycleTransition.moveClusterStateToStep(index, currentState, nextStepKey, nowSupplier, stepRegistry, false);
} else {
// either the policy has changed or the step is now
// not the same as when we submitted the update task. In

View File

@ -60,8 +60,8 @@ public class SetStepInfoUpdateTask extends ClusterStateUpdateTask {
Settings indexSettings = idxMeta.getSettings();
LifecycleExecutionState indexILMData = LifecycleExecutionState.fromIndexMetadata(idxMeta);
if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings))
&& Objects.equals(currentStepKey, IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
return IndexLifecycleRunner.addStepInfoToClusterState(index, currentState, stepInfo);
&& Objects.equals(currentStepKey, LifecycleExecutionState.getCurrentStepKey(indexILMData))) {
return IndexLifecycleTransition.addStepInfoToClusterState(index, currentState, stepInfo);
} else {
// either the policy has changed or the step is now
// not the same as when we submitted the update task. In

View File

@ -63,7 +63,7 @@ public class TransportMoveToStepAction extends TransportMasterNodeAction<Request
new AckedClusterStateUpdateTask<Response>(request, listener) {
@Override
public ClusterState execute(ClusterState currentState) {
return indexLifecycleService.moveClusterStateToStep(currentState, request.getIndex(), request.getCurrentStepKey(),
return indexLifecycleService.moveClusterStateToStep(currentState, indexMetaData.getIndex(), request.getCurrentStepKey(),
request.getNextStepKey());
}

View File

@ -23,7 +23,7 @@ import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.ilm.action.RemoveIndexLifecyclePolicyAction;
import org.elasticsearch.xpack.core.ilm.action.RemoveIndexLifecyclePolicyAction.Request;
import org.elasticsearch.xpack.core.ilm.action.RemoveIndexLifecyclePolicyAction.Response;
import org.elasticsearch.xpack.ilm.IndexLifecycleRunner;
import org.elasticsearch.xpack.ilm.IndexLifecycleTransition;
import java.io.IOException;
import java.util.ArrayList;
@ -64,7 +64,7 @@ public class TransportRemoveIndexLifecyclePolicyAction extends TransportMasterNo
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
return IndexLifecycleRunner.removePolicyForIndexes(indices, currentState, failedIndexes);
return IndexLifecycleTransition.removePolicyForIndexes(indices, currentState, failedIndexes);
}
@Override

View File

@ -158,7 +158,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(secondStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
@ -175,7 +175,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(thirdStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(0L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
@ -214,7 +214,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(secondStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(0L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
@ -233,7 +233,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(secondStepKey));
assertThat(firstStep.getExecuteCount(), equalTo(0L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));
@ -264,7 +264,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(new StepKey(firstStepKey.getPhase(), firstStepKey.getAction(), ErrorStep.NAME)));
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(secondStep.getExecuteCount(), equalTo(0L));
@ -284,7 +284,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(mixedPolicyName, index, startStep, policyStepsRegistry, null, () -> now);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey currentStepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(currentStepKey, equalTo(new StepKey(firstStepKey.getPhase(), firstStepKey.getAction(), ErrorStep.NAME)));
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(secondStep.getExecuteCount(), equalTo(1L));

View File

@ -0,0 +1,784 @@
/*
* 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.
*/
package org.elasticsearch.xpack.ilm;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.ilm.AbstractStepTestCase;
import org.elasticsearch.xpack.core.ilm.ErrorStep;
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.ilm.LifecycleAction;
import org.elasticsearch.xpack.core.ilm.LifecycleExecutionState;
import org.elasticsearch.xpack.core.ilm.LifecyclePolicy;
import org.elasticsearch.xpack.core.ilm.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.ilm.LifecyclePolicyTests;
import org.elasticsearch.xpack.core.ilm.LifecycleSettings;
import org.elasticsearch.xpack.core.ilm.MockAction;
import org.elasticsearch.xpack.core.ilm.MockStep;
import org.elasticsearch.xpack.core.ilm.OperationMode;
import org.elasticsearch.xpack.core.ilm.Phase;
import org.elasticsearch.xpack.core.ilm.RolloverAction;
import org.elasticsearch.xpack.core.ilm.Step;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.elasticsearch.xpack.core.ilm.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY;
import static org.elasticsearch.xpack.core.ilm.LifecyclePolicyTestsUtils.newTestLifecyclePolicy;
import static org.elasticsearch.xpack.ilm.IndexLifecycleRunnerTests.createOneStepPolicyStepRegistry;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
public class IndexLifecycleTransitionTests extends ESTestCase {
public void testMoveClusterStateToNextStep() {
String indexName = "my_index";
LifecyclePolicy policy = randomValueOtherThanMany(p -> p.getPhases().size() == 0,
() -> LifecyclePolicyTests.randomTestLifecyclePolicy("policy"));
Phase nextPhase = policy.getPhases().values().stream()
.findFirst().orElseThrow(() -> new AssertionError("expected next phase to be present"));
List<LifecyclePolicyMetadata> policyMetadatas = Collections.singletonList(
new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong()));
Step.StepKey currentStep = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStep = new Step.StepKey(nextPhase.getName(), "next_action", "next_step");
long now = randomNonNegativeLong();
// test going from null lifecycle settings to next step
ClusterState clusterState = buildClusterState(indexName,
Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName()), LifecycleExecutionState.builder().build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
PolicyStepsRegistry stepsRegistry = createOneStepPolicyStepRegistry(policy.getName(),
new MockStep(nextStep, nextStep));
ClusterState newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStep,
() -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
// test going from set currentStep settings to nextStep
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName());
if (randomBoolean()) {
lifecycleState.setStepInfo(randomAlphaOfLength(20));
}
clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
index = clusterState.metaData().index(indexName).getIndex();
newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState,
nextStep, () -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
}
public void testMoveClusterStateToNextStepSamePhase() {
String indexName = "my_index";
LifecyclePolicy policy = randomValueOtherThanMany(p -> p.getPhases().size() == 0,
() -> LifecyclePolicyTests.randomTestLifecyclePolicy("policy"));
List<LifecyclePolicyMetadata> policyMetadatas = Collections.singletonList(
new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong()));
Step.StepKey currentStep = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStep = new Step.StepKey("current_phase", "next_action", "next_step");
long now = randomNonNegativeLong();
ClusterState clusterState = buildClusterState(indexName,
Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName()),
LifecycleExecutionState.builder()
.setPhase(currentStep.getPhase())
.setAction(currentStep.getAction())
.setStep(currentStep.getName())
.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
PolicyStepsRegistry stepsRegistry = createOneStepPolicyStepRegistry(policy.getName(),
new MockStep(nextStep, nextStep));
ClusterState newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStep,
() -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
if (randomBoolean()) {
lifecycleState.setStepInfo(randomAlphaOfLength(20));
}
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName());
clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
index = clusterState.metaData().index(indexName).getIndex();
newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStep,
() -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
}
public void testMoveClusterStateToNextStepSameAction() {
String indexName = "my_index";
LifecyclePolicy policy = randomValueOtherThanMany(p -> p.getPhases().size() == 0,
() -> LifecyclePolicyTests.randomTestLifecyclePolicy("policy"));
List<LifecyclePolicyMetadata> policyMetadatas = Collections.singletonList(
new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong()));
Step.StepKey currentStep = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStep = new Step.StepKey("current_phase", "current_action", "next_step");
long now = randomNonNegativeLong();
ClusterState clusterState = buildClusterState(indexName,
Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName()),
LifecycleExecutionState.builder()
.setPhase(currentStep.getPhase())
.setAction(currentStep.getAction())
.setStep(currentStep.getName())
.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
PolicyStepsRegistry stepsRegistry = createOneStepPolicyStepRegistry(policy.getName(),
new MockStep(nextStep, nextStep));
ClusterState newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStep,
() -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
if (randomBoolean()) {
lifecycleState.setStepInfo(randomAlphaOfLength(20));
}
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policy.getName());
clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
index = clusterState.metaData().index(indexName).getIndex();
newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStep,
() -> now, stepsRegistry, false);
assertClusterStateOnNextStep(clusterState, index, currentStep, nextStep, newClusterState, now);
}
public void testSuccessfulValidatedMoveClusterStateToNextStep() {
String indexName = "my_index";
String policyName = "my_policy";
LifecyclePolicy policy = randomValueOtherThanMany(p -> p.getPhases().size() == 0,
() -> LifecyclePolicyTests.randomTestLifecyclePolicy(policyName));
Phase nextPhase = policy.getPhases().values().stream()
.findFirst().orElseThrow(() -> new AssertionError("expected next phase to be present"));
List<LifecyclePolicyMetadata> policyMetadatas = Collections.singletonList(
new LifecyclePolicyMetadata(policy, Collections.emptyMap(), randomNonNegativeLong(), randomNonNegativeLong()));
Step.StepKey currentStepKey = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStepKey = new Step.StepKey(nextPhase.getName(), "next_action", "next_step");
long now = randomNonNegativeLong();
Step step = new MockStep(nextStepKey, nextStepKey);
PolicyStepsRegistry stepRegistry = createOneStepPolicyStepRegistry(policyName, step);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStepKey.getPhase());
lifecycleState.setAction(currentStepKey.getAction());
lifecycleState.setStep(currentStepKey.getName());
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policyName);
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
ClusterState newClusterState = IndexLifecycleTransition.moveClusterStateToStep(index, clusterState,
nextStepKey, () -> now, stepRegistry, true);
assertClusterStateOnNextStep(clusterState, index, currentStepKey, nextStepKey, newClusterState, now);
}
public void testValidatedMoveClusterStateToNextStepWithoutPolicy() {
String indexName = "my_index";
String policyName = "policy";
Step.StepKey currentStepKey = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStepKey = new Step.StepKey("next_phase", "next_action", "next_step");
long now = randomNonNegativeLong();
Step step = new MockStep(nextStepKey, nextStepKey);
PolicyStepsRegistry stepRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, randomBoolean() ? "" : null);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStepKey.getPhase());
lifecycleState.setAction(currentStepKey.getAction());
lifecycleState.setStep(currentStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), Collections.emptyList());
Index index = clusterState.metaData().index(indexName).getIndex();
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStepKey, () -> now, stepRegistry, true));
assertThat(exception.getMessage(), equalTo("index [my_index] is not associated with an Index Lifecycle Policy"));
}
public void testValidatedMoveClusterStateToNextStepInvalidNextStep() {
String indexName = "my_index";
String policyName = "my_policy";
Step.StepKey currentStepKey = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStepKey = new Step.StepKey("next_phase", "next_action", "next_step");
long now = randomNonNegativeLong();
Step step = new MockStep(currentStepKey, nextStepKey);
PolicyStepsRegistry stepRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStepKey.getPhase());
lifecycleState.setAction(currentStepKey.getAction());
lifecycleState.setStep(currentStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), Collections.emptyList());
Index index = clusterState.metaData().index(indexName).getIndex();
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToStep(index, clusterState, nextStepKey, () -> now, stepRegistry, true));
assertThat(exception.getMessage(),
equalTo("step [{\"phase\":\"next_phase\",\"action\":\"next_action\",\"name\":\"next_step\"}] " +
"for index [my_index] with policy [my_policy] does not exist"));
}
public void testMoveClusterStateToErrorStep() throws IOException {
String indexName = "my_index";
Step.StepKey currentStep = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey nextStepKey = new Step.StepKey("next_phase", "next_action", "next_step");
long now = randomNonNegativeLong();
Exception cause = new ElasticsearchException("THIS IS AN EXPECTED CAUSE");
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
ClusterState clusterState = buildClusterState(indexName, Settings.builder(), lifecycleState.build(), Collections.emptyList());
Index index = clusterState.metaData().index(indexName).getIndex();
ClusterState newClusterState = IndexLifecycleTransition.moveClusterStateToErrorStep(index, clusterState, cause,
() -> now, (idxMeta, stepKey) -> new MockStep(stepKey, nextStepKey));
assertClusterStateOnErrorStep(clusterState, index, currentStep, newClusterState, now,
"{\"type\":\"exception\",\"reason\":\"THIS IS AN EXPECTED CAUSE\"");
cause = new IllegalArgumentException("non elasticsearch-exception");
newClusterState = IndexLifecycleTransition.moveClusterStateToErrorStep(index, clusterState, cause, () -> now,
(idxMeta, stepKey) -> new MockStep(stepKey, nextStepKey));
assertClusterStateOnErrorStep(clusterState, index, currentStep, newClusterState, now,
"{\"type\":\"illegal_argument_exception\",\"reason\":\"non elasticsearch-exception\",\"stack_trace\":\"");
}
public void testAddStepInfoToClusterState() throws IOException {
String indexName = "my_index";
Step.StepKey currentStep = new Step.StepKey("current_phase", "current_action", "current_step");
RandomStepInfo stepInfo = new RandomStepInfo(() -> randomAlphaOfLength(10));
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
ClusterState clusterState = buildClusterState(indexName, Settings.builder(), lifecycleState.build(), Collections.emptyList());
Index index = clusterState.metaData().index(indexName).getIndex();
ClusterState newClusterState = IndexLifecycleTransition.addStepInfoToClusterState(index, clusterState, stepInfo);
assertClusterStateStepInfo(clusterState, index, currentStep, newClusterState, stepInfo);
ClusterState runAgainClusterState = IndexLifecycleTransition.addStepInfoToClusterState(index, newClusterState, stepInfo);
assertSame(newClusterState, runAgainClusterState);
}
public void testRemovePolicyForIndex() {
String indexName = randomAlphaOfLength(10);
String oldPolicyName = "old_policy";
Step.StepKey currentStep = new Step.StepKey(randomAlphaOfLength(10), MockAction.NAME, randomAlphaOfLength(10));
LifecyclePolicy oldPolicy = createPolicy(oldPolicyName, currentStep, null);
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, oldPolicyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
List<LifecyclePolicyMetadata> policyMetadatas = new ArrayList<>();
policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleTransition.removePolicyForIndexes(indices, clusterState, failedIndexes);
assertTrue(failedIndexes.isEmpty());
assertIndexNotManagedByILM(newClusterState, index);
}
public void testRemovePolicyForIndexNoCurrentPolicy() {
String indexName = randomAlphaOfLength(10);
Settings.Builder indexSettingsBuilder = Settings.builder();
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, LifecycleExecutionState.builder().build(),
Collections.emptyList());
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleTransition.removePolicyForIndexes(indices, clusterState, failedIndexes);
assertTrue(failedIndexes.isEmpty());
assertIndexNotManagedByILM(newClusterState, index);
}
public void testRemovePolicyForIndexIndexDoesntExist() {
String indexName = randomAlphaOfLength(10);
String oldPolicyName = "old_policy";
LifecyclePolicy oldPolicy = newTestLifecyclePolicy(oldPolicyName, Collections.emptyMap());
Step.StepKey currentStep = AbstractStepTestCase.randomStepKey();
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, oldPolicyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
List<LifecyclePolicyMetadata> policyMetadatas = new ArrayList<>();
policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
Index index = new Index("doesnt_exist", "im_not_here");
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleTransition.removePolicyForIndexes(indices, clusterState, failedIndexes);
assertEquals(1, failedIndexes.size());
assertEquals("doesnt_exist", failedIndexes.get(0));
assertSame(clusterState, newClusterState);
}
public void testRemovePolicyForIndexIndexInUnsafe() {
String indexName = randomAlphaOfLength(10);
String oldPolicyName = "old_policy";
Step.StepKey currentStep = new Step.StepKey(randomAlphaOfLength(10), MockAction.NAME, randomAlphaOfLength(10));
LifecyclePolicy oldPolicy = createPolicy(oldPolicyName, null, currentStep);
Settings.Builder indexSettingsBuilder = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, oldPolicyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
List<LifecyclePolicyMetadata> policyMetadatas = new ArrayList<>();
policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleTransition.removePolicyForIndexes(indices, clusterState, failedIndexes);
assertTrue(failedIndexes.isEmpty());
assertIndexNotManagedByILM(newClusterState, index);
}
public void testRemovePolicyWithIndexingComplete() {
String indexName = randomAlphaOfLength(10);
String oldPolicyName = "old_policy";
Step.StepKey currentStep = new Step.StepKey(randomAlphaOfLength(10), MockAction.NAME, randomAlphaOfLength(10));
LifecyclePolicy oldPolicy = createPolicy(oldPolicyName, null, currentStep);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, oldPolicyName)
.put(LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE, true);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(currentStep.getPhase());
lifecycleState.setAction(currentStep.getAction());
lifecycleState.setStep(currentStep.getName());
List<LifecyclePolicyMetadata> policyMetadatas = new ArrayList<>();
policyMetadatas.add(new LifecyclePolicyMetadata(oldPolicy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong()));
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), policyMetadatas);
Index index = clusterState.metaData().index(indexName).getIndex();
Index[] indices = new Index[] { index };
List<String> failedIndexes = new ArrayList<>();
ClusterState newClusterState = IndexLifecycleTransition.removePolicyForIndexes(indices, clusterState, failedIndexes);
assertTrue(failedIndexes.isEmpty());
assertIndexNotManagedByILM(newClusterState, index);
}
public void testValidateTransitionThrowsExceptionForMissingIndexPolicy() {
IndexMetaData indexMetaData = IndexMetaData.builder("index").settings(settings(Version.CURRENT))
.numberOfShards(randomIntBetween(1, 5))
.numberOfReplicas(randomIntBetween(0, 5))
.build();
Step.StepKey currentStepKey = new Step.StepKey("hot", "action", "firstStep");
Step.StepKey nextStepKey = new Step.StepKey("hot", "action", "secondStep");
Step currentStep = new MockStep(currentStepKey, nextStepKey);
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry("policy", currentStep);
expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.validateTransition(indexMetaData, currentStepKey, nextStepKey, policyRegistry));
}
public void testValidateTransitionThrowsExceptionIfTheCurrentStepIsIncorrect() {
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase("hot");
lifecycleState.setAction("action");
lifecycleState.setStep("another_step");
String policy = "policy";
IndexMetaData indexMetaData = buildIndexMetadata(policy, lifecycleState);
Step.StepKey currentStepKey = new Step.StepKey("hot", "action", "firstStep");
Step.StepKey nextStepKey = new Step.StepKey("hot", "action", "secondStep");
Step currentStep = new MockStep(currentStepKey, nextStepKey);
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policy, currentStep);
expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.validateTransition(indexMetaData, currentStepKey, nextStepKey, policyRegistry));
}
public void testValidateTransitionThrowsExceptionIfNextStepDoesNotExist() {
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase("hot");
lifecycleState.setAction("action");
lifecycleState.setStep("firstStep");
String policy = "policy";
IndexMetaData indexMetaData = buildIndexMetadata(policy, lifecycleState);
Step.StepKey currentStepKey = new Step.StepKey("hot", "action", "firstStep");
Step.StepKey nextStepKey = new Step.StepKey("hot", "action", "secondStep");
Step currentStep = new MockStep(currentStepKey, nextStepKey);
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policy, currentStep);
expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.validateTransition(indexMetaData, currentStepKey, nextStepKey, policyRegistry));
}
public void testValidateValidTransition() {
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase("hot");
lifecycleState.setAction("action");
lifecycleState.setStep("firstStep");
String policy = "policy";
IndexMetaData indexMetaData = buildIndexMetadata(policy, lifecycleState);
Step.StepKey currentStepKey = new Step.StepKey("hot", "action", "firstStep");
Step.StepKey nextStepKey = new Step.StepKey("hot", "action", "secondStep");
Step finalStep = new MockStep(nextStepKey, new Step.StepKey("hot", "action", "completed"));
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policy, finalStep);
try {
IndexLifecycleTransition.validateTransition(indexMetaData, currentStepKey, nextStepKey, policyRegistry);
} catch (Exception e) {
logger.error(e);
fail("validateTransition should not throw exception on valid transitions");
}
}
public void testMoveClusterStateToFailedStep() {
String indexName = "my_index";
String policyName = "my_policy";
long now = randomNonNegativeLong();
Step.StepKey failedStepKey = new Step.StepKey("current_phase", MockAction.NAME, "current_step");
Step.StepKey errorStepKey = new Step.StepKey(failedStepKey.getPhase(), failedStepKey.getAction(), ErrorStep.NAME);
Step step = new MockStep(failedStepKey, null);
LifecyclePolicy policy = createPolicy(policyName, failedStepKey, null);
LifecyclePolicyMetadata policyMetadata = new LifecyclePolicyMetadata(policy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(errorStepKey.getPhase());
lifecycleState.setPhaseTime(now);
lifecycleState.setAction(errorStepKey.getAction());
lifecycleState.setActionTime(now);
lifecycleState.setStep(errorStepKey.getName());
lifecycleState.setStepTime(now);
lifecycleState.setFailedStep(failedStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(),
Collections.singletonList(policyMetadata));
Index index = clusterState.metaData().index(indexName).getIndex();
ClusterState nextClusterState = IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
indexName, () -> now, policyRegistry, false);
IndexLifecycleRunnerTests.assertClusterStateOnNextStep(clusterState, index, errorStepKey, failedStepKey,
nextClusterState, now);
LifecycleExecutionState executionState = LifecycleExecutionState.fromIndexMetadata(nextClusterState.metaData().index(indexName));
assertThat("manual move to failed step should not count as a retry", executionState.getFailedStepRetryCount(), is(nullValue()));
}
public void testMoveClusterStateToFailedStepWithUnknownStep() {
String indexName = "my_index";
String policyName = "my_policy";
long now = randomNonNegativeLong();
Step.StepKey failedStepKey = new Step.StepKey("current_phase", MockAction.NAME, "current_step");
Step.StepKey errorStepKey = new Step.StepKey(failedStepKey.getPhase(), failedStepKey.getAction(), ErrorStep.NAME);
Step.StepKey registeredStepKey = new Step.StepKey(randomFrom(failedStepKey.getPhase(), "other"),
MockAction.NAME, "different_step");
Step step = new MockStep(registeredStepKey, null);
LifecyclePolicy policy = createPolicy(policyName, failedStepKey, null);
LifecyclePolicyMetadata policyMetadata = new LifecyclePolicyMetadata(policy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(errorStepKey.getPhase());
lifecycleState.setPhaseTime(now);
lifecycleState.setAction(errorStepKey.getAction());
lifecycleState.setActionTime(now);
lifecycleState.setStep(errorStepKey.getName());
lifecycleState.setStepTime(now);
lifecycleState.setFailedStep(failedStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(),
Collections.singletonList(policyMetadata));
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
indexName, () -> now, policyRegistry, false));
assertThat(exception.getMessage(), equalTo("step [" + failedStepKey
+ "] for index [my_index] with policy [my_policy] does not exist"));
}
public void testMoveClusterStateToFailedStepIndexNotFound() {
String existingIndexName = "my_index";
String invalidIndexName = "does_not_exist";
ClusterState clusterState = buildClusterState(existingIndexName, Settings.builder(), LifecycleExecutionState.builder().build(),
Collections.emptyList());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
invalidIndexName, () -> 0L, null, false));
assertThat(exception.getMessage(), equalTo("index [" + invalidIndexName + "] does not exist"));
}
public void testMoveClusterStateToFailedStepInvalidPolicySetting() {
String indexName = "my_index";
String policyName = "my_policy";
long now = randomNonNegativeLong();
Step.StepKey failedStepKey = new Step.StepKey("current_phase", "current_action", "current_step");
Step.StepKey errorStepKey = new Step.StepKey(failedStepKey.getPhase(), failedStepKey.getAction(), ErrorStep.NAME);
Step step = new MockStep(failedStepKey, null);
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, (String) null);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(errorStepKey.getPhase());
lifecycleState.setAction(errorStepKey.getAction());
lifecycleState.setStep(errorStepKey.getName());
lifecycleState.setFailedStep(failedStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), Collections.emptyList());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
indexName, () -> now, policyRegistry, false));
assertThat(exception.getMessage(), equalTo("index [" + indexName + "] is not associated with an Index Lifecycle Policy"));
}
public void testMoveClusterStateToFailedNotOnError() {
String indexName = "my_index";
String policyName = "my_policy";
long now = randomNonNegativeLong();
Step.StepKey failedStepKey = new Step.StepKey("current_phase", "current_action", "current_step");
Step step = new MockStep(failedStepKey, null);
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policyName, step);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, (String) null);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(failedStepKey.getPhase());
lifecycleState.setAction(failedStepKey.getAction());
lifecycleState.setStep(failedStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(), Collections.emptyList());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
indexName, () -> now, policyRegistry, false));
assertThat(exception.getMessage(), equalTo("cannot retry an action for an index [" + indexName
+ "] that has not encountered an error when running a Lifecycle Policy"));
}
public void testMoveClusterStateToPreviouslyFailedStepAsAutomaticRetry() {
String indexName = "my_index";
String policyName = "my_policy";
long now = randomNonNegativeLong();
Step.StepKey failedStepKey = new Step.StepKey("current_phase", MockAction.NAME, "current_step");
Step.StepKey errorStepKey = new Step.StepKey(failedStepKey.getPhase(), failedStepKey.getAction(), ErrorStep.NAME);
Step retryableStep = new IndexLifecycleRunnerTests.RetryableMockStep(failedStepKey, null);
LifecyclePolicy policy = createPolicy(policyName, failedStepKey, null);
LifecyclePolicyMetadata policyMetadata = new LifecyclePolicyMetadata(policy, Collections.emptyMap(),
randomNonNegativeLong(), randomNonNegativeLong());
PolicyStepsRegistry policyRegistry = createOneStepPolicyStepRegistry(policyName, retryableStep);
Settings.Builder indexSettingsBuilder = Settings.builder()
.put(LifecycleSettings.LIFECYCLE_NAME, policyName);
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
lifecycleState.setPhase(errorStepKey.getPhase());
lifecycleState.setPhaseTime(now);
lifecycleState.setAction(errorStepKey.getAction());
lifecycleState.setActionTime(now);
lifecycleState.setStep(errorStepKey.getName());
lifecycleState.setStepTime(now);
lifecycleState.setFailedStep(failedStepKey.getName());
ClusterState clusterState = buildClusterState(indexName, indexSettingsBuilder, lifecycleState.build(),
Collections.singletonList(policyMetadata));
Index index = clusterState.metaData().index(indexName).getIndex();
ClusterState nextClusterState = IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(clusterState,
indexName, () -> now, policyRegistry, true);
IndexLifecycleRunnerTests.assertClusterStateOnNextStep(clusterState, index, errorStepKey, failedStepKey,
nextClusterState, now);
LifecycleExecutionState executionState = LifecycleExecutionState.fromIndexMetadata(nextClusterState.metaData().index(indexName));
assertThat(executionState.getFailedStepRetryCount(), is(1));
}
private static LifecyclePolicy createPolicy(String policyName, Step.StepKey safeStep, Step.StepKey unsafeStep) {
Map<String, Phase> phases = new HashMap<>();
if (safeStep != null) {
assert MockAction.NAME.equals(safeStep.getAction()) : "The safe action needs to be MockAction.NAME";
assert unsafeStep == null
|| safeStep.getPhase().equals(unsafeStep.getPhase()) == false : "safe and unsafe actions must be in different phases";
Map<String, LifecycleAction> actions = new HashMap<>();
List<Step> steps = Collections.singletonList(new MockStep(safeStep, null));
MockAction safeAction = new MockAction(steps, true);
actions.put(safeAction.getWriteableName(), safeAction);
Phase phase = new Phase(safeStep.getPhase(), TimeValue.timeValueMillis(0), actions);
phases.put(phase.getName(), phase);
}
if (unsafeStep != null) {
assert MockAction.NAME.equals(unsafeStep.getAction()) : "The unsafe action needs to be MockAction.NAME";
Map<String, LifecycleAction> actions = new HashMap<>();
List<Step> steps = Collections.singletonList(new MockStep(unsafeStep, null));
MockAction unsafeAction = new MockAction(steps, false);
actions.put(unsafeAction.getWriteableName(), unsafeAction);
Phase phase = new Phase(unsafeStep.getPhase(), TimeValue.timeValueMillis(0), actions);
phases.put(phase.getName(), phase);
}
return newTestLifecyclePolicy(policyName, phases);
}
private ClusterState buildClusterState(String indexName, Settings.Builder indexSettingsBuilder,
LifecycleExecutionState lifecycleState,
List<LifecyclePolicyMetadata> lifecyclePolicyMetadatas) {
Settings indexSettings = indexSettingsBuilder.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0).put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build();
IndexMetaData indexMetadata = IndexMetaData.builder(indexName)
.settings(indexSettings)
.putCustom(ILM_CUSTOM_METADATA_KEY, lifecycleState.asMap())
.build();
Map<String, LifecyclePolicyMetadata> lifecyclePolicyMetadatasMap = lifecyclePolicyMetadatas.stream()
.collect(Collectors.toMap(LifecyclePolicyMetadata::getName, Function.identity()));
IndexLifecycleMetadata indexLifecycleMetadata = new IndexLifecycleMetadata(lifecyclePolicyMetadatasMap, OperationMode.RUNNING);
MetaData metadata = MetaData.builder().put(indexMetadata, true).putCustom(IndexLifecycleMetadata.TYPE, indexLifecycleMetadata)
.build();
return ClusterState.builder(new ClusterName("my_cluster")).metaData(metadata).build();
}
public static void assertIndexNotManagedByILM(ClusterState clusterState, Index index) {
MetaData metadata = clusterState.metaData();
assertNotNull(metadata);
IndexMetaData indexMetadata = metadata.getIndexSafe(index);
assertNotNull(indexMetadata);
Settings indexSettings = indexMetadata.getSettings();
assertNotNull(indexSettings);
assertFalse(LifecycleSettings.LIFECYCLE_NAME_SETTING.exists(indexSettings));
assertFalse(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING.exists(indexSettings));
assertFalse(LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING.exists(indexSettings));
}
public static void assertClusterStateOnNextStep(ClusterState oldClusterState, Index index, Step.StepKey currentStep,
Step.StepKey nextStep, ClusterState newClusterState, long now) {
assertNotSame(oldClusterState, newClusterState);
MetaData newMetadata = newClusterState.metaData();
assertNotSame(oldClusterState.metaData(), newMetadata);
IndexMetaData newIndexMetadata = newMetadata.getIndexSafe(index);
assertNotSame(oldClusterState.metaData().index(index), newIndexMetadata);
LifecycleExecutionState newLifecycleState = LifecycleExecutionState
.fromIndexMetadata(newClusterState.metaData().index(index));
LifecycleExecutionState oldLifecycleState = LifecycleExecutionState
.fromIndexMetadata(oldClusterState.metaData().index(index));
assertNotSame(oldLifecycleState, newLifecycleState);
assertEquals(nextStep.getPhase(), newLifecycleState.getPhase());
assertEquals(nextStep.getAction(), newLifecycleState.getAction());
assertEquals(nextStep.getName(), newLifecycleState.getStep());
if (currentStep.getPhase().equals(nextStep.getPhase())) {
assertEquals("expected phase times to be the same but they were different",
oldLifecycleState.getPhaseTime(), newLifecycleState.getPhaseTime());
} else {
assertEquals(now, newLifecycleState.getPhaseTime().longValue());
}
if (currentStep.getAction().equals(nextStep.getAction())) {
assertEquals("expected action times to be the same but they were different",
oldLifecycleState.getActionTime(), newLifecycleState.getActionTime());
} else {
assertEquals(now, newLifecycleState.getActionTime().longValue());
}
assertEquals(now, newLifecycleState.getStepTime().longValue());
assertEquals(null, newLifecycleState.getFailedStep());
assertEquals(null, newLifecycleState.getStepInfo());
}
private IndexMetaData buildIndexMetadata(String policy, LifecycleExecutionState.Builder lifecycleState) {
return IndexMetaData.builder("index")
.settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_NAME, policy))
.numberOfShards(randomIntBetween(1, 5))
.numberOfReplicas(randomIntBetween(0, 5))
.putCustom(ILM_CUSTOM_METADATA_KEY, lifecycleState.build().asMap())
.build();
}
private void assertClusterStateOnErrorStep(ClusterState oldClusterState, Index index, Step.StepKey currentStep,
ClusterState newClusterState, long now, String expectedCauseValue) {
assertNotSame(oldClusterState, newClusterState);
MetaData newMetadata = newClusterState.metaData();
assertNotSame(oldClusterState.metaData(), newMetadata);
IndexMetaData newIndexMetadata = newMetadata.getIndexSafe(index);
assertNotSame(oldClusterState.metaData().index(index), newIndexMetadata);
LifecycleExecutionState newLifecycleState = LifecycleExecutionState
.fromIndexMetadata(newClusterState.metaData().index(index));
LifecycleExecutionState oldLifecycleState = LifecycleExecutionState
.fromIndexMetadata(oldClusterState.metaData().index(index));
assertNotSame(oldLifecycleState, newLifecycleState);
assertEquals(currentStep.getPhase(), newLifecycleState.getPhase());
assertEquals(currentStep.getAction(), newLifecycleState.getAction());
assertEquals(ErrorStep.NAME, newLifecycleState.getStep());
assertEquals(currentStep.getName(), newLifecycleState.getFailedStep());
assertThat(newLifecycleState.getStepInfo(), containsString(expectedCauseValue));
assertEquals(oldLifecycleState.getPhaseTime(), newLifecycleState.getPhaseTime());
assertEquals(oldLifecycleState.getActionTime(), newLifecycleState.getActionTime());
assertEquals(now, newLifecycleState.getStepTime().longValue());
}
private void assertClusterStateStepInfo(ClusterState oldClusterState, Index index, Step.StepKey currentStep,
ClusterState newClusterState, ToXContentObject stepInfo) throws IOException {
XContentBuilder stepInfoXContentBuilder = JsonXContent.contentBuilder();
stepInfo.toXContent(stepInfoXContentBuilder, ToXContent.EMPTY_PARAMS);
String expectedstepInfoValue = BytesReference.bytes(stepInfoXContentBuilder).utf8ToString();
assertNotSame(oldClusterState, newClusterState);
MetaData newMetadata = newClusterState.metaData();
assertNotSame(oldClusterState.metaData(), newMetadata);
IndexMetaData newIndexMetadata = newMetadata.getIndexSafe(index);
assertNotSame(oldClusterState.metaData().index(index), newIndexMetadata);
LifecycleExecutionState newLifecycleState = LifecycleExecutionState
.fromIndexMetadata(newClusterState.metaData().index(index));
LifecycleExecutionState oldLifecycleState = LifecycleExecutionState
.fromIndexMetadata(oldClusterState.metaData().index(index));
assertNotSame(oldLifecycleState, newLifecycleState);
assertEquals(currentStep.getPhase(), newLifecycleState.getPhase());
assertEquals(currentStep.getAction(), newLifecycleState.getAction());
assertEquals(currentStep.getName(), newLifecycleState.getStep());
assertEquals(expectedstepInfoValue, newLifecycleState.getStepInfo());
assertEquals(oldLifecycleState.getPhaseTime(), newLifecycleState.getPhaseTime());
assertEquals(oldLifecycleState.getActionTime(), newLifecycleState.getActionTime());
assertEquals(newLifecycleState.getStepTime(), newLifecycleState.getStepTime());
}
}

View File

@ -78,7 +78,7 @@ public class MoveToErrorStepUpdateTaskTests extends ESTestCase {
(idxMeta, stepKey) -> new MockStep(stepKey, nextStepKey));
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey actualKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey actualKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(actualKey, equalTo(new StepKey(currentStepKey.getPhase(), currentStepKey.getAction(), ErrorStep.NAME)));
assertThat(lifecycleState.getFailedStep(), equalTo(currentStepKey.getName()));
assertThat(lifecycleState.getPhaseTime(), nullValue());

View File

@ -13,6 +13,7 @@ import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
@ -71,10 +72,10 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
AtomicBoolean changed = new AtomicBoolean(false);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, nextStepKey,
() -> now, state -> changed.set(true));
() -> now, new AlwaysExistingStepRegistry(), state -> changed.set(true));
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey actualKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey actualKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(actualKey, equalTo(nextStepKey));
assertThat(lifecycleState.getPhaseTime(), equalTo(now));
assertThat(lifecycleState.getActionTime(), equalTo(now));
@ -88,7 +89,8 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
StepKey notCurrentStepKey = new StepKey("not-current", "not-current", "not-current");
long now = randomNonNegativeLong();
setStateToKey(notCurrentStepKey, now);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, null, () -> now, null);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, null,
() -> now, new AlwaysExistingStepRegistry(), null);
ClusterState newState = task.execute(clusterState);
assertSame(newState, clusterState);
}
@ -98,7 +100,8 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
long now = randomNonNegativeLong();
setStateToKey(currentStepKey, now);
setStatePolicy("not-" + policy);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, null, () -> now, null);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, null, () -> now,
new AlwaysExistingStepRegistry(), null);
ClusterState newState = task.execute(clusterState);
assertSame(newState, clusterState);
}
@ -113,10 +116,10 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
SetOnce<Boolean> changed = new SetOnce<>();
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey,
invalidNextStep, () -> now, s -> changed.set(true));
invalidNextStep, () -> now, new AlwaysExistingStepRegistry(), s -> changed.set(true));
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey actualKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey actualKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(actualKey, equalTo(invalidNextStep));
assertThat(lifecycleState.getPhaseTime(), equalTo(now));
assertThat(lifecycleState.getActionTime(), equalTo(now));
@ -132,7 +135,8 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
setStateToKey(currentStepKey, now);
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, nextStepKey, () -> now, state -> {});
MoveToNextStepUpdateTask task = new MoveToNextStepUpdateTask(index, policy, currentStepKey, nextStepKey, () -> now,
new AlwaysExistingStepRegistry(), state -> {});
Exception expectedException = new RuntimeException();
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> task.onFailure(randomAlphaOfLength(10), expectedException));
@ -141,6 +145,21 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
assertSame(expectedException, exception.getCause());
}
/**
* Fake policy steps registry that will always pass validation that the step exists
*/
private static class AlwaysExistingStepRegistry extends PolicyStepsRegistry {
AlwaysExistingStepRegistry() {
super(new NamedXContentRegistry(Collections.emptyList()), null);
}
@Override
public boolean stepExists(String policy, StepKey stepKey) {
return true;
}
}
private void setStatePolicy(String policy) {
clusterState = ClusterState.builder(clusterState)
.metaData(MetaData.builder(clusterState.metaData())

View File

@ -61,7 +61,7 @@ public class SetStepInfoUpdateTaskTests extends ESTestCase {
SetStepInfoUpdateTask task = new SetStepInfoUpdateTask(index, policy, currentStepKey, stepInfo);
ClusterState newState = task.execute(clusterState);
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(newState.getMetaData().index(index));
StepKey actualKey = IndexLifecycleRunner.getCurrentStepKey(lifecycleState);
StepKey actualKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState);
assertThat(actualKey, equalTo(currentStepKey));
assertThat(lifecycleState.getPhaseTime(), nullValue());
assertThat(lifecycleState.getActionTime(), nullValue());