diff --git a/docs/reference/ilm/actions/ilm-readonly.asciidoc b/docs/reference/ilm/actions/ilm-readonly.asciidoc index fbb5125268783..d7a3e05e25bb8 100644 --- a/docs/reference/ilm/actions/ilm-readonly.asciidoc +++ b/docs/reference/ilm/actions/ilm-readonly.asciidoc @@ -2,10 +2,13 @@ [[ilm-readonly]] === Read only -Phases allowed: warm. +Phases allowed: hot, warm. Makes the index <>. +To use the `readonly` action in the `hot` phase, the `rollover` action *must* be present. +If no rollover action is configured, {ilm-init} will reject the policy. + [[ilm-read-only-options]] ==== Options diff --git a/docs/reference/ilm/ilm-index-lifecycle.asciidoc b/docs/reference/ilm/ilm-index-lifecycle.asciidoc index a43d979a2ec76..3357dd367aaca 100644 --- a/docs/reference/ilm/ilm-index-lifecycle.asciidoc +++ b/docs/reference/ilm/ilm-index-lifecycle.asciidoc @@ -78,6 +78,7 @@ the rollover criteria, it could be 20 minutes before the rollover is complete. - <> - <> - <> + - <> - <> - <> * Warm diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java index 492ede06cbd43..d3bf38892444e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleType.java @@ -40,7 +40,7 @@ public class TimeseriesLifecycleType implements LifecycleType { static final String DELETE_PHASE = "delete"; static final List VALID_PHASES = Arrays.asList(HOT_PHASE, WARM_PHASE, COLD_PHASE, DELETE_PHASE); static final List ORDERED_VALID_HOT_ACTIONS = Arrays.asList(SetPriorityAction.NAME, UnfollowAction.NAME, RolloverAction.NAME, - ShrinkAction.NAME, ForceMergeAction.NAME); + ReadOnlyAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME); static final List ORDERED_VALID_WARM_ACTIONS = Arrays.asList(SetPriorityAction.NAME, UnfollowAction.NAME, ReadOnlyAction.NAME, AllocateAction.NAME, MigrateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME); static final List ORDERED_VALID_COLD_ACTIONS = Arrays.asList(SetPriorityAction.NAME, UnfollowAction.NAME, AllocateAction.NAME, @@ -56,7 +56,8 @@ public class TimeseriesLifecycleType implements LifecycleType { COLD_PHASE, VALID_COLD_ACTIONS, DELETE_PHASE, VALID_DELETE_ACTIONS); - static final Set HOT_ACTIONS_THAT_REQUIRE_ROLLOVER = Sets.newHashSet(ShrinkAction.NAME, ForceMergeAction.NAME); + static final Set HOT_ACTIONS_THAT_REQUIRE_ROLLOVER = Sets.newHashSet(ReadOnlyAction.NAME, ShrinkAction.NAME, + ForceMergeAction.NAME); private TimeseriesLifecycleType() { } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java index dfe2666ba4172..ee51129c05964 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java @@ -406,7 +406,6 @@ public void testGetNextActionName() { assertInvalidAction("hot", "foo", new String[] { RolloverAction.NAME }); assertInvalidAction("hot", AllocateAction.NAME, new String[] { RolloverAction.NAME }); assertInvalidAction("hot", DeleteAction.NAME, new String[] { RolloverAction.NAME }); - assertInvalidAction("hot", ReadOnlyAction.NAME, new String[] { RolloverAction.NAME }); // Warm Phase assertNextActionName("warm", SetPriorityAction.NAME, UnfollowAction.NAME, diff --git a/x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java index 0a9c1aee4f13f..faabc7281f4d5 100644 --- a/x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesLifecycleActionsIT.java @@ -433,7 +433,8 @@ public void testDeleteDuringSnapshot() throws Exception { } public void testReadOnly() throws Exception { - createIndexWithSettings(client(), index, alias, Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1) + createIndexWithSettings(client(), index, alias, Settings.builder() + .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1) .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)); createNewSingletonPolicy(client(), policy, "warm", new ReadOnlyAction()); updatePolicy(index, policy); @@ -444,6 +445,35 @@ public void testReadOnly() throws Exception { }); } + public void testReadOnlyInTheHotPhase() throws Exception { + String originalIndex = index + "-000001"; + + // add a policy + Map hotActions = Map.of( + RolloverAction.NAME, new RolloverAction(null, null, 1L), + ReadOnlyAction.NAME, new ReadOnlyAction()); + Map phases = Map.of( + "hot", new Phase("hot", TimeValue.ZERO, hotActions)); + LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, phases); + Request createPolicyRequest = new Request("PUT", "_ilm/policy/" + policy); + createPolicyRequest.setJsonEntity("{ \"policy\":" + Strings.toString(lifecyclePolicy) + "}"); + client().performRequest(createPolicyRequest); + + // then create the index and index a document to trigger rollover + createIndexWithSettings(client(), originalIndex, alias, Settings.builder() + .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) + .put("index.lifecycle.rollover_alias", alias) + .put("index.lifecycle.name", policy)); + index(client(), originalIndex, "_id", "foo", "bar"); + + assertBusy(() -> { + Map settings = getOnlyIndexSettings(client(), originalIndex); + assertThat(getStepKeyForIndex(client(), originalIndex), equalTo(PhaseCompleteStep.finalStep("hot").getKey())); + assertThat(settings.get(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey()), equalTo("true")); + }); + } + public void forceMergeActionWithCodec(String codec) throws Exception { createIndexWithSettings(client(), index, alias, Settings.builder().put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1) .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)); diff --git a/x-pack/plugin/ilm/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/ilm/10_basic.yml b/x-pack/plugin/ilm/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/ilm/10_basic.yml index fb985d27be8d8..2adc223af13cb 100644 --- a/x-pack/plugin/ilm/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/ilm/10_basic.yml +++ b/x-pack/plugin/ilm/qa/rest/src/yamlRestTest/resources/rest-api-spec/test/ilm/10_basic.yml @@ -258,3 +258,21 @@ setup: } } } + + - do: + catch: bad_request + ilm.put_lifecycle: + policy: "my_invalid_lifecycle" + body: | + { + "policy": { + "phases": { + "hot": { + "min_age": "0s", + "actions": { + "readonly": {} + } + } + } + } + }