use of org.opensearch.indices.cluster.ClusterStateChanges in project OpenSearch by opensearch-project.
the class FailedNodeRoutingTests method testRandomClusterPromotesNewestReplica.
public void testRandomClusterPromotesNewestReplica() throws InterruptedException {
ThreadPool threadPool = new TestThreadPool(getClass().getName());
ClusterStateChanges cluster = new ClusterStateChanges(xContentRegistry(), threadPool);
ClusterState state = randomInitialClusterState();
// randomly add nodes of mixed versions
logger.info("--> adding random nodes");
for (int i = 0; i < randomIntBetween(4, 8); i++) {
DiscoveryNodes newNodes = DiscoveryNodes.builder(state.nodes()).add(createNode()).build();
state = ClusterState.builder(state).nodes(newNodes).build();
// always reroute after adding node
state = cluster.reroute(state, new ClusterRerouteRequest());
}
// Log the node versions (for debugging if necessary)
for (ObjectCursor<DiscoveryNode> cursor : state.nodes().getDataNodes().values()) {
Version nodeVer = cursor.value.getVersion();
logger.info("--> node [{}] has version [{}]", cursor.value.getId(), nodeVer);
}
// randomly create some indices
logger.info("--> creating some indices");
for (int i = 0; i < randomIntBetween(2, 5); i++) {
String name = "index_" + randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
Settings.Builder settingsBuilder = Settings.builder().put(SETTING_NUMBER_OF_SHARDS, randomIntBetween(1, 4)).put(SETTING_NUMBER_OF_REPLICAS, randomIntBetween(2, 4));
CreateIndexRequest request = new CreateIndexRequest(name, settingsBuilder.build()).waitForActiveShards(ActiveShardCount.NONE);
state = cluster.createIndex(state, request);
assertTrue(state.metadata().hasIndex(name));
}
logger.info("--> starting shards");
state = cluster.applyStartedShards(state, state.getRoutingNodes().shardsWithState(INITIALIZING));
logger.info("--> starting replicas a random number of times");
for (int i = 0; i < randomIntBetween(1, 10); i++) {
state = cluster.applyStartedShards(state, state.getRoutingNodes().shardsWithState(INITIALIZING));
}
boolean keepGoing = true;
while (keepGoing) {
List<ShardRouting> primaries = state.getRoutingNodes().shardsWithState(STARTED).stream().filter(ShardRouting::primary).collect(Collectors.toList());
// Pick a random subset of primaries to fail
List<FailedShard> shardsToFail = new ArrayList<>();
List<ShardRouting> failedPrimaries = randomSubsetOf(primaries);
failedPrimaries.stream().forEach(sr -> {
shardsToFail.add(new FailedShard(randomFrom(sr), "failed primary", new Exception(), randomBoolean()));
});
logger.info("--> state before failing shards: {}", state);
state = cluster.applyFailedShards(state, shardsToFail);
final ClusterState compareState = state;
failedPrimaries.forEach(shardRouting -> {
logger.info("--> verifying version for {}", shardRouting);
ShardRouting newPrimary = compareState.routingTable().index(shardRouting.index()).shard(shardRouting.id()).primaryShard();
Version newPrimaryVersion = getNodeVersion(newPrimary, compareState);
logger.info("--> new primary is on version {}: {}", newPrimaryVersion, newPrimary);
compareState.routingTable().shardRoutingTable(newPrimary.shardId()).shardsWithState(STARTED).stream().forEach(sr -> {
Version candidateVer = getNodeVersion(sr, compareState);
if (candidateVer != null) {
logger.info("--> candidate on {} node; shard routing: {}", candidateVer, sr);
assertTrue("candidate was not on the newest version, new primary is on " + newPrimaryVersion + " and there is a candidate on " + candidateVer, candidateVer.onOrBefore(newPrimaryVersion));
}
});
});
keepGoing = randomBoolean();
}
terminate(threadPool);
}
use of org.opensearch.indices.cluster.ClusterStateChanges in project OpenSearch by opensearch-project.
the class TransportReplicationActionTests method testClosedIndexOnReroute.
public void testClosedIndexOnReroute() {
final String index = "test";
// no replicas in oder to skip the replication part
ClusterStateChanges clusterStateChanges = new ClusterStateChanges(xContentRegistry(), threadPool);
setState(clusterService, clusterStateChanges.closeIndices(clusterStateChanges.createIndex(clusterService.state(), new CreateIndexRequest(index)), new CloseIndexRequest(index)));
assertThat(clusterService.state().metadata().indices().get(index).getState(), equalTo(IndexMetadata.State.CLOSE));
logger.debug("--> using initial state:\n{}", clusterService.state());
Request request = new Request(new ShardId(clusterService.state().metadata().indices().get(index).getIndex(), 0)).timeout("1ms");
PlainActionFuture<TestResponse> listener = new PlainActionFuture<>();
ReplicationTask task = maybeTask();
TestAction action = new TestAction(Settings.EMPTY, "internal:testActionWithBlocks", transportService, clusterService, shardStateAction, threadPool);
TestAction.ReroutePhase reroutePhase = action.new ReroutePhase(task, request, listener);
reroutePhase.run();
assertListenerThrows("must throw index closed exception", listener, IndexClosedException.class);
assertPhase(task, "failed");
assertFalse(request.isRetrySet.get());
}
use of org.opensearch.indices.cluster.ClusterStateChanges in project OpenSearch by opensearch-project.
the class AutoExpandReplicasTests method testAutoExpandWhenNodeLeavesAndPossiblyRejoins.
/**
* Checks that when nodes leave the cluster that the auto-expand-replica functionality only triggers after failing the shards on
* the removed nodes. This ensures that active shards on other live nodes are not failed if the primary resided on a now dead node.
* Instead, one of the replicas on the live nodes first gets promoted to primary, and the auto-expansion (removing replicas) only
* triggers in a follow-up step.
*/
public void testAutoExpandWhenNodeLeavesAndPossiblyRejoins() throws InterruptedException {
final ThreadPool threadPool = new TestThreadPool(getClass().getName());
final ClusterStateChanges cluster = new ClusterStateChanges(xContentRegistry(), threadPool);
try {
List<DiscoveryNode> allNodes = new ArrayList<>();
// local node is the master
DiscoveryNode localNode = createNode(DiscoveryNodeRole.MASTER_ROLE);
allNodes.add(localNode);
int numDataNodes = randomIntBetween(3, 5);
List<DiscoveryNode> dataNodes = new ArrayList<>(numDataNodes);
for (int i = 0; i < numDataNodes; i++) {
dataNodes.add(createNode(DiscoveryNodeRole.DATA_ROLE));
}
allNodes.addAll(dataNodes);
ClusterState state = ClusterStateCreationUtils.state(localNode, localNode, allNodes.toArray(new DiscoveryNode[0]));
CreateIndexRequest request = new CreateIndexRequest("index", Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_AUTO_EXPAND_REPLICAS, "0-all").build()).waitForActiveShards(ActiveShardCount.NONE);
state = cluster.createIndex(state, request);
assertTrue(state.metadata().hasIndex("index"));
while (state.routingTable().index("index").shard(0).allShardsStarted() == false) {
logger.info(state);
state = cluster.applyStartedShards(state, state.routingTable().index("index").shard(0).shardsWithState(ShardRoutingState.INITIALIZING));
state = cluster.reroute(state, new ClusterRerouteRequest());
}
IndexShardRoutingTable preTable = state.routingTable().index("index").shard(0);
final Set<String> unchangedNodeIds;
final IndexShardRoutingTable postTable;
if (randomBoolean()) {
// simulate node removal
List<DiscoveryNode> nodesToRemove = randomSubsetOf(2, dataNodes);
unchangedNodeIds = dataNodes.stream().filter(n -> nodesToRemove.contains(n) == false).map(DiscoveryNode::getId).collect(Collectors.toSet());
state = cluster.removeNodes(state, nodesToRemove);
postTable = state.routingTable().index("index").shard(0);
assertTrue("not all shards started in " + state.toString(), postTable.allShardsStarted());
assertThat(postTable.toString(), postTable.getAllAllocationIds(), everyItem(is(in(preTable.getAllAllocationIds()))));
} else {
// fake an election where conflicting nodes are removed and readded
state = ClusterState.builder(state).nodes(DiscoveryNodes.builder(state.nodes()).masterNodeId(null).build()).build();
List<DiscoveryNode> conflictingNodes = randomSubsetOf(2, dataNodes);
unchangedNodeIds = dataNodes.stream().filter(n -> conflictingNodes.contains(n) == false).map(DiscoveryNode::getId).collect(Collectors.toSet());
List<DiscoveryNode> nodesToAdd = conflictingNodes.stream().map(n -> new DiscoveryNode(n.getName(), n.getId(), buildNewFakeTransportAddress(), n.getAttributes(), n.getRoles(), n.getVersion())).collect(Collectors.toList());
if (randomBoolean()) {
nodesToAdd.add(createNode(DiscoveryNodeRole.DATA_ROLE));
}
state = cluster.joinNodesAndBecomeMaster(state, nodesToAdd);
postTable = state.routingTable().index("index").shard(0);
}
Set<String> unchangedAllocationIds = preTable.getShards().stream().filter(shr -> unchangedNodeIds.contains(shr.currentNodeId())).map(shr -> shr.allocationId().getId()).collect(Collectors.toSet());
assertThat(postTable.toString(), unchangedAllocationIds, everyItem(is(in(postTable.getAllAllocationIds()))));
postTable.getShards().forEach(shardRouting -> {
if (shardRouting.assignedToNode() && unchangedAllocationIds.contains(shardRouting.allocationId().getId())) {
assertTrue("Shard should be active: " + shardRouting, shardRouting.active());
}
});
} finally {
terminate(threadPool);
}
}
use of org.opensearch.indices.cluster.ClusterStateChanges in project OpenSearch by opensearch-project.
the class AutoExpandReplicasTests method testOnlyAutoExpandAllocationFilteringAfterAllNodesUpgraded.
public void testOnlyAutoExpandAllocationFilteringAfterAllNodesUpgraded() {
final ThreadPool threadPool = new TestThreadPool(getClass().getName());
final ClusterStateChanges cluster = new ClusterStateChanges(xContentRegistry(), threadPool);
try {
List<DiscoveryNode> allNodes = new ArrayList<>();
DiscoveryNode oldNode = createNode(VersionUtils.randomVersionBetween(random(), LegacyESVersion.V_7_0_0, LegacyESVersion.V_7_5_1), DiscoveryNodeRole.MASTER_ROLE, DiscoveryNodeRole.DATA_ROLE);
// local node is the master
allNodes.add(oldNode);
ClusterState state = ClusterStateCreationUtils.state(oldNode, oldNode, allNodes.toArray(new DiscoveryNode[0]));
CreateIndexRequest request = new CreateIndexRequest("index", Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_AUTO_EXPAND_REPLICAS, "0-all").build()).waitForActiveShards(ActiveShardCount.NONE);
state = cluster.createIndex(state, request);
assertTrue(state.metadata().hasIndex("index"));
while (state.routingTable().index("index").shard(0).allShardsStarted() == false) {
logger.info(state);
state = cluster.applyStartedShards(state, state.routingTable().index("index").shard(0).shardsWithState(ShardRoutingState.INITIALIZING));
state = cluster.reroute(state, new ClusterRerouteRequest());
}
// local
DiscoveryNode newNode = createNode(LegacyESVersion.V_7_6_0, DiscoveryNodeRole.MASTER_ROLE, DiscoveryNodeRole.DATA_ROLE);
// node
// is
// the
// master
state = cluster.addNodes(state, Collections.singletonList(newNode));
// use allocation filtering
state = cluster.updateSettings(state, new UpdateSettingsRequest("index").settings(Settings.builder().put(IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + "._name", oldNode.getName()).build()));
while (state.routingTable().index("index").shard(0).allShardsStarted() == false) {
logger.info(state);
state = cluster.applyStartedShards(state, state.routingTable().index("index").shard(0).shardsWithState(ShardRoutingState.INITIALIZING));
state = cluster.reroute(state, new ClusterRerouteRequest());
}
// check that presence of old node means that auto-expansion does not take allocation filtering into account
assertThat(state.routingTable().index("index").shard(0).size(), equalTo(2));
// remove old node and check that auto-expansion takes allocation filtering into account
state = cluster.removeNodes(state, Collections.singletonList(oldNode));
assertThat(state.routingTable().index("index").shard(0).size(), equalTo(1));
} finally {
terminate(threadPool);
}
}
Aggregations