Skip to content

Commit 6e9f338

Browse files
authored
stop throwing an IllegalStateException for unrecognized steps (#32212)
Since the reason for a step not being found in a registry may be due to staleness of the registry between it and the cluster state, we do not want to throw an IllegalStateException. Staleness is something that will be self-healing after follow-up applications of the cluster state updates, so this is a recoverable issue that should log a warning instead of throwing an exception Closes #32181.
1 parent a314efc commit 6e9f338

File tree

6 files changed

+71
-34
lines changed

6 files changed

+71
-34
lines changed

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import org.apache.logging.log4j.Logger;
1111
import org.elasticsearch.ElasticsearchException;
12+
import org.elasticsearch.action.support.TransportAction;
1213
import org.elasticsearch.cluster.ClusterState;
1314
import org.elasticsearch.cluster.metadata.IndexMetaData;
1415
import org.elasticsearch.cluster.metadata.MetaData;
@@ -64,8 +65,11 @@ public void runPolicy(String policy, IndexMetaData indexMetaData, ClusterState c
6465
}
6566
Step currentStep = getCurrentStep(stepRegistry, policy, indexSettings);
6667
if (currentStep == null) {
67-
throw new IllegalStateException(
68-
"current step for index [" + indexMetaData.getIndex().getName() + "] with policy [" + policy + "] is not recognized");
68+
// This may happen in the case that there is invalid ilm-step index settings or the stepRegistry is out of
69+
// sync with the current cluster state
70+
logger.warn("current step [" + getCurrentStepKey(indexSettings) + "] for index [" + indexMetaData.getIndex().getName()
71+
+ "] with policy [" + policy + "] is not recognized");
72+
return;
6973
}
7074
logger.debug("running policy with current-step[" + currentStep.getKey() + "]");
7175
if (currentStep instanceof TerminalPolicyStep) {
@@ -164,6 +168,23 @@ static Step getCurrentStep(PolicyStepsRegistry stepRegistry, String policy, Sett
164168
}
165169
}
166170

171+
/**
172+
* This method is intended for handling moving to different steps from {@link TransportAction} executions.
173+
* For this reason, it is reasonable to throw {@link IllegalArgumentException} when state is not as expected.
174+
* @param indexName
175+
* The index whose step is to change
176+
* @param currentState
177+
* The current {@link ClusterState}
178+
* @param currentStepKey
179+
* The current {@link StepKey} found for the index in the current cluster state
180+
* @param nextStepKey
181+
* The next step to move the index into
182+
* @param nowSupplier
183+
* The current-time supplier for updating when steps changed
184+
* @param stepRegistry
185+
* The steps registry to check a step-key's existence in the index's current policy
186+
* @return The updated cluster state where the index moved to <code>nextStepKey</code>
187+
*/
167188
static ClusterState moveClusterStateToStep(String indexName, ClusterState currentState, StepKey currentStepKey,
168189
StepKey nextStepKey, LongSupplier nowSupplier,
169190
PolicyStepsRegistry stepRegistry) {
@@ -180,10 +201,9 @@ static ClusterState moveClusterStateToStep(String indexName, ClusterState curren
180201
throw new IllegalArgumentException("index [" + indexName + "] is not on current step [" + currentStepKey + "]");
181202
}
182203

183-
try {
184-
stepRegistry.getStep(indexPolicySetting, nextStepKey);
185-
} catch (IllegalStateException e) {
186-
throw new IllegalArgumentException(e.getMessage());
204+
Step nextStep = stepRegistry.getStep(indexPolicySetting, nextStepKey);
205+
if (nextStep == null) {
206+
throw new IllegalArgumentException("step [" + nextStepKey + "] with policy [" + indexPolicySetting + "] does not exist");
187207
}
188208

189209
return IndexLifecycleRunner.moveClusterStateToNextStep(idxMeta.getIndex(), currentState, currentStepKey, nextStepKey, nowSupplier);
@@ -358,7 +378,7 @@ private static boolean canSetPolicy(StepKey currentStepKey, LifecyclePolicy curr
358378
return true;
359379
}
360380
}
361-
381+
362382
private static boolean isActionChanged(StepKey stepKey, LifecyclePolicy currentPolicy, LifecyclePolicy newPolicy) {
363383
LifecycleAction currentAction = getActionFromPolicy(currentPolicy, stepKey.getPhase(), stepKey.getAction());
364384
LifecycleAction newAction = getActionFromPolicy(newPolicy, stepKey.getPhase(), stepKey.getAction());
@@ -385,7 +405,7 @@ private static LifecycleAction getActionFromPolicy(LifecyclePolicy policy, Strin
385405
* state where it is able to deal with the policy being updated to
386406
* <code>newPolicy</code>. If any of these indexes is not in a state wheree
387407
* it can deal with the update the method will return <code>false</code>.
388-
*
408+
*
389409
* @param policyName
390410
* the name of the policy being updated
391411
* @param newPolicy

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
*/
66
package org.elasticsearch.xpack.indexlifecycle;
77

8+
import org.apache.logging.log4j.Logger;
89
import org.elasticsearch.client.Client;
910
import org.elasticsearch.cluster.ClusterState;
1011
import org.elasticsearch.cluster.Diff;
1112
import org.elasticsearch.cluster.DiffableUtils;
13+
import org.elasticsearch.common.logging.ESLoggerFactory;
1214
import org.elasticsearch.xpack.core.ClientHelper;
1315
import org.elasticsearch.xpack.core.indexlifecycle.ErrorStep;
1416
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
@@ -23,6 +25,8 @@
2325
import java.util.function.LongSupplier;
2426

2527
public class PolicyStepsRegistry {
28+
private static final Logger logger = ESLoggerFactory.getLogger(PolicyStepsRegistry.class);
29+
2630
// keeps track of existing policies in the cluster state
2731
private SortedMap<String, LifecyclePolicyMetadata> lifecyclePolicyMap;
2832
// keeps track of what the first step in a policy is
@@ -104,13 +108,9 @@ public Step getStep(String policy, Step.StepKey stepKey) {
104108
}
105109
Map<Step.StepKey, Step> steps = stepMap.get(policy);
106110
if (steps == null) {
107-
throw new IllegalStateException("policy [" + policy + "] does not exist");
108-
}
109-
Step step = steps.get(stepKey);
110-
if (step == null) {
111-
throw new IllegalStateException("step [" + stepKey + "] does not exist");
111+
return null;
112112
}
113-
return step;
113+
return steps.get(stepKey);
114114
}
115115

116116
public Step getFirstStep(String policy) {

x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/ExecuteStepsUpdateTaskTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
5252
private static final StepKey firstStepKey = new StepKey("phase_1", "action_1", "step_1");
5353
private static final StepKey secondStepKey = new StepKey("phase_1", "action_1", "step_2");
5454
private static final StepKey thirdStepKey = new StepKey("phase_1", "action_1", "step_3");
55+
private static final StepKey invalidStepKey = new StepKey("invalid", "invalid", "invalid");
5556
private ClusterState clusterState;
5657
private PolicyStepsRegistry policyStepsRegistry;
5758
private String mixedPolicyName;
5859
private String allClusterPolicyName;
60+
private String invalidPolicyName;
5961
private Index index;
6062
private MockClusterStateActionStep firstStep;
6163
private MockClusterStateWaitStep secondStep;
@@ -75,17 +77,23 @@ public void prepareState() {
7577
thirdStep = new MockStep(thirdStepKey, null);
7678
mixedPolicyName = randomAlphaOfLengthBetween(5, 10);
7779
allClusterPolicyName = randomAlphaOfLengthBetween(1, 4);
80+
invalidPolicyName = randomAlphaOfLength(11);
7881
Phase mixedPhase = new Phase("first_phase", TimeValue.ZERO, Collections.singletonMap(MockAction.NAME,
7982
new MockAction(Arrays.asList(firstStep, secondStep, thirdStep))));
8083
Phase allClusterPhase = new Phase("first_phase", TimeValue.ZERO, Collections.singletonMap(MockAction.NAME,
8184
new MockAction(Arrays.asList(firstStep, allClusterSecondStep))));
85+
Phase invalidPhase = new Phase("invalid_phase", TimeValue.ZERO, Collections.singletonMap(MockAction.NAME,
86+
new MockAction(Arrays.asList(new MockClusterStateActionStep(firstStepKey, invalidStepKey)))));
8287
LifecyclePolicy mixedPolicy = new LifecyclePolicy(TestLifecycleType.INSTANCE, mixedPolicyName,
8388
Collections.singletonMap(mixedPhase.getName(), mixedPhase));
8489
LifecyclePolicy allClusterPolicy = new LifecyclePolicy(TestLifecycleType.INSTANCE, allClusterPolicyName,
8590
Collections.singletonMap(allClusterPhase.getName(), allClusterPhase));
91+
LifecyclePolicy invalidPolicy = new LifecyclePolicy(TestLifecycleType.INSTANCE, invalidPolicyName,
92+
Collections.singletonMap(invalidPhase.getName(), invalidPhase));
8693
Map<String, LifecyclePolicyMetadata> policyMap = new HashMap<>();
8794
policyMap.put(mixedPolicyName, new LifecyclePolicyMetadata(mixedPolicy, Collections.emptyMap()));
8895
policyMap.put(allClusterPolicyName, new LifecyclePolicyMetadata(allClusterPolicy, Collections.emptyMap()));
96+
policyMap.put(invalidPolicyName, new LifecyclePolicyMetadata(invalidPolicy, Collections.emptyMap()));
8997
policyStepsRegistry = new PolicyStepsRegistry();
9098

9199
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
@@ -165,6 +173,26 @@ public void testExecuteUntilFirstNonClusterStateStep() throws IOException {
165173
assertThat(LifecycleSettings.LIFECYCLE_STEP_INFO_SETTING.get(newState.metaData().index(index).getSettings()), equalTo(""));
166174
}
167175

176+
public void testExecuteInvalidStartStep() throws IOException {
177+
setStateToKey(firstStepKey);
178+
Step startStep = policyStepsRegistry.getStep(mixedPolicyName, firstStepKey);
179+
long now = randomNonNegativeLong();
180+
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(invalidPolicyName, index, startStep, policyStepsRegistry, () -> now);
181+
ClusterState newState = task.execute(clusterState);
182+
assertSame(newState, clusterState);
183+
184+
}
185+
186+
public void testExecuteUntilNullStep() throws IOException {
187+
setStateToKey(firstStepKey);
188+
Step startStep = policyStepsRegistry.getStep(invalidPolicyName, firstStepKey);
189+
long now = randomNonNegativeLong();
190+
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(invalidPolicyName, index, startStep, policyStepsRegistry, () -> now);
191+
ClusterState newState = task.execute(clusterState);
192+
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
193+
assertThat(currentStepKey, equalTo(invalidStepKey));
194+
}
195+
168196
public void testExecuteIncompleteWaitStepNoInfo() throws IOException {
169197
secondStep.setWillComplete(false);
170198
setStateToKey(secondStepKey);

x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,13 @@ public void testRunPolicyAsyncWaitStepClusterStateChangeIgnored() {
332332

333333
public void testRunPolicyWithNoStepsInRegistry() {
334334
String policyName = "cluster_state_action_policy";
335-
StepKey stepKey = new StepKey("phase", "action", "cluster_state_action_step");
336335
ClusterService clusterService = mock(ClusterService.class);
337336
IndexLifecycleRunner runner = new IndexLifecycleRunner(new PolicyStepsRegistry(), clusterService, () -> 0L);
338337
IndexMetaData indexMetaData = IndexMetaData.builder("my_index").settings(settings(Version.CURRENT))
339338
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
340-
341-
IllegalStateException exception = expectThrows(IllegalStateException.class,
342-
() -> runner.runPolicy(policyName, indexMetaData, null, randomBoolean()));
343-
assertEquals("current step for index [my_index] with policy [cluster_state_action_policy] is not recognized",
344-
exception.getMessage());
339+
// verify that no exception is thrown
340+
runner.runPolicy(policyName, indexMetaData, null, randomBoolean());
345341
Mockito.verifyZeroInteractions(clusterService);
346-
347342
}
348343

349344
public void testRunPolicyUnknownStepType() {
@@ -524,13 +519,8 @@ public void testGetCurrentStep() {
524519
.put(LifecycleSettings.LIFECYCLE_ACTION, "action_1")
525520
.put(LifecycleSettings.LIFECYCLE_STEP, "step_3")
526521
.build();
527-
IllegalStateException exception = expectThrows(IllegalStateException.class,
528-
() -> IndexLifecycleRunner.getCurrentStep(registry, policyName, invalidIndexSettings));
529-
assertEquals("step [{\"phase\":\"phase_1\",\"action\":\"action_1\",\"name\":\"step_3\"}] does not exist", exception.getMessage());
530-
531-
exception = expectThrows(IllegalStateException.class,
532-
() -> IndexLifecycleRunner.getCurrentStep(registry, "policy_does_not_exist", invalidIndexSettings));
533-
assertEquals("policy [policy_does_not_exist] does not exist", exception.getMessage());
522+
assertNull(IndexLifecycleRunner.getCurrentStep(registry, policyName, invalidIndexSettings));
523+
assertNull(IndexLifecycleRunner.getCurrentStep(registry, "policy_does_not_exist", invalidIndexSettings));
534524
}
535525

536526
public void testMoveClusterStateToNextStep() {
@@ -688,7 +678,8 @@ public void testValidatedMoveClusterStateToNextStepInvalidNextStep() {
688678
() -> IndexLifecycleRunner.moveClusterStateToStep(indexName, clusterState, currentStepKey,
689679
nextStepKey, () -> now, stepRegistry));
690680
assertThat(exception.getMessage(),
691-
equalTo("step [{\"phase\":\"next_phase\",\"action\":\"next_action\",\"name\":\"next_step\"}] does not exist"));
681+
equalTo("step [{\"phase\":\"next_phase\",\"action\":\"next_action\",\"name\":\"next_step\"}] " +
682+
"with policy [my_policy] does not exist"));
692683
}
693684

694685
public void testMoveClusterStateToErrorStep() throws IOException {

x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistryTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ public void testGetStepErrorStep() {
7979
public void testGetStepUnknownPolicy() {
8080
String policyName = randomAlphaOfLengthBetween(2, 10);
8181
PolicyStepsRegistry registry = new PolicyStepsRegistry(null, null, Collections.emptyMap());
82-
IllegalStateException exception = expectThrows(IllegalStateException.class, () -> registry.getStep(policyName, MOCK_STEP_KEY));
83-
assertThat(exception.getMessage(), equalTo("policy [" + policyName +"] does not exist"));
82+
assertNull(registry.getStep(policyName, MOCK_STEP_KEY));
8483
}
8584

8685
public void testGetStepUnknownStepKey() {
@@ -91,8 +90,7 @@ public void testGetStepUnknownStepKey() {
9190
PolicyStepsRegistry registry = new PolicyStepsRegistry(null, null, stepMap);
9291
Step.StepKey unknownStepKey = new Step.StepKey(MOCK_STEP_KEY.getPhase(),
9392
MOCK_STEP_KEY.getAction(),MOCK_STEP_KEY.getName() + "not");
94-
IllegalStateException exception = expectThrows(IllegalStateException.class, () -> registry.getStep(policyName, unknownStepKey));
95-
assertThat(exception.getMessage(), equalTo("step [" + unknownStepKey +"] does not exist"));
93+
assertNull(registry.getStep(policyName, unknownStepKey));
9694
}
9795

9896
public void testUpdateFromNothingToSomethingToNothing() {

x-pack/plugin/src/test/resources/rest-api-spec/test/index_lifecycle/20_move_to_step.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ teardown:
138138
action: "invalid"
139139
name: "invalid"
140140
- match: { error.root_cause.0.type: "illegal_argument_exception" }
141-
- match: { error.root_cause.0.reason: "step [{\"phase\":\"invalid\",\"action\":\"invalid\",\"name\":\"invalid\"}] does not exist" }
141+
- match: { error.root_cause.0.reason: "step [{\"phase\":\"invalid\",\"action\":\"invalid\",\"name\":\"invalid\"}] with policy [my_moveable_timeseries_lifecycle] does not exist" }
142142

143143
- do:
144144
acknowledge: true

0 commit comments

Comments
 (0)