|
@@ -0,0 +1,240 @@
|
|
|
+/*
|
|
|
+ * 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.core.ilm;
|
|
|
+
|
|
|
+import org.elasticsearch.Version;
|
|
|
+import org.elasticsearch.cluster.ClusterName;
|
|
|
+import org.elasticsearch.cluster.ClusterState;
|
|
|
+import org.elasticsearch.cluster.metadata.AliasMetaData;
|
|
|
+import org.elasticsearch.cluster.metadata.IndexMetaData;
|
|
|
+import org.elasticsearch.cluster.metadata.MetaData;
|
|
|
+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.common.Strings;
|
|
|
+import org.elasticsearch.common.xcontent.ToXContent;
|
|
|
+import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
|
+import org.elasticsearch.common.xcontent.json.JsonXContent;
|
|
|
+import org.elasticsearch.index.Index;
|
|
|
+import org.elasticsearch.xpack.core.ilm.Step.StepKey;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.UUID;
|
|
|
+
|
|
|
+import static org.elasticsearch.xpack.core.ilm.WaitForActiveShardsStep.parseIndexNameCounter;
|
|
|
+import static org.hamcrest.Matchers.containsString;
|
|
|
+import static org.hamcrest.Matchers.is;
|
|
|
+
|
|
|
+public class WaitForActiveShardsTests extends AbstractStepTestCase<WaitForActiveShardsStep> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public WaitForActiveShardsStep createRandomInstance() {
|
|
|
+ StepKey stepKey = randomStepKey();
|
|
|
+ StepKey nextStepKey = randomStepKey();
|
|
|
+
|
|
|
+ return new WaitForActiveShardsStep(stepKey, nextStepKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public WaitForActiveShardsStep mutateInstance(WaitForActiveShardsStep 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 WaitForActiveShardsStep(key, nextKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public WaitForActiveShardsStep copyInstance(WaitForActiveShardsStep instance) {
|
|
|
+ return new WaitForActiveShardsStep(instance.getKey(), instance.getNextStepKey());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testIsConditionMetThrowsExceptionWhenRolloverAliasIsNotSet() {
|
|
|
+ String alias = randomAlphaOfLength(5);
|
|
|
+ IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10))
|
|
|
+ .putAlias(AliasMetaData.builder(alias))
|
|
|
+ .settings(settings(Version.CURRENT))
|
|
|
+ .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
|
|
|
+ ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
|
|
|
+ .metaData(MetaData.builder().put(indexMetaData, true).build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ try {
|
|
|
+ createRandomInstance().isConditionMet(indexMetaData.getIndex(), clusterState);
|
|
|
+ fail("expected the invocation to fail");
|
|
|
+ } catch (IllegalStateException e) {
|
|
|
+ assertThat(e.getMessage(), is("setting [" + RolloverAction.LIFECYCLE_ROLLOVER_ALIAS
|
|
|
+ + "] is not set on index [" + indexMetaData.getIndex().getName() + "]"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testResultEvaluatedOnWriteIndexAliasWhenExists() {
|
|
|
+ String alias = randomAlphaOfLength(5);
|
|
|
+ IndexMetaData originalIndex = IndexMetaData.builder("index-000000")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(false))
|
|
|
+ .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias))
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(randomIntBetween(0, 5))
|
|
|
+ .build();
|
|
|
+ IndexMetaData rolledIndex = IndexMetaData.builder("index-000001")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(true))
|
|
|
+ .settings(settings(Version.CURRENT)
|
|
|
+ .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias)
|
|
|
+ .put("index.write.wait_for_active_shards", "all")
|
|
|
+ )
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(1)
|
|
|
+ .build();
|
|
|
+ IndexRoutingTable.Builder routingTable = new IndexRoutingTable.Builder(rolledIndex.getIndex());
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node", null, true,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node2", null, false,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
|
|
|
+ .metaData(MetaData.builder().put(originalIndex, true)
|
|
|
+ .put(rolledIndex, true)
|
|
|
+ .build())
|
|
|
+ .routingTable(RoutingTable.builder().add(routingTable.build()).build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ assertThat("the rolled index has both the primary and the replica shards started so the condition should be met",
|
|
|
+ createRandomInstance().isConditionMet(originalIndex.getIndex(), clusterState).isComplete(), is(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testResultEvaluatedOnOnlyIndexTheAliasPointsToIfWriteIndexIsNull() {
|
|
|
+ String alias = randomAlphaOfLength(5);
|
|
|
+ IndexMetaData originalIndex = IndexMetaData.builder("index-000000")
|
|
|
+ .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias))
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(randomIntBetween(0, 5))
|
|
|
+ .build();
|
|
|
+ IndexMetaData rolledIndex = IndexMetaData.builder("index-000001")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(false))
|
|
|
+ .settings(settings(Version.CURRENT)
|
|
|
+ .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias)
|
|
|
+ .put("index.write.wait_for_active_shards", "all")
|
|
|
+ )
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(1)
|
|
|
+ .build();
|
|
|
+ IndexRoutingTable.Builder routingTable = new IndexRoutingTable.Builder(rolledIndex.getIndex());
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node", null, true,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node2", null, false,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
|
|
|
+ .metaData(MetaData.builder().put(originalIndex, true)
|
|
|
+ .put(rolledIndex, true)
|
|
|
+ .build())
|
|
|
+ .routingTable(RoutingTable.builder().add(routingTable.build()).build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ assertThat("the index the alias is pointing to has both the primary and the replica shards started so the condition should be" +
|
|
|
+ " met", createRandomInstance().isConditionMet(originalIndex.getIndex(), clusterState).isComplete(), is(true));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testResultReportsMeaningfulMessage() throws IOException {
|
|
|
+ String alias = randomAlphaOfLength(5);
|
|
|
+ IndexMetaData originalIndex = IndexMetaData.builder("index-000000")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(false))
|
|
|
+ .settings(settings(Version.CURRENT).put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias))
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(randomIntBetween(0, 5))
|
|
|
+ .build();
|
|
|
+ IndexMetaData rolledIndex = IndexMetaData.builder("index-000001")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(true))
|
|
|
+ .settings(settings(Version.CURRENT)
|
|
|
+ .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias)
|
|
|
+ .put("index.write.wait_for_active_shards", "3")
|
|
|
+ )
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(2)
|
|
|
+ .build();
|
|
|
+ IndexRoutingTable.Builder routingTable = new IndexRoutingTable.Builder(rolledIndex.getIndex());
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node", null, true,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ routingTable.addShard(TestShardRouting.newShardRouting(rolledIndex.getIndex().getName(), 0, "node2", null, false,
|
|
|
+ ShardRoutingState.STARTED));
|
|
|
+ ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
|
|
|
+ .metaData(MetaData.builder().put(originalIndex, true)
|
|
|
+ .put(rolledIndex, true)
|
|
|
+ .build())
|
|
|
+ .routingTable(RoutingTable.builder().add(routingTable.build()).build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ ClusterStateWaitStep.Result result = createRandomInstance().isConditionMet(originalIndex.getIndex(), clusterState);
|
|
|
+ assertThat(result.isComplete(), is(false));
|
|
|
+
|
|
|
+ XContentBuilder expected = new WaitForActiveShardsStep.ActiveShardsInfo(2, "3", false).toXContent(JsonXContent.contentBuilder(),
|
|
|
+ ToXContent.EMPTY_PARAMS);
|
|
|
+ String actualResultAsString = Strings.toString(result.getInfomationContext());
|
|
|
+ assertThat(actualResultAsString, is(Strings.toString(expected)));
|
|
|
+ assertThat(actualResultAsString, containsString("waiting for [3] shards to become active, but only [2] are active"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testResultReportsErrorMessage() {
|
|
|
+ String alias = randomAlphaOfLength(5);
|
|
|
+ IndexMetaData rolledIndex = IndexMetaData.builder("index-000001")
|
|
|
+ .putAlias(AliasMetaData.builder(alias).writeIndex(true))
|
|
|
+ .settings(settings(Version.CURRENT)
|
|
|
+ .put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, alias)
|
|
|
+ .put("index.write.wait_for_active_shards", "3")
|
|
|
+ )
|
|
|
+ .numberOfShards(1)
|
|
|
+ .numberOfReplicas(2)
|
|
|
+ .build();
|
|
|
+ ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
|
|
|
+ .metaData(MetaData.builder().put(rolledIndex, true).build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ WaitForActiveShardsStep step = createRandomInstance();
|
|
|
+ ClusterStateWaitStep.Result result = step.isConditionMet(new Index("index-000000", UUID.randomUUID().toString()),
|
|
|
+ clusterState);
|
|
|
+ assertThat(result.isComplete(), is(false));
|
|
|
+
|
|
|
+ String actualResultAsString = Strings.toString(result.getInfomationContext());
|
|
|
+ assertThat(actualResultAsString,
|
|
|
+ containsString("[" + step.getKey().getAction() + "] lifecycle action for index [index-000000] executed but " +
|
|
|
+ "index no longer exists"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testParseIndexNameReturnsCounter() {
|
|
|
+ assertThat(parseIndexNameCounter("logs-000003"), is(3));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testParseIndexNameSupportsDateMathPattern() {
|
|
|
+ assertThat(parseIndexNameCounter("<logs-{now/d}-1>"), is(1));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testParseIndexNameThrowExceptionWhenNoSeparatorIsPresent() {
|
|
|
+ try {
|
|
|
+ parseIndexNameCounter("testIndexNameWithoutDash");
|
|
|
+ fail("expected to fail as the index name contains no - separator");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e.getMessage(), is("no - separator found in index name [testIndexNameWithoutDash]"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testParseIndexNameCannotFormatNumber() {
|
|
|
+ try {
|
|
|
+ parseIndexNameCounter("testIndexName-000a2");
|
|
|
+ fail("expected to fail as the index name doesn't end with digits");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ assertThat(e.getMessage(), is("unable to parse the index name [testIndexName-000a2] to extract the counter"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|