This commit adds the `index.routing.allocation.prefer._tier` setting to the `DataTierAllocationDecider`. This special-purpose allocation setting lets a user specify a preference-based list of tiers for an index to be assigned to. For example, if the setting were set to: ``` "index.routing.allocation.prefer._tier": "data_hot,data_warm,data_content" ``` If the cluster contains any nodes with the `data_hot` role, the decider will only allow them to be allocated on the `data_hot` node(s). If there are no `data_hot` nodes, but there are `data_warm` and `data_content` nodes, then the index will be allowed to be allocated on `data_warm` nodes. This allows us to specify an index's preference for tier(s) without causing the index to be unassigned if no nodes of a preferred tier are available. Subsequent work will change the ILM migration to make additional use of this setting. Relates to #60848
This commit is contained in:
parent
c2e73ba061
commit
4a08928c47
|
@ -396,7 +396,7 @@ Returns:
|
||||||
"index.creation_date": "1474389951325",
|
"index.creation_date": "1474389951325",
|
||||||
"index.uuid": "n6gzFZTgS664GUfx0Xrpjw",
|
"index.uuid": "n6gzFZTgS664GUfx0Xrpjw",
|
||||||
"index.version.created": ...,
|
"index.version.created": ...,
|
||||||
"index.routing.allocation.include._tier" : "data_content",
|
"index.routing.allocation.include._tier_preference" : "data_content",
|
||||||
"index.provided_name" : "my-index-000001"
|
"index.provided_name" : "my-index-000001"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,7 +433,7 @@ Returns:
|
||||||
"routing": {
|
"routing": {
|
||||||
"allocation": {
|
"allocation": {
|
||||||
"include": {
|
"include": {
|
||||||
"_tier": "data_content"
|
"_tier_preference": "data_content"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -116,7 +116,7 @@ PUT /my-index-000001?master_timeout=1s&timeout=1s
|
||||||
{
|
{
|
||||||
"settings": {
|
"settings": {
|
||||||
"index.routing.allocation.include._name": "non_existent_node",
|
"index.routing.allocation.include._name": "non_existent_node",
|
||||||
"index.routing.allocation.include._tier": null
|
"index.routing.allocation.include._tier_preference": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,7 @@ public class RecoveryIT extends AbstractRollingTestCase {
|
||||||
// but the recovering copy will be seen as invalid and the cluster health won't return to GREEN
|
// but the recovering copy will be seen as invalid and the cluster health won't return to GREEN
|
||||||
// before timing out
|
// before timing out
|
||||||
.put(INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING.getKey(), "100ms")
|
.put(INDEX_DELAYED_NODE_LEFT_TIMEOUT_SETTING.getKey(), "100ms")
|
||||||
.put("index.routing.allocation.include._tier", "")
|
.put("index.routing.allocation.include._tier_preference", "")
|
||||||
.put(SETTING_ALLOCATION_MAX_RETRY.getKey(), "0"); // fail faster
|
.put(SETTING_ALLOCATION_MAX_RETRY.getKey(), "0"); // fail faster
|
||||||
createIndex(index, settings.build());
|
createIndex(index, settings.build());
|
||||||
indexDocs(index, 0, 10);
|
indexDocs(index, 0, 10);
|
||||||
|
@ -267,7 +267,7 @@ public class RecoveryIT extends AbstractRollingTestCase {
|
||||||
.put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0)
|
.put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0)
|
||||||
.put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)
|
.put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)
|
||||||
.put("index.routing.allocation.include._id", oldNode)
|
.put("index.routing.allocation.include._id", oldNode)
|
||||||
.putNull("index.routing.allocation.include._tier")
|
.putNull("index.routing.allocation.include._tier_preference")
|
||||||
);
|
);
|
||||||
ensureGreen(index); // wait for the primary to be assigned
|
ensureGreen(index); // wait for the primary to be assigned
|
||||||
ensureNoInitializingShards(); // wait for all other shard activity to finish
|
ensureNoInitializingShards(); // wait for all other shard activity to finish
|
||||||
|
@ -290,7 +290,7 @@ public class RecoveryIT extends AbstractRollingTestCase {
|
||||||
updateIndexSettings(index, Settings.builder()
|
updateIndexSettings(index, Settings.builder()
|
||||||
.put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 2)
|
.put(IndexMetadata.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 2)
|
||||||
.put("index.routing.allocation.include._id", (String)null)
|
.put("index.routing.allocation.include._id", (String)null)
|
||||||
.putNull("index.routing.allocation.include._tier")
|
.putNull("index.routing.allocation.include._tier_preference")
|
||||||
);
|
);
|
||||||
asyncIndexDocs(index, 60, 45).get();
|
asyncIndexDocs(index, 60, 45).get();
|
||||||
ensureGreen(index);
|
ensureGreen(index);
|
||||||
|
|
|
@ -181,7 +181,7 @@ public class DiscoveryNodeFilters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("_tier".equals(attr)) {
|
} else if (attr != null && attr.startsWith("_tier")) {
|
||||||
// Always allow _tier as an attribute, will be handled elsewhere
|
// Always allow _tier as an attribute, will be handled elsewhere
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class PrimaryFollowerAllocationIT extends CcrIntegTestCase {
|
||||||
final PutFollowAction.Request putFollowRequest = putFollow(leaderIndex, followerIndex);
|
final PutFollowAction.Request putFollowRequest = putFollow(leaderIndex, followerIndex);
|
||||||
putFollowRequest.setSettings(Settings.builder()
|
putFollowRequest.setSettings(Settings.builder()
|
||||||
.put("index.routing.allocation.include._name", String.join(",", dataOnlyNodes))
|
.put("index.routing.allocation.include._name", String.join(",", dataOnlyNodes))
|
||||||
.putNull("index.routing.allocation.include._tier")
|
.putNull("index.routing.allocation.include._tier_preference")
|
||||||
.build());
|
.build());
|
||||||
putFollowRequest.waitForActiveShards(ActiveShardCount.ONE);
|
putFollowRequest.waitForActiveShards(ActiveShardCount.ONE);
|
||||||
putFollowRequest.timeout(TimeValue.timeValueSeconds(2));
|
putFollowRequest.timeout(TimeValue.timeValueSeconds(2));
|
||||||
|
@ -84,7 +84,7 @@ public class PrimaryFollowerAllocationIT extends CcrIntegTestCase {
|
||||||
.put("index.routing.rebalance.enable", "none")
|
.put("index.routing.rebalance.enable", "none")
|
||||||
.put("index.routing.allocation.include._name",
|
.put("index.routing.allocation.include._name",
|
||||||
Stream.concat(dataOnlyNodes.stream(), dataAndRemoteNodes.stream()).collect(Collectors.joining(",")))
|
Stream.concat(dataOnlyNodes.stream(), dataAndRemoteNodes.stream()).collect(Collectors.joining(",")))
|
||||||
.putNull("index.routing.allocation.include._tier")
|
.putNull("index.routing.allocation.include._tier_preference")
|
||||||
.build());
|
.build());
|
||||||
final PutFollowAction.Response response = followerClient().execute(PutFollowAction.INSTANCE, putFollowRequest).get();
|
final PutFollowAction.Response response = followerClient().execute(PutFollowAction.INSTANCE, putFollowRequest).get();
|
||||||
assertTrue(response.isFollowIndexShardsAcked());
|
assertTrue(response.isFollowIndexShardsAcked());
|
||||||
|
@ -108,8 +108,8 @@ public class PrimaryFollowerAllocationIT extends CcrIntegTestCase {
|
||||||
followerClient().admin().indices().prepareUpdateSettings(followerIndex)
|
followerClient().admin().indices().prepareUpdateSettings(followerIndex)
|
||||||
.setMasterNodeTimeout(TimeValue.MAX_VALUE)
|
.setMasterNodeTimeout(TimeValue.MAX_VALUE)
|
||||||
.setSettings(Settings.builder()
|
.setSettings(Settings.builder()
|
||||||
.put("index.routing.allocation.include._name", String.join(",", dataOnlyNodes))
|
.putNull("index.routing.allocation.include._tier_preference")
|
||||||
.putNull("index.routing.allocation.include._tier"))
|
.put("index.routing.allocation.include._name", String.join(",", dataOnlyNodes)))
|
||||||
.get();
|
.get();
|
||||||
assertBusy(() -> {
|
assertBusy(() -> {
|
||||||
final ClusterState state = getFollowerCluster().client().admin().cluster().prepareState().get().getState();
|
final ClusterState state = getFollowerCluster().client().admin().cluster().prepareState().get().getState();
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
||||||
|
|
||||||
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_CONTENT));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(DataTier.DATA_CONTENT));
|
||||||
|
|
||||||
// index should be red
|
// index should be red
|
||||||
assertThat(client().admin().cluster().prepareHealth(index).get().getIndices().get(index).getStatus(),
|
assertThat(client().admin().cluster().prepareHealth(index).get().getIndices().get(index).getStatus(),
|
||||||
|
@ -51,7 +51,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
logger.info("--> starting content node");
|
logger.info("--> starting content node");
|
||||||
startContentOnlyNode();
|
startContentOnlyNode();
|
||||||
} else {
|
} else {
|
||||||
logger.info("--> starting hot node");
|
logger.info("--> starting data node");
|
||||||
startDataNode();
|
startDataNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
||||||
String setting = randomBoolean() ? DataTierAllocationDecider.INDEX_ROUTING_REQUIRE :
|
String setting = randomBoolean() ? DataTierAllocationDecider.INDEX_ROUTING_REQUIRE :
|
||||||
DataTierAllocationDecider.INDEX_ROUTING_INCLUDE;
|
DataTierAllocationDecider.INDEX_ROUTING_PREFER;
|
||||||
|
|
||||||
client().admin().indices().prepareCreate(index)
|
client().admin().indices().prepareCreate(index)
|
||||||
.setWaitForActiveShards(0)
|
.setWaitForActiveShards(0)
|
||||||
|
@ -89,13 +89,13 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
client().admin().indices().prepareCreate(index)
|
client().admin().indices().prepareCreate(index)
|
||||||
.setWaitForActiveShards(0)
|
.setWaitForActiveShards(0)
|
||||||
.setSettings(Settings.builder()
|
.setSettings(Settings.builder()
|
||||||
.putNull(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE))
|
.putNull(DataTierAllocationDecider.INDEX_ROUTING_PREFER))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(""));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(""));
|
||||||
// Even the key shouldn't exist if it has been nulled out
|
// Even the key shouldn't exist if it has been nulled out
|
||||||
assertFalse(idxSettings.keySet().toString(), idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE));
|
assertFalse(idxSettings.keySet().toString(), idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_PREFER));
|
||||||
|
|
||||||
// index should be yellow
|
// index should be yellow
|
||||||
logger.info("--> waiting for {} to be yellow", index);
|
logger.info("--> waiting for {} to be yellow", index);
|
||||||
|
@ -103,7 +103,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
|
|
||||||
client().admin().indices().prepareDelete(index).get();
|
client().admin().indices().prepareDelete(index).get();
|
||||||
|
|
||||||
// Now test it overriding the "require" setting, in which case the include should be skipped
|
// Now test it overriding the "require" setting, in which case the preference should be skipped
|
||||||
client().admin().indices().prepareCreate(index)
|
client().admin().indices().prepareCreate(index)
|
||||||
.setWaitForActiveShards(0)
|
.setWaitForActiveShards(0)
|
||||||
.setSettings(Settings.builder()
|
.setSettings(Settings.builder()
|
||||||
|
@ -111,9 +111,9 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(""));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(""));
|
||||||
// The key should not be put in place since it was overridden
|
// The key should not be put in place since it was overridden
|
||||||
assertFalse(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE));
|
assertFalse(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_PREFER));
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING.get(idxSettings), equalTo(DataTier.DATA_COLD));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING.get(idxSettings), equalTo(DataTier.DATA_COLD));
|
||||||
|
|
||||||
// index should be yellow
|
// index should be yellow
|
||||||
|
@ -134,7 +134,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
.setSettings(Settings.builder()
|
.setSettings(Settings.builder()
|
||||||
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 2)
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 2)
|
||||||
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
.put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, "data_warm"))
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm"))
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
client().admin().indices().prepareAddBlock(IndexMetadata.APIBlock.READ_ONLY, index).get();
|
client().admin().indices().prepareAddBlock(IndexMetadata.APIBlock.READ_ONLY, index).get();
|
||||||
|
@ -150,7 +150,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index + "-shrunk")
|
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index + "-shrunk")
|
||||||
.get().getSettings().get(index + "-shrunk");
|
.get().getSettings().get(index + "-shrunk");
|
||||||
// It should inherit the setting of its originator
|
// It should inherit the setting of its originator
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_WARM));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(DataTier.DATA_WARM));
|
||||||
|
|
||||||
// Required or else the test cleanup fails because it can't delete the indices
|
// Required or else the test cleanup fails because it can't delete the indices
|
||||||
client().admin().indices().prepareUpdateSettings(index, index + "-shrunk")
|
client().admin().indices().prepareUpdateSettings(index, index + "-shrunk")
|
||||||
|
@ -172,7 +172,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
||||||
|
|
||||||
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
||||||
assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE), equalTo(false));
|
assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_PREFER), equalTo(false));
|
||||||
|
|
||||||
// index should be yellow
|
// index should be yellow
|
||||||
ensureYellow(index);
|
ensureYellow(index);
|
||||||
|
@ -180,7 +180,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
client().admin().indices().prepareDelete(index).get();
|
client().admin().indices().prepareDelete(index).get();
|
||||||
|
|
||||||
t = new Template(Settings.builder()
|
t = new Template(Settings.builder()
|
||||||
.putNull(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE)
|
.putNull(DataTierAllocationDecider.INDEX_ROUTING_PREFER)
|
||||||
.build(), null, null);
|
.build(), null, null);
|
||||||
ct = new ComposableIndexTemplate(Collections.singletonList(index), t, null, null, null, null, null);
|
ct = new ComposableIndexTemplate(Collections.singletonList(index), t, null, null, null, null, null);
|
||||||
client().execute(PutComposableIndexTemplateAction.INSTANCE,
|
client().execute(PutComposableIndexTemplateAction.INSTANCE,
|
||||||
|
@ -189,7 +189,7 @@ public class DataTierIT extends ESIntegTestCase {
|
||||||
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
||||||
|
|
||||||
idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
||||||
assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE), equalTo(false));
|
assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_PREFER), equalTo(false));
|
||||||
|
|
||||||
ensureYellow(index);
|
ensureYellow(index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
package org.elasticsearch.xpack.cluster.routing.allocation;
|
package org.elasticsearch.xpack.cluster.routing.allocation;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.cursors.ObjectCursor;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNodeRole;
|
import org.elasticsearch.cluster.node.DiscoveryNodeRole;
|
||||||
|
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||||
import org.elasticsearch.cluster.routing.RoutingNode;
|
import org.elasticsearch.cluster.routing.RoutingNode;
|
||||||
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;
|
||||||
|
@ -21,6 +23,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.xpack.core.DataTier;
|
import org.elasticsearch.xpack.core.DataTier;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -38,6 +41,7 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
public static final String CLUSTER_ROUTING_EXCLUDE = "cluster.routing.allocation.exclude._tier";
|
public static final String CLUSTER_ROUTING_EXCLUDE = "cluster.routing.allocation.exclude._tier";
|
||||||
public static final String INDEX_ROUTING_REQUIRE = "index.routing.allocation.require._tier";
|
public static final String INDEX_ROUTING_REQUIRE = "index.routing.allocation.require._tier";
|
||||||
public static final String INDEX_ROUTING_INCLUDE = "index.routing.allocation.include._tier";
|
public static final String INDEX_ROUTING_INCLUDE = "index.routing.allocation.include._tier";
|
||||||
|
public static final String INDEX_ROUTING_PREFER = "index.routing.allocation.include._tier_preference";
|
||||||
public static final String INDEX_ROUTING_EXCLUDE = "index.routing.allocation.exclude._tier";
|
public static final String INDEX_ROUTING_EXCLUDE = "index.routing.allocation.exclude._tier";
|
||||||
|
|
||||||
public static final Setting<String> CLUSTER_ROUTING_REQUIRE_SETTING = Setting.simpleString(CLUSTER_ROUTING_REQUIRE,
|
public static final Setting<String> CLUSTER_ROUTING_REQUIRE_SETTING = Setting.simpleString(CLUSTER_ROUTING_REQUIRE,
|
||||||
|
@ -52,6 +56,8 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope);
|
DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope);
|
||||||
public static final Setting<String> INDEX_ROUTING_EXCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_EXCLUDE,
|
public static final Setting<String> INDEX_ROUTING_EXCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_EXCLUDE,
|
||||||
DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope);
|
DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope);
|
||||||
|
public static final Setting<String> INDEX_ROUTING_PREFER_SETTING = Setting.simpleString(INDEX_ROUTING_PREFER,
|
||||||
|
DataTierAllocationDecider::validateTierSetting, Setting.Property.Dynamic, Setting.Property.IndexScope);
|
||||||
|
|
||||||
private static void validateTierSetting(String setting) {
|
private static void validateTierSetting(String setting) {
|
||||||
if (Strings.hasText(setting)) {
|
if (Strings.hasText(setting)) {
|
||||||
|
@ -101,7 +107,12 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
return decision;
|
return decision;
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require tier filters");
|
decision = shouldIndexPreferTier(indexMetadata, node, allocation);
|
||||||
|
if (decision != null) {
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require/prefer tier filters");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Decision shouldFilter(ShardRouting shardRouting, DiscoveryNode node, RoutingAllocation allocation) {
|
private Decision shouldFilter(ShardRouting shardRouting, DiscoveryNode node, RoutingAllocation allocation) {
|
||||||
|
@ -115,7 +126,12 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
return decision;
|
return decision;
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require tier filters");
|
decision = shouldIndexPreferTier(allocation.metadata().getIndexSafe(shardRouting.index()), node, allocation);
|
||||||
|
if (decision != null) {
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require/prefer tier filters");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Decision shouldFilter(IndexMetadata indexMd, DiscoveryNode node, RoutingAllocation allocation) {
|
private Decision shouldFilter(IndexMetadata indexMd, DiscoveryNode node, RoutingAllocation allocation) {
|
||||||
|
@ -129,7 +145,37 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
return decision;
|
return decision;
|
||||||
}
|
}
|
||||||
|
|
||||||
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require tier filters");
|
decision = shouldIndexPreferTier(indexMd, node, allocation);
|
||||||
|
if (decision != null) {
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocation.decision(Decision.YES, NAME, "node passes include/exclude/require/prefer tier filters");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Decision shouldIndexPreferTier(IndexMetadata indexMetadata, DiscoveryNode node, RoutingAllocation allocation) {
|
||||||
|
Settings indexSettings = indexMetadata.getSettings();
|
||||||
|
String tierPreference = INDEX_ROUTING_PREFER_SETTING.get(indexSettings);
|
||||||
|
|
||||||
|
if (Strings.hasText(tierPreference)) {
|
||||||
|
Optional<String> tier = preferredAvailableTier(tierPreference, allocation.nodes());
|
||||||
|
if (tier.isPresent()) {
|
||||||
|
String tierName = tier.get();
|
||||||
|
// The OpType doesn't actually matter here, because we have
|
||||||
|
// selected only a single tier as our "preferred" tier
|
||||||
|
if (allocationAllowed(OpType.AND, tierName, node)) {
|
||||||
|
return allocation.decision(Decision.YES, NAME,
|
||||||
|
"index has a preference for tiers [%s] and node has tier [%s]", tierPreference, tierName);
|
||||||
|
} else {
|
||||||
|
return allocation.decision(Decision.NO, NAME,
|
||||||
|
"index has a preference for tiers [%s] and node does not meet the required [%s] tier", tierPreference, tierName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return allocation.decision(Decision.NO, NAME, "index has a preference for tiers [%s], " +
|
||||||
|
"but no nodes for any of those tiers are available in the cluster", tierPreference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Decision shouldIndexFilter(IndexMetadata indexMd, DiscoveryNode node, RoutingAllocation allocation) {
|
private Decision shouldIndexFilter(IndexMetadata indexMd, DiscoveryNode node, RoutingAllocation allocation) {
|
||||||
|
@ -186,6 +232,31 @@ public class DataTierAllocationDecider extends AllocationDecider {
|
||||||
OR
|
OR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string of comma-separated prioritized tiers (highest priority
|
||||||
|
* first) and an allocation, find the highest priority tier for which nodes
|
||||||
|
* exist. If no nodes for any of the tiers are available, returns an empty
|
||||||
|
* {@code Optional<String>}.
|
||||||
|
*/
|
||||||
|
static Optional<String> preferredAvailableTier(String prioritizedTiers, DiscoveryNodes nodes) {
|
||||||
|
String[] tiers = Strings.tokenizeToStringArray(prioritizedTiers, ",");
|
||||||
|
return Arrays.stream(tiers).filter(tier -> tierNodesPresent(tier, nodes)).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean tierNodesPresent(String singleTier, DiscoveryNodes nodes) {
|
||||||
|
assert singleTier.equals(DiscoveryNodeRole.DATA_ROLE.roleName()) || DataTier.validTierName(singleTier) :
|
||||||
|
"tier " + singleTier + " is an invalid tier name";
|
||||||
|
for (ObjectCursor<DiscoveryNode> node : nodes.getNodes().values()) {
|
||||||
|
if (node.value.getRoles().stream()
|
||||||
|
.map(DiscoveryNodeRole::roleName)
|
||||||
|
.anyMatch(s -> s.equals(DiscoveryNodeRole.DATA_ROLE.roleName()) || s.equals(singleTier))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static boolean allocationAllowed(OpType opType, String tierSetting, DiscoveryNode node) {
|
private static boolean allocationAllowed(OpType opType, String tierSetting, DiscoveryNode node) {
|
||||||
String[] values = Strings.tokenizeToStringArray(tierSetting, ",");
|
String[] values = Strings.tokenizeToStringArray(tierSetting, ",");
|
||||||
for (String value : values) {
|
for (String value : values) {
|
||||||
|
|
|
@ -156,9 +156,9 @@ public class DataTier {
|
||||||
@Override
|
@Override
|
||||||
public Settings getAdditionalIndexSettings(String indexName, boolean isDataStreamIndex, Settings indexSettings) {
|
public Settings getAdditionalIndexSettings(String indexName, boolean isDataStreamIndex, Settings indexSettings) {
|
||||||
Set<String> settings = indexSettings.keySet();
|
Set<String> settings = indexSettings.keySet();
|
||||||
if (settings.contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE)) {
|
if (settings.contains(DataTierAllocationDecider.INDEX_ROUTING_PREFER)) {
|
||||||
// It's okay to put it, it will be removed or overridden by the template/request settings
|
// It's okay to put it, it will be removed or overridden by the template/request settings
|
||||||
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, DATA_HOT).build();
|
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DATA_HOT).build();
|
||||||
} else if (settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_PREFIX + ".")) ||
|
} else if (settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_PREFIX + ".")) ||
|
||||||
settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + ".")) ||
|
settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_PREFIX + ".")) ||
|
||||||
settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_PREFIX + "."))) {
|
settings.stream().anyMatch(s -> s.startsWith(IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_PREFIX + "."))) {
|
||||||
|
@ -170,9 +170,9 @@ public class DataTier {
|
||||||
// tier if the index is part of a data stream, the "content"
|
// tier if the index is part of a data stream, the "content"
|
||||||
// tier if it is not.
|
// tier if it is not.
|
||||||
if (isDataStreamIndex) {
|
if (isDataStreamIndex) {
|
||||||
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, DATA_HOT).build();
|
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DATA_HOT).build();
|
||||||
} else {
|
} else {
|
||||||
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, DATA_CONTENT).build();
|
return Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, DATA_CONTENT).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,7 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
|
||||||
settings.add(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING);
|
settings.add(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING);
|
||||||
settings.add(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING);
|
settings.add(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING);
|
||||||
settings.add(DataTierAllocationDecider.INDEX_ROUTING_EXCLUDE_SETTING);
|
settings.add(DataTierAllocationDecider.INDEX_ROUTING_EXCLUDE_SETTING);
|
||||||
|
settings.add(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING);
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class MigrateAction implements LifecycleAction {
|
||||||
Settings.Builder migrationSettings = Settings.builder();
|
Settings.Builder migrationSettings = Settings.builder();
|
||||||
String dataTierName = "data_" + phase;
|
String dataTierName = "data_" + phase;
|
||||||
assert DataTier.validTierName(dataTierName) : "invalid data tier name:" + dataTierName;
|
assert DataTier.validTierName(dataTierName) : "invalid data tier name:" + dataTierName;
|
||||||
migrationSettings.put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, dataTierName);
|
migrationSettings.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, dataTierName);
|
||||||
UpdateSettingsStep updateMigrationSettingStep = new UpdateSettingsStep(migrationKey, migrationRoutedKey, client,
|
UpdateSettingsStep updateMigrationSettingStep = new UpdateSettingsStep(migrationKey, migrationRoutedKey, client,
|
||||||
migrationSettings.build());
|
migrationSettings.build());
|
||||||
DataTierMigrationRoutedStep migrationRoutedStep = new DataTierMigrationRoutedStep(migrationRoutedKey, nextStepKey);
|
DataTierMigrationRoutedStep migrationRoutedStep = new DataTierMigrationRoutedStep(migrationRoutedKey, nextStepKey);
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.elasticsearch.xpack.core.DataTier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
@ -47,6 +48,7 @@ public class DataTierAllocationDeciderTests extends ESAllocationTestCase {
|
||||||
private static final DiscoveryNode HOT_NODE = newNode("node-hot", Collections.singleton(DataTier.DATA_HOT_NODE_ROLE));
|
private static final DiscoveryNode HOT_NODE = newNode("node-hot", Collections.singleton(DataTier.DATA_HOT_NODE_ROLE));
|
||||||
private static final DiscoveryNode WARM_NODE = newNode("node-warm", Collections.singleton(DataTier.DATA_WARM_NODE_ROLE));
|
private static final DiscoveryNode WARM_NODE = newNode("node-warm", Collections.singleton(DataTier.DATA_WARM_NODE_ROLE));
|
||||||
private static final DiscoveryNode COLD_NODE = newNode("node-cold", Collections.singleton(DataTier.DATA_COLD_NODE_ROLE));
|
private static final DiscoveryNode COLD_NODE = newNode("node-cold", Collections.singleton(DataTier.DATA_COLD_NODE_ROLE));
|
||||||
|
private static final DiscoveryNode CONTENT_NODE = newNode("node-content", Collections.singleton(DataTier.DATA_CONTENT_NODE_ROLE));
|
||||||
private static final DiscoveryNode DATA_NODE = newNode("node-data", Collections.singleton(DiscoveryNodeRole.DATA_ROLE));
|
private static final DiscoveryNode DATA_NODE = newNode("node-data", Collections.singleton(DiscoveryNodeRole.DATA_ROLE));
|
||||||
|
|
||||||
private final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ALL_SETTINGS);
|
private final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ALL_SETTINGS);
|
||||||
|
@ -274,6 +276,277 @@ public class DataTierAllocationDeciderTests extends ESAllocationTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testIndexPrefer() {
|
||||||
|
ClusterState state = ClusterState.builder(service.reroute(ClusterState.EMPTY_STATE, "initial state"))
|
||||||
|
.nodes(DiscoveryNodes.builder()
|
||||||
|
.add(HOT_NODE)
|
||||||
|
.build())
|
||||||
|
.metadata(Metadata.builder()
|
||||||
|
.put(IndexMetadata.builder("myindex")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetadata.SETTING_INDEX_UUID, "myindex")
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm,data_cold")
|
||||||
|
.build()))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, state.getRoutingNodes(), state,
|
||||||
|
null, 0);
|
||||||
|
allocation.debugDecision(true);
|
||||||
|
Decision d;
|
||||||
|
RoutingNode node;
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(HOT_NODE, WARM_NODE, COLD_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold], " +
|
||||||
|
"but no nodes for any of those tiers are available in the cluster"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold], " +
|
||||||
|
"but no nodes for any of those tiers are available in the cluster"));
|
||||||
|
}
|
||||||
|
|
||||||
|
state = ClusterState.builder(service.reroute(ClusterState.EMPTY_STATE, "initial state"))
|
||||||
|
.nodes(DiscoveryNodes.builder()
|
||||||
|
.add(HOT_NODE)
|
||||||
|
.add(COLD_NODE)
|
||||||
|
.build())
|
||||||
|
.metadata(Metadata.builder()
|
||||||
|
.put(IndexMetadata.builder("myindex")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetadata.SETTING_INDEX_UUID, "myindex")
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm,data_cold")
|
||||||
|
.build()))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
allocation = new RoutingAllocation(allocationDeciders, state.getRoutingNodes(), state, null, 0);
|
||||||
|
allocation.debugDecision(true);
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(HOT_NODE, WARM_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_cold] tier"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_cold] tier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(COLD_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_cold]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_cold]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexPreferWithInclude() {
|
||||||
|
ClusterState state = ClusterState.builder(service.reroute(ClusterState.EMPTY_STATE, "initial state"))
|
||||||
|
.nodes(DiscoveryNodes.builder()
|
||||||
|
.add(WARM_NODE)
|
||||||
|
.add(COLD_NODE)
|
||||||
|
.build())
|
||||||
|
.metadata(Metadata.builder()
|
||||||
|
.put(IndexMetadata.builder("myindex")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetadata.SETTING_INDEX_UUID, "myindex")
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, "data_cold")
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm,data_cold")
|
||||||
|
.build()))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, state.getRoutingNodes(), state,
|
||||||
|
null, 0);
|
||||||
|
allocation.debugDecision(true);
|
||||||
|
Decision d;
|
||||||
|
RoutingNode node;
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(HOT_NODE, WARM_NODE, CONTENT_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node does not match any index setting [index.routing.allocation.include._tier] tier filters [data_cold]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node does not match any index setting [index.routing.allocation.include._tier] tier filters [data_cold]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(COLD_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(DATA_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_warm]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_warm]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexPreferWithExclude() {
|
||||||
|
ClusterState state = ClusterState.builder(service.reroute(ClusterState.EMPTY_STATE, "initial state"))
|
||||||
|
.nodes(DiscoveryNodes.builder()
|
||||||
|
.add(WARM_NODE)
|
||||||
|
.add(COLD_NODE)
|
||||||
|
.build())
|
||||||
|
.metadata(Metadata.builder()
|
||||||
|
.put(IndexMetadata.builder("myindex")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetadata.SETTING_INDEX_UUID, "myindex")
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_EXCLUDE, "data_warm")
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm,data_cold")
|
||||||
|
.build()))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, state.getRoutingNodes(), state,
|
||||||
|
null, 0);
|
||||||
|
allocation.debugDecision(true);
|
||||||
|
Decision d;
|
||||||
|
RoutingNode node;
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(HOT_NODE, COLD_NODE, CONTENT_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(WARM_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node matches any index setting [index.routing.allocation.exclude._tier] tier filters [data_warm]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node matches any index setting [index.routing.allocation.exclude._tier] tier filters [data_warm]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(DATA_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node matches any index setting [index.routing.allocation.exclude._tier] tier filters [data_warm]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node matches any index setting [index.routing.allocation.exclude._tier] tier filters [data_warm]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIndexPreferWithRequire() {
|
||||||
|
ClusterState state = ClusterState.builder(service.reroute(ClusterState.EMPTY_STATE, "initial state"))
|
||||||
|
.nodes(DiscoveryNodes.builder()
|
||||||
|
.add(WARM_NODE)
|
||||||
|
.add(COLD_NODE)
|
||||||
|
.build())
|
||||||
|
.metadata(Metadata.builder()
|
||||||
|
.put(IndexMetadata.builder("myindex")
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetadata.SETTING_INDEX_UUID, "myindex")
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
||||||
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE, "data_cold")
|
||||||
|
.put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "data_warm,data_cold")
|
||||||
|
.build()))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
RoutingAllocation allocation = new RoutingAllocation(allocationDeciders, state.getRoutingNodes(), state,
|
||||||
|
null, 0);
|
||||||
|
allocation.debugDecision(true);
|
||||||
|
Decision d;
|
||||||
|
RoutingNode node;
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(HOT_NODE, WARM_NODE, CONTENT_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node does not match all index setting [index.routing.allocation.require._tier] tier filters [data_cold]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("node does not match all index setting [index.routing.allocation.require._tier] tier filters [data_cold]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(COLD_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.NO));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] " +
|
||||||
|
"and node does not meet the required [data_warm] tier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DiscoveryNode n : Arrays.asList(DATA_NODE)) {
|
||||||
|
node = new RoutingNode(n.getId(), n, shard);
|
||||||
|
d = decider.canAllocate(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_warm]"));
|
||||||
|
d = decider.canRemain(shard, node, allocation);
|
||||||
|
assertThat(node.toString(), d.type(), equalTo(Decision.Type.YES));
|
||||||
|
assertThat(node.toString(), d.getExplanation(),
|
||||||
|
containsString("index has a preference for tiers [data_warm,data_cold] and node has tier [data_warm]"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testClusterAndIndex() {
|
public void testClusterAndIndex() {
|
||||||
ClusterState state = prepareState(service.reroute(ClusterState.EMPTY_STATE, "initial state"),
|
ClusterState state = prepareState(service.reroute(ClusterState.EMPTY_STATE, "initial state"),
|
||||||
Settings.builder()
|
Settings.builder()
|
||||||
|
@ -323,6 +596,60 @@ public class DataTierAllocationDeciderTests extends ESAllocationTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTierNodesPresent() {
|
||||||
|
DiscoveryNodes nodes = DiscoveryNodes.builder().build();
|
||||||
|
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_hot", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_warm", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_cold", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_content", nodes));
|
||||||
|
|
||||||
|
nodes = DiscoveryNodes.builder()
|
||||||
|
.add(WARM_NODE)
|
||||||
|
.add(CONTENT_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_hot", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_warm", nodes));
|
||||||
|
assertFalse(DataTierAllocationDecider.tierNodesPresent("data_cold", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_content", nodes));
|
||||||
|
|
||||||
|
nodes = DiscoveryNodes.builder()
|
||||||
|
.add(DATA_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_hot", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_warm", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_cold", nodes));
|
||||||
|
assertTrue(DataTierAllocationDecider.tierNodesPresent("data_content", nodes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPreferredTierAvailable() {
|
||||||
|
DiscoveryNodes nodes = DiscoveryNodes.builder().build();
|
||||||
|
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data", nodes), equalTo(Optional.empty()));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_hot,data_warm", nodes), equalTo(Optional.empty()));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_warm,data_content", nodes), equalTo(Optional.empty()));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_cold", nodes), equalTo(Optional.empty()));
|
||||||
|
|
||||||
|
nodes = DiscoveryNodes.builder()
|
||||||
|
.add(WARM_NODE)
|
||||||
|
.add(CONTENT_NODE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data", nodes), equalTo(Optional.empty()));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_hot,data_warm", nodes), equalTo(Optional.of("data_warm")));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_warm,data_content", nodes), equalTo(Optional.of("data_warm")));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_content,data_warm", nodes), equalTo(Optional.of("data_content")));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_hot,data_content,data_warm", nodes),
|
||||||
|
equalTo(Optional.of("data_content")));
|
||||||
|
assertThat(DataTierAllocationDecider.preferredAvailableTier("data_hot,data_cold,data_warm", nodes),
|
||||||
|
equalTo(Optional.of("data_warm")));
|
||||||
|
}
|
||||||
|
|
||||||
private ClusterState prepareState(ClusterState initialState) {
|
private ClusterState prepareState(ClusterState initialState) {
|
||||||
return prepareState(initialState, Settings.EMPTY);
|
return prepareState(initialState, Settings.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class DataTierDataStreamIT extends ESIntegTestCase {
|
||||||
.get()
|
.get()
|
||||||
.getSettings()
|
.getSettings()
|
||||||
.get(DataStream.getDefaultBackingIndexName(index, 1));
|
.get(DataStream.getDefaultBackingIndexName(index, 1));
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_HOT));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(DataTier.DATA_HOT));
|
||||||
|
|
||||||
logger.info("--> waiting for {} to be yellow", index);
|
logger.info("--> waiting for {} to be yellow", index);
|
||||||
ensureYellow(index);
|
ensureYellow(index);
|
||||||
|
@ -78,7 +78,7 @@ public class DataTierDataStreamIT extends ESIntegTestCase {
|
||||||
.get()
|
.get()
|
||||||
.getSettings()
|
.getSettings()
|
||||||
.get(DataStream.getDefaultBackingIndexName(index, 2));
|
.get(DataStream.getDefaultBackingIndexName(index, 2));
|
||||||
assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_HOT));
|
assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(idxSettings), equalTo(DataTier.DATA_HOT));
|
||||||
|
|
||||||
client().execute(DeleteDataStreamAction.INSTANCE, new DeleteDataStreamAction.Request(new String[] { index }));
|
client().execute(DeleteDataStreamAction.INSTANCE, new DeleteDataStreamAction.Request(new String[] { index }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,7 +657,7 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase {
|
||||||
createIndexWithSettings(client(), index, alias, Settings.builder()
|
createIndexWithSettings(client(), index, alias, Settings.builder()
|
||||||
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, numShards)
|
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, numShards)
|
||||||
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||||
.putNull(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE));
|
.putNull(DataTierAllocationDecider.INDEX_ROUTING_PREFER));
|
||||||
|
|
||||||
ensureGreen(index);
|
ensureGreen(index);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue