From 6993c8d393c73f2354021e5d875ffb091b963966 Mon Sep 17 00:00:00 2001 From: Gordon Brown Date: Mon, 1 Oct 2018 16:14:00 -0600 Subject: [PATCH 1/3] Provide useful error when a policy doesn't exist 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. --- .../indexlifecycle/IndexLifecycleRunner.java | 16 ++++-- .../indexlifecycle/PolicyStepsRegistry.java | 4 ++ .../indexlifecycle/SetStepInfoUpdateTask.java | 3 +- .../StepInfoExceptionWrapper.java | 56 +++++++++++++++++++ .../IndexLifecycleRunnerTests.java | 7 ++- .../StepInfoExceptionWrapperTests.java | 54 ++++++++++++++++++ .../TimeSeriesLifecycleActionsIT.java | 55 ++++++++++++++++++ 7 files changed, 187 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java create mode 100644 x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java index 3c868332f5f95..45ef12404bfa6 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java @@ -93,11 +93,17 @@ public void runPolicy(String policy, IndexMetaData indexMetaData, ClusterState c } Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState); if (currentStep == null) { - // This may happen in the case that there is invalid ilm-step index settings or the stepRegistry is out of - // sync with the current cluster state - logger.warn("current step [" + getCurrentStepKey(lifecycleState) + "] for index [" + indexMetaData.getIndex().getName() - + "] with policy [" + policy + "] is not recognized"); - return; + if (stepRegistry.policyExists(policy) == false) { + logger.trace("policy [{}] for index [{}] does not exist, recording this in step_info for this index", + policy, indexMetaData.getIndex().getName()); + setStepInfo(indexMetaData.getIndex(), policy, getCurrentStepKey(lifecycleState), + new StepInfoExceptionWrapper(new IllegalArgumentException("policy [" + policy + "] does not exist"))); + return; + } else { + logger.error("current step [" + getCurrentStepKey(lifecycleState) + "] for index [" + indexMetaData.getIndex().getName() + + "] with policy [" + policy + "] is not recognized"); + return; + } } logger.debug("running policy with current-step [" + currentStep.getKey() + "]"); if (currentStep instanceof TerminalPolicyStep) { diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java index 89b8c9b431990..3677d3b6a6d75 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java @@ -223,6 +223,10 @@ public boolean stepExists(final String policy, final Step.StepKey stepKey) { } } + public boolean policyExists(final String policy) { + return lifecyclePolicyMap.containsKey(policy); + } + public Step getFirstStep(String policy) { return firstStepMap.get(policy); } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java index bbba07fd8522d..64c1d68b66dfa 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java @@ -18,6 +18,7 @@ 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 +59,7 @@ public ClusterState execute(ClusterState currentState) throws IOException { 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 diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java new file mode 100644 index 0000000000000..7de398fecd2ec --- /dev/null +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java @@ -0,0 +1,56 @@ +/* + * 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.indexlifecycle; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.Objects; + +/** + * Wraps an Exception so that it can be passed to things which require an + * {@link org.elasticsearch.common.xcontent.ToXContentObject}. + */ +public class StepInfoExceptionWrapper implements ToXContentObject { + private final Throwable exception; + + public StepInfoExceptionWrapper(Throwable exception) { + this.exception = Objects.requireNonNull(exception); + } + + Class getExceptionType() { + return exception.getClass(); + } + + String getMessage() { + return exception.getMessage(); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + ElasticsearchException.generateThrowableXContent(builder, params, exception); + builder.endObject(); + return builder; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StepInfoExceptionWrapper that = (StepInfoExceptionWrapper) o; + return Objects.equals(exception.getMessage(), that.exception.getMessage()) + && Objects.equals(exception.getClass(), that.exception.getClass()); + } + + @Override + public int hashCode() { + return Objects.hash(exception.getClass(), exception.getMessage()); + } +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java index 9994b56612ce8..76678c417c724 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java @@ -349,7 +349,7 @@ public void testRunPolicyAsyncWaitStepClusterStateChangeIgnored() { 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), @@ -358,7 +358,10 @@ public void testRunPolicyWithNoStepsInRegistry() { .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); // verify that no exception is thrown runner.runPolicy(policyName, indexMetaData, null, randomBoolean()); - Mockito.verifyZeroInteractions(clusterService); + Mockito.verify(clusterService, Mockito.times(1)).submitStateUpdateTask(Mockito.matches("ILM"), + Mockito.argThat(new SetStepInfoUpdateTaskMatcher(indexMetaData.getIndex(), policyName, null, + new StepInfoExceptionWrapper(new IllegalArgumentException("policy [" + policyName + "] does not exist"))))); + Mockito.verifyNoMoreInteractions(clusterService); } public void testRunPolicyUnknownStepType() { diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java new file mode 100644 index 0000000000000..31b79b2cd0f9a --- /dev/null +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java @@ -0,0 +1,54 @@ +/* + * 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.indexlifecycle; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.EqualsHashCodeTestUtils; + +public class StepInfoExceptionWrapperTests extends ESTestCase { + + public void testEqualsAndHashcode() { + EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), (original) -> { + try { + return copy(original); + } catch (Exception e) { + // This should never happen + throw new RuntimeException(e); + } + }, (original) -> { + try { + return mutate(original); + } catch (Exception e) { + // This should never happen + throw new RuntimeException(e); + } + }); + } + + private static StepInfoExceptionWrapper createTestInstance() { + return new StepInfoExceptionWrapper(new Exception(randomAlphaOfLengthBetween(5,20))); + } + + private static StepInfoExceptionWrapper copy(final StepInfoExceptionWrapper original) throws Exception { + Throwable thing = original.getExceptionType().getConstructor(String.class).newInstance(original.getMessage()); + return new StepInfoExceptionWrapper(thing); + } + + @SuppressWarnings("unchecked") + private static StepInfoExceptionWrapper mutate(final StepInfoExceptionWrapper original) throws Exception { + Class exceptionType = randomValueOtherThan(original.getExceptionType(), () -> + randomFrom(RuntimeException.class, IllegalArgumentException.class, Exception.class, IllegalStateException.class)); + final String message; + if (randomBoolean()) { + message = original.getMessage(); + } else { + message = randomAlphaOfLengthBetween(5, 20); + } + return new StepInfoExceptionWrapper(exceptionType.getConstructor(String.class).newInstance(message)); + } + +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java index 00ad87d50b826..bf4e8a44f8f5d 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java @@ -28,6 +28,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.Phase; import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction; +import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction; import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep; @@ -192,6 +193,60 @@ public void testShrinkAction() throws Exception { 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 responseMap; + try (InputStream is = response.getEntity().getContent()) { + responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true); + } + logger.info(responseMap); + Map indexStatus = (Map)((Map) 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)indexStatus.get("step_info")).get("reason")); + assertEquals("illegal_argument_exception", + ((Map)indexStatus.get("step_info")).get("type")); + }); + + } + private void createNewSingletonPolicy(String phaseName, LifecycleAction action) throws IOException { createNewSingletonPolicy(phaseName, action, TimeValue.ZERO); } From 6b084b27e09dbe69bd1a1f5c544a02da7ce7342d Mon Sep 17 00:00:00 2001 From: Gordon Brown Date: Tue, 2 Oct 2018 09:43:34 -0600 Subject: [PATCH 2/3] Review comments --- .../xpack/indexlifecycle/IndexLifecycleRunner.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java index 45ef12404bfa6..e08ad07eabdab 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java @@ -94,14 +94,14 @@ public void runPolicy(String policy, IndexMetaData indexMetaData, ClusterState c Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState); if (currentStep == null) { if (stepRegistry.policyExists(policy) == false) { - logger.trace("policy [{}] for index [{}] does not exist, recording this in step_info for this index", + logger.debug("policy [{}] for index [{}] does not exist, recording this in step_info for this index", policy, indexMetaData.getIndex().getName()); setStepInfo(indexMetaData.getIndex(), policy, getCurrentStepKey(lifecycleState), new StepInfoExceptionWrapper(new IllegalArgumentException("policy [" + policy + "] does not exist"))); return; } else { - logger.error("current step [" + getCurrentStepKey(lifecycleState) + "] for index [" + indexMetaData.getIndex().getName() - + "] with policy [" + policy + "] is not recognized"); + logger.error("current step [{}] for index [{}] with policy [{}] is not recognized", + getCurrentStepKey(lifecycleState), indexMetaData.getIndex().getName(), policy); return; } } From b3df5c8ba2b7334a1e8cadeb2e86cbae6ecb1c9d Mon Sep 17 00:00:00 2001 From: Gordon Brown Date: Wed, 3 Oct 2018 15:37:38 -0600 Subject: [PATCH 3/3] Take two at serializing exceptions --- .../indexlifecycle/IndexLifecycleRunner.java | 27 ++++++--- .../indexlifecycle/SetStepInfoUpdateTask.java | 17 ++++++ .../StepInfoExceptionWrapper.java | 56 ------------------- .../IndexLifecycleRunnerTests.java | 22 +++++++- .../StepInfoExceptionWrapperTests.java | 54 ------------------ 5 files changed, 54 insertions(+), 122 deletions(-) delete mode 100644 x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java delete mode 100644 x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java index 8a3fc672809b2..8c7fb212ff63a 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java @@ -7,7 +7,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.lucene.util.BytesRef; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.support.TransportAction; import org.elasticsearch.cluster.ClusterState; @@ -98,14 +97,11 @@ public void runPeriodicStep(String policy, IndexMetaData indexMetaData) { Step currentStep = getCurrentStep(stepRegistry, policy, indexMetaData, lifecycleState); if (currentStep == null) { if (stepRegistry.policyExists(policy) == false) { - logger.debug("policy [{}] for index [{}] does not exist, recording this in step_info for this index", - policy, indexMetaData.getIndex().getName()); - setStepInfo(indexMetaData.getIndex(), policy, getCurrentStepKey(lifecycleState), - new StepInfoExceptionWrapper(new IllegalArgumentException("policy [" + policy + "] does not exist"))); + markPolicyDoesNotExist(policy, indexMetaData.getIndex(), lifecycleState); return; } else { logger.error("current step [{}] for index [{}] with policy [{}] is not recognized", - getCurrentStepKey(lifecycleState), indexMetaData.getIndex().getName(), policy); + getCurrentStepKey(lifecycleState), index, policy); return; } } @@ -206,9 +202,14 @@ public void runPolicyAfterStateChange(String policy, IndexMetaData indexMetaData } 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) { @@ -545,4 +546,12 @@ private static IndexMetaData.Builder removePolicyForIndex(IndexMetaData indexMet 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"))); + } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java index 64c1d68b66dfa..72c7aa81b9d77 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/SetStepInfoUpdateTask.java @@ -12,6 +12,7 @@ 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; @@ -74,4 +75,20 @@ public void onFailure(String source, Exception e) { 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; + } + } } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java deleted file mode 100644 index 7de398fecd2ec..0000000000000 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapper.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.indexlifecycle; - -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Objects; - -/** - * Wraps an Exception so that it can be passed to things which require an - * {@link org.elasticsearch.common.xcontent.ToXContentObject}. - */ -public class StepInfoExceptionWrapper implements ToXContentObject { - private final Throwable exception; - - public StepInfoExceptionWrapper(Throwable exception) { - this.exception = Objects.requireNonNull(exception); - } - - Class getExceptionType() { - return exception.getClass(); - } - - String getMessage() { - return exception.getMessage(); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - ElasticsearchException.generateThrowableXContent(builder, params, exception); - builder.endObject(); - return builder; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - StepInfoExceptionWrapper that = (StepInfoExceptionWrapper) o; - return Objects.equals(exception.getMessage(), that.exception.getMessage()) - && Objects.equals(exception.getClass(), that.exception.getClass()); - } - - @Override - public int hashCode() { - return Objects.hash(exception.getClass(), exception.getMessage()); - } -} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java index 27c93899c78cf..0c84e7c2dd104 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunnerTests.java @@ -520,9 +520,15 @@ public void testRunPolicyThatDoesntExist() { .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); // verify that no exception is thrown runner.runPolicyAfterStateChange(policyName, indexMetaData); - Mockito.verify(clusterService, Mockito.times(1)).submitStateUpdateTask(Mockito.matches("ILM"), + Mockito.verify(clusterService, Mockito.times(1)).submitStateUpdateTask(Mockito.matches("ilm-set-step-info"), Mockito.argThat(new SetStepInfoUpdateTaskMatcher(indexMetaData.getIndex(), policyName, null, - new StepInfoExceptionWrapper(new IllegalArgumentException("policy [" + policyName + "] does not exist"))))); + (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); } @@ -1605,7 +1611,17 @@ public boolean matches(Object argument) { 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); + } } } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java deleted file mode 100644 index 31b79b2cd0f9a..0000000000000 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/StepInfoExceptionWrapperTests.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.indexlifecycle; - -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.test.EqualsHashCodeTestUtils; - -public class StepInfoExceptionWrapperTests extends ESTestCase { - - public void testEqualsAndHashcode() { - EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), (original) -> { - try { - return copy(original); - } catch (Exception e) { - // This should never happen - throw new RuntimeException(e); - } - }, (original) -> { - try { - return mutate(original); - } catch (Exception e) { - // This should never happen - throw new RuntimeException(e); - } - }); - } - - private static StepInfoExceptionWrapper createTestInstance() { - return new StepInfoExceptionWrapper(new Exception(randomAlphaOfLengthBetween(5,20))); - } - - private static StepInfoExceptionWrapper copy(final StepInfoExceptionWrapper original) throws Exception { - Throwable thing = original.getExceptionType().getConstructor(String.class).newInstance(original.getMessage()); - return new StepInfoExceptionWrapper(thing); - } - - @SuppressWarnings("unchecked") - private static StepInfoExceptionWrapper mutate(final StepInfoExceptionWrapper original) throws Exception { - Class exceptionType = randomValueOtherThan(original.getExceptionType(), () -> - randomFrom(RuntimeException.class, IllegalArgumentException.class, Exception.class, IllegalStateException.class)); - final String message; - if (randomBoolean()) { - message = original.getMessage(); - } else { - message = randomAlphaOfLengthBetween(5, 20); - } - return new StepInfoExceptionWrapper(exceptionType.getConstructor(String.class).newInstance(message)); - } - -}