소스 검색

Allow writes to ILM shrink action target index (#107121)

The source index of a shrink action is made read-only to perform the shrink. During shrink, settings are copied from source index to target index, causing the target index to also be read-only. This change adds a shrink policy argument making the target index writable after shrinking. The default is to keep the read-only setting to preserve current behavior.

closes #106599
Parker Timmins 1 년 전
부모
커밋
3288f46fd9
20개의 변경된 파일208개의 추가작업 그리고 64개의 파일을 삭제
  1. 6 0
      docs/changelog/107121.yaml
  2. 5 1
      docs/reference/ilm/actions/ilm-shrink.asciidoc
  3. 1 0
      docs/reference/index-modules/blocks.asciidoc
  4. 1 0
      server/src/main/java/org/elasticsearch/TransportVersions.java
  5. 41 10
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java
  6. 53 23
      x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java
  7. 4 4
      x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java
  8. 2 2
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/MigrateToDataTiersIT.java
  9. 1 1
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/TimeSeriesRestDriver.java
  10. 1 1
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/ExplainLifecycleIT.java
  11. 1 1
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesDataStreamsIT.java
  12. 1 1
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeseriesMoveToStepIT.java
  13. 2 2
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/actions/SearchableSnapshotActionIT.java
  14. 80 9
      x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/actions/ShrinkActionIT.java
  15. 1 1
      x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java
  16. 1 1
      x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java
  17. 1 1
      x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java
  18. 3 3
      x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/cluster/metadata/MetadataMigrateToDataTiersRoutingServiceTests.java
  19. 1 1
      x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java
  20. 2 2
      x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistryTests.java

+ 6 - 0
docs/changelog/107121.yaml

@@ -0,0 +1,6 @@
+pr: 107121
+summary: Add a flag to re-enable writes on the final index after an ILM shrink action.
+area: ILM+SLM
+type: enhancement
+issues:
+  - 106599

+ 5 - 1
docs/reference/ilm/actions/ilm-shrink.asciidoc

@@ -4,7 +4,7 @@
 
 Phases allowed: hot, warm.
 
-Sets a source index to <<index-blocks-read-only,read-only>> and shrinks it into
+<<index-blocks-write,Blocks writes>> on a source index and shrinks it into
 a new index with fewer primary shards. The name of the resulting index is
 `shrink-<random-uuid>-<original-index-name>`. This action corresponds to the
 <<indices-shrink-index,shrink API>>.
@@ -50,6 +50,10 @@ with totaling 1000gb, then the target index will have 20 primary shards; if the
 with totaling 4000gb, then the target index will still have 60 primary shards. This parameter conflicts
 with `number_of_shards` in the `settings`, only one of them may be set.
 
+`allow_write_after_shrink`::
+(Optional, boolean)
+If true, the shrunken index is made writable by removing the <<index-blocks-write,write block>>. Defaults to false.
+
 
 [[ilm-shrink-ex]]
 ==== Example

+ 1 - 0
docs/reference/index-modules/blocks.asciidoc

@@ -49,6 +49,7 @@ for help with resolving watermark issues.
 
     Set to `true` to disable read operations against the index.
 
+[[index-blocks-write]]
 `index.blocks.write`::
 
     Set to `true` to disable data write operations against the index. Unlike

+ 1 - 0
server/src/main/java/org/elasticsearch/TransportVersions.java

@@ -173,6 +173,7 @@ public class TransportVersions {
     public static final TransportVersion HIGHLIGHTERS_TAGS_ON_FIELD_LEVEL = def(8_632_00_0);
     public static final TransportVersion TRACK_FLUSH_TIME_EXCLUDING_WAITING_ON_LOCKS = def(8_633_00_0);
     public static final TransportVersion ML_INFERENCE_AZURE_OPENAI_EMBEDDINGS = def(8_634_00_0);
+    public static final TransportVersion ILM_SHRINK_ENABLE_WRITE = def(8_635_00_0);
 
     /*
      * STOP! READ THIS FIRST! No, really,

+ 41 - 10
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/ShrinkAction.java

@@ -8,13 +8,16 @@ package org.elasticsearch.xpack.core.ilm;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.elasticsearch.TransportVersions;
 import org.elasticsearch.action.admin.indices.shrink.ResizeNumberOfShardsCalculator;
 import org.elasticsearch.action.admin.indices.stats.IndexShardStats;
 import org.elasticsearch.client.internal.Client;
 import org.elasticsearch.cluster.metadata.IndexAbstraction;
+import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.core.Nullable;
 import org.elasticsearch.xcontent.ConstructingObjectParser;
@@ -26,9 +29,10 @@ import org.elasticsearch.xpack.core.ilm.Step.StepKey;
 
 import java.io.IOException;
 import java.time.Instant;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.elasticsearch.xpack.core.ilm.ShrinkIndexNameSupplier.SHRUNKEN_INDEX_PREFIX;
 
@@ -41,12 +45,13 @@ public class ShrinkAction implements LifecycleAction {
     public static final String NAME = "shrink";
     public static final ParseField NUMBER_OF_SHARDS_FIELD = new ParseField("number_of_shards");
     public static final ParseField MAX_PRIMARY_SHARD_SIZE = new ParseField("max_primary_shard_size");
+    public static final ParseField ALLOW_WRITE_AFTER_SHRINK = new ParseField("allow_write_after_shrink");
     public static final String CONDITIONAL_SKIP_SHRINK_STEP = BranchingStep.NAME + "-check-prerequisites";
     public static final String CONDITIONAL_DATASTREAM_CHECK_KEY = BranchingStep.NAME + "-on-datastream-check";
 
     private static final ConstructingObjectParser<ShrinkAction, Void> PARSER = new ConstructingObjectParser<>(
         NAME,
-        a -> new ShrinkAction((Integer) a[0], (ByteSizeValue) a[1])
+        a -> new ShrinkAction((Integer) a[0], (ByteSizeValue) a[1], (a[2] != null && (Boolean) a[2]))
     );
 
     static {
@@ -57,16 +62,22 @@ public class ShrinkAction implements LifecycleAction {
             MAX_PRIMARY_SHARD_SIZE,
             ObjectParser.ValueType.STRING
         );
+        PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), ALLOW_WRITE_AFTER_SHRINK);
     }
 
+    public static final Settings CLEAR_WRITE_BLOCK_SETTINGS = Settings.builder()
+        .put(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey(), (String) null)
+        .build();
+
     private Integer numberOfShards;
     private ByteSizeValue maxPrimaryShardSize;
+    private boolean allowWriteAfterShrink;
 
     public static ShrinkAction parse(XContentParser parser) throws IOException {
         return PARSER.parse(parser, null);
     }
 
-    public ShrinkAction(@Nullable Integer numberOfShards, @Nullable ByteSizeValue maxPrimaryShardSize) {
+    public ShrinkAction(@Nullable Integer numberOfShards, @Nullable ByteSizeValue maxPrimaryShardSize, boolean allowWriteAfterShrink) {
         if (numberOfShards != null && maxPrimaryShardSize != null) {
             throw new IllegalArgumentException("Cannot set both [number_of_shards] and [max_primary_shard_size]");
         }
@@ -84,6 +95,7 @@ public class ShrinkAction implements LifecycleAction {
             }
             this.numberOfShards = numberOfShards;
         }
+        this.allowWriteAfterShrink = allowWriteAfterShrink;
     }
 
     public ShrinkAction(StreamInput in) throws IOException {
@@ -94,6 +106,7 @@ public class ShrinkAction implements LifecycleAction {
             this.numberOfShards = null;
             this.maxPrimaryShardSize = ByteSizeValue.readFrom(in);
         }
+        this.allowWriteAfterShrink = in.getTransportVersion().onOrAfter(TransportVersions.ILM_SHRINK_ENABLE_WRITE) && in.readBoolean();
     }
 
     public Integer getNumberOfShards() {
@@ -104,6 +117,10 @@ public class ShrinkAction implements LifecycleAction {
         return maxPrimaryShardSize;
     }
 
+    public boolean getAllowWriteAfterShrink() {
+        return allowWriteAfterShrink;
+    }
+
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         boolean hasNumberOfShards = numberOfShards != null;
@@ -113,6 +130,9 @@ public class ShrinkAction implements LifecycleAction {
         } else {
             maxPrimaryShardSize.writeTo(out);
         }
+        if (out.getTransportVersion().onOrAfter(TransportVersions.ILM_SHRINK_ENABLE_WRITE)) {
+            out.writeBoolean(this.allowWriteAfterShrink);
+        }
     }
 
     @Override
@@ -129,6 +149,7 @@ public class ShrinkAction implements LifecycleAction {
         if (maxPrimaryShardSize != null) {
             builder.field(MAX_PRIMARY_SHARD_SIZE.getPreferredName(), maxPrimaryShardSize);
         }
+        builder.field(ALLOW_WRITE_AFTER_SHRINK.getPreferredName(), allowWriteAfterShrink);
         builder.endObject();
         return builder;
     }
@@ -158,11 +179,13 @@ public class ShrinkAction implements LifecycleAction {
         StepKey isShrunkIndexKey = new StepKey(phase, NAME, ShrunkenIndexCheckStep.NAME);
         StepKey replaceDataStreamIndexKey = new StepKey(phase, NAME, ReplaceDataStreamBackingIndexStep.NAME);
         StepKey deleteIndexKey = new StepKey(phase, NAME, DeleteStep.NAME);
+        StepKey allowWriteKey = new StepKey(phase, NAME, UpdateSettingsStep.NAME);
+        StepKey lastOrNextStep = allowWriteAfterShrink ? allowWriteKey : nextStepKey;
 
         AsyncBranchingStep conditionalSkipShrinkStep = new AsyncBranchingStep(
             preShrinkBranchingKey,
             checkNotWriteIndex,
-            nextStepKey,
+            lastOrNextStep,
             (indexMetadata, clusterState, listener) -> {
                 if (indexMetadata.getSettings().get(LifecycleSettings.SNAPSHOT_INDEX_NAME) != null) {
                     logger.warn(
@@ -242,7 +265,6 @@ public class ShrinkAction implements LifecycleAction {
             setSingleNodeKey
         );
         ShrinkStep shrink = new ShrinkStep(shrinkKey, enoughShardsKey, client, numberOfShards, maxPrimaryShardSize);
-
         // wait until the shrunk index is recovered. we again wait until the configured threshold is breached and if the shrunk index has
         // not successfully recovered until then, we rewind to the "cleanup-shrink-index" step to delete this unsuccessful shrunk index
         // and retry the operation by generating a new shrink index name and attempting to shrink again
@@ -278,8 +300,12 @@ public class ShrinkAction implements LifecycleAction {
             ShrinkIndexNameSupplier::getShrinkIndexName
         );
         DeleteStep deleteSourceIndexStep = new DeleteStep(deleteIndexKey, isShrunkIndexKey, client);
-        ShrunkenIndexCheckStep waitOnShrinkTakeover = new ShrunkenIndexCheckStep(isShrunkIndexKey, nextStepKey);
-        return Arrays.asList(
+        ShrunkenIndexCheckStep waitOnShrinkTakeover = new ShrunkenIndexCheckStep(isShrunkIndexKey, lastOrNextStep);
+        UpdateSettingsStep allowWriteAfterShrinkStep = allowWriteAfterShrink
+            ? new UpdateSettingsStep(allowWriteKey, nextStepKey, client, CLEAR_WRITE_BLOCK_SETTINGS)
+            : null;
+
+        Stream<Step> steps = Stream.of(
             conditionalSkipShrinkStep,
             checkNotWriteIndexStep,
             waitForNoFollowersStep,
@@ -297,8 +323,11 @@ public class ShrinkAction implements LifecycleAction {
             aliasSwapAndDelete,
             waitOnShrinkTakeover,
             replaceDataStreamBackingIndex,
-            deleteSourceIndexStep
+            deleteSourceIndexStep,
+            allowWriteAfterShrinkStep
         );
+
+        return steps.filter(Objects::nonNull).collect(Collectors.toList());
     }
 
     @Override
@@ -306,12 +335,14 @@ public class ShrinkAction implements LifecycleAction {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         ShrinkAction that = (ShrinkAction) o;
-        return Objects.equals(numberOfShards, that.numberOfShards) && Objects.equals(maxPrimaryShardSize, that.maxPrimaryShardSize);
+        return Objects.equals(numberOfShards, that.numberOfShards)
+            && Objects.equals(maxPrimaryShardSize, that.maxPrimaryShardSize)
+            && Objects.equals(allowWriteAfterShrink, that.allowWriteAfterShrink);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(numberOfShards, maxPrimaryShardSize);
+        return Objects.hash(numberOfShards, maxPrimaryShardSize, allowWriteAfterShrink);
     }
 
     @Override

+ 53 - 23
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/ShrinkActionTests.java

@@ -66,19 +66,30 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
 
     static ShrinkAction randomInstance() {
         if (randomBoolean()) {
-            return new ShrinkAction(randomIntBetween(1, 100), null);
+            return new ShrinkAction(randomIntBetween(1, 100), null, randomBoolean());
         } else {
-            return new ShrinkAction(null, ByteSizeValue.ofBytes(randomIntBetween(1, 100)));
+            return new ShrinkAction(null, ByteSizeValue.ofBytes(randomIntBetween(1, 100)), randomBoolean());
         }
     }
 
     @Override
     protected ShrinkAction mutateInstance(ShrinkAction action) {
-        if (action.getNumberOfShards() != null) {
-            return new ShrinkAction(action.getNumberOfShards() + randomIntBetween(1, 2), null);
-        } else {
-            return new ShrinkAction(null, ByteSizeValue.ofBytes(action.getMaxPrimaryShardSize().getBytes() + 1));
+        Integer numberOfShards = action.getNumberOfShards();
+        ByteSizeValue maxPrimaryShardSize = action.getMaxPrimaryShardSize();
+        boolean allowWriteAfterShrink = action.getAllowWriteAfterShrink();
+
+        switch (randomInt(2)) {
+            case 0 -> {
+                numberOfShards = randomValueOtherThan(numberOfShards, () -> randomIntBetween(1, 100));
+                maxPrimaryShardSize = null;
+            }
+            case 1 -> {
+                maxPrimaryShardSize = randomValueOtherThan(maxPrimaryShardSize, () -> ByteSizeValue.ofBytes(randomIntBetween(1, 100)));
+                numberOfShards = null;
+            }
+            case 2 -> allowWriteAfterShrink = allowWriteAfterShrink == false;
         }
+        return new ShrinkAction(numberOfShards, maxPrimaryShardSize, allowWriteAfterShrink);
     }
 
     @Override
@@ -87,24 +98,27 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
     }
 
     public void testNonPositiveShardNumber() {
-        Exception e = expectThrows(Exception.class, () -> new ShrinkAction(randomIntBetween(-100, 0), null));
+        Exception e = expectThrows(Exception.class, () -> new ShrinkAction(randomIntBetween(-100, 0), null, randomBoolean()));
         assertThat(e.getMessage(), equalTo("[number_of_shards] must be greater than 0"));
     }
 
     public void testMaxPrimaryShardSize() {
         ByteSizeValue maxPrimaryShardSize1 = ByteSizeValue.ofBytes(10);
-        Exception e1 = expectThrows(Exception.class, () -> new ShrinkAction(randomIntBetween(1, 100), maxPrimaryShardSize1));
+        Exception e1 = expectThrows(
+            Exception.class,
+            () -> new ShrinkAction(randomIntBetween(1, 100), maxPrimaryShardSize1, randomBoolean())
+        );
         assertThat(e1.getMessage(), equalTo("Cannot set both [number_of_shards] and [max_primary_shard_size]"));
 
         ByteSizeValue maxPrimaryShardSize2 = ByteSizeValue.ZERO;
-        Exception e2 = expectThrows(Exception.class, () -> new ShrinkAction(null, maxPrimaryShardSize2));
+        Exception e2 = expectThrows(Exception.class, () -> new ShrinkAction(null, maxPrimaryShardSize2, randomBoolean()));
         assertThat(e2.getMessage(), equalTo("[max_primary_shard_size] must be greater than 0"));
     }
 
     public void testPerformActionWithSkipBecauseOfShardNumber() throws InterruptedException {
         String lifecycleName = randomAlphaOfLengthBetween(4, 10);
         int numberOfShards = randomIntBetween(1, 10);
-        ShrinkAction action = new ShrinkAction(numberOfShards, null);
+        ShrinkAction action = new ShrinkAction(numberOfShards, null, randomBoolean());
         StepKey nextStepKey = new StepKey(
             randomAlphaOfLengthBetween(1, 10),
             randomAlphaOfLengthBetween(1, 10),
@@ -121,7 +135,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
     public void testPerformActionWithSkipBecauseOfSearchableSnapshot() throws InterruptedException {
         String lifecycleName = randomAlphaOfLengthBetween(4, 10);
         int numberOfShards = randomIntBetween(1, 10);
-        ShrinkAction action = new ShrinkAction(numberOfShards, null);
+        ShrinkAction action = new ShrinkAction(numberOfShards, null, randomBoolean());
         StepKey nextStepKey = new StepKey(
             randomAlphaOfLengthBetween(1, 10),
             randomAlphaOfLengthBetween(1, 10),
@@ -143,7 +157,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
         int divisor = randomFrom(2, 3, 6);
         int expectedFinalShards = numShards / divisor;
         String lifecycleName = randomAlphaOfLengthBetween(4, 10);
-        ShrinkAction action = new ShrinkAction(expectedFinalShards, null);
+        ShrinkAction action = new ShrinkAction(expectedFinalShards, null, randomBoolean());
         StepKey nextStepKey = new StepKey(
             randomAlphaOfLengthBetween(1, 10),
             randomAlphaOfLengthBetween(1, 10),
@@ -160,7 +174,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
     public void testFailureIsPropagated() throws InterruptedException {
         String lifecycleName = randomAlphaOfLengthBetween(4, 10);
         int numberOfShards = randomIntBetween(1, 10);
-        ShrinkAction action = new ShrinkAction(numberOfShards, null);
+        ShrinkAction action = new ShrinkAction(numberOfShards, null, randomBoolean());
         StepKey nextStepKey = new StepKey(
             randomAlphaOfLengthBetween(1, 10),
             randomAlphaOfLengthBetween(1, 10),
@@ -185,7 +199,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
     ) throws InterruptedException {
         String phase = randomAlphaOfLengthBetween(1, 10);
         List<Step> steps = action.toSteps(client, phase, nextStepKey);
-        AsyncBranchingStep step = ((AsyncBranchingStep) steps.get(0));
+        AsyncBranchingStep branchStep = ((AsyncBranchingStep) steps.get(0));
 
         LifecyclePolicy policy = new LifecyclePolicy(
             lifecycleName,
@@ -211,11 +225,11 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
                         indexMetadataBuilder.putCustom(
                             LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY,
                             LifecycleExecutionState.builder()
-                                .setPhase(step.getKey().phase())
+                                .setPhase(branchStep.getKey().phase())
                                 .setPhaseTime(0L)
-                                .setAction(step.getKey().action())
+                                .setAction(branchStep.getKey().action())
                                 .setActionTime(0L)
-                                .setStep(step.getKey().name())
+                                .setStep(branchStep.getKey().name())
                                 .setStepTime(0L)
                                 .build()
                                 .asMap()
@@ -226,7 +240,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
         setUpIndicesStatsRequestMock(indexName, withError);
         CountDownLatch countDownLatch = new CountDownLatch(1);
         AtomicBoolean failurePropagated = new AtomicBoolean(false);
-        step.performAction(state.metadata().index(indexName), state, null, new ActionListener<>() {
+        branchStep.performAction(state.metadata().index(indexName), state, null, new ActionListener<>() {
             @Override
             public void onResponse(Void unused) {
                 countDownLatch.countDown();
@@ -244,12 +258,18 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
             }
         });
         assertTrue(countDownLatch.await(5, TimeUnit.SECONDS));
+
         if (withError) {
             assertTrue(failurePropagated.get());
         } else if (shouldSkip) {
-            assertThat(step.getNextStepKey(), equalTo(nextStepKey));
+            if (action.getAllowWriteAfterShrink()) {
+                Step lastStep = steps.get(steps.size() - 1);
+                assertThat(branchStep.getNextStepKey(), equalTo(lastStep.getKey()));
+            } else {
+                assertThat(branchStep.getNextStepKey(), equalTo(nextStepKey));
+            }
         } else {
-            assertThat(step.getNextStepKey(), equalTo(steps.get(1).getKey()));
+            assertThat(branchStep.getNextStepKey(), equalTo(steps.get(1).getKey()));
         }
     }
 
@@ -262,7 +282,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
             randomAlphaOfLengthBetween(1, 10)
         );
         List<Step> steps = action.toSteps(client, phase, nextStepKey);
-        assertThat(steps.size(), equalTo(18));
+        assertThat(steps.size(), equalTo(action.getAllowWriteAfterShrink() ? 19 : 18));
         StepKey expectedFirstKey = new StepKey(phase, ShrinkAction.NAME, ShrinkAction.CONDITIONAL_SKIP_SHRINK_STEP);
         StepKey expectedSecondKey = new StepKey(phase, ShrinkAction.NAME, CheckNotDataStreamWriteIndexStep.NAME);
         StepKey expectedThirdKey = new StepKey(phase, ShrinkAction.NAME, WaitForNoFollowersStep.NAME);
@@ -281,12 +301,16 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
         StepKey expectedSixteenKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME);
         StepKey expectedSeventeenKey = new StepKey(phase, ShrinkAction.NAME, ReplaceDataStreamBackingIndexStep.NAME);
         StepKey expectedEighteenKey = new StepKey(phase, ShrinkAction.NAME, DeleteStep.NAME);
+        StepKey expectedNineteenthKey = new StepKey(phase, ShrinkAction.NAME, UpdateSettingsStep.NAME);
 
         assertTrue(steps.get(0) instanceof AsyncBranchingStep);
         assertThat(steps.get(0).getKey(), equalTo(expectedFirstKey));
         expectThrows(IllegalStateException.class, () -> steps.get(0).getNextStepKey());
         assertThat(((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnFalse(), equalTo(expectedSecondKey));
-        assertThat(((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnTrue(), equalTo(nextStepKey));
+        assertThat(
+            ((AsyncBranchingStep) steps.get(0)).getNextStepKeyOnTrue(),
+            equalTo(action.getAllowWriteAfterShrink() ? expectedNineteenthKey : nextStepKey)
+        );
 
         assertTrue(steps.get(1) instanceof CheckNotDataStreamWriteIndexStep);
         assertThat(steps.get(1).getKey(), equalTo(expectedSecondKey));
@@ -357,7 +381,7 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
 
         assertTrue(steps.get(15) instanceof ShrunkenIndexCheckStep);
         assertThat(steps.get(15).getKey(), equalTo(expectedSixteenKey));
-        assertThat(steps.get(15).getNextStepKey(), equalTo(nextStepKey));
+        assertThat(steps.get(15).getNextStepKey(), equalTo(action.getAllowWriteAfterShrink() ? expectedNineteenthKey : nextStepKey));
 
         assertTrue(steps.get(16) instanceof ReplaceDataStreamBackingIndexStep);
         assertThat(steps.get(16).getKey(), equalTo(expectedSeventeenKey));
@@ -366,6 +390,12 @@ public class ShrinkActionTests extends AbstractActionTestCase<ShrinkAction> {
         assertTrue(steps.get(17) instanceof DeleteStep);
         assertThat(steps.get(17).getKey(), equalTo(expectedEighteenKey));
         assertThat(steps.get(17).getNextStepKey(), equalTo(expectedSixteenKey));
+
+        if (action.getAllowWriteAfterShrink()) {
+            assertTrue(steps.get(18) instanceof UpdateSettingsStep);
+            assertThat(steps.get(18).getKey(), equalTo(expectedNineteenthKey));
+            assertThat(steps.get(18).getNextStepKey(), equalTo(nextStepKey));
+        }
     }
 
     private void setUpIndicesStatsRequestMock(String index, boolean withError) {

+ 4 - 4
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/TimeseriesLifecycleTypeTests.java

@@ -74,7 +74,7 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase {
         null,
         null
     );
-    private static final ShrinkAction TEST_SHRINK_ACTION = new ShrinkAction(1, null);
+    private static final ShrinkAction TEST_SHRINK_ACTION = new ShrinkAction(1, null, false);
     private static final ReadOnlyAction TEST_READ_ONLY_ACTION = new ReadOnlyAction();
     private static final SetPriorityAction TEST_PRIORITY_ACTION = new SetPriorityAction(0);
 
@@ -261,7 +261,7 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase {
     public void testValidateActionsFollowingSearchableSnapshot() {
         {
             Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(SearchableSnapshotAction.NAME, new SearchableSnapshotAction("repo")));
-            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null)));
+            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null, false)));
             Phase coldPhase = new Phase("cold", TimeValue.ZERO, Map.of(FreezeAction.NAME, FreezeAction.INSTANCE));
             IllegalArgumentException e = expectThrows(
                 IllegalArgumentException.class,
@@ -277,7 +277,7 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase {
         }
 
         {
-            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null)));
+            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null, false)));
             Phase coldPhase = new Phase(
                 "cold",
                 TimeValue.ZERO,
@@ -299,7 +299,7 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase {
 
         {
             Phase hotPhase = new Phase("hot", TimeValue.ZERO, Map.of(SearchableSnapshotAction.NAME, new SearchableSnapshotAction("repo")));
-            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null)));
+            Phase warmPhase = new Phase("warm", TimeValue.ZERO, Map.of(ShrinkAction.NAME, new ShrinkAction(1, null, false)));
             Phase coldPhase = new Phase(
                 "cold",
                 TimeValue.ZERO,

+ 2 - 2
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/MigrateToDataTiersIT.java

@@ -102,7 +102,7 @@ public class MigrateToDataTiersIT extends ESRestTestCase {
         warmActions.put(SetPriorityAction.NAME, new SetPriorityAction(50));
         warmActions.put(ForceMergeAction.NAME, new ForceMergeAction(1, null));
         warmActions.put(AllocateAction.NAME, new AllocateAction(null, null, singletonMap("data", "warm"), null, null));
-        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null));
+        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null, false));
         Map<String, LifecycleAction> coldActions = new HashMap<>();
         coldActions.put(SetPriorityAction.NAME, new SetPriorityAction(0));
         coldActions.put(AllocateAction.NAME, new AllocateAction(0, null, null, null, singletonMap("data", "cold")));
@@ -378,7 +378,7 @@ public class MigrateToDataTiersIT extends ESRestTestCase {
         warmActions.put(SetPriorityAction.NAME, new SetPriorityAction(50));
         warmActions.put(ForceMergeAction.NAME, new ForceMergeAction(1, null));
         warmActions.put(AllocateAction.NAME, new AllocateAction(null, null, singletonMap("data", "warm"), null, null));
-        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null));
+        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null, false));
         Map<String, LifecycleAction> coldActions = new HashMap<>();
         coldActions.put(SetPriorityAction.NAME, new SetPriorityAction(0));
         coldActions.put(AllocateAction.NAME, new AllocateAction(0, null, null, null, singletonMap("data", "cold")));

+ 1 - 1
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/TimeSeriesRestDriver.java

@@ -207,7 +207,7 @@ public final class TimeSeriesRestDriver {
                 null
             )
         );
-        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null));
+        warmActions.put(ShrinkAction.NAME, new ShrinkAction(1, null, false));
         Map<String, LifecycleAction> coldActions = new HashMap<>();
         coldActions.put(SetPriorityAction.NAME, new SetPriorityAction(0));
         coldActions.put(

+ 1 - 1
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/ExplainLifecycleIT.java

@@ -76,7 +76,7 @@ public class ExplainLifecycleIT extends ESRestTestCase {
         {
             // Create a "shrink-only-policy"
             Map<String, LifecycleAction> warmActions = new HashMap<>();
-            warmActions.put(ShrinkAction.NAME, new ShrinkAction(17, null));
+            warmActions.put(ShrinkAction.NAME, new ShrinkAction(17, null, false));
             Map<String, Phase> phases = new HashMap<>();
             phases.put("warm", new Phase("warm", TimeValue.ZERO, warmActions));
             LifecyclePolicy lifecyclePolicy = new LifecyclePolicy("shrink-only-policy", phases);

+ 1 - 1
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeSeriesDataStreamsIT.java

@@ -122,7 +122,7 @@ public class TimeSeriesDataStreamsIT extends ESRestTestCase {
 
     @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/70595")
     public void testShrinkActionInPolicyWithoutHotPhase() throws Exception {
-        createNewSingletonPolicy(client(), policyName, "warm", new ShrinkAction(1, null));
+        createNewSingletonPolicy(client(), policyName, "warm", new ShrinkAction(1, null, false));
         createComposableTemplate(client(), template, dataStream + "*", getTemplate(policyName));
         indexDocument(client(), dataStream, true);
 

+ 1 - 1
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/TimeseriesMoveToStepIT.java

@@ -142,7 +142,7 @@ public class TimeseriesMoveToStepIT extends ESRestTestCase {
     }
 
     public void testMoveToInjectedStep() throws Exception {
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(1, null), TimeValue.timeValueHours(12));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(1, null, false), TimeValue.timeValueHours(12));
 
         createIndexWithSettings(
             client(),

+ 2 - 2
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/actions/SearchableSnapshotActionIT.java

@@ -326,7 +326,7 @@ public class SearchableSnapshotActionIT extends ESRestTestCase {
             new Phase(
                 "warm",
                 TimeValue.ZERO,
-                Map.of(ShrinkAction.NAME, new ShrinkAction(1, null), ForceMergeAction.NAME, new ForceMergeAction(1, null))
+                Map.of(ShrinkAction.NAME, new ShrinkAction(1, null, false), ForceMergeAction.NAME, new ForceMergeAction(1, null))
             ),
             new Phase("cold", TimeValue.ZERO, Map.of(SearchableSnapshotAction.NAME, new SearchableSnapshotAction(snapshotRepo))),
             null,
@@ -416,7 +416,7 @@ public class SearchableSnapshotActionIT extends ESRestTestCase {
             new Phase(
                 "warm",
                 TimeValue.ZERO,
-                Map.of(ShrinkAction.NAME, new ShrinkAction(1, null), ForceMergeAction.NAME, new ForceMergeAction(1, null))
+                Map.of(ShrinkAction.NAME, new ShrinkAction(1, null, false), ForceMergeAction.NAME, new ForceMergeAction(1, null))
             ),
             new Phase("cold", TimeValue.ZERO, Map.of(FreezeAction.NAME, FreezeAction.INSTANCE)),
             null,

+ 80 - 9
x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/ilm/actions/ShrinkActionIT.java

@@ -83,7 +83,7 @@ public class ShrinkActionIT extends ESRestTestCase {
             alias,
             Settings.builder().put(SETTING_NUMBER_OF_SHARDS, numShards).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
         );
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null, false));
         updatePolicy(client(), index, policy);
 
         String shrunkenIndexName = waitAndGetShrinkIndexName(client(), index);
@@ -109,7 +109,7 @@ public class ShrinkActionIT extends ESRestTestCase {
             alias,
             Settings.builder().put(SETTING_NUMBER_OF_SHARDS, numberOfShards).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
         );
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(numberOfShards, null));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(numberOfShards, null, false));
         updatePolicy(client(), index, policy);
         assertBusy(() -> {
             assertTrue(indexExists(index));
@@ -130,7 +130,7 @@ public class ShrinkActionIT extends ESRestTestCase {
             alias,
             Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
         );
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(null, ByteSizeValue.ofGb(50)));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(null, ByteSizeValue.ofGb(50), false));
         updatePolicy(client(), index, policy);
         assertBusy(() -> {
             assertTrue(indexExists(index));
@@ -161,7 +161,7 @@ public class ShrinkActionIT extends ESRestTestCase {
         );
         assertOK(client().performRequest(request));
         // create delete policy
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(1, null), TimeValue.timeValueMillis(0));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(1, null, false), TimeValue.timeValueMillis(0));
         // create index without policy
         createIndexWithSettings(
             client(),
@@ -209,7 +209,8 @@ public class ShrinkActionIT extends ESRestTestCase {
             RolloverAction.NAME,
             new RolloverAction(null, null, null, 1L, null, null, null, null, null, null),
             ShrinkAction.NAME,
-            new ShrinkAction(expectedFinalShards, null)
+            new ShrinkAction(expectedFinalShards, null, false)
+
         );
         Map<String, Phase> phases = Map.of("hot", new Phase("hot", TimeValue.ZERO, hotActions));
         LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, phases);
@@ -279,7 +280,7 @@ public class ShrinkActionIT extends ESRestTestCase {
         // assign the policy that'll attempt to shrink the index (disabling the migrate action as it'll otherwise wait for
         // all shards to be active and we want that to happen as part of the shrink action)
         MigrateAction migrateAction = MigrateAction.DISABLED;
-        ShrinkAction shrinkAction = new ShrinkAction(expectedFinalShards, null);
+        ShrinkAction shrinkAction = new ShrinkAction(expectedFinalShards, null, false);
         Phase phase = new Phase(
             "warm",
             TimeValue.ZERO,
@@ -332,7 +333,8 @@ public class ShrinkActionIT extends ESRestTestCase {
             alias,
             Settings.builder().put(SETTING_NUMBER_OF_SHARDS, numShards).put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
         );
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(numShards + randomIntBetween(1, numShards), null));
+        var shrinkAction = new ShrinkAction(numShards + randomIntBetween(1, numShards), null, false);
+        createNewSingletonPolicy(client(), policy, "warm", shrinkAction);
         updatePolicy(client(), index, policy);
         assertBusy(
             () -> assertThat(
@@ -344,7 +346,7 @@ public class ShrinkActionIT extends ESRestTestCase {
         );
 
         // update policy to be correct
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null, false));
         updatePolicy(client(), index, policy);
 
         // assert corrected policy is picked up and index is shrunken
@@ -379,7 +381,7 @@ public class ShrinkActionIT extends ESRestTestCase {
                 .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
                 .put(ShardsLimitAllocationDecider.INDEX_TOTAL_SHARDS_PER_NODE_SETTING.getKey(), numShards - 2)
         );
-        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null));
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null, false));
         updatePolicy(client(), index, policy);
 
         String shrunkenIndexName = waitAndGetShrinkIndexName(client(), index);
@@ -397,4 +399,73 @@ public class ShrinkActionIT extends ESRestTestCase {
         });
         expectThrows(ResponseException.class, () -> indexDocument(client(), index));
     }
+
+    public void testAllowWritesInShrunkIndex() throws Exception {
+        int numShards = 4;
+        int divisor = randomFrom(2, 4);
+        int expectedFinalShards = numShards / divisor;
+        boolean initialIndexIsReadOnly = randomBoolean();
+        createIndexWithSettings(
+            client(),
+            index,
+            alias,
+            Settings.builder()
+                .put(SETTING_NUMBER_OF_SHARDS, numShards)
+                .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
+                .put(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey(), initialIndexIsReadOnly ? "true" : null)
+        );
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(expectedFinalShards, null, true));
+        updatePolicy(client(), index, policy);
+
+        String shrunkenIndexName = waitAndGetShrinkIndexName(client(), index);
+        assertBusy(() -> assertTrue(indexExists(shrunkenIndexName)), 30, TimeUnit.SECONDS);
+        assertBusy(() -> assertTrue(aliasExists(shrunkenIndexName, index)));
+        assertBusy(
+            () -> assertThat(getStepKeyForIndex(client(), shrunkenIndexName), equalTo(PhaseCompleteStep.finalStep("warm").getKey()))
+        );
+        assertBusy(() -> {
+            Map<String, Object> settings = getOnlyIndexSettings(client(), shrunkenIndexName);
+            assertThat(settings.get(SETTING_NUMBER_OF_SHARDS), equalTo(String.valueOf(expectedFinalShards)));
+            assertThat(settings.get(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_id"), nullValue());
+
+            // check that write block removed
+            assertNull(settings.get(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey()));
+        });
+
+        indexDocument(client(), index);
+        // check that actually wrote to index
+        assertBusy(() -> assertDocCount(client(), index, 1));
+    }
+
+    public void testAllowWritesWhenShrinkIsSkipped() throws Exception {
+        int numberOfShards = randomFrom(1, 2);
+        boolean initialIndexIsReadOnly = randomBoolean();
+        createIndexWithSettings(
+            client(),
+            index,
+            alias,
+            Settings.builder()
+                .put(SETTING_NUMBER_OF_SHARDS, numberOfShards)
+                .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
+                .put(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey(), initialIndexIsReadOnly ? "true" : null)
+        );
+        createNewSingletonPolicy(client(), policy, "warm", new ShrinkAction(numberOfShards, null, true));
+        updatePolicy(client(), index, policy);
+        assertBusy(() -> {
+            assertTrue(indexExists(index));
+            Map<String, Object> settings = getOnlyIndexSettings(client(), index);
+            assertThat(getStepKeyForIndex(client(), index), equalTo(PhaseCompleteStep.finalStep("warm").getKey()));
+            assertThat(settings.get(SETTING_NUMBER_OF_SHARDS), equalTo(String.valueOf(numberOfShards)));
+            assertThat(settings.get(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_id"), nullValue());
+            // the shrink action was effectively skipped so there must not be any `shrink_index_name` in the ILM state
+            assertThat(explainIndex(client(), index).get(SHRINK_INDEX_NAME), nullValue());
+
+            // check that write block removed
+            assertNull(settings.get(IndexMetadata.INDEX_BLOCKS_WRITE_SETTING.getKey()));
+        });
+
+        indexDocument(client(), index);
+        // check that actually wrote to index
+        assertBusy(() -> assertDocCount(client(), index, 1));
+    }
 }

+ 1 - 1
x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ClusterStateWaitThresholdBreachTests.java

@@ -88,7 +88,7 @@ public class ClusterStateWaitThresholdBreachTests extends ESIntegTestCase {
         Phase warmPhase = new Phase(
             "warm",
             TimeValue.ZERO,
-            Map.of(MigrateAction.NAME, MigrateAction.DISABLED, ShrinkAction.NAME, new ShrinkAction(1, null))
+            Map.of(MigrateAction.NAME, MigrateAction.DISABLED, ShrinkAction.NAME, new ShrinkAction(1, null, false))
         );
         LifecyclePolicy lifecyclePolicy = new LifecyclePolicy(policy, Map.of("warm", warmPhase));
         PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(lifecyclePolicy);

+ 1 - 1
x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeIT.java

@@ -70,7 +70,7 @@ public class ILMMultiNodeIT extends ESIntegTestCase {
 
         RolloverAction rolloverAction = new RolloverAction(null, null, null, 1L, null, null, null, null, null, null);
         Phase hotPhase = new Phase("hot", TimeValue.ZERO, Collections.singletonMap(rolloverAction.getWriteableName(), rolloverAction));
-        ShrinkAction shrinkAction = new ShrinkAction(1, null);
+        ShrinkAction shrinkAction = new ShrinkAction(1, null, false);
         Phase warmPhase = new Phase("warm", TimeValue.ZERO, Collections.singletonMap(shrinkAction.getWriteableName(), shrinkAction));
         Map<String, Phase> phases = new HashMap<>();
         phases.put(hotPhase.getName(), hotPhase);

+ 1 - 1
x-pack/plugin/ilm/src/internalClusterTest/java/org/elasticsearch/xpack/ilm/ILMMultiNodeWithCCRDisabledIT.java

@@ -70,7 +70,7 @@ public class ILMMultiNodeWithCCRDisabledIT extends ESIntegTestCase {
         ensureGreen();
         Map<String, LifecycleAction> actions = new HashMap<>();
         RolloverAction rolloverAction = new RolloverAction(null, null, null, 1L, null, null, null, null, null, null);
-        ShrinkAction shrinkAction = new ShrinkAction(1, null);
+        ShrinkAction shrinkAction = new ShrinkAction(1, null, false);
         actions.put(rolloverAction.getWriteableName(), rolloverAction);
         actions.put(shrinkAction.getWriteableName(), shrinkAction);
         Phase hotPhase = new Phase("hot", TimeValue.ZERO, actions);

+ 3 - 3
x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/cluster/metadata/MetadataMigrateToDataTiersRoutingServiceTests.java

@@ -102,7 +102,7 @@ public class MetadataMigrateToDataTiersRoutingServiceTests extends ESTestCase {
     }
 
     public void testMigrateIlmPolicyForIndexWithoutILMMetadata() {
-        ShrinkAction shrinkAction = new ShrinkAction(2, null);
+        ShrinkAction shrinkAction = new ShrinkAction(2, null, false);
         AllocateAction warmAllocateAction = new AllocateAction(null, null, Map.of("data", "warm"), null, Map.of("rack", "rack1"));
         AllocateAction coldAllocateAction = new AllocateAction(0, null, null, null, Map.of("data", "cold"));
         SetPriorityAction warmSetPriority = new SetPriorityAction(100);
@@ -153,7 +153,7 @@ public class MetadataMigrateToDataTiersRoutingServiceTests extends ESTestCase {
     }
 
     public void testMigrateIlmPolicyForPhaseWithDeactivatedMigrateAction() {
-        ShrinkAction shrinkAction = new ShrinkAction(2, null);
+        ShrinkAction shrinkAction = new ShrinkAction(2, null, false);
         AllocateAction warmAllocateAction = new AllocateAction(null, null, Map.of("data", "warm"), null, Map.of("rack", "rack1"));
 
         LifecyclePolicy policy = new LifecyclePolicy(
@@ -216,7 +216,7 @@ public class MetadataMigrateToDataTiersRoutingServiceTests extends ESTestCase {
 
     @SuppressWarnings("unchecked")
     public void testMigrateIlmPolicyRefreshesCachedPhase() {
-        ShrinkAction shrinkAction = new ShrinkAction(2, null);
+        ShrinkAction shrinkAction = new ShrinkAction(2, null, false);
         AllocateAction warmAllocateAction = new AllocateAction(null, null, Map.of("data", "warm"), null, Map.of("rack", "rack1"));
         AllocateAction coldAllocateAction = new AllocateAction(0, null, null, null, Map.of("data", "cold"));
         SetPriorityAction warmSetPriority = new SetPriorityAction(100);

+ 1 - 1
x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java

@@ -233,7 +233,7 @@ public class IndexLifecycleServiceTests extends ESTestCase {
 
     public void testRequestedStopInShrinkActionButNotShrinkStep() {
         // test all the shrink action steps that ILM can be stopped during (basically all of them minus the actual shrink)
-        ShrinkAction action = new ShrinkAction(1, null);
+        ShrinkAction action = new ShrinkAction(1, null, false);
         action.toSteps(mock(Client.class), "warm", randomStepKey())
             .stream()
             .map(sk -> sk.getKey().name())

+ 2 - 2
x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/PolicyStepsRegistryTests.java

@@ -335,7 +335,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
         Mockito.when(client.settings()).thenReturn(Settings.EMPTY);
         String policyName = randomAlphaOfLength(5);
         Map<String, LifecycleAction> actions = new HashMap<>();
-        actions.put("shrink", new ShrinkAction(1, null));
+        actions.put("shrink", new ShrinkAction(1, null, false));
         Map<String, Phase> phases = new HashMap<>();
         Phase warmPhase = new Phase("warm", TimeValue.ZERO, actions);
         PhaseExecutionInfo pei = new PhaseExecutionInfo(policyName, warmPhase, 1, randomNonNegativeLong());
@@ -344,7 +344,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
         LifecyclePolicy newPolicy = new LifecyclePolicy(policyName, phases);
         // Modify the policy
         actions = new HashMap<>();
-        actions.put("shrink", new ShrinkAction(2, null));
+        actions.put("shrink", new ShrinkAction(2, null, false));
         phases = new HashMap<>();
         phases.put("warm", new Phase("warm", TimeValue.ZERO, actions));
         LifecyclePolicy updatedPolicy = new LifecyclePolicy(policyName, phases);