Skip to content

Commit 8205cdd

Browse files
authored
[7.x] Refactor IndexLifecycleRunner to split state modificatio… (elastic#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.
1 parent 1c5a139 commit 8205cdd

18 files changed

+1446
-1223
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleExecutionState.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import org.elasticsearch.ElasticsearchException;
1010
import org.elasticsearch.cluster.metadata.IndexMetaData;
11+
import org.elasticsearch.common.Nullable;
12+
import org.elasticsearch.common.Strings;
1113

1214
import java.util.Collections;
1315
import java.util.HashMap;
@@ -78,6 +80,31 @@ public static LifecycleExecutionState fromIndexMetadata(IndexMetaData indexMetaD
7880
return fromCustomMetadata(customData);
7981
}
8082

83+
/**
84+
* Retrieves the current {@link Step.StepKey} from the lifecycle state. Note that
85+
* it is illegal for the step to be set with the phase and/or action unset,
86+
* or for the step to be unset with the phase and/or action set. All three
87+
* settings must be either present or missing.
88+
*
89+
* @param lifecycleState the index custom data to extract the {@link Step.StepKey} from.
90+
*/
91+
@Nullable
92+
public static Step.StepKey getCurrentStepKey(LifecycleExecutionState lifecycleState) {
93+
Objects.requireNonNull(lifecycleState, "cannot determine current step key as lifecycle state is null");
94+
String currentPhase = lifecycleState.getPhase();
95+
String currentAction = lifecycleState.getAction();
96+
String currentStep = lifecycleState.getStep();
97+
if (Strings.isNullOrEmpty(currentStep)) {
98+
assert Strings.isNullOrEmpty(currentPhase) : "Current phase is not empty: " + currentPhase;
99+
assert Strings.isNullOrEmpty(currentAction) : "Current action is not empty: " + currentAction;
100+
return null;
101+
} else {
102+
assert Strings.isNullOrEmpty(currentPhase) == false;
103+
assert Strings.isNullOrEmpty(currentAction) == false;
104+
return new Step.StepKey(currentPhase, currentAction, currentStep);
105+
}
106+
}
107+
81108
public static Builder builder() {
82109
return new Builder();
83110
}
@@ -278,6 +305,11 @@ public int hashCode() {
278305
getStepInfo(), getPhaseDefinition(), getLifecycleDate(), getPhaseTime(), getActionTime(), getStepTime());
279306
}
280307

308+
@Override
309+
public String toString() {
310+
return asMap().toString();
311+
}
312+
281313
public static class Builder {
282314
private String phase;
283315
private String action;

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/LifecycleExecutionStateTests.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,69 @@ public void testEqualsAndHashcode() {
7171
LifecycleExecutionStateTests::mutate);
7272
}
7373

74+
public void testGetCurrentStepKey() {
75+
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder();
76+
Step.StepKey stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState.build());
77+
assertNull(stepKey);
78+
79+
String phase = randomAlphaOfLength(20);
80+
String action = randomAlphaOfLength(20);
81+
String step = randomAlphaOfLength(20);
82+
LifecycleExecutionState.Builder lifecycleState2 = LifecycleExecutionState.builder();
83+
lifecycleState2.setPhase(phase);
84+
lifecycleState2.setAction(action);
85+
lifecycleState2.setStep(step);
86+
stepKey = LifecycleExecutionState.getCurrentStepKey(lifecycleState2.build());
87+
assertNotNull(stepKey);
88+
assertEquals(phase, stepKey.getPhase());
89+
assertEquals(action, stepKey.getAction());
90+
assertEquals(step, stepKey.getName());
91+
92+
phase = randomAlphaOfLength(20);
93+
action = randomAlphaOfLength(20);
94+
step = null;
95+
LifecycleExecutionState.Builder lifecycleState3 = LifecycleExecutionState.builder();
96+
lifecycleState3.setPhase(phase);
97+
lifecycleState3.setAction(action);
98+
lifecycleState3.setStep(step);
99+
AssertionError error3 = expectThrows(AssertionError.class,
100+
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState3.build()));
101+
assertEquals("Current phase is not empty: " + phase, error3.getMessage());
102+
103+
phase = null;
104+
action = randomAlphaOfLength(20);
105+
step = null;
106+
LifecycleExecutionState.Builder lifecycleState4 = LifecycleExecutionState.builder();
107+
lifecycleState4.setPhase(phase);
108+
lifecycleState4.setAction(action);
109+
lifecycleState4.setStep(step);
110+
AssertionError error4 = expectThrows(AssertionError.class,
111+
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState4.build()));
112+
assertEquals("Current action is not empty: " + action, error4.getMessage());
113+
114+
phase = null;
115+
action = randomAlphaOfLength(20);
116+
step = randomAlphaOfLength(20);
117+
LifecycleExecutionState.Builder lifecycleState5 = LifecycleExecutionState.builder();
118+
lifecycleState5.setPhase(phase);
119+
lifecycleState5.setAction(action);
120+
lifecycleState5.setStep(step);
121+
AssertionError error5 = expectThrows(AssertionError.class,
122+
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState5.build()));
123+
assertNull(error5.getMessage());
124+
125+
phase = null;
126+
action = null;
127+
step = randomAlphaOfLength(20);
128+
LifecycleExecutionState.Builder lifecycleState6 = LifecycleExecutionState.builder();
129+
lifecycleState6.setPhase(phase);
130+
lifecycleState6.setAction(action);
131+
lifecycleState6.setStep(step);
132+
AssertionError error6 = expectThrows(AssertionError.class,
133+
() -> LifecycleExecutionState.getCurrentStepKey(lifecycleState6.build()));
134+
assertNull(error6.getMessage());
135+
}
136+
74137
private static LifecycleExecutionState mutate(LifecycleExecutionState toMutate) {
75138
LifecycleExecutionState.Builder newState = LifecycleExecutionState.builder(toMutate);
76139
boolean changed = false;

x-pack/plugin/ilm/qa/rest/src/test/resources/rest-api-spec/test/ilm/40_explain_lifecycle.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ teardown:
115115
- match: { indices.my_index.step: "complete" }
116116
- is_true: indices.my_index.phase_time_millis
117117
- is_true: indices.my_index.age
118+
- is_true: indices.my_index.phase_execution
118119
- is_false: indices.my_index.failed_step
119120
- is_false: indices.my_index.step_info
120-
- is_false: indices.my_index.phase_execution
121121

122122
- is_false: indices.my_index2
123123
- is_false: indices.another_index
@@ -139,9 +139,9 @@ teardown:
139139
- match: { indices.my_index.step: "complete" }
140140
- is_true: indices.my_index.phase_time_millis
141141
- is_true: indices.my_index.age
142+
- is_true: indices.my_index.phase_execution
142143
- is_false: indices.my_index.failed_step
143144
- is_false: indices.my_index.step_info
144-
- is_false: indices.my_index.phase_execution
145145

146146
- is_true: indices.my_index2.managed
147147
- match: { indices.my_index2.index: "my_index2" }
@@ -151,9 +151,9 @@ teardown:
151151
- match: { indices.my_index2.step: "complete" }
152152
- is_true: indices.my_index2.phase_time_millis
153153
- is_true: indices.my_index2.age
154+
- is_true: indices.my_index2.phase_execution
154155
- is_false: indices.my_index2.failed_step
155156
- is_false: indices.my_index2.step_info
156-
- is_false: indices.my_index2.phase_execution
157157

158158
- is_false: indices.another_index
159159
- is_false: indices.unmanaged_index
@@ -178,9 +178,9 @@ teardown:
178178
- match: { indices.my_index.step: "complete" }
179179
- is_true: indices.my_index.phase_time_millis
180180
- is_true: indices.my_index.age
181+
- is_true: indices.my_index.phase_execution
181182
- is_false: indices.my_index.failed_step
182183
- is_false: indices.my_index.step_info
183-
- is_false: indices.my_index.phase_execution
184184

185185
- is_true: indices.my_index2.managed
186186
- match: { indices.my_index2.index: "my_index2" }
@@ -190,9 +190,9 @@ teardown:
190190
- match: { indices.my_index2.step: "complete" }
191191
- is_true: indices.my_index2.phase_time_millis
192192
- is_true: indices.my_index2.age
193+
- is_true: indices.my_index2.phase_execution
193194
- is_false: indices.my_index2.failed_step
194195
- is_false: indices.my_index2.step_info
195-
- is_false: indices.my_index2.phase_execution
196196

197197
- is_true: indices.another_index.managed
198198
- match: { indices.another_index.index: "another_index" }
@@ -202,9 +202,9 @@ teardown:
202202
- match: { indices.another_index.step: "complete" }
203203
- is_true: indices.another_index.phase_time_millis
204204
- is_true: indices.another_index.age
205+
- is_true: indices.another_index.phase_execution
205206
- is_false: indices.another_index.failed_step
206207
- is_false: indices.another_index.step_info
207-
- is_false: indices.another_index.phase_execution
208208

209209
- match: { indices.unmanaged_index.index: "unmanaged_index" }
210210
- is_false: indices.unmanaged_index.managed

x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/ExecuteStepsUpdateTask.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.elasticsearch.index.Index;
1717
import org.elasticsearch.xpack.core.ilm.ClusterStateActionStep;
1818
import org.elasticsearch.xpack.core.ilm.ClusterStateWaitStep;
19-
import org.elasticsearch.xpack.core.ilm.LifecycleExecutionState;
2019
import org.elasticsearch.xpack.core.ilm.Step;
2120
import org.elasticsearch.xpack.core.ilm.TerminalPolicyStep;
2221

@@ -78,8 +77,7 @@ public ClusterState execute(final ClusterState currentState) throws IOException
7877
// This index doesn't exist any more, there's nothing to execute currently
7978
return currentState;
8079
}
81-
Step registeredCurrentStep = IndexLifecycleRunner.getCurrentStep(policyStepsRegistry, policy, indexMetaData,
82-
LifecycleExecutionState.fromIndexMetadata(indexMetaData));
80+
Step registeredCurrentStep = IndexLifecycleRunner.getCurrentStep(policyStepsRegistry, policy, indexMetaData);
8381
if (currentStep.equals(registeredCurrentStep)) {
8482
ClusterState state = currentState;
8583
// We can do cluster state steps all together until we
@@ -103,8 +101,8 @@ public ClusterState execute(final ClusterState currentState) throws IOException
103101
return state;
104102
} else {
105103
logger.trace("[{}] moving cluster state to next step [{}]", index.getName(), nextStepKey);
106-
state = IndexLifecycleRunner.moveClusterStateToNextStep(index, state, currentStep.getKey(),
107-
nextStepKey, nowSupplier, false);
104+
state = IndexLifecycleTransition.moveClusterStateToStep(index, state, nextStepKey, nowSupplier,
105+
policyStepsRegistry, false);
108106
}
109107
} else {
110108
// set here to make sure that the clusterProcessed knows to execute the
@@ -130,8 +128,8 @@ public ClusterState execute(final ClusterState currentState) throws IOException
130128
if (currentStep.getNextStepKey() == null) {
131129
return state;
132130
} else {
133-
state = IndexLifecycleRunner.moveClusterStateToNextStep(index, state, currentStep.getKey(),
134-
currentStep.getNextStepKey(), nowSupplier, false);
131+
state = IndexLifecycleTransition.moveClusterStateToStep(index, state,
132+
currentStep.getNextStepKey(), nowSupplier, policyStepsRegistry,false);
135133
}
136134
} else {
137135
logger.trace("[{}] condition not met ({}) [{}], returning existing state",
@@ -145,7 +143,7 @@ public ClusterState execute(final ClusterState currentState) throws IOException
145143
if (stepInfo == null) {
146144
return state;
147145
} else {
148-
return IndexLifecycleRunner.addStepInfoToClusterState(index, state, stepInfo);
146+
return IndexLifecycleTransition.addStepInfoToClusterState(index, state, stepInfo);
149147
}
150148
}
151149
}

0 commit comments

Comments
 (0)