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:
Tal Levy 2018-08-08 11:43:29 -07:00 committed by GitHub
parent 2d925c9a9a
commit 2fc3f1d04c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 164 additions and 595 deletions

View File

@ -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" +

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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(

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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:

View File

@ -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);