|
@@ -0,0 +1,219 @@
|
|
|
+/*
|
|
|
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
|
+ * or more contributor license agreements. Licensed under the Elastic License;
|
|
|
+ * you may not use this file except in compliance with the Elastic License.
|
|
|
+ */
|
|
|
+
|
|
|
+package org.elasticsearch.xpack.cluster.routing.allocation;
|
|
|
+
|
|
|
+import org.elasticsearch.action.admin.indices.shrink.ResizeType;
|
|
|
+import org.elasticsearch.action.admin.indices.template.put.PutComposableIndexTemplateAction;
|
|
|
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
|
|
+import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
|
|
|
+import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
|
+import org.elasticsearch.cluster.metadata.Template;
|
|
|
+import org.elasticsearch.common.settings.Settings;
|
|
|
+import org.elasticsearch.plugins.Plugin;
|
|
|
+import org.elasticsearch.test.ESIntegTestCase;
|
|
|
+import org.elasticsearch.xpack.core.DataTier;
|
|
|
+import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
|
|
|
+
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.Collections;
|
|
|
+
|
|
|
+import static org.hamcrest.Matchers.equalTo;
|
|
|
+
|
|
|
+@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, numClientNodes = 0)
|
|
|
+public class DataTierIT extends ESIntegTestCase {
|
|
|
+ private static final String index = "myindex";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected Collection<Class<? extends Plugin>> nodePlugins() {
|
|
|
+ return Collections.singleton(LocalStateCompositeXPackPlugin.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testDefaultAllocateToHot() {
|
|
|
+ startWarmOnlyNode();
|
|
|
+ startColdOnlyNode();
|
|
|
+ ensureGreen();
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
|
|
+
|
|
|
+ Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_HOT));
|
|
|
+
|
|
|
+ // index should be red
|
|
|
+ assertThat(client().admin().cluster().prepareHealth(index).get().getIndices().get(index).getStatus(),
|
|
|
+ equalTo(ClusterHealthStatus.RED));
|
|
|
+
|
|
|
+ logger.info("--> starting hot node");
|
|
|
+ startHotOnlyNode();
|
|
|
+
|
|
|
+ logger.info("--> waiting for {} to be yellow", index);
|
|
|
+ ensureYellow(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testOverrideDefaultAllocation() {
|
|
|
+ startWarmOnlyNode();
|
|
|
+ startColdOnlyNode();
|
|
|
+ ensureGreen();
|
|
|
+
|
|
|
+ String setting = randomBoolean() ? DataTierAllocationDecider.INDEX_ROUTING_REQUIRE :
|
|
|
+ DataTierAllocationDecider.INDEX_ROUTING_INCLUDE;
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index)
|
|
|
+ .setWaitForActiveShards(0)
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .put(setting, DataTier.DATA_WARM))
|
|
|
+ .get();
|
|
|
+
|
|
|
+ Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(idxSettings.get(setting), equalTo(DataTier.DATA_WARM));
|
|
|
+
|
|
|
+ // index should be yellow
|
|
|
+ logger.info("--> waiting for {} to be yellow", index);
|
|
|
+ ensureYellow(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testRequestSettingOverridesAllocation() {
|
|
|
+ startWarmOnlyNode();
|
|
|
+ startColdOnlyNode();
|
|
|
+ ensureGreen();
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index)
|
|
|
+ .setWaitForActiveShards(0)
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .putNull(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE))
|
|
|
+ .get();
|
|
|
+
|
|
|
+ Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(""));
|
|
|
+ // Even the key shouldn't exist if it has been nulled out
|
|
|
+ assertFalse(idxSettings.keySet().toString(), idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE));
|
|
|
+
|
|
|
+ // index should be yellow
|
|
|
+ logger.info("--> waiting for {} to be yellow", index);
|
|
|
+ ensureYellow(index);
|
|
|
+
|
|
|
+ client().admin().indices().prepareDelete(index).get();
|
|
|
+
|
|
|
+ // Now test it overriding the "require" setting, in which case the include should be skipped
|
|
|
+ client().admin().indices().prepareCreate(index)
|
|
|
+ .setWaitForActiveShards(0)
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .put(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE, DataTier.DATA_COLD))
|
|
|
+ .get();
|
|
|
+
|
|
|
+ idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(""));
|
|
|
+ // The key should not be put in place since it was overridden
|
|
|
+ assertFalse(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE));
|
|
|
+ assertThat(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE_SETTING.get(idxSettings), equalTo(DataTier.DATA_COLD));
|
|
|
+
|
|
|
+ // index should be yellow
|
|
|
+ logger.info("--> waiting for {} to be yellow", index);
|
|
|
+ ensureYellow(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * When a new index is created from source metadata (as during a shrink), the data tier
|
|
|
+ * default setting should *not* be applied. This test checks that behavior.
|
|
|
+ */
|
|
|
+ public void testShrinkStaysOnTier() {
|
|
|
+ startWarmOnlyNode();
|
|
|
+ startHotOnlyNode();
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index)
|
|
|
+ .setWaitForActiveShards(0)
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 2)
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
|
|
+ .put(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE, "data_warm"))
|
|
|
+ .get();
|
|
|
+
|
|
|
+ client().admin().indices().prepareAddBlock(IndexMetadata.APIBlock.READ_ONLY, index).get();
|
|
|
+ client().admin().indices().prepareResizeIndex(index, index + "-shrunk")
|
|
|
+ .setResizeType(ResizeType.SHRINK)
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
|
|
|
+ .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
|
|
|
+ .build()).get();
|
|
|
+
|
|
|
+ ensureGreen(index + "-shrunk");
|
|
|
+
|
|
|
+ Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index + "-shrunk")
|
|
|
+ .get().getSettings().get(index + "-shrunk");
|
|
|
+ // It should inherit the setting of its originator
|
|
|
+ assertThat(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE_SETTING.get(idxSettings), equalTo(DataTier.DATA_WARM));
|
|
|
+
|
|
|
+ // Required or else the test cleanup fails because it can't delete the indices
|
|
|
+ client().admin().indices().prepareUpdateSettings(index, index + "-shrunk")
|
|
|
+ .setSettings(Settings.builder()
|
|
|
+ .put("index.blocks.read_only", false))
|
|
|
+ .get();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testTemplateOverridesDefaults() {
|
|
|
+ startWarmOnlyNode();
|
|
|
+
|
|
|
+ Template t = new Template(Settings.builder()
|
|
|
+ .put(DataTierAllocationDecider.INDEX_ROUTING_REQUIRE, DataTier.DATA_WARM)
|
|
|
+ .build(), null, null);
|
|
|
+ ComposableIndexTemplate ct = new ComposableIndexTemplate(Collections.singletonList(index), t, null, null, null, null, null);
|
|
|
+ client().execute(PutComposableIndexTemplateAction.INSTANCE,
|
|
|
+ new PutComposableIndexTemplateAction.Request("template").indexTemplate(ct)).actionGet();
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
|
|
+
|
|
|
+ Settings idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE), equalTo(false));
|
|
|
+
|
|
|
+ // index should be yellow
|
|
|
+ ensureYellow(index);
|
|
|
+
|
|
|
+ client().admin().indices().prepareDelete(index).get();
|
|
|
+
|
|
|
+ t = new Template(Settings.builder()
|
|
|
+ .putNull(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE)
|
|
|
+ .build(), null, null);
|
|
|
+ ct = new ComposableIndexTemplate(Collections.singletonList(index), t, null, null, null, null, null);
|
|
|
+ client().execute(PutComposableIndexTemplateAction.INSTANCE,
|
|
|
+ new PutComposableIndexTemplateAction.Request("template").indexTemplate(ct)).actionGet();
|
|
|
+
|
|
|
+ client().admin().indices().prepareCreate(index).setWaitForActiveShards(0).get();
|
|
|
+
|
|
|
+ idxSettings = client().admin().indices().prepareGetIndex().addIndices(index).get().getSettings().get(index);
|
|
|
+ assertThat(idxSettings.keySet().contains(DataTierAllocationDecider.INDEX_ROUTING_INCLUDE), equalTo(false));
|
|
|
+
|
|
|
+ ensureYellow(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void startHotOnlyNode() {
|
|
|
+ Settings nodeSettings = Settings.builder()
|
|
|
+ .putList("node.roles", Arrays.asList("master", "data_hot", "ingest"))
|
|
|
+ .build();
|
|
|
+ internalCluster().startNode(nodeSettings);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void startWarmOnlyNode() {
|
|
|
+ Settings nodeSettings = Settings.builder()
|
|
|
+ .putList("node.roles", Arrays.asList("master", "data_warm", "ingest"))
|
|
|
+ .build();
|
|
|
+ internalCluster().startNode(nodeSettings);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void startColdOnlyNode() {
|
|
|
+ Settings nodeSettings = Settings.builder()
|
|
|
+ .putList("node.roles", Arrays.asList("master", "data_cold", "ingest"))
|
|
|
+ .build();
|
|
|
+ internalCluster().startNode(nodeSettings);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void startFrozenOnlyNode() {
|
|
|
+ Settings nodeSettings = Settings.builder()
|
|
|
+ .putList("node.roles", Arrays.asList("master", "data_frozen", "ingest"))
|
|
|
+ .build();
|
|
|
+ internalCluster().startNode(nodeSettings);
|
|
|
+ }
|
|
|
+}
|