From 51b631fb3f95e5eb78a5cd6c8254c83e5b4596df Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Mon, 30 Sep 2019 22:17:51 +0100 Subject: [PATCH 1/8] ILM: Skip rolling indexes that are already rolled An index with an ILM policy that has a `rollover` action in one of the phases was rolled over when the ILM conditions dictated regardless if it was already rolled over (eg. manually after modifying an index template in order to force the creation of a new index that uses the new mappings). This commit adds the `index.lifecycle.rollover.skip_rolled` setting, which defaults to true, to change this behaviour and have ILM check if the index it's about to roll has not been rolled over in the meantime. --- docs/reference/settings/ilm-settings.asciidoc | 11 ++ .../xpack/core/ilm/LifecycleSettings.java | 3 + .../core/ilm/WaitForRolloverReadyStep.java | 8 ++ .../ilm/WaitForRolloverReadyStepTests.java | 100 ++++++++++++++++++ .../xpack/ilm/IndexLifecycle.java | 1 + 5 files changed, 123 insertions(+) diff --git a/docs/reference/settings/ilm-settings.asciidoc b/docs/reference/settings/ilm-settings.asciidoc index 97ae65d181523..b7ecd5dbb779e 100644 --- a/docs/reference/settings/ilm-settings.asciidoc +++ b/docs/reference/settings/ilm-settings.asciidoc @@ -23,6 +23,17 @@ policy that contains a rollover action. When the index rolls over, the alias is updated to reflect that the index is no longer the write index. For more information about rollover, see <>. +`index.lifecycle.rollover.skip_rolled`:: (Expert Setting) +When configured to `false` {ilm} will attempt to rollover the index, in case +the `rollover` action is configured for a phase, even if it was manually rolled +over since the last {ilm} cycle. +Allowing {ilm} to rollover the index will potentially fail due to +`is_write_index` now being `false` or, if the index was manually rolled under +a different alias than the `rollover_alias`, due to the rollover target index +already existing. +By default {ilm} will detect this situation and skip trying to rollover the +index again. + `indices.lifecycle.poll_interval`:: (<>) How often {ilm} checks for indices that meet policy criteria. Defaults to `10m`. diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java index 6fea7cf877373..18aad9d4007ad 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java @@ -19,6 +19,7 @@ public class LifecycleSettings { public static final String LIFECYCLE_INDEXING_COMPLETE = "index.lifecycle.indexing_complete"; public static final String LIFECYCLE_ORIGINATION_DATE = "index.lifecycle.origination_date"; public static final String LIFECYCLE_PARSE_ORIGINATION_DATE = "index.lifecycle.parse_origination_date"; + public static final String LIFECYCLE_ROLLOVER_SKIP_ROLLED = "index.lifecycle.rollover.skip_rolled"; public static final String SLM_HISTORY_INDEX_ENABLED = "slm.history_index_enabled"; public static final String SLM_RETENTION_SCHEDULE = "slm.retention_schedule"; @@ -35,6 +36,8 @@ public class LifecycleSettings { Setting.longSetting(LIFECYCLE_ORIGINATION_DATE, -1, -1, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING = Setting.boolSetting(LIFECYCLE_PARSE_ORIGINATION_DATE, false, Setting.Property.Dynamic, Setting.Property.IndexScope); + public static final Setting LIFECYCLE_ROLLOVER_SKIP_ROLLED_SETTING = Setting.boolSetting(LIFECYCLE_ROLLOVER_SKIP_ROLLED, + true, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting SLM_HISTORY_INDEX_ENABLED_SETTING = Setting.boolSetting(SLM_HISTORY_INDEX_ENABLED, true, Setting.Property.NodeScope); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java index 405a4e3422b3a..9fbf0aa17a659 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java @@ -22,6 +22,8 @@ import java.util.Locale; import java.util.Objects; +import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED; + /** * Waits for at least one rollover condition to be satisfied, using the Rollover API's dry_run option. */ @@ -53,6 +55,12 @@ public void evaluateCondition(IndexMetaData indexMetaData, Listener listener) { return; } + if (indexMetaData.getSettings().getAsBoolean(LIFECYCLE_ROLLOVER_SKIP_ROLLED, true) && + indexMetaData.getRolloverInfos().get(rolloverAlias) != null) { + logger.trace("Index {} was already rolled, skipping", indexMetaData.getIndex().getName()); + return; + } + // The order of the following checks is important in ways which may not be obvious. // First, figure out if 1) The configured alias points to this index, and if so, diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java index a41463e2f2300..f46fa04ee1aa8 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.action.admin.indices.rollover.MaxAgeCondition; import org.elasticsearch.action.admin.indices.rollover.MaxDocsCondition; import org.elasticsearch.action.admin.indices.rollover.MaxSizeCondition; +import org.elasticsearch.action.admin.indices.rollover.RolloverInfo; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverResponse; import org.elasticsearch.client.AdminClient; @@ -29,12 +30,14 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.Collections; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED; import static org.hamcrest.Matchers.equalTo; public class WaitForRolloverReadyStepTests extends AbstractStepTestCase { @@ -173,6 +176,103 @@ public void onFailure(Exception e) { Mockito.verify(indicesClient, Mockito.only()).rolloverIndex(Mockito.any(), Mockito.any()); } + public void testEvaluateDoesntTriggerRolloverForIndexManuallyRolledOnLifecycleRolloverAlias() { + String rolloverAlias = randomAlphaOfLength(5); + IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) + .putAlias(AliasMetaData.builder(rolloverAlias)) + .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias)) + .putRolloverInfo(new RolloverInfo(rolloverAlias, Collections.singletonList(new MaxSizeCondition(new ByteSizeValue(2L))), + System.currentTimeMillis())) + .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); + + WaitForRolloverReadyStep step = createRandomInstance(); + IndicesAdminClient indicesClient = indicesAdminClientMock(); + + step.evaluateCondition(indexMetaData, new AsyncWaitStep.Listener() { + + @Override + public void onResponse(boolean complete, ToXContentObject informationContext) { + } + + @Override + public void onFailure(Exception e) { + throw new AssertionError("Unexpected method call", e); + } + }); + + Mockito.verify(indicesClient, Mockito.never()).rolloverIndex(Mockito.any(), Mockito.any()); + } + + public void testEvaluateTriggersRolloverForIndexManuallyRolledOnDifferentAlias() { + String rolloverAlias = randomAlphaOfLength(5); + IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) + .putAlias(AliasMetaData.builder(rolloverAlias)) + .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias)) + .putRolloverInfo(new RolloverInfo(randomAlphaOfLength(5), + Collections.singletonList(new MaxSizeCondition(new ByteSizeValue(2L))), + System.currentTimeMillis()) + ) + .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); + + WaitForRolloverReadyStep step = createRandomInstance(); + IndicesAdminClient indicesClient = indicesAdminClientMock(); + + step.evaluateCondition(indexMetaData, new AsyncWaitStep.Listener() { + + @Override + public void onResponse(boolean complete, ToXContentObject informationContext) { + } + + @Override + public void onFailure(Exception e) { + throw new AssertionError("Unexpected method call", e); + } + }); + + Mockito.verify(indicesClient, Mockito.only()).rolloverIndex(Mockito.any(), Mockito.any()); + } + + private IndicesAdminClient indicesAdminClientMock() { + AdminClient adminClient = Mockito.mock(AdminClient.class); + IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); + Mockito.when(client.admin()).thenReturn(adminClient); + Mockito.when(adminClient.indices()).thenReturn(indicesClient); + return indicesClient; + } + + public void testSkippingRolledIndexesIsDisabledBySetting() { + String rolloverAlias = randomAlphaOfLength(5); + IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) + .putAlias(AliasMetaData.builder(rolloverAlias)) + .settings( + settings(Version.CURRENT) + .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias) + .put(LIFECYCLE_ROLLOVER_SKIP_ROLLED, false) + ) + .putRolloverInfo(new RolloverInfo(rolloverAlias, + Collections.singletonList(new MaxSizeCondition(new ByteSizeValue(2L))), + System.currentTimeMillis()) + ) + .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); + + WaitForRolloverReadyStep step = createRandomInstance(); + IndicesAdminClient indicesClient = indicesAdminClientMock(); + + step.evaluateCondition(indexMetaData, new AsyncWaitStep.Listener() { + + @Override + public void onResponse(boolean complete, ToXContentObject informationContext) { + } + + @Override + public void onFailure(Exception e) { + throw new AssertionError("Unexpected method call", e); + } + }); + + Mockito.verify(indicesClient, Mockito.only()).rolloverIndex(Mockito.any(), Mockito.any()); + } + public void testPerformActionWithIndexingComplete() { String alias = randomAlphaOfLength(5); IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java index 39e27f2a5afe5..d9641db3c4544 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java @@ -143,6 +143,7 @@ public List> getSettings() { LifecycleSettings.LIFECYCLE_NAME_SETTING, LifecycleSettings.LIFECYCLE_ORIGINATION_DATE_SETTING, LifecycleSettings.LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING, + LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED_SETTING, LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING, RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING, LifecycleSettings.SLM_HISTORY_INDEX_ENABLED_SETTING, From 3ae12a768bb7c4afb218d792df60ce52acfd7540 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Mon, 30 Sep 2019 23:14:52 +0100 Subject: [PATCH 2/8] Fix test that expects ILM to fail when rolling over a rolled index --- .../elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java index ac385ce1c54b9..6c67d4e550120 100644 --- a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java @@ -16,6 +16,7 @@ import org.elasticsearch.client.RestClient; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -736,6 +737,7 @@ public void testRemoveAndReaddPolicy() throws Exception { Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) .put(LifecycleSettings.LIFECYCLE_NAME, policy) + .put(LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED, false) .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, "alias")); // Index a document From 617a2f4a3cae53d40a078ec7e304dbd4fae9317e Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 13:23:00 +0100 Subject: [PATCH 3/8] Drop the index.lifecycle.rollover.skip_rolled setting --- .../elasticsearch/xpack/core/ilm/LifecycleSettings.java | 3 --- .../xpack/core/ilm/WaitForRolloverReadyStep.java | 8 +++----- .../java/org/elasticsearch/xpack/ilm/IndexLifecycle.java | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java index 18aad9d4007ad..6fea7cf877373 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/LifecycleSettings.java @@ -19,7 +19,6 @@ public class LifecycleSettings { public static final String LIFECYCLE_INDEXING_COMPLETE = "index.lifecycle.indexing_complete"; public static final String LIFECYCLE_ORIGINATION_DATE = "index.lifecycle.origination_date"; public static final String LIFECYCLE_PARSE_ORIGINATION_DATE = "index.lifecycle.parse_origination_date"; - public static final String LIFECYCLE_ROLLOVER_SKIP_ROLLED = "index.lifecycle.rollover.skip_rolled"; public static final String SLM_HISTORY_INDEX_ENABLED = "slm.history_index_enabled"; public static final String SLM_RETENTION_SCHEDULE = "slm.retention_schedule"; @@ -36,8 +35,6 @@ public class LifecycleSettings { Setting.longSetting(LIFECYCLE_ORIGINATION_DATE, -1, -1, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING = Setting.boolSetting(LIFECYCLE_PARSE_ORIGINATION_DATE, false, Setting.Property.Dynamic, Setting.Property.IndexScope); - public static final Setting LIFECYCLE_ROLLOVER_SKIP_ROLLED_SETTING = Setting.boolSetting(LIFECYCLE_ROLLOVER_SKIP_ROLLED, - true, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting SLM_HISTORY_INDEX_ENABLED_SETTING = Setting.boolSetting(SLM_HISTORY_INDEX_ENABLED, true, Setting.Property.NodeScope); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java index 9fbf0aa17a659..6191a5091417a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java @@ -22,8 +22,6 @@ import java.util.Locale; import java.util.Objects; -import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED; - /** * Waits for at least one rollover condition to be satisfied, using the Rollover API's dry_run option. */ @@ -55,9 +53,9 @@ public void evaluateCondition(IndexMetaData indexMetaData, Listener listener) { return; } - if (indexMetaData.getSettings().getAsBoolean(LIFECYCLE_ROLLOVER_SKIP_ROLLED, true) && - indexMetaData.getRolloverInfos().get(rolloverAlias) != null) { - logger.trace("Index {} was already rolled, skipping", indexMetaData.getIndex().getName()); + if (indexMetaData.getRolloverInfos().get(rolloverAlias) != null) { + logger.info("index [{}] was already rolled over for alias [{}], not attempting to roll over again", + indexMetaData.getIndex().getName(), rolloverAlias); return; } diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java index d9641db3c4544..39e27f2a5afe5 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java @@ -143,7 +143,6 @@ public List> getSettings() { LifecycleSettings.LIFECYCLE_NAME_SETTING, LifecycleSettings.LIFECYCLE_ORIGINATION_DATE_SETTING, LifecycleSettings.LIFECYCLE_PARSE_ORIGINATION_DATE_SETTING, - LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED_SETTING, LifecycleSettings.LIFECYCLE_INDEXING_COMPLETE_SETTING, RolloverAction.LIFECYCLE_ROLLOVER_ALIAS_SETTING, LifecycleSettings.SLM_HISTORY_INDEX_ENABLED_SETTING, From 2a70f55f1a9a4fd1dd72ac0da2a9f3f076869fa8 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 13:23:40 +0100 Subject: [PATCH 4/8] Complete the WaitForRolloverReadyStep --- .../core/ilm/WaitForRolloverReadyStep.java | 1 + .../ilm/WaitForRolloverReadyStepTests.java | 53 ++++--------------- 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java index 6191a5091417a..3aba5df62c51c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStep.java @@ -56,6 +56,7 @@ public void evaluateCondition(IndexMetaData indexMetaData, Listener listener) { if (indexMetaData.getRolloverInfos().get(rolloverAlias) != null) { logger.info("index [{}] was already rolled over for alias [{}], not attempting to roll over again", indexMetaData.getIndex().getName(), rolloverAlias); + listener.onResponse(true, new WaitForRolloverReadyStep.EmptyInfo()); return; } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java index f46fa04ee1aa8..69494cd6948a6 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/WaitForRolloverReadyStepTests.java @@ -37,8 +37,8 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.elasticsearch.xpack.core.ilm.LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; public class WaitForRolloverReadyStepTests extends AbstractStepTestCase { @@ -192,6 +192,7 @@ public void testEvaluateDoesntTriggerRolloverForIndexManuallyRolledOnLifecycleRo @Override public void onResponse(boolean complete, ToXContentObject informationContext) { + assertThat(complete, is(true)); } @Override @@ -221,47 +222,7 @@ public void testEvaluateTriggersRolloverForIndexManuallyRolledOnDifferentAlias() @Override public void onResponse(boolean complete, ToXContentObject informationContext) { - } - - @Override - public void onFailure(Exception e) { - throw new AssertionError("Unexpected method call", e); - } - }); - - Mockito.verify(indicesClient, Mockito.only()).rolloverIndex(Mockito.any(), Mockito.any()); - } - - private IndicesAdminClient indicesAdminClientMock() { - AdminClient adminClient = Mockito.mock(AdminClient.class); - IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); - Mockito.when(client.admin()).thenReturn(adminClient); - Mockito.when(adminClient.indices()).thenReturn(indicesClient); - return indicesClient; - } - - public void testSkippingRolledIndexesIsDisabledBySetting() { - String rolloverAlias = randomAlphaOfLength(5); - IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) - .putAlias(AliasMetaData.builder(rolloverAlias)) - .settings( - settings(Version.CURRENT) - .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias) - .put(LIFECYCLE_ROLLOVER_SKIP_ROLLED, false) - ) - .putRolloverInfo(new RolloverInfo(rolloverAlias, - Collections.singletonList(new MaxSizeCondition(new ByteSizeValue(2L))), - System.currentTimeMillis()) - ) - .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); - - WaitForRolloverReadyStep step = createRandomInstance(); - IndicesAdminClient indicesClient = indicesAdminClientMock(); - - step.evaluateCondition(indexMetaData, new AsyncWaitStep.Listener() { - - @Override - public void onResponse(boolean complete, ToXContentObject informationContext) { + assertThat(complete, is(true)); } @Override @@ -499,4 +460,12 @@ public void onFailure(Exception e) { "%s [%s] does not point to index [%s]", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias, indexMetaData.getIndex().getName()))); } + + private IndicesAdminClient indicesAdminClientMock() { + AdminClient adminClient = Mockito.mock(AdminClient.class); + IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); + Mockito.when(client.admin()).thenReturn(adminClient); + Mockito.when(adminClient.indices()).thenReturn(indicesClient); + return indicesClient; + } } From 837f98a22adfcfc20f35fe405857490e6b5b210f Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 13:24:13 +0100 Subject: [PATCH 5/8] RolloverStep checks for already rolled index --- .../xpack/core/ilm/RolloverStep.java | 7 ++++ .../xpack/core/ilm/RolloverStepTests.java | 37 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/RolloverStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/RolloverStep.java index a7c57324964bd..90b9d15f21b85 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/RolloverStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/RolloverStep.java @@ -49,6 +49,13 @@ public void performAction(IndexMetaData indexMetaData, ClusterState currentClust return; } + if (indexMetaData.getRolloverInfos().get(rolloverAlias) != null) { + logger.info("index [{}] was already rolled over for alias [{}], not attempting to roll over again", + indexMetaData.getIndex().getName(), rolloverAlias); + listener.onResponse(true); + return; + } + if (indexMetaData.getAliases().containsKey(rolloverAlias) == false) { listener.onFailure(new IllegalArgumentException(String.format(Locale.ROOT, "%s [%s] does not point to index [%s]", RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias, diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/RolloverStepTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/RolloverStepTests.java index 5c7c4ce2ce5b4..cb8e09ab462f4 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/RolloverStepTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/RolloverStepTests.java @@ -8,6 +8,8 @@ import org.apache.lucene.util.SetOnce; import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.rollover.MaxSizeCondition; +import org.elasticsearch.action.admin.indices.rollover.RolloverInfo; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverResponse; import org.elasticsearch.client.AdminClient; @@ -15,6 +17,7 @@ import org.elasticsearch.client.IndicesAdminClient; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.xpack.core.ilm.Step.StepKey; import org.junit.Before; import org.mockito.Mockito; @@ -25,6 +28,7 @@ import java.util.Locale; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.core.Is.is; public class RolloverStepTests extends AbstractStepTestCase { @@ -154,6 +158,39 @@ public void onFailure(Exception e) { assertEquals(true, actionCompleted.get()); } + public void testPerformActionSkipsRolloverForAlreadyRolledIndex() { + String rolloverAlias = randomAlphaOfLength(5); + IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) + .putAlias(AliasMetaData.builder(rolloverAlias)) + .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, rolloverAlias)) + .putRolloverInfo(new RolloverInfo(rolloverAlias, + Collections.singletonList(new MaxSizeCondition(new ByteSizeValue(2L))), + System.currentTimeMillis()) + ) + .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); + + RolloverStep step = createRandomInstance(); + AdminClient adminClient = Mockito.mock(AdminClient.class); + IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); + Mockito.when(client.admin()).thenReturn(adminClient); + Mockito.when(adminClient.indices()).thenReturn(indicesClient); + + step.performAction(indexMetaData, null, null, new AsyncActionStep.Listener() { + + @Override + public void onResponse(boolean complete) { + assertThat(complete, is(true)); + } + + @Override + public void onFailure(Exception e) { + throw new AssertionError("Unexpected method call", e); + } + }); + + Mockito.verify(indicesClient, Mockito.never()).rolloverIndex(Mockito.any(), Mockito.any()); + } + public void testPerformActionFailure() { String alias = randomAlphaOfLength(5); IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) From ffaa20d4e734264e71ed32d274ca96452a1e06d6 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 13:26:14 +0100 Subject: [PATCH 6/8] Adapt readd policy test to not expect error --- .../xpack/ilm/TimeSeriesLifecycleActionsIT.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java index 6c67d4e550120..08a18522d293a 100644 --- a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java @@ -16,7 +16,6 @@ import org.elasticsearch.client.RestClient; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.component.Lifecycle; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -737,7 +736,6 @@ public void testRemoveAndReaddPolicy() throws Exception { Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) .put(LifecycleSettings.LIFECYCLE_NAME, policy) - .put(LifecycleSettings.LIFECYCLE_ROLLOVER_SKIP_ROLLED, false) .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, "alias")); // Index a document @@ -762,20 +760,6 @@ public void testRemoveAndReaddPolicy() throws Exception { client().performRequest(addPolicyRequest); assertBusy(() -> assertTrue((boolean) explainIndex(originalIndex).getOrDefault("managed", false))); - // Wait for rollover to error - assertBusy(() -> assertThat(getStepKeyForIndex(originalIndex), equalTo(new StepKey("hot", RolloverAction.NAME, ErrorStep.NAME)))); - - // Set indexing complete - Request setIndexingCompleteRequest = new Request("PUT", "/" + originalIndex + "/_settings"); - setIndexingCompleteRequest.setJsonEntity("{\n" + - " \"index.lifecycle.indexing_complete\": true\n" + - "}"); - client().performRequest(setIndexingCompleteRequest); - - // Retry policy - Request retryRequest = new Request("POST", "/" + originalIndex + "/_ilm/retry"); - client().performRequest(retryRequest); - // Wait for everything to be copacetic assertBusy(() -> assertThat(getStepKeyForIndex(originalIndex), equalTo(TerminalPolicyStep.KEY))); } From fabc7bf799d3a27214fc93225f3dc0ade765d437 Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 13:27:26 +0100 Subject: [PATCH 7/8] ILM w rollover on already rolled index integ test --- .../ilm/TimeSeriesLifecycleActionsIT.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java index 08a18522d293a..84e050157cf2e 100644 --- a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java @@ -861,6 +861,79 @@ public void testExplainFilters() throws Exception { }); } + public void testILMRolloverOnManuallyRolledIndex() throws Exception { + String originalIndex = index + "-000001"; + String secondIndex = index + "-000002"; + String thirdIndex = index + "-000003"; + + // Configure ILM to run every second + Request updateLifecylePollSetting = new Request("PUT", "_cluster/settings"); + updateLifecylePollSetting.setJsonEntity("{" + + " \"transient\": {\n" + + "\"indices.lifecycle.poll_interval\" : \"1s\" \n" + + " }\n" + + "}"); + client().performRequest(updateLifecylePollSetting); + + // Set up a policy with rollover + createNewSingletonPolicy("hot", new RolloverAction(null, null, 2L)); + Request createIndexTemplate = new Request("PUT", "_template/rolling_indexes"); + createIndexTemplate.setJsonEntity("{" + + "\"index_patterns\": [\""+ index + "-*\"], \n" + + " \"settings\": {\n" + + " \"number_of_shards\": 1,\n" + + " \"number_of_replicas\": 0,\n" + + " \"index.lifecycle.name\": \"" + policy+ "\", \n" + + " \"index.lifecycle.rollover_alias\": \"alias\"\n" + + " }\n" + + "}"); + client().performRequest(createIndexTemplate); + + createIndexWithSettings( + originalIndex, + Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0), + true + ); + + // Index a document + index(client(), originalIndex, "1", "foo", "bar"); + Request refreshOriginalIndex = new Request("POST", "/" + originalIndex + "/_refresh"); + client().performRequest(refreshOriginalIndex); + + // Manual rollover + Request rolloverRequest = new Request("POST", "/alias/_rollover"); + rolloverRequest.setJsonEntity("{\n" + + " \"conditions\": {\n" + + " \"max_docs\": \"1\"\n" + + " }\n" + + "}" + ); + client().performRequest(rolloverRequest); + assertBusy(() -> assertTrue(indexExists(secondIndex))); + + // Index another document into the original index so the ILM rollover policy condition is met + index(client(), originalIndex, "2", "foo", "bar"); + client().performRequest(refreshOriginalIndex); + + // Wait for the rollover policy to execute + assertBusy(() -> assertThat(getStepKeyForIndex(originalIndex), equalTo(TerminalPolicyStep.KEY))); + + // ILM should manage the second index after attempting (and skipping) rolling the original index + assertBusy(() -> assertTrue((boolean) explainIndex(secondIndex).getOrDefault("managed", true))); + + // index some documents to trigger an ILM rollover + index(client(), "alias", "1", "foo", "bar"); + index(client(), "alias", "2", "foo", "bar"); + index(client(), "alias", "3", "foo", "bar"); + Request refreshSecondIndex = new Request("POST", "/" + secondIndex + "/_refresh"); + client().performRequest(refreshSecondIndex).getStatusLine(); + + // ILM should rollover the second index even though it skipped the first one + assertBusy(() -> assertThat(getStepKeyForIndex(secondIndex), equalTo(TerminalPolicyStep.KEY))); + assertBusy(() -> assertTrue(indexExists(thirdIndex))); + } + private void createFullPolicy(TimeValue hotTime) throws IOException { Map hotActions = new HashMap<>(); hotActions.put(SetPriorityAction.NAME, new SetPriorityAction(100)); From 742f6c2c13f6a196227e44f44cf4bede4ab344ed Mon Sep 17 00:00:00 2001 From: Andrei Dan Date: Fri, 4 Oct 2019 14:15:40 +0100 Subject: [PATCH 8/8] Remove docs for index.lifecycle.rollover.skip_rolled --- docs/reference/settings/ilm-settings.asciidoc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/reference/settings/ilm-settings.asciidoc b/docs/reference/settings/ilm-settings.asciidoc index b7ecd5dbb779e..97ae65d181523 100644 --- a/docs/reference/settings/ilm-settings.asciidoc +++ b/docs/reference/settings/ilm-settings.asciidoc @@ -23,17 +23,6 @@ policy that contains a rollover action. When the index rolls over, the alias is updated to reflect that the index is no longer the write index. For more information about rollover, see <>. -`index.lifecycle.rollover.skip_rolled`:: (Expert Setting) -When configured to `false` {ilm} will attempt to rollover the index, in case -the `rollover` action is configured for a phase, even if it was manually rolled -over since the last {ilm} cycle. -Allowing {ilm} to rollover the index will potentially fail due to -`is_write_index` now being `false` or, if the index was manually rolled under -a different alias than the `rollover_alias`, due to the rollover target index -already existing. -By default {ilm} will detect this situation and skip trying to rollover the -index again. - `indices.lifecycle.poll_interval`:: (<>) How often {ilm} checks for indices that meet policy criteria. Defaults to `10m`.