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.
This commit is contained in:
parent
2d925c9a9a
commit
2fc3f1d04c
|
@ -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" +
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<AllocateAction, Void> PARSER = new ConstructingObjectParser<>(NAME,
|
||||
a -> new AllocateAction((Map<String, String>) a[0], (Map<String, String>) a[1], (Map<String, String>) a[2]));
|
||||
a -> new AllocateAction((Integer) a[0], (Map<String, String>) a[1], (Map<String, String>) a[2], (Map<String, String>) 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<String, String> include;
|
||||
private final Map<String, String> exclude;
|
||||
private final Map<String, String> require;
|
||||
|
@ -49,7 +52,7 @@ public class AllocateAction implements LifecycleAction {
|
|||
return PARSER.apply(parser, null);
|
||||
}
|
||||
|
||||
public AllocateAction(Map<String, String> include, Map<String, String> exclude, Map<String, String> require) {
|
||||
public AllocateAction(Integer numberOfReplicas, Map<String, String> include, Map<String, String> exclude, Map<String, String> 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<String, String>) in.readGenericValue(), (Map<String, String>) in.readGenericValue(),
|
||||
this(in.readOptionalVInt(), (Map<String, String>) in.readGenericValue(), (Map<String, String>) in.readGenericValue(),
|
||||
(Map<String, String>) in.readGenericValue());
|
||||
}
|
||||
|
||||
public Integer getNumberOfReplicas() {
|
||||
return numberOfReplicas;
|
||||
}
|
||||
|
||||
public Map<String, String> 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
|
||||
|
|
|
@ -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<Info, Void> 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
|
||||
|
|
|
@ -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<ReplicasAction, Void> 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<Step> 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<StepKey> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Info, Void> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,8 +37,8 @@ public class TimeseriesLifecycleType implements LifecycleType {
|
|||
static final List<String> VALID_PHASES = Arrays.asList("hot", "warm", "cold", "delete");
|
||||
static final List<String> ORDERED_VALID_HOT_ACTIONS = Collections.singletonList(RolloverAction.NAME);
|
||||
static final List<String> ORDERED_VALID_WARM_ACTIONS = Arrays.asList(ReadOnlyAction.NAME, AllocateAction.NAME,
|
||||
ReplicasAction.NAME, ShrinkAction.NAME, ForceMergeAction.NAME);
|
||||
static final List<String> ORDERED_VALID_COLD_ACTIONS = Arrays.asList(AllocateAction.NAME, ReplicasAction.NAME);
|
||||
ShrinkAction.NAME, ForceMergeAction.NAME);
|
||||
static final List<String> ORDERED_VALID_COLD_ACTIONS = Arrays.asList(AllocateAction.NAME);
|
||||
static final List<String> ORDERED_VALID_DELETE_ACTIONS = Arrays.asList(DeleteAction.NAME);
|
||||
static final Set<String> VALID_HOT_ACTIONS = Sets.newHashSet(ORDERED_VALID_HOT_ACTIONS);
|
||||
static final Set<String> 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<String> orderedActionNames;
|
||||
|
|
|
@ -48,7 +48,8 @@ public class AllocateActionTests extends AbstractActionTestCase<AllocateAction>
|
|||
} 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<AllocateAction>
|
|||
Map<String, String> include = instance.getInclude();
|
||||
Map<String, String> exclude = instance.getExclude();
|
||||
Map<String, String> 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<AllocateAction>
|
|||
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<AllocateAction>
|
|||
Map<String, String> exclude = randomBoolean() ? null : Collections.emptyMap();
|
||||
Map<String, String> 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<String, String> include = randomMap(1, 5);
|
||||
Map<String, String> exclude = randomBoolean() ? null : Collections.emptyMap();
|
||||
Map<String, String> 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<String, String> randomMap(int minEntries, int maxEntries) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
int numIncludes = randomIntBetween(minEntries, maxEntries);
|
||||
|
@ -114,6 +128,9 @@ public class AllocateActionTests extends AbstractActionTestCase<AllocateAction>
|
|||
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(
|
||||
|
|
|
@ -17,7 +17,7 @@ public class AllocationRoutedStepInfoTests extends AbstractXContentTestCase<Allo
|
|||
|
||||
@Override
|
||||
protected Info createTestInstance() {
|
||||
return new Info(randomNonNegativeLong(), randomBoolean());
|
||||
return new Info(randomNonNegativeLong(), randomNonNegativeLong(), randomBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,23 +37,27 @@ public class AllocationRoutedStepInfoTests extends AbstractXContentTestCase<Allo
|
|||
}
|
||||
|
||||
protected final Info copyInstance(Info instance) throws IOException {
|
||||
return new Info(instance.getNumberShardsLeftToAllocate(), instance.allShardsActive());
|
||||
return new Info(instance.getActualReplicas(), instance.getNumberShardsLeftToAllocate(), instance.allShardsActive());
|
||||
}
|
||||
|
||||
protected Info mutateInstance(Info instance) throws IOException {
|
||||
long actualReplicas = instance.getActualReplicas();
|
||||
long shardsToAllocate = instance.getNumberShardsLeftToAllocate();
|
||||
boolean allShardsActive = instance.allShardsActive();
|
||||
switch (between(0, 1)) {
|
||||
switch (between(0, 2)) {
|
||||
case 0:
|
||||
shardsToAllocate += between(1, 20);
|
||||
break;
|
||||
case 1:
|
||||
allShardsActive = allShardsActive == false;
|
||||
break;
|
||||
case 2:
|
||||
actualReplicas += between(1, 20);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Illegal randomisation branch");
|
||||
}
|
||||
return new Info(shardsToAllocate, allShardsActive);
|
||||
return new Info(actualReplicas, shardsToAllocate, allShardsActive);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.node.Node;
|
|||
import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateWaitStep.Result;
|
||||
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class AllocationRoutedStepTests extends AbstractStepTestCase<AllocationRoutedStep> {
|
||||
|
@ -168,7 +169,7 @@ public class AllocationRoutedStepTests extends AbstractStepTestCase<AllocationRo
|
|||
|
||||
AllocationRoutedStep step = createRandomInstance();
|
||||
assertAllocateStatus(index, 2, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable,
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(1, true)));
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(0, 1, true)));
|
||||
}
|
||||
|
||||
public void testExecuteAllocateNotCompleteOnlyOneCopyAllocated() throws Exception {
|
||||
|
@ -204,7 +205,7 @@ public class AllocationRoutedStepTests extends AbstractStepTestCase<AllocationRo
|
|||
|
||||
AllocationRoutedStep step = new AllocationRoutedStep(randomStepKey(), randomStepKey(), true);
|
||||
assertAllocateStatus(index, 2, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable,
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(1, true)));
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(0, 1, true)));
|
||||
}
|
||||
|
||||
public void testExecuteAllocateUnassigned() throws Exception {
|
||||
|
@ -239,7 +240,46 @@ public class AllocationRoutedStepTests extends AbstractStepTestCase<AllocationRo
|
|||
|
||||
AllocationRoutedStep step = createRandomInstance();
|
||||
assertAllocateStatus(index, 2, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable,
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(-1, false)));
|
||||
new ClusterStateWaitStep.Result(false, new AllocationRoutedStep.Info(0, -1, false)));
|
||||
}
|
||||
|
||||
/**
|
||||
* this tests the scenario where
|
||||
*
|
||||
* PUT index
|
||||
* {
|
||||
* "settings": {
|
||||
* "number_of_replicas": 0,
|
||||
* "number_of_shards": 1
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* PUT index/_settings
|
||||
* {
|
||||
* "number_of_replicas": 1,
|
||||
* "index.routing.allocation.include._name": "{node-name}"
|
||||
* }
|
||||
*/
|
||||
public void testExecuteReplicasNotAllocatedOnSingleNode() {
|
||||
Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
|
||||
Map<String, String> 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 {
|
||||
|
|
|
@ -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<ReplicasAction> {
|
||||
|
||||
@Override
|
||||
protected ReplicasAction doParseInstance(XContentParser parser) {
|
||||
return ReplicasAction.parse(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReplicasAction createTestInstance() {
|
||||
return new ReplicasAction(randomIntBetween(0, 10));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reader<ReplicasAction> 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<Step> 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());
|
||||
}
|
||||
}
|
|
@ -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<ReplicasAllocatedStep.Info> {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<ReplicasAllocatedStep> {
|
||||
|
||||
@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());
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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<String, Object> 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<String, Object> 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);
|
||||
|
|
Loading…
Reference in New Issue