Skip to content

Commit de1e80a

Browse files
committed
Provide useful error when a policy doesn't exist (#34206)
When an index is configured to use a lifecycle policy that does not exist, this will now be noted in the step_info for that policy.
1 parent 1733f54 commit de1e80a

File tree

5 files changed

+123
-10
lines changed

5 files changed

+123
-10
lines changed

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,14 @@ public void runPeriodicStep(String policy, IndexMetaData indexMetaData) {
9696
}
9797
Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
9898
if (currentStep == null) {
99-
logger.warn("current step [{}] for index [{}] with policy [{}] is not recognized",
100-
getCurrentStepKey(lifecycleState), index, policy);
101-
return;
99+
if (stepRegistry.policyExists(policy) == false) {
100+
markPolicyDoesNotExist(policy, indexMetaData.getIndex(), lifecycleState);
101+
return;
102+
} else {
103+
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
104+
getCurrentStepKey(lifecycleState), index, policy);
105+
return;
106+
}
102107
}
103108

104109
if (currentStep instanceof TerminalPolicyStep) {
@@ -197,9 +202,14 @@ public void runPolicyAfterStateChange(String policy, IndexMetaData indexMetaData
197202
}
198203
Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
199204
if (currentStep == null) {
200-
logger.warn("current step [{}] for index [{}] with policy [{}] is not recognized",
201-
getCurrentStepKey(lifecycleState), index, policy);
202-
return;
205+
if (stepRegistry.policyExists(policy) == false) {
206+
markPolicyDoesNotExist(policy, indexMetaData.getIndex(), lifecycleState);
207+
return;
208+
} else {
209+
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
210+
getCurrentStepKey(lifecycleState), index, policy);
211+
return;
212+
}
203213
}
204214

205215
if (currentStep instanceof TerminalPolicyStep) {
@@ -536,4 +546,12 @@ private static IndexMetaData.Builder removePolicyForIndex(IndexMetaData indexMet
536546
builder.removeCustom(ILM_CUSTOM_METADATA_KEY);
537547
return builder.settings(newSettings);
538548
}
549+
550+
private void markPolicyDoesNotExist(String policyName, Index index, LifecycleExecutionState executionState) {
551+
logger.debug("policy [{}] for index [{}] does not exist, recording this in step_info for this index",
552+
policyName, index.getName());
553+
setStepInfo(index, policyName, getCurrentStepKey(executionState),
554+
new SetStepInfoUpdateTask.ExceptionWrapper(
555+
new IllegalArgumentException("policy [" + policyName + "] does not exist")));
556+
}
539557
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ public boolean stepExists(final String policy, final Step.StepKey stepKey) {
227227
}
228228
}
229229

230+
public boolean policyExists(final String policy) {
231+
return lifecyclePolicyMap.containsKey(policy);
232+
}
233+
230234
public Step getFirstStep(String policy) {
231235
return firstStepMap.get(policy);
232236
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
import org.elasticsearch.cluster.metadata.IndexMetaData;
1313
import org.elasticsearch.common.settings.Settings;
1414
import org.elasticsearch.common.xcontent.ToXContentObject;
15+
import org.elasticsearch.common.xcontent.XContentBuilder;
1516
import org.elasticsearch.index.Index;
1617
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleExecutionState;
1718
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
1819
import org.elasticsearch.xpack.core.indexlifecycle.Step;
1920

2021
import java.io.IOException;
22+
import java.util.Objects;
2123

2224
public class SetStepInfoUpdateTask extends ClusterStateUpdateTask {
2325
private final Index index;
@@ -58,7 +60,7 @@ public ClusterState execute(ClusterState currentState) throws IOException {
5860
Settings indexSettings = idxMeta.getSettings();
5961
LifecycleExecutionState indexILMData = LifecycleExecutionState.fromIndexMetadata(idxMeta);
6062
if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings))
61-
&& currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
63+
&& Objects.equals(currentStepKey, IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
6264
return IndexLifecycleRunner.addStepInfoToClusterState(index, currentState, stepInfo);
6365
} else {
6466
// either the policy has changed or the step is now
@@ -73,4 +75,20 @@ public void onFailure(String source, Exception e) {
7375
throw new ElasticsearchException("policy [" + policy + "] for index [" + index.getName()
7476
+ "] failed trying to set step info for step [" + currentStepKey + "].", e);
7577
}
78+
79+
public static class ExceptionWrapper implements ToXContentObject {
80+
private final Throwable exception;
81+
82+
public ExceptionWrapper(Throwable exception) {
83+
this.exception = exception;
84+
}
85+
86+
@Override
87+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
88+
builder.startObject();
89+
ElasticsearchException.generateThrowableXContent(builder, params, exception);
90+
builder.endObject();
91+
return builder;
92+
}
93+
}
7694
}

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ public void testRunPolicyAsyncWaitStepClusterStateChangeIgnored() {
511511
Mockito.verifyZeroInteractions(clusterService);
512512
}
513513

514-
public void testRunPolicyWithNoStepsInRegistry() {
514+
public void testRunPolicyThatDoesntExist() {
515515
String policyName = "cluster_state_action_policy";
516516
ClusterService clusterService = mock(ClusterService.class);
517517
IndexLifecycleRunner runner = new IndexLifecycleRunner(new PolicyStepsRegistry(NamedXContentRegistry.EMPTY, null),
@@ -520,7 +520,16 @@ public void testRunPolicyWithNoStepsInRegistry() {
520520
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
521521
// verify that no exception is thrown
522522
runner.runPolicyAfterStateChange(policyName, indexMetaData);
523-
Mockito.verifyZeroInteractions(clusterService);
523+
Mockito.verify(clusterService, Mockito.times(1)).submitStateUpdateTask(Mockito.matches("ilm-set-step-info"),
524+
Mockito.argThat(new SetStepInfoUpdateTaskMatcher(indexMetaData.getIndex(), policyName, null,
525+
(builder, params) -> {
526+
builder.startObject();
527+
builder.field("reason", "policy [does_not_exist] does not exist");
528+
builder.field("type", "illegal_argument_exception");
529+
builder.endObject();
530+
return builder;
531+
})));
532+
Mockito.verifyNoMoreInteractions(clusterService);
524533
}
525534

526535
public void testGetCurrentStepKey() {
@@ -1602,7 +1611,17 @@ public boolean matches(Object argument) {
16021611
return Objects.equals(index, task.getIndex()) &&
16031612
Objects.equals(policy, task.getPolicy())&&
16041613
Objects.equals(currentStepKey, task.getCurrentStepKey()) &&
1605-
Objects.equals(stepInfo, task.getStepInfo());
1614+
Objects.equals(xContentToString(stepInfo), xContentToString(task.getStepInfo()));
1615+
}
1616+
1617+
private String xContentToString(ToXContentObject xContent) {
1618+
try {
1619+
XContentBuilder builder = JsonXContent.contentBuilder();
1620+
stepInfo.toXContent(builder, ToXContent.EMPTY_PARAMS);
1621+
return BytesReference.bytes(builder).utf8ToString();
1622+
} catch (IOException ex) {
1623+
throw new RuntimeException(ex);
1624+
}
16061625
}
16071626

16081627
}

x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,60 @@ public void testShrinkAction() throws Exception {
238238
expectThrows(ResponseException.class, this::indexDocument);
239239
}
240240

241+
@SuppressWarnings("unchecked")
242+
public void testNonexistentPolicy() throws Exception {
243+
String indexPrefix = randomAlphaOfLengthBetween(5,15).toLowerCase(Locale.ROOT);
244+
final StringEntity template = new StringEntity("{\n" +
245+
" \"index_patterns\": \"" + indexPrefix + "*\",\n" +
246+
" \"settings\": {\n" +
247+
" \"index\": {\n" +
248+
" \"lifecycle\": {\n" +
249+
" \"name\": \"does_not_exist\",\n" +
250+
" \"rollover_alias\": \"test_alias\"\n" +
251+
" }\n" +
252+
" }\n" +
253+
" }\n" +
254+
"}", ContentType.APPLICATION_JSON);
255+
Request templateRequest = new Request("PUT", "_template/test");
256+
templateRequest.setEntity(template);
257+
client().performRequest(templateRequest);
258+
259+
policy = randomAlphaOfLengthBetween(5,20);
260+
createNewSingletonPolicy("hot", new RolloverAction(null, null, 1L));
261+
262+
index = indexPrefix + "-000001";
263+
final StringEntity putIndex = new StringEntity("{\n" +
264+
" \"aliases\": {\n" +
265+
" \"test_alias\": {\n" +
266+
" \"is_write_index\": true\n" +
267+
" }\n" +
268+
" }\n" +
269+
"}", ContentType.APPLICATION_JSON);
270+
Request putIndexRequest = new Request("PUT", index);
271+
putIndexRequest.setEntity(putIndex);
272+
client().performRequest(putIndexRequest);
273+
indexDocument();
274+
275+
assertBusy(() -> {
276+
Request explainRequest = new Request("GET", index + "/_ilm/explain");
277+
Response response = client().performRequest(explainRequest);
278+
Map<String, Object> responseMap;
279+
try (InputStream is = response.getEntity().getContent()) {
280+
responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
281+
}
282+
logger.info(responseMap);
283+
Map<String, Object> indexStatus = (Map<String, Object>)((Map<String, Object>) responseMap.get("indices")).get(index);
284+
assertNull(indexStatus.get("phase"));
285+
assertNull(indexStatus.get("action"));
286+
assertNull(indexStatus.get("step"));
287+
assertEquals("policy [does_not_exist] does not exist",
288+
((Map<String, String>)indexStatus.get("step_info")).get("reason"));
289+
assertEquals("illegal_argument_exception",
290+
((Map<String, String>)indexStatus.get("step_info")).get("type"));
291+
});
292+
293+
}
294+
241295
private void createNewSingletonPolicy(String phaseName, LifecycleAction action) throws IOException {
242296
createNewSingletonPolicy(phaseName, action, TimeValue.ZERO);
243297
}

0 commit comments

Comments
 (0)