|
17 | 17 | import org.elasticsearch.cluster.metadata.IndexMetadata;
|
18 | 18 | import org.elasticsearch.cluster.metadata.Metadata;
|
19 | 19 | import org.elasticsearch.cluster.node.DiscoveryNodes;
|
| 20 | +import org.elasticsearch.cluster.routing.RoutingNode; |
20 | 21 | import org.elasticsearch.cluster.routing.RoutingTable;
|
21 | 22 | import org.elasticsearch.cluster.routing.ShardRouting;
|
22 | 23 | import org.elasticsearch.cluster.routing.ShardRoutingState;
|
23 | 24 | import org.elasticsearch.cluster.routing.allocation.command.AllocationCommands;
|
24 | 25 | import org.elasticsearch.cluster.routing.allocation.command.CancelAllocationCommand;
|
25 | 26 | import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand;
|
| 27 | +import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders; |
26 | 28 | import org.elasticsearch.cluster.routing.allocation.decider.AwarenessAllocationDecider;
|
27 | 29 | import org.elasticsearch.cluster.routing.allocation.decider.ClusterRebalanceAllocationDecider;
|
| 30 | +import org.elasticsearch.cluster.routing.allocation.decider.Decision; |
| 31 | +import org.elasticsearch.common.settings.ClusterSettings; |
28 | 32 | import org.elasticsearch.common.settings.Settings;
|
29 | 33 |
|
30 | 34 | import java.util.HashMap;
|
31 | 35 | import java.util.Map;
|
| 36 | +import java.util.function.UnaryOperator; |
| 37 | +import java.util.stream.StreamSupport; |
32 | 38 |
|
33 | 39 | import static java.util.Collections.emptyMap;
|
| 40 | +import static java.util.Collections.singletonList; |
34 | 41 | import static java.util.Collections.singletonMap;
|
35 | 42 | import static org.elasticsearch.cluster.routing.ShardRoutingState.INITIALIZING;
|
36 | 43 | import static org.elasticsearch.cluster.routing.ShardRoutingState.RELOCATING;
|
@@ -937,4 +944,85 @@ public void testNodesWithoutAttributeAreIgnored() {
|
937 | 944 | assertTrue(clusterState.getRoutingNodes().node("X-0").isEmpty());
|
938 | 945 | }
|
939 | 946 |
|
| 947 | + public void testExplanation() { |
| 948 | + testExplanation(Settings.builder() |
| 949 | + .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(), "zone"), |
| 950 | + UnaryOperator.identity(), |
| 951 | + "there are [5] copies of this shard and [2] values for attribute [zone] ([a, b] from nodes in the cluster and " + |
| 952 | + "no forced awareness) so there may be at most [3] copies of this shard allocated to nodes with each " + |
| 953 | + "value, but (including this copy) there would be [4] copies allocated to nodes with [node.attr.zone: a]"); |
| 954 | + } |
| 955 | + |
| 956 | + public void testExplanationWithMissingAttribute() { |
| 957 | + testExplanation(Settings.builder() |
| 958 | + .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(), "zone"), |
| 959 | + n -> n.add(newNode("X-0", emptyMap())), |
| 960 | + "there are [5] copies of this shard and [2] values for attribute [zone] ([a, b] from nodes in the cluster and " + |
| 961 | + "no forced awareness) so there may be at most [3] copies of this shard allocated to nodes with each " + |
| 962 | + "value, but (including this copy) there would be [4] copies allocated to nodes with [node.attr.zone: a]"); |
| 963 | + } |
| 964 | + |
| 965 | + public void testExplanationWithForcedAttributes() { |
| 966 | + testExplanation(Settings.builder() |
| 967 | + .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(), "zone") |
| 968 | + .put(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_FORCE_GROUP_SETTING.getKey() + "zone.values", |
| 969 | + "b,c"), |
| 970 | + UnaryOperator.identity(), |
| 971 | + "there are [5] copies of this shard and [3] values for attribute [zone] ([a, b] from nodes in the cluster and " + |
| 972 | + "[b, c] from forced awareness) so there may be at most [2] copies of this shard allocated to nodes with each " + |
| 973 | + "value, but (including this copy) there would be [3] copies allocated to nodes with [node.attr.zone: a]"); |
| 974 | + } |
| 975 | + |
| 976 | + private void testExplanation( |
| 977 | + Settings.Builder settingsBuilder, |
| 978 | + UnaryOperator<DiscoveryNodes.Builder> nodesOperator, |
| 979 | + String expectedMessage) { |
| 980 | + final Settings settings = settingsBuilder |
| 981 | + .build(); |
| 982 | + |
| 983 | + final AllocationService strategy = createAllocationService(settings); |
| 984 | + |
| 985 | + final Metadata metadata = Metadata.builder() |
| 986 | + .put(IndexMetadata.builder("test").settings(settings(Version.CURRENT)).numberOfShards(1).numberOfReplicas(4)) |
| 987 | + .build(); |
| 988 | + |
| 989 | + final ClusterState clusterState = applyStartedShardsUntilNoChange( |
| 990 | + ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.get(Settings.EMPTY)) |
| 991 | + .metadata(metadata) |
| 992 | + .routingTable(RoutingTable.builder() |
| 993 | + .addAsNew(metadata.index("test")) |
| 994 | + .build()) |
| 995 | + .nodes(nodesOperator.apply(DiscoveryNodes.builder() |
| 996 | + .add(newNode("A-0", singletonMap("zone", "a"))) |
| 997 | + .add(newNode("A-1", singletonMap("zone", "a"))) |
| 998 | + .add(newNode("A-2", singletonMap("zone", "a"))) |
| 999 | + .add(newNode("A-3", singletonMap("zone", "a"))) |
| 1000 | + .add(newNode("A-4", singletonMap("zone", "a"))) |
| 1001 | + .add(newNode("B-0", singletonMap("zone", "b")))) |
| 1002 | + ).build(), strategy); |
| 1003 | + |
| 1004 | + final ShardRouting unassignedShard = clusterState.getRoutingNodes().shardsWithState(UNASSIGNED).get(0); |
| 1005 | + |
| 1006 | + final AwarenessAllocationDecider decider = new AwarenessAllocationDecider( |
| 1007 | + settings, |
| 1008 | + new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS)); |
| 1009 | + |
| 1010 | + final RoutingNode emptyNode = StreamSupport.stream(clusterState.getRoutingNodes().spliterator(), false) |
| 1011 | + .filter(RoutingNode::isEmpty).findFirst().orElseThrow(AssertionError::new); |
| 1012 | + |
| 1013 | + final RoutingAllocation routingAllocation = new RoutingAllocation( |
| 1014 | + new AllocationDeciders(singletonList(decider)), |
| 1015 | + clusterState.getRoutingNodes(), |
| 1016 | + clusterState, |
| 1017 | + null, |
| 1018 | + null, |
| 1019 | + 0L); |
| 1020 | + routingAllocation.debugDecision(true); |
| 1021 | + |
| 1022 | + final Decision decision = decider.canAllocate(unassignedShard, emptyNode, routingAllocation); |
| 1023 | + assertThat(decision.type(), equalTo(Decision.Type.NO)); |
| 1024 | + assertThat(decision.label(), equalTo("awareness")); |
| 1025 | + assertThat(decision.getExplanation(), equalTo(expectedMessage)); |
| 1026 | + } |
| 1027 | + |
940 | 1028 | }
|
0 commit comments