Adds tests for AllocateAction and its steps

Also tweaks some of the code in the steps of the allocate action
This commit is contained in:
Colin Goodheart-Smithe 2018-04-09 13:59:25 +01:00
parent 47ed2e5b23
commit 2eb8fd9336
9 changed files with 400 additions and 439 deletions

View File

@ -7,15 +7,11 @@ package org.elasticsearch.xpack.core.indexlifecycle;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -50,9 +46,6 @@ public class AllocateAction implements LifecycleAction {
private final Map<String, String> include; private final Map<String, String> include;
private final Map<String, String> exclude; private final Map<String, String> exclude;
private final Map<String, String> require; private final Map<String, String> require;
private static final AllocationDeciders ALLOCATION_DECIDERS = new AllocationDeciders(Settings.EMPTY,
Collections.singletonList(new FilterAllocationDecider(Settings.EMPTY,
new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS))));
public static AllocateAction parse(XContentParser parser) { public static AllocateAction parse(XContentParser parser) {
return PARSER.apply(parser, null); return PARSER.apply(parser, null);
@ -124,12 +117,12 @@ public class AllocateAction implements LifecycleAction {
@Override @Override
public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) { public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
StepKey enoughKey = new StepKey(phase, NAME, "enough-shards-allocated"); StepKey enoughKey = new StepKey(phase, NAME, EnoughShardsWaitStep.NAME);
StepKey allocateKey = new StepKey(phase, NAME, "update-allocation"); StepKey allocateKey = new StepKey(phase, NAME, UpdateAllocationSettingsStep.NAME);
StepKey allocationRoutedKey = new StepKey(phase, NAME, "check-allocation"); StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME);
UpdateAllocationSettingsStep allocateStep = new UpdateAllocationSettingsStep(allocateKey, allocationRoutedKey, UpdateAllocationSettingsStep allocateStep = new UpdateAllocationSettingsStep(allocateKey, allocationRoutedKey,
include, exclude, require); include, exclude, require);
AllocationRoutedStep routedCheckStep = new AllocationRoutedStep(allocationRoutedKey, nextStepKey, ALLOCATION_DECIDERS); AllocationRoutedStep routedCheckStep = new AllocationRoutedStep(allocationRoutedKey, nextStepKey);
return Arrays.asList(new EnoughShardsWaitStep(enoughKey, allocateKey), allocateStep, routedCheckStep); return Arrays.asList(new EnoughShardsWaitStep(enoughKey, allocateKey), allocateStep, routedCheckStep);
} }

View File

@ -6,46 +6,65 @@
package org.elasticsearch.xpack.core.indexlifecycle; package org.elasticsearch.xpack.core.indexlifecycle;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.allocation.RoutingAllocation; import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders; import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
import org.elasticsearch.cluster.routing.allocation.decider.Decision; import org.elasticsearch.cluster.routing.allocation.decider.Decision;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import java.util.Collections;
import java.util.List; import java.util.List;
public class AllocationRoutedStep extends ClusterStateWaitStep { public class AllocationRoutedStep extends ClusterStateWaitStep {
public static final String NAME = "check-allocation";
private static final Logger logger = ESLoggerFactory.getLogger(AllocationRoutedStep.class); private static final Logger logger = ESLoggerFactory.getLogger(AllocationRoutedStep.class);
private AllocationDeciders allocationDeciders; private static final AllocationDeciders ALLOCATION_DECIDERS = new AllocationDeciders(Settings.EMPTY, Collections.singletonList(
new FilterAllocationDecider(Settings.EMPTY, new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS))));
AllocationRoutedStep(StepKey key, StepKey nextStepKey, AllocationDeciders allocationDeciders) { AllocationRoutedStep(StepKey key, StepKey nextStepKey) {
super(key, nextStepKey); super(key, nextStepKey);
this.allocationDeciders = allocationDeciders;
} }
@Override @Override
public boolean isConditionMet(Index index, ClusterState clusterState) { public boolean isConditionMet(Index index, ClusterState clusterState) {
// All the allocation attributes are already set so just need to check if the allocation has happened if (ActiveShardCount.ALL.enoughShardsActive(clusterState, index.getName()) == false) {
RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, clusterState.getRoutingNodes(), clusterState, null, logger.debug("[{}] lifecycle action for index [{}] cannot make progress because not all shards are active",
System.nanoTime()); getKey().getAction(), index.getName());
return false;
}
IndexMetaData idxMeta = clusterState.metaData().index(index);
if (idxMeta == null) {
throw new IndexNotFoundException("Index not found when executing " + getKey().getAction() + " lifecycle action.",
index.getName());
}
// All the allocation attributes are already set so just need to check
// if the allocation has happened
RoutingAllocation allocation = new RoutingAllocation(ALLOCATION_DECIDERS, clusterState.getRoutingNodes(), clusterState, null,
System.nanoTime());
int allocationPendingShards = 0; int allocationPendingShards = 0;
List<ShardRouting> allShards = clusterState.getRoutingTable().allShards(index.getName()); List<ShardRouting> allShards = clusterState.getRoutingTable().allShards(index.getName());
for (ShardRouting shardRouting : allShards) { for (ShardRouting shardRouting : allShards) {
assert shardRouting.active() : "Shard not active, found " + shardRouting.state() + "for shard with id: "
+ shardRouting.shardId();
String currentNodeId = shardRouting.currentNodeId(); String currentNodeId = shardRouting.currentNodeId();
boolean canRemainOnCurrentNode = allocationDeciders.canRemain(shardRouting, boolean canRemainOnCurrentNode = ALLOCATION_DECIDERS
clusterState.getRoutingNodes().node(currentNodeId), allocation).type() == Decision.Type.YES; .canRemain(shardRouting, clusterState.getRoutingNodes().node(currentNodeId), allocation).type() == Decision.Type.YES;
if (canRemainOnCurrentNode == false) { if (canRemainOnCurrentNode == false) {
allocationPendingShards++; allocationPendingShards++;
} }
} }
if (allocationPendingShards > 0) { if (allocationPendingShards > 0) {
logger.debug("[{}] lifecycle action for index [{}] waiting for [{}] shards " logger.debug(
+ "to be allocated to nodes matching the given filters", getKey().getAction(), index, allocationPendingShards); "[{}] lifecycle action for index [{}] waiting for [{}] shards " + "to be allocated to nodes matching the given filters",
getKey().getAction(), index, allocationPendingShards);
return false; return false;
} else { } else {
logger.debug("[{}] lifecycle action for index [{}] complete", getKey().getAction(), index); logger.debug("[{}] lifecycle action for index [{}] complete", getKey().getAction(), index);

View File

@ -10,6 +10,8 @@ import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
public class EnoughShardsWaitStep extends ClusterStateWaitStep { public class EnoughShardsWaitStep extends ClusterStateWaitStep {
public static final String NAME = "enough-shards-allocated";
public EnoughShardsWaitStep(StepKey key, StepKey nextStepKey) { public EnoughShardsWaitStep(StepKey key, StepKey nextStepKey) {
super(key, nextStepKey); super(key, nextStepKey);
} }

View File

@ -42,7 +42,8 @@ public abstract class Step {
return false; return false;
} }
Step other = (Step) obj; Step other = (Step) obj;
return Objects.equals(key, other.key) && Objects.equals(nextStepKey, other.nextStepKey); return Objects.equals(key, other.key) &&
Objects.equals(nextStepKey, other.nextStepKey);
} }
@Override @Override
@ -87,7 +88,9 @@ public abstract class Step {
return false; return false;
} }
StepKey other = (StepKey) obj; StepKey other = (StepKey) obj;
return Objects.equals(phase, other.phase) && Objects.equals(action, other.action) && Objects.equals(name, other.name); return Objects.equals(phase, other.phase) &&
Objects.equals(action, other.action) &&
Objects.equals(name, other.name);
} }
@Override @Override

View File

@ -12,8 +12,11 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import java.util.Map; import java.util.Map;
import java.util.Objects;
public class UpdateAllocationSettingsStep extends ClusterStateActionStep { public class UpdateAllocationSettingsStep extends ClusterStateActionStep {
public static final String NAME = "update-allocation";
private final Map<String, String> include; private final Map<String, String> include;
private final Map<String, String> exclude; private final Map<String, String> exclude;
private final Map<String, String> require; private final Map<String, String> require;
@ -54,4 +57,36 @@ public class UpdateAllocationSettingsStep extends ClusterStateActionStep {
return existingValue == null || (existingValue.equals(e.getValue()) == false); return existingValue == null || (existingValue.equals(e.getValue()) == false);
}).forEach(e -> newSettingsBuilder.put(settingPrefix + e.getKey(), e.getValue())); }).forEach(e -> newSettingsBuilder.put(settingPrefix + e.getKey(), e.getValue()));
} }
Map<String, String> getInclude() {
return include;
}
Map<String, String> getExclude() {
return exclude;
}
Map<String, String> getRequire() {
return require;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), include, exclude, require);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UpdateAllocationSettingsStep other = (UpdateAllocationSettingsStep) obj;
return super.equals(obj) &&
Objects.equals(include, other.include) &&
Objects.equals(exclude, other.exclude) &&
Objects.equals(require, other.require);
}
} }

View File

@ -5,39 +5,15 @@
*/ */
package org.elasticsearch.xpack.core.indexlifecycle; package org.elasticsearch.xpack.core.indexlifecycle;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.Version;
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.cluster.routing.UnassignedInfo;
import org.elasticsearch.cluster.routing.UnassignedInfo.Reason;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.AbstractSerializingTestCase; import org.elasticsearch.test.AbstractSerializingTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer;
import static org.hamcrest.Matchers.instanceOf;
public class AllocateActionTests extends AbstractSerializingTestCase<AllocateAction> { public class AllocateActionTests extends AbstractSerializingTestCase<AllocateAction> {
@ -112,371 +88,7 @@ public class AllocateActionTests extends AbstractSerializingTestCase<AllocateAct
+ "must contain attributes for action " + AllocateAction.NAME, exception.getMessage()); + "must contain attributes for action " + AllocateAction.NAME, exception.getMessage());
} }
// public void testExecuteNoExistingSettings() throws Exception { public static Map<String, String> randomMap(int minEntries, int maxEntries) {
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// Settings.Builder existingSettings = Settings.builder().put("index.version.created", Version.CURRENT.id);
// Settings.Builder expectedSettings = Settings.builder();
// includes.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v));
// excludes.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v));
// requires.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v));
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// assertSettingsUpdate(action, existingSettings, expectedSettings.build());
// }
//
// public void testExecuteSettingsUnassignedShards() throws Exception {
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// Settings.Builder existingSettings = Settings.builder().put("index.version.created", Version.CURRENT.id);
// Settings.Builder expectedSettings = Settings.builder();
// includes.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v));
// excludes.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v));
// requires.forEach((k, v) -> expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v));
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// assertSettingsUpdate(action, existingSettings, expectedSettings.build());
// }
//
// public void testExecuteSomeExistingSettings() throws Exception {
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// Settings.Builder existingSettings = Settings.builder().put("index.version.created", Version.CURRENT.id);
// Settings.Builder expectedSettings = Settings.builder();
// includes.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// }
// });
// excludes.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// }
// });
// requires.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// }
// });
//
// // make sure there is at least one setting that is missing
// if (expectedSettings.keys().isEmpty()) {
// String key = randomAlphaOfLengthBetween(1, 20);
// String value = randomAlphaOfLengthBetween(1, 20);
// includes.put(key, value);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value);
// }
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// assertSettingsUpdate(action, existingSettings, expectedSettings.build());
// }
//
// public void testExecuteSomeExistingSettingsDifferentValue() throws Exception {
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// Settings.Builder existingSettings = Settings.builder().put("index.version.created", Version.CURRENT.id);
// Settings.Builder expectedSettings = Settings.builder();
// includes.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v + randomAlphaOfLength(4));
// }
// });
// excludes.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v + randomAlphaOfLength(4));
// }
// });
// requires.forEach((k, v) -> {
// if (randomBoolean()) {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// } else {
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v + randomAlphaOfLength(4));
// }
// });
//
// // make sure there is at least one setting that is different
// if (expectedSettings.keys().isEmpty()) {
// String key = randomAlphaOfLengthBetween(1, 20);
// String value = randomAlphaOfLengthBetween(1, 20);
// includes.put(key, value);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value);
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + key, value + randomAlphaOfLength(4));
// }
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// assertSettingsUpdate(action, existingSettings, expectedSettings.build());
// }
//
// public void testExecuteUpdateSettingsFail() throws Exception {
// Settings expectedSettings = Settings.builder().put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + "box_type", "foo")
// .put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + "box_type", "bar")
// .put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "box_type", "baz").build();
// IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLengthBetween(1, 20))
// .settings(Settings.builder().put("index.version.created", Version.CURRENT.id)).numberOfShards(randomIntBetween(1, 5))
// .numberOfReplicas(randomIntBetween(0, 5)).build();
// Index index = indexMetadata.getIndex();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(index).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true, ShardRoutingState.STARTED)))
// .build())
// .build();
// Exception exception = new RuntimeException();
//
// BiConsumer<Settings, Listener> settingsUpdater = (s, l) -> {
// assertEquals(expectedSettings, s);
// l.onFailure(exception);
// };
//
// Map<String, String> includes = new HashMap<>();
// includes.put("box_type", "foo");
// Map<String, String> excludes = new HashMap<>();
// excludes.put("box_type", "bar");
// Map<String, String> requires = new HashMap<>();
// requires.put("box_type", "baz");
//
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// RuntimeException thrownException =
// expectActionFailure(index, clusterState, null, action, settingsUpdater, RuntimeException.class);
// assertSame(exception, thrownException);
//
// }
//
// public void testExecuteAllocateComplete() throws Exception {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// 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();
// includes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
// });
// excludes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// });
// requires.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
// });
//
// IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(index)
// .addShard(TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true, ShardRoutingState.STARTED));
//
// AllocateAction action = new AllocateAction(includes, excludes, requires);
// assertAllocateStatus(index, 1, 0, action, existingSettings, node1Settings, node2Settings, indexRoutingTable,
// true);
// }
//
// public void testExecuteAllocateNotComplete() throws Exception {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// 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();
// includes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
// });
// excludes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// });
// requires.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.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, 1), "node2", true, ShardRoutingState.STARTED));
//
// AllocateAction action = new AllocateAction(includes, excludes, requires);
// assertAllocateStatus(index, 2, 0, action, existingSettings, node1Settings, node2Settings, indexRoutingTable,
// false);
// }
//
// public void testExecuteAllocateUnassigned() throws Exception {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Map<String, String> includes = randomMap(1, 5);
// Map<String, String> excludes = randomMap(1, 5);
// Map<String, String> requires = randomMap(1, 5);
// 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();
// includes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
// });
// excludes.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
// });
// requires.forEach((k, v) -> {
// existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
// node1Settings.put(Node.NODE_ATTRIBUTES.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, 1), null, null, true, ShardRoutingState.UNASSIGNED,
// new UnassignedInfo(randomFrom(Reason.values()), "the shard is intentionally unassigned")));
//
// AllocateAction action = new AllocateAction(includes, excludes, requires);
// assertAllocateStatus(index, 2, 0, action, existingSettings, node1Settings, node2Settings, indexRoutingTable,
// false);
// }
//
// public void testExecuteIndexMissing() throws Exception {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).build();
//
// BiConsumer<Settings, Listener> settingsUpdater = (s, l) -> {
// throw new AssertionError("Unexpected settings update");
// };
//
// Map<String, String> includes = new HashMap<>();
// includes.put("box_type", "foo");
// Map<String, String> excludes = new HashMap<>();
// excludes.put("box_type", "bar");
// Map<String, String> requires = new HashMap<>();
// requires.put("box_type", "baz");
//
// AllocateAction action = new AllocateAction(includes, excludes, requires);
//
// IndexNotFoundException thrownException = expectActionFailure(index, clusterState, null, action, settingsUpdater,
// IndexNotFoundException.class);
// assertEquals("Index not found when executing " + AllocateAction.NAME + " lifecycle action.", thrownException.getMessage());
// assertEquals(index.getName(), thrownException.getIndex().getName());
// }
//
// private void assertSettingsUpdate(AllocateAction action, Settings.Builder existingSettings, Settings expectedSettings) {
// IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLengthBetween(1, 20)).settings(existingSettings)
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// Index index = indexMetadata.getIndex();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(index).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true, ShardRoutingState.STARTED)))
// .build())
// .build();
//
// BiConsumer<Settings, Listener> settingsUpdater = (s, l) -> {
// assertEquals(expectedSettings, s);
// l.onSuccess(false);
// };
// assertActionStatus(index, clusterState, null, action, settingsUpdater, false);
// }
//
// private void assertAllocateStatus(Index index, int shards, int replicas, AllocateAction action, Settings.Builder existingSettings,
// Settings.Builder node1Settings, Settings.Builder node2Settings, IndexRoutingTable.Builder indexRoutingTable,
// boolean expectComplete) {
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()).settings(existingSettings).numberOfShards(shards)
// .numberOfReplicas(replicas).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
//
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .nodes(DiscoveryNodes.builder()
// .add(DiscoveryNode.createLocal(node1Settings.build(), new TransportAddress(TransportAddress.META_ADDRESS, 9200),
// "node1"))
// .add(DiscoveryNode.createLocal(node2Settings.build(), new TransportAddress(TransportAddress.META_ADDRESS, 9201),
// "node2")))
// .routingTable(RoutingTable.builder().add(indexRoutingTable).build()).build();
// ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY,
// Sets.newHashSet(FilterAllocationDecider.CLUSTER_ROUTING_INCLUDE_GROUP_SETTING,
// FilterAllocationDecider.CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING,
// FilterAllocationDecider.CLUSTER_ROUTING_REQUIRE_GROUP_SETTING));
//
// BiConsumer<Settings, Listener> settingsUpdater = (s, l) -> {
// throw new AssertionError("Unexpected settings update");
// };
//
// assertActionStatus(index, clusterState, clusterSettings, action, settingsUpdater, expectComplete);
// }
//
// private void assertActionStatus(Index index, ClusterState clusterState, ClusterSettings clusterSettings, AllocateAction action,
// BiConsumer<Settings, Listener> settingsUpdater, boolean expectComplete) {
//
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// action.execute(index, settingsUpdater, clusterState, clusterSettings, new Listener() {
//
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call");
// }
// });
//
// assertEquals(expectComplete, actionCompleted.get());
// }
//
// private <E> E expectActionFailure(Index index, ClusterState clusterState, ClusterSettings clusterSettings, AllocateAction action,
// BiConsumer<Settings, Listener> settingsUpdater, Class<E> expectedExceptionType) {
//
// SetOnce<E> exceptionThrown = new SetOnce<>();
// action.execute(index, settingsUpdater, clusterState, clusterSettings, new Listener() {
//
// @Override
// public void onSuccess(boolean completed) {
// throw new AssertionError("Unexpected method call");
// }
//
// @SuppressWarnings("unchecked")
// @Override
// public void onFailure(Exception e) {
// assertThat(e, instanceOf(expectedExceptionType));
// exceptionThrown.set((E) e);
// }
// });
//
// return exceptionThrown.get();
// }
private Map<String, String> randomMap(int minEntries, int maxEntries) {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
int numIncludes = randomIntBetween(minEntries, maxEntries); int numIncludes = randomIntBetween(minEntries, maxEntries);
for (int i = 0; i < numIncludes; i++) { for (int i = 0; i < numIncludes; i++) {
@ -485,4 +97,29 @@ public class AllocateActionTests extends AbstractSerializingTestCase<AllocateAct
return map; return map;
} }
public void testToSteps() {
AllocateAction 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(3, steps.size());
StepKey expectedFirstStepKey = new StepKey(phase, AllocateAction.NAME, EnoughShardsWaitStep.NAME);
StepKey expectedSecondStepKey = new StepKey(phase, AllocateAction.NAME, UpdateAllocationSettingsStep.NAME);
StepKey expectedThirdStepKey = new StepKey(phase, AllocateAction.NAME, AllocationRoutedStep.NAME);
EnoughShardsWaitStep firstStep = (EnoughShardsWaitStep) steps.get(0);
assertEquals(expectedFirstStepKey, firstStep.getKey());
assertEquals(expectedSecondStepKey, firstStep.getNextStepKey());
UpdateAllocationSettingsStep secondStep = (UpdateAllocationSettingsStep) steps.get(1);
assertEquals(expectedSecondStepKey, secondStep.getKey());
assertEquals(expectedThirdStepKey, secondStep.getNextStepKey());
assertEquals(action.getInclude(), secondStep.getInclude());
assertEquals(action.getExclude(), secondStep.getExclude());
assertEquals(action.getRequire(), secondStep.getRequire());
AllocationRoutedStep thirdStep = (AllocationRoutedStep) steps.get(2);
assertEquals(expectedThirdStepKey, thirdStep.getKey());
assertEquals(nextStepKey, thirdStep.getNextStepKey());
}
} }

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.core.indexlifecycle; package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
@ -13,22 +14,166 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.routing.RoutingTable;
import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider; import org.elasticsearch.cluster.routing.ShardRoutingState;
import org.elasticsearch.cluster.routing.TestShardRouting;
import org.elasticsearch.cluster.routing.UnassignedInfo;
import org.elasticsearch.cluster.routing.UnassignedInfo.Reason;
import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.util.Map;
public class AllocationRoutedStepTests extends ESTestCase { public class AllocationRoutedStepTests extends ESTestCase {
public void testCanStay() { public AllocationRoutedStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
return new AllocationRoutedStep(stepKey, nextStepKey);
} }
private void assertAllocateStatus(Index index, int shards, int replicas, AllocateAction action, Settings.Builder existingSettings, public AllocationRoutedStep mutateInstance(AllocationRoutedStep instance) {
StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey();
switch (between(0, 1)) {
case 0:
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 1:
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new AllocationRoutedStep(key, nextKey);
}
public void testHashcodeAndEquals() {
EqualsHashCodeTestUtils.checkEqualsAndHashCode(createRandomInstance(),
instance -> new AllocationRoutedStep(instance.getKey(), instance.getNextStepKey()), this::mutateInstance);
}
public void testConditionMet() {
Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
Map<String, String> includes = AllocateActionTests.randomMap(1, 5);
Map<String, String> excludes = AllocateActionTests.randomMap(1, 5);
Map<String, String> requires = AllocateActionTests.randomMap(1, 5);
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();
includes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
});
excludes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
});
requires.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
});
IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(index)
.addShard(TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true, ShardRoutingState.STARTED));
AllocationRoutedStep step = createRandomInstance();
assertAllocateStatus(index, 1, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable, true);
}
public void testExecuteAllocateNotComplete() throws Exception {
Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
Map<String, String> includes = AllocateActionTests.randomMap(1, 5);
Map<String, String> excludes = AllocateActionTests.randomMap(1, 5);
Map<String, String> requires = AllocateActionTests.randomMap(1, 5);
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();
includes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
});
excludes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
});
requires.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.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, 1), "node2", true, ShardRoutingState.STARTED));
AllocationRoutedStep step = createRandomInstance();
assertAllocateStatus(index, 2, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable, false);
}
public void testExecuteAllocateUnassigned() throws Exception {
Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
Map<String, String> includes = AllocateActionTests.randomMap(1, 5);
Map<String, String> excludes = AllocateActionTests.randomMap(1, 5);
Map<String, String> requires = AllocateActionTests.randomMap(1, 5);
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();
includes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.getKey() + k, v);
});
excludes.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + k, v);
});
requires.forEach((k, v) -> {
existingSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
expectedSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + k, v);
node1Settings.put(Node.NODE_ATTRIBUTES.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, 1), null, null, true, ShardRoutingState.UNASSIGNED,
new UnassignedInfo(randomFrom(Reason.values()), "the shard is intentionally unassigned")));
AllocationRoutedStep step = createRandomInstance();
assertAllocateStatus(index, 2, 0, step, existingSettings, node1Settings, node2Settings, indexRoutingTable, false);
}
public void testExecuteIndexMissing() throws Exception {
Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).build();
AllocationRoutedStep 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());
}
private void assertAllocateStatus(Index index, int shards, int replicas, AllocationRoutedStep step, Settings.Builder existingSettings,
Settings.Builder node1Settings, Settings.Builder node2Settings, Settings.Builder node1Settings, Settings.Builder node2Settings,
IndexRoutingTable.Builder indexRoutingTable, boolean expectComplete) { IndexRoutingTable.Builder indexRoutingTable, boolean expectComplete) {
IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()).settings(existingSettings).numberOfShards(shards) IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()).settings(existingSettings).numberOfShards(shards)
@ -43,9 +188,6 @@ public class AllocationRoutedStepTests extends ESTestCase {
.add(DiscoveryNode.createLocal(node2Settings.build(), new TransportAddress(TransportAddress.META_ADDRESS, 9201), .add(DiscoveryNode.createLocal(node2Settings.build(), new TransportAddress(TransportAddress.META_ADDRESS, 9201),
"node2"))) "node2")))
.routingTable(RoutingTable.builder().add(indexRoutingTable).build()).build(); .routingTable(RoutingTable.builder().add(indexRoutingTable).build()).build();
ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, assertEquals(expectComplete, step.isConditionMet(index, clusterState));
Sets.newHashSet(FilterAllocationDecider.CLUSTER_ROUTING_INCLUDE_GROUP_SETTING,
FilterAllocationDecider.CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING,
FilterAllocationDecider.CLUSTER_ROUTING_REQUIRE_GROUP_SETTING));
} }
} }

View File

@ -6,6 +6,8 @@
package org.elasticsearch.xpack.core.indexlifecycle; package org.elasticsearch.xpack.core.indexlifecycle;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
@ -22,9 +24,42 @@ import org.elasticsearch.index.Index;
import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
@Repeat(iterations = 1000, useConstantSeed = false)
public class EnoughShardsWaitStepTests extends ESTestCase { public class EnoughShardsWaitStepTests extends ESTestCase {
public EnoughShardsWaitStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
return new EnoughShardsWaitStep(stepKey, nextStepKey);
}
public EnoughShardsWaitStep mutateInstance(EnoughShardsWaitStep instance) {
StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey();
switch (between(0, 1)) {
case 0:
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 1:
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new EnoughShardsWaitStep(key, nextKey);
}
public void testHashcodeAndEquals() {
EqualsHashCodeTestUtils.checkEqualsAndHashCode(createRandomInstance(),
instance -> new EnoughShardsWaitStep(instance.getKey(), instance.getNextStepKey()), this::mutateInstance);
}
public void testConditionMet() { public void testConditionMet() {
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5)) IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT)) .settings(settings(Version.CURRENT))
@ -51,7 +86,7 @@ public class EnoughShardsWaitStepTests extends ESTestCase {
.build()) .build())
.build(); .build();
EnoughShardsWaitStep step = new EnoughShardsWaitStep(null, null); EnoughShardsWaitStep step = createRandomInstance();
assertTrue(step.isConditionMet(indexMetadata.getIndex(), clusterState)); assertTrue(step.isConditionMet(indexMetadata.getIndex(), clusterState));
} }
@ -81,7 +116,7 @@ public class EnoughShardsWaitStepTests extends ESTestCase {
.build()) .build())
.build(); .build();
EnoughShardsWaitStep step = new EnoughShardsWaitStep(null, null); EnoughShardsWaitStep step = createRandomInstance();
assertFalse(step.isConditionMet(indexMetadata.getIndex(), clusterState)); assertFalse(step.isConditionMet(indexMetadata.getIndex(), clusterState));
} }
} }

View File

@ -14,8 +14,11 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -24,7 +27,57 @@ import static org.hamcrest.Matchers.equalTo;
public class UpdateAllocationSettingsStepTests extends ESTestCase { public class UpdateAllocationSettingsStepTests extends ESTestCase {
public void testModify() { public UpdateAllocationSettingsStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
Map<String, String> include = AllocateActionTests.randomMap(0, 10);
Map<String, String> exclude = AllocateActionTests.randomMap(0, 10);
Map<String, String> require = AllocateActionTests.randomMap(0, 10);
return new UpdateAllocationSettingsStep(stepKey, nextStepKey, include, exclude, require);
}
public UpdateAllocationSettingsStep mutateInstance(UpdateAllocationSettingsStep instance) {
StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey();
Map<String, String> include = instance.getInclude();
Map<String, String> exclude = instance.getExclude();
Map<String, String> require = instance.getRequire();
switch (between(0, 4)) {
case 0:
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 1:
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 2:
include = new HashMap<>(include);
include.put(randomAlphaOfLengthBetween(11, 15), randomAlphaOfLengthBetween(1, 20));
break;
case 3:
exclude = new HashMap<>(exclude);
exclude.put(randomAlphaOfLengthBetween(11, 15), randomAlphaOfLengthBetween(1, 20));
break;
case 4:
require = new HashMap<>(require);
require.put(randomAlphaOfLengthBetween(11, 15), randomAlphaOfLengthBetween(1, 20));
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new UpdateAllocationSettingsStep(key, nextKey, include, exclude, require);
}
public void testHashcodeAndEquals() {
EqualsHashCodeTestUtils.checkEqualsAndHashCode(createRandomInstance(),
instance -> new UpdateAllocationSettingsStep(instance.getKey(), instance.getNextStepKey(), instance.getInclude(),
instance.getExclude(), instance.getRequire()),
this::mutateInstance);
}
public void testPerformAction() {
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5)) IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT)) .settings(settings(Version.CURRENT))
.numberOfShards(1) .numberOfShards(1)
@ -36,18 +89,21 @@ public class UpdateAllocationSettingsStepTests extends ESTestCase {
Index index = indexMetadata.getIndex(); Index index = indexMetadata.getIndex();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build(); ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
Map<String, String> include = UpdateAllocationSettingsStep step = createRandomInstance();
randomBoolean() ? Collections.singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5)) : Collections.emptyMap();
Map<String, String> exclude =
randomBoolean() ? Collections.singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5)) : Collections.emptyMap();
Map<String, String> require =
randomBoolean() ? Collections.singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5)) : Collections.emptyMap();
UpdateAllocationSettingsStep step = new UpdateAllocationSettingsStep(null, null, include, exclude, require);
ClusterState newState = step.performAction(index, clusterState); ClusterState newState = step.performAction(index, clusterState);
assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey()), equalTo(include)); assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey()), equalTo(step.getInclude()));
assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey()), equalTo(exclude)); assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey()), equalTo(step.getExclude()));
assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey()), equalTo(require)); assertThat(getRouting(index, newState, IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey()), equalTo(step.getRequire()));
}
public void testPerformActionNoIndex() {
MetaData metaData = MetaData.builder().persistentSettings(settings(Version.CURRENT).build()).build();
Index index = new Index("invalid_index", "invalid_index_id");
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
UpdateAllocationSettingsStep step = createRandomInstance();
ClusterState newState = step.performAction(index, clusterState);
assertSame(clusterState, newState);
} }
public void testAddMissingAttr() { public void testAddMissingAttr() {
@ -67,6 +123,45 @@ public class UpdateAllocationSettingsStepTests extends ESTestCase {
assertThat(newSettingsBuilder.build(), equalTo(expectedSettingsBuilder.build())); assertThat(newSettingsBuilder.build(), equalTo(expectedSettingsBuilder.build()));
} }
public void testAddMissingAttrDiffenerentValue() {
String prefix = randomFrom(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey(),
IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey(),
IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey());
String newKey = randomAlphaOfLength(4);
String newValue = randomAlphaOfLength(5);
Map<String, String> newAttrs = Collections.singletonMap(newKey, newValue);
Settings existingSettings = Settings.builder()
.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + "box_type", "foo")
.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + "box_type", "bar")
.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "box_type", "baz")
.put(prefix + newKey, "1234").build();
Settings.Builder newSettingsBuilder = Settings.builder();
UpdateAllocationSettingsStep.addMissingAttrs(newAttrs, prefix, existingSettings, newSettingsBuilder);
Settings.Builder expectedSettingsBuilder = Settings.builder();
newAttrs.forEach((k, v) -> expectedSettingsBuilder.put(prefix + k, v));
assertThat(newSettingsBuilder.build(), equalTo(expectedSettingsBuilder.build()));
}
public void testAddMissingAttrNoneMissing() {
String prefix = randomFrom(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey(),
IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey(),
IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey());
String newKey = randomAlphaOfLength(4);
String newValue = randomAlphaOfLength(5);
Map<String, String> newAttrs = Collections.singletonMap(newKey, newValue);
Settings existingSettings = Settings.builder()
.put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_SETTING.getKey() + "box_type", "foo")
.put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey() + "box_type", "bar")
.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "box_type", "baz")
.put(prefix + newKey, newValue).build();
Settings.Builder newSettingsBuilder = Settings.builder();
UpdateAllocationSettingsStep.addMissingAttrs(newAttrs, prefix, existingSettings, newSettingsBuilder);
Settings.Builder expectedSettingsBuilder = Settings.builder();
assertThat(newSettingsBuilder.build(), equalTo(expectedSettingsBuilder.build()));
}
private Map<String, String> getRouting(Index index, ClusterState clusterState, String settingPrefix) { private Map<String, String> getRouting(Index index, ClusterState clusterState, String settingPrefix) {
Settings includeSettings = clusterState.metaData().index(index).getSettings() Settings includeSettings = clusterState.metaData().index(index).getSettings()
.getByPrefix(settingPrefix); .getByPrefix(settingPrefix);