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.
This commit is contained in:
Gordon Brown 2018-10-04 08:21:55 -06:00 committed by GitHub
parent d66a63ed7a
commit 13d89295c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 10 deletions

View File

@ -96,9 +96,14 @@ public class IndexLifecycleRunner {
}
Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
if (currentStep == null) {
logger.warn("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
return;
if (stepRegistry.policyExists(policy) == false) {
markPolicyDoesNotExist(policy, indexMetaData.getIndex(), lifecycleState);
return;
} else {
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
return;
}
}
if (currentStep instanceof TerminalPolicyStep) {
@ -197,9 +202,14 @@ public class IndexLifecycleRunner {
}
Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState);
if (currentStep == null) {
logger.warn("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
return;
if (stepRegistry.policyExists(policy) == false) {
markPolicyDoesNotExist(policy, indexMetaData.getIndex(), lifecycleState);
return;
} else {
logger.error("current step [{}] for index [{}] with policy [{}] is not recognized",
getCurrentStepKey(lifecycleState), index, policy);
return;
}
}
if (currentStep instanceof TerminalPolicyStep) {
@ -536,4 +546,12 @@ public class IndexLifecycleRunner {
builder.removeCustom(ILM_CUSTOM_METADATA_KEY);
return builder.settings(newSettings);
}
private void markPolicyDoesNotExist(String policyName, Index index, LifecycleExecutionState executionState) {
logger.debug("policy [{}] for index [{}] does not exist, recording this in step_info for this index",
policyName, index.getName());
setStepInfo(index, policyName, getCurrentStepKey(executionState),
new SetStepInfoUpdateTask.ExceptionWrapper(
new IllegalArgumentException("policy [" + policyName + "] does not exist")));
}
}

View File

@ -227,6 +227,10 @@ public class PolicyStepsRegistry {
}
}
public boolean policyExists(final String policy) {
return lifecyclePolicyMap.containsKey(policy);
}
public Step getFirstStep(String policy) {
return firstStepMap.get(policy);
}

View File

@ -12,12 +12,14 @@ import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleExecutionState;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.Step;
import java.io.IOException;
import java.util.Objects;
public class SetStepInfoUpdateTask extends ClusterStateUpdateTask {
private final Index index;
@ -58,7 +60,7 @@ public class SetStepInfoUpdateTask 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))) {
&& Objects.equals(currentStepKey, IndexLifecycleRunner.getCurrentStepKey(indexILMData))) {
return IndexLifecycleRunner.addStepInfoToClusterState(index, currentState, stepInfo);
} else {
// either the policy has changed or the step is now
@ -73,4 +75,20 @@ public class SetStepInfoUpdateTask extends ClusterStateUpdateTask {
throw new ElasticsearchException("policy [" + policy + "] for index [" + index.getName()
+ "] failed trying to set step info for step [" + currentStepKey + "].", e);
}
public static class ExceptionWrapper implements ToXContentObject {
private final Throwable exception;
public ExceptionWrapper(Throwable exception) {
this.exception = exception;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
ElasticsearchException.generateThrowableXContent(builder, params, exception);
builder.endObject();
return builder;
}
}
}

View File

@ -511,7 +511,7 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
Mockito.verifyZeroInteractions(clusterService);
}
public void testRunPolicyWithNoStepsInRegistry() {
public void testRunPolicyThatDoesntExist() {
String policyName = "cluster_state_action_policy";
ClusterService clusterService = mock(ClusterService.class);
IndexLifecycleRunner runner = new IndexLifecycleRunner(new PolicyStepsRegistry(NamedXContentRegistry.EMPTY, null),
@ -520,7 +520,16 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// verify that no exception is thrown
runner.runPolicyAfterStateChange(policyName, indexMetaData);
Mockito.verifyZeroInteractions(clusterService);
Mockito.verify(clusterService, Mockito.times(1)).submitStateUpdateTask(Mockito.matches("ilm-set-step-info"),
Mockito.argThat(new SetStepInfoUpdateTaskMatcher(indexMetaData.getIndex(), policyName, null,
(builder, params) -> {
builder.startObject();
builder.field("reason", "policy [does_not_exist] does not exist");
builder.field("type", "illegal_argument_exception");
builder.endObject();
return builder;
})));
Mockito.verifyNoMoreInteractions(clusterService);
}
public void testGetCurrentStepKey() {
@ -1602,7 +1611,17 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
return Objects.equals(index, task.getIndex()) &&
Objects.equals(policy, task.getPolicy())&&
Objects.equals(currentStepKey, task.getCurrentStepKey()) &&
Objects.equals(stepInfo, task.getStepInfo());
Objects.equals(xContentToString(stepInfo), xContentToString(task.getStepInfo()));
}
private String xContentToString(ToXContentObject xContent) {
try {
XContentBuilder builder = JsonXContent.contentBuilder();
stepInfo.toXContent(builder, ToXContent.EMPTY_PARAMS);
return BytesReference.bytes(builder).utf8ToString();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -238,6 +238,60 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
expectThrows(ResponseException.class, this::indexDocument);
}
@SuppressWarnings("unchecked")
public void testNonexistentPolicy() throws Exception {
String indexPrefix = randomAlphaOfLengthBetween(5,15).toLowerCase(Locale.ROOT);
final StringEntity template = new StringEntity("{\n" +
" \"index_patterns\": \"" + indexPrefix + "*\",\n" +
" \"settings\": {\n" +
" \"index\": {\n" +
" \"lifecycle\": {\n" +
" \"name\": \"does_not_exist\",\n" +
" \"rollover_alias\": \"test_alias\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}", ContentType.APPLICATION_JSON);
Request templateRequest = new Request("PUT", "_template/test");
templateRequest.setEntity(template);
client().performRequest(templateRequest);
policy = randomAlphaOfLengthBetween(5,20);
createNewSingletonPolicy("hot", new RolloverAction(null, null, 1L));
index = indexPrefix + "-000001";
final StringEntity putIndex = new StringEntity("{\n" +
" \"aliases\": {\n" +
" \"test_alias\": {\n" +
" \"is_write_index\": true\n" +
" }\n" +
" }\n" +
"}", ContentType.APPLICATION_JSON);
Request putIndexRequest = new Request("PUT", index);
putIndexRequest.setEntity(putIndex);
client().performRequest(putIndexRequest);
indexDocument();
assertBusy(() -> {
Request explainRequest = new Request("GET", index + "/_ilm/explain");
Response response = client().performRequest(explainRequest);
Map<String, Object> responseMap;
try (InputStream is = response.getEntity().getContent()) {
responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
}
logger.info(responseMap);
Map<String, Object> indexStatus = (Map<String, Object>)((Map<String, Object>) responseMap.get("indices")).get(index);
assertNull(indexStatus.get("phase"));
assertNull(indexStatus.get("action"));
assertNull(indexStatus.get("step"));
assertEquals("policy [does_not_exist] does not exist",
((Map<String, String>)indexStatus.get("step_info")).get("reason"));
assertEquals("illegal_argument_exception",
((Map<String, String>)indexStatus.get("step_info")).get("type"));
});
}
private void createNewSingletonPolicy(String phaseName, LifecycleAction action) throws IOException {
createNewSingletonPolicy(phaseName, action, TimeValue.ZERO);
}