From 2fc3f1d04ce8f1aa78ac8f71dbfb8a7180010b79 Mon Sep 17 00:00:00 2001 From: Tal Levy Date: Wed, 8 Aug 2018 11:43:29 -0700 Subject: [PATCH] move replicas action functionality into AllocateAction (#32523) Since replica counts and allocation rules are set separately, it is not always clear how many replicas are to be allocated in the allocate action. Moving the replicas action to occur at the same time as the allocate action, resolves this confusion that could end an undesired state. This means that the ReplicasAction is removed, and a new optional replicas parameter is added to AllocateAction. --- .../client/IndexLifecycleIT.java | 2 +- .../xpack/core/XPackClientPlugin.java | 3 - .../core/indexlifecycle/AllocateAction.java | 33 ++++- .../indexlifecycle/AllocationRoutedStep.java | 44 +++--- .../core/indexlifecycle/ReplicasAction.java | 123 ----------------- .../indexlifecycle/ReplicasAllocatedStep.java | 123 ----------------- .../TimeseriesLifecycleType.java | 6 +- .../indexlifecycle/AllocateActionTests.java | 25 +++- .../AllocationRoutedStepInfoTests.java | 12 +- .../AllocationRoutedStepTests.java | 46 ++++++- .../indexlifecycle/ReplicasActionTests.java | 63 --------- .../ReplicasAllocatedStepInfoTests.java | 54 -------- .../ReplicasAllocatedStepTests.java | 128 ------------------ .../TimeseriesLifecycleTypeTests.java | 60 +++----- .../TimeSeriesLifecycleActionsIT.java | 37 +++-- 15 files changed, 164 insertions(+), 595 deletions(-) delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAction.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStep.java delete mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasActionTests.java delete mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepInfoTests.java delete mode 100644 x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepTests.java diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java index ac50fa745d7..15abe6b524b 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java @@ -68,7 +68,7 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase { " \"cold\": {\n" + " \"after\": \"2000s\",\n" + " \"actions\": {\n" + - " \"replicas\": {\n" + + " \"allocate\": {\n" + " \"number_of_replicas\": 0\n" + " }\n" + " }\n" + diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java index 76df45d8a5e..dc097665633 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java @@ -49,7 +49,6 @@ import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleType; import org.elasticsearch.xpack.core.indexlifecycle.ReadOnlyAction; -import org.elasticsearch.xpack.core.indexlifecycle.ReplicasAction; import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction; import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction; import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType; @@ -408,7 +407,6 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl new NamedWriteableRegistry.Entry(LifecycleAction.class, AllocateAction.NAME, AllocateAction::new), new NamedWriteableRegistry.Entry(LifecycleAction.class, ForceMergeAction.NAME, ForceMergeAction::new), new NamedWriteableRegistry.Entry(LifecycleAction.class, ReadOnlyAction.NAME, ReadOnlyAction::new), - new NamedWriteableRegistry.Entry(LifecycleAction.class, ReplicasAction.NAME, ReplicasAction::new), new NamedWriteableRegistry.Entry(LifecycleAction.class, RolloverAction.NAME, RolloverAction::new), new NamedWriteableRegistry.Entry(LifecycleAction.class, ShrinkAction.NAME, ShrinkAction::new), new NamedWriteableRegistry.Entry(LifecycleAction.class, DeleteAction.NAME, DeleteAction::new) @@ -452,7 +450,6 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(AllocateAction.NAME), AllocateAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ForceMergeAction.NAME), ForceMergeAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReadOnlyAction.NAME), ReadOnlyAction::parse), - new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ReplicasAction.NAME), ReplicasAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(RolloverAction.NAME), RolloverAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(ShrinkAction.NAME), ShrinkAction::parse), new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(DeleteAction.NAME), DeleteAction::parse) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java index 2e4ebbf4ac1..9cd74353237 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateAction.java @@ -27,20 +27,23 @@ import java.util.Objects; public class AllocateAction implements LifecycleAction { public static final String NAME = "allocate"; + public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); public static final ParseField INCLUDE_FIELD = new ParseField("include"); public static final ParseField EXCLUDE_FIELD = new ParseField("exclude"); public static final ParseField REQUIRE_FIELD = new ParseField("require"); @SuppressWarnings("unchecked") private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, - a -> new AllocateAction((Map) a[0], (Map) a[1], (Map) a[2])); + a -> new AllocateAction((Integer) a[0], (Map) a[1], (Map) a[2], (Map) a[3])); static { + PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), NUMBER_OF_REPLICAS_FIELD); PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), INCLUDE_FIELD); PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), EXCLUDE_FIELD); PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.mapStrings(), REQUIRE_FIELD); } + private final Integer numberOfReplicas; private final Map include; private final Map exclude; private final Map require; @@ -49,7 +52,7 @@ public class AllocateAction implements LifecycleAction { return PARSER.apply(parser, null); } - public AllocateAction(Map include, Map exclude, Map require) { + public AllocateAction(Integer numberOfReplicas, Map include, Map exclude, Map require) { if (include == null) { this.include = Collections.emptyMap(); } else { @@ -65,19 +68,27 @@ public class AllocateAction implements LifecycleAction { } else { this.require = require; } - if (this.include.isEmpty() && this.exclude.isEmpty() && this.require.isEmpty()) { + if (this.include.isEmpty() && this.exclude.isEmpty() && this.require.isEmpty() && numberOfReplicas == null) { throw new IllegalArgumentException( "At least one of " + INCLUDE_FIELD.getPreferredName() + ", " + EXCLUDE_FIELD.getPreferredName() + " or " + REQUIRE_FIELD.getPreferredName() + "must contain attributes for action " + NAME); } + if (numberOfReplicas != null && numberOfReplicas < 0) { + throw new IllegalArgumentException("[" + NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0"); + } + this.numberOfReplicas = numberOfReplicas; } @SuppressWarnings("unchecked") public AllocateAction(StreamInput in) throws IOException { - this((Map) in.readGenericValue(), (Map) in.readGenericValue(), + this(in.readOptionalVInt(), (Map) in.readGenericValue(), (Map) in.readGenericValue(), (Map) in.readGenericValue()); } + public Integer getNumberOfReplicas() { + return numberOfReplicas; + } + public Map getInclude() { return include; } @@ -92,6 +103,7 @@ public class AllocateAction implements LifecycleAction { @Override public void writeTo(StreamOutput out) throws IOException { + out.writeOptionalVInt(numberOfReplicas); out.writeGenericValue(include); out.writeGenericValue(exclude); out.writeGenericValue(require); @@ -105,6 +117,9 @@ public class AllocateAction implements LifecycleAction { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); + if (numberOfReplicas != null) { + builder.field(NUMBER_OF_REPLICAS_FIELD.getPreferredName(), numberOfReplicas); + } builder.field(INCLUDE_FIELD.getPreferredName(), include); builder.field(EXCLUDE_FIELD.getPreferredName(), exclude); builder.field(REQUIRE_FIELD.getPreferredName(), require); @@ -123,6 +138,9 @@ public class AllocateAction implements LifecycleAction { StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME); Settings.Builder newSettings = Settings.builder(); + if (numberOfReplicas != null) { + newSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numberOfReplicas); + } include.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); exclude.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + key, value)); require.forEach((key, value) -> newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + key, value)); @@ -140,7 +158,7 @@ public class AllocateAction implements LifecycleAction { @Override public int hashCode() { - return Objects.hash(include, exclude, require); + return Objects.hash(numberOfReplicas, include, exclude, require); } @Override @@ -152,7 +170,10 @@ public class AllocateAction implements LifecycleAction { return false; } AllocateAction other = (AllocateAction) obj; - return Objects.equals(include, other.include) && Objects.equals(exclude, other.exclude) && Objects.equals(require, other.require); + return Objects.equals(numberOfReplicas, other.numberOfReplicas) && + Objects.equals(include, other.include) && + Objects.equals(exclude, other.exclude) && + Objects.equals(require, other.require); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStep.java index 7ee7868ba85..560029ba857 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStep.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStep.java @@ -54,15 +54,15 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { @Override public Result isConditionMet(Index index, ClusterState clusterState) { - if (ActiveShardCount.ALL.enoughShardsActive(clusterState, index.getName()) == false) { - logger.debug("[{}] lifecycle action for index [{}] cannot make progress because not all shards are active", - getKey().getAction(), index.getName()); - return new Result(false, new Info(-1, false)); - } IndexMetaData idxMeta = clusterState.metaData().index(index); if (idxMeta == null) { throw new IndexNotFoundException("Index not found when executing " + getKey().getAction() + " lifecycle action.", - index.getName()); + index.getName()); + } + if (ActiveShardCount.ALL.enoughShardsActive(clusterState, index.getName()) == false) { + logger.debug("[{}] lifecycle action for index [{}] cannot make progress because not all shards are active", + getKey().getAction(), index.getName()); + return new Result(false, new Info(idxMeta.getNumberOfReplicas(), -1, false)); } // All the allocation attributes are already set so just need to check // if the allocation has happened @@ -94,7 +94,7 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { logger.debug( "[{}] lifecycle action for index [{}] waiting for [{}] shards " + "to be allocated to nodes matching the given filters", getKey().getAction(), index, allocationPendingAllShards); - return new Result(false, new Info(allocationPendingAllShards, true)); + return new Result(false, new Info(idxMeta.getNumberOfReplicas(), allocationPendingAllShards, true)); } else { logger.debug("[{}] lifecycle action for index [{}] complete", getKey().getAction(), index); return new Result(true, null); @@ -105,7 +105,7 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { public int hashCode() { return Objects.hash(super.hashCode(), waitOnAllShardCopies); } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -115,29 +115,33 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { return false; } AllocationRoutedStep other = (AllocationRoutedStep) obj; - return super.equals(obj) && + return super.equals(obj) && Objects.equals(waitOnAllShardCopies, other.waitOnAllShardCopies); } - + public static final class Info implements ToXContentObject { + private final long actualReplicas; private final long numberShardsLeftToAllocate; private final boolean allShardsActive; private final String message; + static final ParseField ACTUAL_REPLICAS = new ParseField("actual_replicas"); static final ParseField SHARDS_TO_ALLOCATE = new ParseField("shards_left_to_allocate"); static final ParseField ALL_SHARDS_ACTIVE = new ParseField("all_shards_active"); static final ParseField MESSAGE = new ParseField("message"); static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("allocation_routed_step_info", - a -> new Info((long) a[0], (boolean) a[1])); + a -> new Info((long) a[0], (long) a[1], (boolean) a[2])); static { + PARSER.declareLong(ConstructingObjectParser.constructorArg(), ACTUAL_REPLICAS); PARSER.declareLong(ConstructingObjectParser.constructorArg(), SHARDS_TO_ALLOCATE); PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), ALL_SHARDS_ACTIVE); PARSER.declareString((i, s) -> {}, MESSAGE); } - public Info(long numberShardsLeftToMerge, boolean allShardsActive) { - this.numberShardsLeftToAllocate = numberShardsLeftToMerge; + public Info(long actualReplicas, long numberShardsLeftToAllocate, boolean allShardsActive) { + this.actualReplicas = actualReplicas; + this.numberShardsLeftToAllocate = numberShardsLeftToAllocate; this.allShardsActive = allShardsActive; if (allShardsActive == false) { message = "Waiting for all shard copies to be active"; @@ -147,10 +151,14 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { } } + public long getActualReplicas() { + return actualReplicas; + } + public long getNumberShardsLeftToAllocate() { return numberShardsLeftToAllocate; } - + public boolean allShardsActive() { return allShardsActive; } @@ -161,13 +169,14 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { builder.field(MESSAGE.getPreferredName(), message); builder.field(SHARDS_TO_ALLOCATE.getPreferredName(), numberShardsLeftToAllocate); builder.field(ALL_SHARDS_ACTIVE.getPreferredName(), allShardsActive); + builder.field(ACTUAL_REPLICAS.getPreferredName(), actualReplicas); builder.endObject(); return builder; } @Override public int hashCode() { - return Objects.hash(numberShardsLeftToAllocate, allShardsActive); + return Objects.hash(actualReplicas, numberShardsLeftToAllocate, allShardsActive); } @Override @@ -179,8 +188,9 @@ public class AllocationRoutedStep extends ClusterStateWaitStep { return false; } Info other = (Info) obj; - return Objects.equals(numberShardsLeftToAllocate, other.numberShardsLeftToAllocate) && - Objects.equals(allShardsActive, other.allShardsActive); + return Objects.equals(actualReplicas, other.actualReplicas) && + Objects.equals(numberShardsLeftToAllocate, other.numberShardsLeftToAllocate) && + Objects.equals(allShardsActive, other.allShardsActive); } @Override diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAction.java deleted file mode 100644 index 4d45f1aa89a..00000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAction.java +++ /dev/null @@ -1,123 +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.core.indexlifecycle; - -import org.elasticsearch.client.Client; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.ParseField; -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.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; - -/** - * A {@link LifecycleAction} that changes the number of replicas for the index. - */ -public class ReplicasAction implements LifecycleAction { - public static final String NAME = "replicas"; - - public static final ParseField NUMBER_OF_REPLICAS_FIELD = new ParseField("number_of_replicas"); - private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>(NAME, - false, a -> new ReplicasAction((Integer) a[0])); - - static { - PARSER.declareInt(constructorArg(), NUMBER_OF_REPLICAS_FIELD); - } - - private int numberOfReplicas; - - public static ReplicasAction parse(XContentParser parser) { - return PARSER.apply(parser, null); - } - - public ReplicasAction(int numberOfReplicas) { - if (numberOfReplicas < 0) { - throw new IllegalArgumentException("[" + NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0"); - } - this.numberOfReplicas = numberOfReplicas; - } - - public ReplicasAction(StreamInput in) throws IOException { - this.numberOfReplicas = in.readVInt(); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(numberOfReplicas); - } - - @Override - public String getWriteableName() { - return NAME; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(NUMBER_OF_REPLICAS_FIELD.getPreferredName(), numberOfReplicas); - builder.endObject(); - return builder; - } - - @Override - public boolean isSafeAction() { - return true; - } - - @Override - public List toSteps(Client client, String phase, Step.StepKey nextStepKey) { - StepKey updateReplicasKey = new StepKey(phase, NAME, UpdateSettingsStep.NAME); - StepKey enoughKey = new StepKey(phase, NAME, ReplicasAllocatedStep.NAME); - Settings replicaSettings = Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numberOfReplicas).build(); - return Arrays.asList(new UpdateSettingsStep(updateReplicasKey, enoughKey, client, replicaSettings), - new ReplicasAllocatedStep(enoughKey, nextStepKey)); - } - - @Override - public List toStepKeys(String phase) { - StepKey updateReplicasKey = new StepKey(phase, NAME, UpdateSettingsStep.NAME); - StepKey enoughKey = new StepKey(phase, NAME, ReplicasAllocatedStep.NAME); - return Arrays.asList(updateReplicasKey, enoughKey); - } - - public int getNumberOfReplicas() { - return numberOfReplicas; - } - - @Override - public int hashCode() { - return Objects.hashCode(numberOfReplicas); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj.getClass() != getClass()) { - return false; - } - ReplicasAction other = (ReplicasAction) obj; - return Objects.equals(numberOfReplicas, other.numberOfReplicas); - } - - @Override - public String toString() { - return Strings.toString(this); - } - -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStep.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStep.java deleted file mode 100644 index 012a2c4515d..00000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStep.java +++ /dev/null @@ -1,123 +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.core.indexlifecycle; - -import org.elasticsearch.action.support.ActiveShardCount; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.xcontent.ConstructingObjectParser; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.IndexNotFoundException; - -import java.io.IOException; -import java.util.Objects; - -public class ReplicasAllocatedStep extends ClusterStateWaitStep { - public static final String NAME = "enough-shards-allocated"; - - public ReplicasAllocatedStep(StepKey key, StepKey nextStepKey) { - super(key, nextStepKey); - } - - @Override - public Result isConditionMet(Index index, ClusterState clusterState) { - IndexMetaData idxMeta = clusterState.metaData().index(index); - if (idxMeta == null) { - throw new IndexNotFoundException("Index not found when executing " + getKey().getAction() + " lifecycle action.", - index.getName()); - } - // We only want to make progress if the cluster state reflects the number of replicas change and all shards are active - boolean allShardsActive = ActiveShardCount.ALL.enoughShardsActive(clusterState, index.getName()); - if (allShardsActive) { - return new Result(true, null); - } else { - return new Result(false, new Info(idxMeta.getNumberOfReplicas(), allShardsActive)); - } - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj != null && getClass() == obj.getClass() && super.equals(obj); - } - - public static final class Info implements ToXContentObject { - - private final long actualReplicas; - private final boolean allShardsActive; - private final String message; - - static final ParseField ACTUAL_REPLICAS = new ParseField("actual_replicas"); - static final ParseField ALL_SHARDS_ACTIVE = new ParseField("all_shards_active"); - static final ParseField MESSAGE = new ParseField("message"); - static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("replicas_allocated_step_info", - a -> new Info((long) a[0], (boolean) a[1])); - static { - PARSER.declareLong(ConstructingObjectParser.constructorArg(), ACTUAL_REPLICAS); - PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), ALL_SHARDS_ACTIVE); - PARSER.declareString((i, s) -> {}, MESSAGE); - } - - public Info(long actualReplicas, boolean allShardsActive) { - this.actualReplicas = actualReplicas; - this.allShardsActive = allShardsActive; - if (allShardsActive == false) { - message = "Waiting for all shard copies to be active"; - } else { - message = ""; - } - } - - public long getActualReplicas() { - return actualReplicas; - } - - public boolean allShardsActive() { - return allShardsActive; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(MESSAGE.getPreferredName(), message); - builder.field(ACTUAL_REPLICAS.getPreferredName(), actualReplicas); - builder.field(ALL_SHARDS_ACTIVE.getPreferredName(), allShardsActive); - builder.endObject(); - return builder; - } - - @Override - public int hashCode() { - return Objects.hash(actualReplicas, allShardsActive); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Info other = (Info) obj; - return Objects.equals(actualReplicas, other.actualReplicas) && - Objects.equals(allShardsActive, other.allShardsActive); - } - - @Override - public String toString() { - return Strings.toString(this); - } - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleType.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleType.java index fb5fcf52956..8ace07e3a9a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleType.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleType.java @@ -37,8 +37,8 @@ public class TimeseriesLifecycleType implements LifecycleType { static final List VALID_PHASES = Arrays.asList("hot", "warm", "cold", "delete"); static final List ORDERED_VALID_HOT_ACTIONS = Collections.singletonList(RolloverAction.NAME); static final List ORDERED_VALID_WARM_ACTIONS = Arrays.asList(ReadOnlyAction.NAME, AllocateAction.NAME, - ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME); - static final List ORDERED_VALID_COLD_ACTIONS = Arrays.asList(AllocateAction.NAME, ReplicasAction.NAME); + ShrinkAction.NAME, ForceMergeAction.NAME); + static final List ORDERED_VALID_COLD_ACTIONS = Arrays.asList(AllocateAction.NAME); static final List ORDERED_VALID_DELETE_ACTIONS = Arrays.asList(DeleteAction.NAME); static final Set VALID_HOT_ACTIONS = Sets.newHashSet(ORDERED_VALID_HOT_ACTIONS); static final Set VALID_WARM_ACTIONS = Sets.newHashSet(ORDERED_VALID_WARM_ACTIONS); @@ -140,7 +140,7 @@ public class TimeseriesLifecycleType implements LifecycleType { throw new IllegalArgumentException("lifecycle type[" + TYPE + "] does not support phase[" + phase.getName() + "]"); } } - + @Override public String getNextActionName(String currentActionName, Phase phase) { List orderedActionNames; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java index 55d68b41610..147e1b7671c 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocateActionTests.java @@ -48,7 +48,8 @@ public class AllocateActionTests extends AbstractActionTestCase } else { requires = randomBoolean() ? null : Collections.emptyMap(); } - return new AllocateAction(includes, excludes, requires); + Integer numberOfReplicas = randomBoolean() ? null : randomIntBetween(0, 10); + return new AllocateAction(numberOfReplicas, includes, excludes, requires); } @Override @@ -61,7 +62,8 @@ public class AllocateActionTests extends AbstractActionTestCase Map include = instance.getInclude(); Map exclude = instance.getExclude(); Map require = instance.getRequire(); - switch (randomIntBetween(0, 2)) { + Integer numberOfReplicas = instance.getNumberOfReplicas(); + switch (randomIntBetween(0, 3)) { case 0: include = new HashMap<>(include); include.put(randomAlphaOfLengthBetween(11, 15), randomAlphaOfLengthBetween(1, 20)); @@ -74,10 +76,13 @@ public class AllocateActionTests extends AbstractActionTestCase require = new HashMap<>(require); require.put(randomAlphaOfLengthBetween(11, 15), randomAlphaOfLengthBetween(1, 20)); break; + case 3: + numberOfReplicas = randomIntBetween(11, 20); + break; default: throw new AssertionError("Illegal randomisation branch"); } - return new AllocateAction(include, exclude, require); + return new AllocateAction(numberOfReplicas, include, exclude, require); } public void testAllMapsNullOrEmpty() { @@ -85,12 +90,21 @@ public class AllocateActionTests extends AbstractActionTestCase Map exclude = randomBoolean() ? null : Collections.emptyMap(); Map require = randomBoolean() ? null : Collections.emptyMap(); IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, - () -> new AllocateAction(include, exclude, require)); + () -> new AllocateAction(null, include, exclude, require)); assertEquals("At least one of " + AllocateAction.INCLUDE_FIELD.getPreferredName() + ", " + AllocateAction.EXCLUDE_FIELD.getPreferredName() + " or " + AllocateAction.REQUIRE_FIELD.getPreferredName() + "must contain attributes for action " + AllocateAction.NAME, exception.getMessage()); } + public void testInvalidNumberOfReplicas() { + Map include = randomMap(1, 5); + Map exclude = randomBoolean() ? null : Collections.emptyMap(); + Map require = randomBoolean() ? null : Collections.emptyMap(); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> new AllocateAction(randomIntBetween(-1000, -1), include, exclude, require)); + assertEquals("[" + AllocateAction.NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0", exception.getMessage()); + } + public static Map randomMap(int minEntries, int maxEntries) { Map map = new HashMap<>(); int numIncludes = randomIntBetween(minEntries, maxEntries); @@ -114,6 +128,9 @@ public class AllocateActionTests extends AbstractActionTestCase assertEquals(expectedFirstStepKey, firstStep.getKey()); assertEquals(expectedSecondStepKey, firstStep.getNextStepKey()); Settings.Builder expectedSettings = Settings.builder(); + if (action.getNumberOfReplicas() != null) { + expectedSettings.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, action.getNumberOfReplicas()); + } action.getInclude().forEach( (key, value) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value)); action.getExclude().forEach( diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStepInfoTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStepInfoTests.java index 8979e0e31f3..80eb89c45b9 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStepInfoTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/AllocationRoutedStepInfoTests.java @@ -17,7 +17,7 @@ public class AllocationRoutedStepInfoTests extends AbstractXContentTestCase { @@ -168,7 +169,7 @@ public class AllocationRoutedStepTests extends AbstractStepTestCase requires = Collections.singletonMap("_name", "node1"); + Settings.Builder existingSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT.id) + .put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID()); + Settings.Builder expectedSettings = Settings.builder(); + Settings.Builder node1Settings = Settings.builder(); + Settings.Builder node2Settings = Settings.builder(); + requires.forEach((k, v) -> { + expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v); + }); + + IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(index) + .addShard(TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true, ShardRoutingState.STARTED)) + .addShard(TestShardRouting.newShardRouting(new ShardId(index, 0), null, null, false, ShardRoutingState.UNASSIGNED, + new UnassignedInfo(Reason.REPLICA_ADDED, "no attempt"))); + + AllocationRoutedStep step = createRandomInstance(); + assertAllocateStatus(index, 1, 1, step, existingSettings, node1Settings, node2Settings, indexRoutingTable, + new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(1, -1, false))); } public void testExecuteIndexMissing() throws Exception { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasActionTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasActionTests.java deleted file mode 100644 index db0d08a401f..00000000000 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasActionTests.java +++ /dev/null @@ -1,63 +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.core.indexlifecycle; - -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.io.stream.Writeable.Reader; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; - -import java.io.IOException; -import java.util.List; - -public class ReplicasActionTests extends AbstractActionTestCase { - - @Override - protected ReplicasAction doParseInstance(XContentParser parser) { - return ReplicasAction.parse(parser); - } - - @Override - protected ReplicasAction createTestInstance() { - return new ReplicasAction(randomIntBetween(0, 10)); - } - - @Override - protected Reader instanceReader() { - return ReplicasAction::new; - } - - @Override - protected ReplicasAction mutateInstance(ReplicasAction instance) throws IOException { - return new ReplicasAction(instance.getNumberOfReplicas() + randomIntBetween(1, 5)); - } - - public void testInvalidNumReplicas() { - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, - () -> new ReplicasAction(randomIntBetween(-1000, -1))); - assertEquals("[" + ReplicasAction.NUMBER_OF_REPLICAS_FIELD.getPreferredName() + "] must be >= 0", exception.getMessage()); - } - - public void testToSteps() { - ReplicasAction action = createTestInstance(); - String phase = randomAlphaOfLengthBetween(1, 10); - StepKey nextStepKey = new StepKey(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10), - randomAlphaOfLengthBetween(1, 10)); - List steps = action.toSteps(null, phase, nextStepKey); - assertNotNull(steps); - assertEquals(2, steps.size()); - StepKey expectedFirstStepKey = new StepKey(phase, ReplicasAction.NAME, UpdateSettingsStep.NAME); - StepKey expectedSecondStepKey = new StepKey(phase, ReplicasAction.NAME, ReplicasAllocatedStep.NAME); - UpdateSettingsStep firstStep = (UpdateSettingsStep) steps.get(0); - assertEquals(expectedFirstStepKey, firstStep.getKey()); - assertEquals(expectedSecondStepKey, firstStep.getNextStepKey()); - assertEquals(1, firstStep.getSettings().size()); - assertEquals(action.getNumberOfReplicas(), IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.get(firstStep.getSettings()).intValue()); - ReplicasAllocatedStep secondStep = (ReplicasAllocatedStep) steps.get(1); - assertEquals(expectedSecondStepKey, secondStep.getKey()); - assertEquals(nextStepKey, secondStep.getNextStepKey()); - } -} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepInfoTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepInfoTests.java deleted file mode 100644 index 9769fd40e23..00000000000 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepInfoTests.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.core.indexlifecycle; - -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.test.AbstractXContentTestCase; -import org.elasticsearch.test.EqualsHashCodeTestUtils; -import org.elasticsearch.xpack.core.indexlifecycle.ReplicasAllocatedStep.Info; - -import java.io.IOException; - -public class ReplicasAllocatedStepInfoTests extends AbstractXContentTestCase { - - @Override - protected Info createTestInstance() { - return new Info(randomNonNegativeLong(), randomBoolean()); - } - - @Override - protected Info doParseInstance(XContentParser parser) throws IOException { - return Info.PARSER.apply(parser, null); - } - - @Override - protected boolean supportsUnknownFields() { - return false; - } - - public final void testEqualsAndHashcode() { - for (int runs = 0; runs < NUMBER_OF_TEST_RUNS; runs++) { - EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), this::copyInstance, this::mutateInstance); - } - } - - protected final Info copyInstance(Info instance) throws IOException { - return new Info(instance.getActualReplicas(), instance.allShardsActive()); - } - - protected Info mutateInstance(Info instance) throws IOException { - long actualReplicas = instance.getActualReplicas(); - boolean allShardsActive = instance.allShardsActive(); - if (randomBoolean()) { - actualReplicas += between(1, 20); - } else { - allShardsActive = allShardsActive == false; - } - return new Info(actualReplicas, allShardsActive); - } - -} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepTests.java deleted file mode 100644 index 325060cf64d..00000000000 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ReplicasAllocatedStepTests.java +++ /dev/null @@ -1,128 +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.core.indexlifecycle; - - -import org.elasticsearch.Version; -import org.elasticsearch.cluster.ClusterName; -import org.elasticsearch.cluster.ClusterState; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.cluster.metadata.MetaData; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.cluster.node.DiscoveryNodes; -import org.elasticsearch.cluster.routing.IndexRoutingTable; -import org.elasticsearch.cluster.routing.RoutingTable; -import org.elasticsearch.cluster.routing.ShardRoutingState; -import org.elasticsearch.cluster.routing.TestShardRouting; -import org.elasticsearch.common.transport.TransportAddress; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.IndexNotFoundException; -import org.elasticsearch.index.shard.ShardId; -import org.elasticsearch.node.Node; -import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateWaitStep.Result; -import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; - -public class ReplicasAllocatedStepTests extends AbstractStepTestCase { - - @Override - public ReplicasAllocatedStep createRandomInstance() { - StepKey stepKey = randomStepKey(); - StepKey nextStepKey = randomStepKey(); - return new ReplicasAllocatedStep(stepKey, nextStepKey); - } - - @Override - public ReplicasAllocatedStep mutateInstance(ReplicasAllocatedStep instance) { - StepKey key = instance.getKey(); - StepKey nextKey = instance.getNextStepKey(); - if (randomBoolean()) { - key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5)); - } else { - nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5)); - } - return new ReplicasAllocatedStep(key, nextKey); - } - - @Override - public ReplicasAllocatedStep copyInstance(ReplicasAllocatedStep instance) { - return new ReplicasAllocatedStep(instance.getKey(), instance.getNextStepKey()); - } - - public void testConditionMet() { - ReplicasAllocatedStep step = createRandomInstance(); - IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5)) - .settings(settings(Version.CURRENT)) - .numberOfShards(1) - .numberOfReplicas(randomIntBetween(0, 5)).build(); - MetaData metaData = MetaData.builder() - .persistentSettings(settings(Version.CURRENT).build()) - .put(IndexMetaData.builder(indexMetadata)) - .build(); - Index index = indexMetadata.getIndex(); - - String nodeId = randomAlphaOfLength(10); - DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT) - .put(Node.NODE_MASTER_SETTING.getKey(), true).build(), - new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId); - - ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT) - .metaData(metaData) - .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) - .routingTable(RoutingTable.builder() - .add(IndexRoutingTable.builder(index).addShard( - TestShardRouting.newShardRouting(new ShardId(index, 0), - nodeId, true, ShardRoutingState.STARTED))) - .build()) - .build(); - Result result = step.isConditionMet(indexMetadata.getIndex(), clusterState); - assertTrue(result.isComplete()); - assertNull(result.getInfomationContext()); - } - - public void testConditionNotMetAllocation() { - ReplicasAllocatedStep step = createRandomInstance(); - IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5)) - .settings(settings(Version.CURRENT)) - .numberOfShards(1) - .numberOfReplicas(randomIntBetween(0, 5)).build(); - MetaData metaData = MetaData.builder() - .persistentSettings(settings(Version.CURRENT).build()) - .put(IndexMetaData.builder(indexMetadata)) - .build(); - Index index = indexMetadata.getIndex(); - - String nodeId = randomAlphaOfLength(10); - DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT) - .put(Node.NODE_MASTER_SETTING.getKey(), true).build(), - new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId); - - ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT) - .metaData(metaData) - .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) - .routingTable(RoutingTable.builder() - .add(IndexRoutingTable.builder(index).addShard( - TestShardRouting.newShardRouting(new ShardId(index, 0), - nodeId, true, ShardRoutingState.INITIALIZING))) - .build()) - .build(); - - Result result = step.isConditionMet(indexMetadata.getIndex(), clusterState); - assertFalse(result.isComplete()); - assertEquals(new ReplicasAllocatedStep.Info(indexMetadata.getNumberOfReplicas(), false), - result.getInfomationContext()); - } - - public void testConditionIndexMissing() throws Exception { - Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20)); - ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).build(); - - ReplicasAllocatedStep step = createRandomInstance(); - - IndexNotFoundException thrownException = expectThrows(IndexNotFoundException.class, () -> step.isConditionMet(index, clusterState)); - assertEquals("Index not found when executing " + step.getKey().getAction() + " lifecycle action.", thrownException.getMessage()); - assertEquals(index.getName(), thrownException.getIndex().getName()); - } -} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleTypeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleTypeTests.java index d1af22172a4..511aa56c399 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleTypeTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/TimeseriesLifecycleTypeTests.java @@ -31,10 +31,10 @@ import static org.hamcrest.Matchers.equalTo; public class TimeseriesLifecycleTypeTests extends ESTestCase { - private static final AllocateAction TEST_ALLOCATE_ACTION = new AllocateAction(Collections.singletonMap("node", "node1"),null, null); + private static final AllocateAction TEST_ALLOCATE_ACTION = + new AllocateAction(2, Collections.singletonMap("node", "node1"),null, null); private static final DeleteAction TEST_DELETE_ACTION = new DeleteAction(); private static final ForceMergeAction TEST_FORCE_MERGE_ACTION = new ForceMergeAction(1); - private static final ReplicasAction TEST_REPLICAS_ACTION = new ReplicasAction(1); private static final RolloverAction TEST_ROLLOVER_ACTION = new RolloverAction(new ByteSizeValue(1), null, null); private static final ShrinkAction TEST_SHRINK_ACTION = new ShrinkAction(1); private static final ReadOnlyAction TEST_READ_ONLY_ACTION = new ReadOnlyAction(); @@ -307,14 +307,11 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase { assertInvalidAction("hot", DeleteAction.NAME, new String[] { RolloverAction.NAME }); assertInvalidAction("hot", ForceMergeAction.NAME, new String[] { RolloverAction.NAME }); assertInvalidAction("hot", ReadOnlyAction.NAME, new String[] { RolloverAction.NAME }); - assertInvalidAction("hot", ReplicasAction.NAME, new String[] { RolloverAction.NAME }); assertInvalidAction("hot", ShrinkAction.NAME, new String[] { RolloverAction.NAME }); // Warm Phase assertNextActionName("warm", ReadOnlyAction.NAME, AllocateAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); - assertNextActionName("warm", ReadOnlyAction.NAME, ReplicasAction.NAME, - new String[] { ReadOnlyAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, ShrinkAction.NAME, new String[] { ReadOnlyAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, ForceMergeAction.NAME, @@ -322,73 +319,53 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase { assertNextActionName("warm", ReadOnlyAction.NAME, null, new String[] { ReadOnlyAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, AllocateAction.NAME, - new String[] { AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); - assertNextActionName("warm", ReadOnlyAction.NAME, ReplicasAction.NAME, - new String[] { ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, ShrinkAction.NAME, new String[] { ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, ForceMergeAction.NAME, new String[] { ForceMergeAction.NAME }); assertNextActionName("warm", ReadOnlyAction.NAME, null, new String[] {}); - assertNextActionName("warm", AllocateAction.NAME, ReplicasAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, ShrinkAction.NAME, new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, ForceMergeAction.NAME, new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, null, new String[] { ReadOnlyAction.NAME, AllocateAction.NAME }); - assertNextActionName("warm", AllocateAction.NAME, ReplicasAction.NAME, - new String[] { ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, ShrinkAction.NAME, new String[] { ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, ForceMergeAction.NAME, new String[] { ForceMergeAction.NAME }); assertNextActionName("warm", AllocateAction.NAME, null, new String[] {}); - assertNextActionName("warm", ReplicasAction.NAME, ShrinkAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); - assertNextActionName("warm", ReplicasAction.NAME, ForceMergeAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ForceMergeAction.NAME }); - assertNextActionName("warm", ReplicasAction.NAME, null, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME }); - - assertNextActionName("warm", ReplicasAction.NAME, ShrinkAction.NAME, new String[] { ShrinkAction.NAME, ForceMergeAction.NAME }); - assertNextActionName("warm", ReplicasAction.NAME, ForceMergeAction.NAME, new String[] { ForceMergeAction.NAME }); - assertNextActionName("warm", ReplicasAction.NAME, null, new String[] {}); - assertNextActionName("warm", ShrinkAction.NAME, ForceMergeAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ShrinkAction.NAME, null, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME }); assertNextActionName("warm", ShrinkAction.NAME, ForceMergeAction.NAME, new String[] { ForceMergeAction.NAME }); assertNextActionName("warm", ShrinkAction.NAME, null, new String[] {}); assertNextActionName("warm", ForceMergeAction.NAME, null, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertNextActionName("warm", ForceMergeAction.NAME, null, new String[] {}); assertInvalidAction("warm", "foo", new String[] { RolloverAction.NAME }); assertInvalidAction("warm", DeleteAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); assertInvalidAction("warm", RolloverAction.NAME, - new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); + new String[] { ReadOnlyAction.NAME, AllocateAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME }); // Cold Phase - assertNextActionName("cold", AllocateAction.NAME, ReplicasAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); assertNextActionName("cold", AllocateAction.NAME, null, new String[] { AllocateAction.NAME }); - assertNextActionName("cold", AllocateAction.NAME, ReplicasAction.NAME, new String[] { ReplicasAction.NAME }); assertNextActionName("cold", AllocateAction.NAME, null, new String[] {}); - assertNextActionName("cold", ReplicasAction.NAME, null, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); assertNextActionName("cold", AllocateAction.NAME, null, new String[] {}); - assertInvalidAction("cold", "foo", new String[] { AllocateAction.NAME, ReplicasAction.NAME }); - assertInvalidAction("cold", DeleteAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); - assertInvalidAction("cold", ForceMergeAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); - assertInvalidAction("cold", ReadOnlyAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); - assertInvalidAction("cold", RolloverAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); - assertInvalidAction("cold", ShrinkAction.NAME, new String[] { AllocateAction.NAME, ReplicasAction.NAME }); + assertInvalidAction("cold", "foo", new String[] { AllocateAction.NAME }); + assertInvalidAction("cold", DeleteAction.NAME, new String[] { AllocateAction.NAME }); + assertInvalidAction("cold", ForceMergeAction.NAME, new String[] { AllocateAction.NAME }); + assertInvalidAction("cold", ReadOnlyAction.NAME, new String[] { AllocateAction.NAME }); + assertInvalidAction("cold", RolloverAction.NAME, new String[] { AllocateAction.NAME }); + assertInvalidAction("cold", ShrinkAction.NAME, new String[] { AllocateAction.NAME }); // Delete Phase assertNextActionName("delete", DeleteAction.NAME, null, new String[] {}); @@ -397,7 +374,6 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase { assertInvalidAction("delete", AllocateAction.NAME, new String[] { DeleteAction.NAME }); assertInvalidAction("delete", ForceMergeAction.NAME, new String[] { DeleteAction.NAME }); assertInvalidAction("delete", ReadOnlyAction.NAME, new String[] { DeleteAction.NAME }); - assertInvalidAction("delete", ReplicasAction.NAME, new String[] { DeleteAction.NAME }); assertInvalidAction("delete", RolloverAction.NAME, new String[] { DeleteAction.NAME }); assertInvalidAction("delete", ShrinkAction.NAME, new String[] { DeleteAction.NAME }); @@ -428,15 +404,13 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase { return Arrays.asList(availableActionNames).stream().map(n -> { switch (n) { case AllocateAction.NAME: - return new AllocateAction(Collections.singletonMap("foo", "bar"), Collections.emptyMap(), Collections.emptyMap()); + return new AllocateAction(null, Collections.singletonMap("foo", "bar"), Collections.emptyMap(), Collections.emptyMap()); case DeleteAction.NAME: return new DeleteAction(); case ForceMergeAction.NAME: return new ForceMergeAction(1); case ReadOnlyAction.NAME: return new ReadOnlyAction(); - case ReplicasAction.NAME: - return new ReplicasAction(1); case RolloverAction.NAME: return new RolloverAction(ByteSizeValue.parseBytesSizeValue("0b", "test"), TimeValue.ZERO, 1L); case ShrinkAction.NAME: @@ -498,8 +472,6 @@ public class TimeseriesLifecycleTypeTests extends ESTestCase { return TEST_FORCE_MERGE_ACTION; case ReadOnlyAction.NAME: return TEST_READ_ONLY_ACTION; - case ReplicasAction.NAME: - return TEST_REPLICAS_ACTION; case RolloverAction.NAME: return TEST_ROLLOVER_ACTION; case ShrinkAction.NAME: 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 fce7f0a2479..dde30ca54e7 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 @@ -24,7 +24,6 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; 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.ReplicasAction; import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import org.elasticsearch.xpack.core.indexlifecycle.TerminalPolicyStep; @@ -69,11 +68,11 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase { client().performRequest(request); } - public void testAllocate() throws Exception { + public void testAllocateOnlyAllocation() throws Exception { createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 2) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)); String allocateNodeName = "node-" + randomFrom(0, 1); - AllocateAction allocateAction = new AllocateAction(null, null, singletonMap("_name", allocateNodeName)); + AllocateAction allocateAction = new AllocateAction(null, null, null, singletonMap("_name", allocateNodeName)); createNewSingletonPolicy(randomFrom("warm", "cold"), allocateAction); updatePolicy(index, policy); assertBusy(() -> { @@ -83,6 +82,22 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase { ensureGreen(index); } + public void testAllocateActionOnlyReplicas() throws Exception { + int numShards = randomFrom(1, 5); + int numReplicas = randomFrom(0, 1); + int finalNumReplicas = (numReplicas + 1) % 2; + createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numShards) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numReplicas)); + AllocateAction allocateAction = new AllocateAction(finalNumReplicas, null, null, null); + createNewSingletonPolicy(randomFrom("warm", "cold"), allocateAction); + updatePolicy(index, policy); + assertBusy(() -> { + Map settings = getOnlyIndexSettings(index); + assertThat(getStepKey(settings), equalTo(TerminalPolicyStep.KEY)); + assertThat(settings.get(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey()), equalTo(String.valueOf(finalNumReplicas))); + }); + } + public void testDelete() throws Exception { createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)); @@ -137,22 +152,6 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase { }); } - public void testReplicasAction() throws Exception { - int numShards = randomFrom(1, 5); - int numReplicas = randomFrom(0, 1); - int finalNumReplicas = (numReplicas + 1) % 2; - createIndexWithSettings(index, Settings.builder().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numShards) - .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numReplicas)); - createNewSingletonPolicy(randomFrom("warm", "cold"), new ReplicasAction(finalNumReplicas)); - updatePolicy(index, policy); - - assertBusy(() -> { - Map settings = getOnlyIndexSettings(index); - assertThat(getStepKey(settings), equalTo(TerminalPolicyStep.KEY)); - assertThat(settings.get(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey()), equalTo(String.valueOf(finalNumReplicas))); - }); - } - public void testShrinkAction() throws Exception { int numShards = 6; int divisor = randomFrom(2, 3, 6);