introduce refactored ShrinkAction

this resulted in a few new steps being introduced

- AliasStep
- EnoughShardsWaitStep
- ShrinkStep
- ShrunkenIndexCheckStep
This commit is contained in:
Tal Levy 2018-04-11 18:10:13 -07:00
parent 20485cf7fb
commit 73ee5a4aa0
10 changed files with 530 additions and 582 deletions

View File

@ -0,0 +1,34 @@
/*
* 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.indexlifecycle;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexMetaData;
public class AliasStep extends AsyncActionStep {
public static final String NAME = "aliases";
public AliasStep(StepKey key, StepKey nextStepKey, Client client) {
super(key, nextStepKey, client);
}
@Override
public void performAction(IndexMetaData indexMetaData, Listener listener) {
// get source index
String index = indexMetaData.getIndex().getName();
// get target shrink index
String targetIndexName = ShrinkStep.SHRUNKEN_INDEX_PREFIX + index;
IndicesAliasesRequest aliasesRequest = new IndicesAliasesRequest()
.addAliasAction(IndicesAliasesRequest.AliasActions.removeIndex().index(index))
.addAliasAction(IndicesAliasesRequest.AliasActions.add().index(targetIndexName).alias(index));
getClient().admin().indices().aliases(aliasesRequest, ActionListener.wrap(response ->
listener.onResponse(true), listener::onFailure));
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.indexlifecycle;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.index.Index;
public class EnoughShardsWaitStep extends ClusterStateWaitStep {
public static final String NAME = "enough-shards-allocated";
private final int numberOfShards;
public EnoughShardsWaitStep(StepKey key, StepKey nextStepKey, int numberOfShards) {
super(key, nextStepKey);
this.numberOfShards = numberOfShards;
}
public int getNumberOfShards() {
return numberOfShards;
}
@Override
public boolean isConditionMet(Index index, ClusterState clusterState) {
// We only want to make progress if all shards are active
return clusterState.metaData().index(index).getNumberOfShards() == numberOfShards &&
ActiveShardCount.ALL.enoughShardsActive(clusterState, index.getName());
}
}

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
@ -14,6 +15,8 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -27,7 +30,6 @@ public class ShrinkAction implements LifecycleAction {
public static final String NAME = "shrink"; public static final String NAME = "shrink";
public static final ParseField NUMBER_OF_SHARDS_FIELD = new ParseField("number_of_shards"); public static final ParseField NUMBER_OF_SHARDS_FIELD = new ParseField("number_of_shards");
// private static final String SHRUNK_INDEX_NAME_PREFIX = "shrunk-";
private static final ConstructingObjectParser<ShrinkAction, CreateIndexRequest> PARSER = private static final ConstructingObjectParser<ShrinkAction, CreateIndexRequest> PARSER =
new ConstructingObjectParser<>(NAME, a -> new ShrinkAction((Integer) a[0])); new ConstructingObjectParser<>(NAME, a -> new ShrinkAction((Integer) a[0]));
@ -76,92 +78,15 @@ public class ShrinkAction implements LifecycleAction {
@Override @Override
public List<Step> toSteps(Client client, String phase, Step.StepKey nextStepKey) { public List<Step> toSteps(Client client, String phase, Step.StepKey nextStepKey) {
// String shrunkenIndexName = SHRUNK_INDEX_NAME_PREFIX + index.getName(); StepKey shrinkKey = new StepKey(phase, NAME, ShrinkStep.NAME);
// // TODO(talevy): magical node.name to allocate to StepKey enoughShardsKey = new StepKey(phase, NAME, EnoughShardsWaitStep.NAME);
// String nodeName = "MAGIC"; StepKey aliasKey = new StepKey(phase, NAME, AliasStep.NAME);
// ClusterStateUpdateStep updateAllocationToOneNode = new ClusterStateUpdateStep( StepKey isShrunkIndexKey = new StepKey(phase, NAME, ShrunkenIndexCheckStep.NAME);
// "move_to_single_node", NAME, phase, index.getName(), (clusterState) -> { ShrinkStep shrink = new ShrinkStep(shrinkKey, enoughShardsKey, client, numberOfShards);
// IndexMetaData idxMeta = clusterState.metaData().index(index); EnoughShardsWaitStep allocated = new EnoughShardsWaitStep(enoughShardsKey, aliasKey, numberOfShards);
// if (idxMeta == null) { AliasStep aliasSwapAndDelete = new AliasStep(aliasKey, isShrunkIndexKey, client);
// return clusterState; ShrunkenIndexCheckStep waitOnShrinkTakeover = new ShrunkenIndexCheckStep(isShrunkIndexKey, nextStepKey);
// } return Arrays.asList(shrink, allocated, aliasSwapAndDelete, waitOnShrinkTakeover);
// Settings.Builder newSettings = Settings.builder()
// .put(IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_PREFIX, "")
// .put(IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_PREFIX, "")
// .put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_name", nodeName);
// return ClusterState.builder(clusterState)
// .metaData(MetaData.builder(clusterState.metaData())
// .updateSettings(newSettings.build(), index.getName())).build();
// });
// resizeRequest.getTargetIndexRequest().settings(Settings.builder()
// .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfShards)
// .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, indexMetaData.getNumberOfReplicas())
// .put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, indexMetaData.getCreationDate())
// .build());
// indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> {
// resizeRequest.getTargetIndexRequest().alias(new Alias(aliasMetaDataObjectCursor.value.alias()));
// });
// // TODO(talevy): needs access to original index metadata, not just Index
// int numReplicas = -1;
// long lifecycleDate = -1L;
// Settings targetIndexSettings = Settings.builder()
// .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfShards)
// .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numReplicas)
// .put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, lifecycleDate)
// .build();
// CreateIndexRequest targetIndexRequest = new CreateIndexRequest(shrunkenIndexName, targetIndexSettings);
// TODO(talevy): need access to indexmetadata
// indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> {
// resizeRequest.getTargetIndexRequest().alias(new Alias(aliasMetaDataObjectCursor.value.alias()));
// });
// ClientStep<ResizeRequestBuilder, ResizeResponse> shrinkStep = new ClientStep<>( "segment_count",
// NAME, phase, index.getName(),
//
// client.admin().indices().prepareResizeIndex(index.getName(), shrunkenIndexName).setTargetIndex(targetIndexRequest),
// currentState -> {
// // check that shrunken index was already created, if so, no need to both client
// IndexMetaData shrunkMetaData = currentState.metaData().index(shrunkenIndexName);
// return shrunkMetaData != null && shrunkenIndexName.equals(IndexMetaData.INDEX_SHRINK_SOURCE_NAME
// .get(shrunkMetaData.getSettings()));
//
// }, ResizeResponse::isAcknowledged);
//
//
// ConditionalWaitStep shrunkenIndexIsAllocated = new ConditionalWaitStep("wait_replicas_allocated", NAME,
// phase, index.getName(), (currentState) -> ActiveShardCount.ALL.enoughShardsActive(currentState, index.getName()) );
//
// ClusterStateUpdateStep deleteAndUpdateAliases = new ClusterStateUpdateStep(
// "delete_this_index_set_aliases_on_shrunken", NAME, phase, index.getName(), (clusterState) -> {
// IndexMetaData idxMeta = clusterState.metaData().index(index);
// if (idxMeta == null) {
// return clusterState;
// }
// TODO(talevy): expose - MetadataDeleteIndexService.deleteIndices(clusterState, Set.of(index.getName()))
// also, looks like deletes are special CS tasks
// AckedClusterStateUpdateTask, Priority.URGENT
// 1. delete index
// 2. assign alias to shrunken index
// 3. assign index.lifecycle settings to shrunken index
// return clusterState;
// });
// UpdateSettingsStep allocateStep = new UpdateSettingsStep();
// UpdateSettingsStep waitForAllocation = new UpdateSettingsStep();
// UpdateSettingsStep allocateStep = new UpdateSettingsStep();
// Step.StepKey allocateKey = new StepKey(phase, NAME, NAME);
// StepKey allocationRoutedKey = new StepKey(phase, NAME, AllocationRoutedStep.NAME);
//
// Settings.Builder newSettings = Settings.builder();
// newSettings.put(IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_name", value));
// UpdateSettingsStep allocateStep = new UpdateSettingsStep(allocateKey, allocationRoutedKey, client, newSettings.build());
// AllocationRoutedStep routedCheckStep = new AllocationRoutedStep(allocationRoutedKey, nextStepKey);
// return Arrays.asList(allocateStep, routedCheckStep);
return Arrays.asList();
} }
@Override @Override

View File

@ -10,37 +10,49 @@ import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import java.util.Objects; import java.util.Objects;
public class ShrinkStep extends AsyncActionStep { public class ShrinkStep extends AsyncActionStep {
public static final String NAME = "shrink"; public static final String NAME = "shrink";
public static final String SHRUNKEN_INDEX_PREFIX = "shrink-";
private String shrunkenIndexName; private int numberOfShards;
public ShrinkStep(StepKey key, StepKey nextStepKey, Client client, String shrunkenIndexName) { public ShrinkStep(StepKey key, StepKey nextStepKey, Client client, int numberOfShards) {
super(key, nextStepKey, client); super(key, nextStepKey, client);
this.shrunkenIndexName = shrunkenIndexName; this.numberOfShards = numberOfShards;
} }
public String getShrunkenIndexName() { public int getNumberOfShards() {
return shrunkenIndexName; return numberOfShards;
} }
@Override @Override
public void performAction(IndexMetaData indexMetaData, Listener listener) { public void performAction(IndexMetaData indexMetaData, Listener listener) {
// if operating on the shrunken index, do nothing
Long lifecycleDate = LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE_SETTING.get(indexMetaData.getSettings()); Long lifecycleDate = LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE_SETTING.get(indexMetaData.getSettings());
if (lifecycleDate == null) { if (lifecycleDate == null) {
throw new IllegalStateException("source index[" + indexMetaData.getIndex().getName() + throw new IllegalStateException("source index[" + indexMetaData.getIndex().getName() +
"] is missing setting[" + LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE); "] is missing setting[" + LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE);
} }
String lifecycle = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexMetaData.getSettings());
String phase = LifecycleSettings.LIFECYCLE_PHASE_SETTING.get(indexMetaData.getSettings());
String action = LifecycleSettings.LIFECYCLE_ACTION_SETTING.get(indexMetaData.getSettings());
Settings relevantTargetSettings = Settings.builder() Settings relevantTargetSettings = Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, indexMetaData.getNumberOfShards()) .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfShards)
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, indexMetaData.getNumberOfReplicas()) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, indexMetaData.getNumberOfReplicas())
.put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, lifecycleDate) .put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, lifecycleDate)
.put(LifecycleSettings.LIFECYCLE_NAME, lifecycle)
.put(LifecycleSettings.LIFECYCLE_PHASE, phase)
.put(LifecycleSettings.LIFECYCLE_ACTION, action)
.put(LifecycleSettings.LIFECYCLE_STEP, ShrunkenIndexCheckStep.NAME) // skip source-index steps
.build(); .build();
String shrunkenIndexName = SHRUNKEN_INDEX_PREFIX + indexMetaData.getIndex().getName();
ResizeRequest resizeRequest = new ResizeRequest(shrunkenIndexName, indexMetaData.getIndex().getName()); ResizeRequest resizeRequest = new ResizeRequest(shrunkenIndexName, indexMetaData.getIndex().getName());
indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> { indexMetaData.getAliases().values().spliterator().forEachRemaining(aliasMetaDataObjectCursor -> {
resizeRequest.getTargetIndexRequest().alias(new Alias(aliasMetaDataObjectCursor.value.alias())); resizeRequest.getTargetIndexRequest().alias(new Alias(aliasMetaDataObjectCursor.value.alias()));
@ -55,7 +67,7 @@ public class ShrinkStep extends AsyncActionStep {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), shrunkenIndexName); return Objects.hash(super.hashCode(), numberOfShards);
} }
@Override @Override
@ -67,7 +79,7 @@ public class ShrinkStep extends AsyncActionStep {
return false; return false;
} }
ShrinkStep other = (ShrinkStep) obj; ShrinkStep other = (ShrinkStep) obj;
return super.equals(obj) && Objects.equals(shrunkenIndexName, other.shrunkenIndexName); return super.equals(obj) && Objects.equals(numberOfShards, other.numberOfShards);
} }
} }

View File

@ -0,0 +1,29 @@
/*
* 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.indexlifecycle;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.Index;
public class ShrunkenIndexCheckStep extends ClusterStateWaitStep {
public static final String NAME = "is-shrunken-index";
public ShrunkenIndexCheckStep(StepKey key, StepKey nextStepKey) {
super(key, nextStepKey);
}
@Override
public boolean isConditionMet(Index index, ClusterState clusterState) {
String shrunkenIndexSource = IndexMetaData.INDEX_SHRINK_SOURCE_NAME.get(
clusterState.metaData().index(index).getSettings());
if (Strings.isNullOrEmpty(shrunkenIndexSource)) {
throw new IllegalStateException("step[" + NAME + "] is checking an un-shrunken index[" + index.getName() + "]");
}
return index.getName().equals(ShrinkStep.SHRUNKEN_INDEX_PREFIX + shrunkenIndexSource);
}
}

View File

@ -0,0 +1,172 @@
/*
* 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.indexlifecycle;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.client.AdminClient;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import org.elasticsearch.xpack.core.indexlifecycle.AsyncActionStep.Listener;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import org.junit.Before;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;
public class AliasStepTests extends ESTestCase {
private Client client;
@Before
public void setup() {
client = Mockito.mock(Client.class);
}
public AliasStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
return new AliasStep(stepKey, nextStepKey, client);
}
public AliasStep mutateInstance(AliasStep 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 AliasStep(key, nextKey, instance.getClient());
}
public void testHashcodeAndEquals() {
EqualsHashCodeTestUtils
.checkEqualsAndHashCode(createRandomInstance(),
instance -> new AliasStep(instance.getKey(), instance.getNextStepKey(), instance.getClient()),
this::mutateInstance);
}
public void testPerformAction() throws Exception {
IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)).settings(settings(Version.CURRENT))
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
AliasStep step = createRandomInstance();
String sourceIndex = indexMetaData.getIndex().getName();
String shrunkenIndex = ShrinkStep.SHRUNKEN_INDEX_PREFIX + sourceIndex;
List<AliasActions> expectedAliasActions = Arrays.asList(
IndicesAliasesRequest.AliasActions.removeIndex().index(sourceIndex),
IndicesAliasesRequest.AliasActions.add().index(shrunkenIndex).alias(sourceIndex));
AdminClient adminClient = Mockito.mock(AdminClient.class);
IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
Mockito.when(client.admin()).thenReturn(adminClient);
Mockito.when(adminClient.indices()).thenReturn(indicesClient);
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
IndicesAliasesRequest request = (IndicesAliasesRequest) invocation.getArguments()[0];
assertThat(request.getAliasActions(), equalTo(expectedAliasActions));
@SuppressWarnings("unchecked")
ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocation.getArguments()[1];
IndicesAliasesResponse response = IndicesAliasesAction.INSTANCE.newResponse();
response.readFrom(StreamInput.wrap(new byte[] { 1 }));
listener.onResponse(response);
return null;
}
}).when(indicesClient).aliases(Mockito.any(), Mockito.any());
SetOnce<Boolean> actionCompleted = new SetOnce<>();
step.performAction(indexMetaData, new Listener() {
@Override
public void onResponse(boolean complete) {
actionCompleted.set(complete);
}
@Override
public void onFailure(Exception e) {
throw new AssertionError("Unexpected method call", e);
}
});
assertTrue(actionCompleted.get());
Mockito.verify(client, Mockito.only()).admin();
Mockito.verify(adminClient, Mockito.only()).indices();
Mockito.verify(indicesClient, Mockito.only()).aliases(Mockito.any(), Mockito.any());
}
public void testPerformActionFailure() throws Exception {
IndexMetaData indexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)).settings(settings(Version.CURRENT))
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
Exception exception = new RuntimeException();
AliasStep step = createRandomInstance();
AdminClient adminClient = Mockito.mock(AdminClient.class);
IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
Mockito.when(client.admin()).thenReturn(adminClient);
Mockito.when(adminClient.indices()).thenReturn(indicesClient);
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
@SuppressWarnings("unchecked")
ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocation.getArguments()[1];
listener.onFailure(exception);
return null;
}
}).when(indicesClient).aliases(Mockito.any(), Mockito.any());
SetOnce<Boolean> exceptionThrown = new SetOnce<>();
step.performAction(indexMetaData, new Listener() {
@Override
public void onResponse(boolean complete) {
throw new AssertionError("Unexpected method call");
}
@Override
public void onFailure(Exception e) {
assertSame(exception, e);
exceptionThrown.set(true);
}
});
assertEquals(true, exceptionThrown.get());
Mockito.verify(client, Mockito.only()).admin();
Mockito.verify(adminClient, Mockito.only()).indices();
Mockito.verify(indicesClient, Mockito.only()).aliases(Mockito.any(), Mockito.any());
}
}

View File

@ -0,0 +1,118 @@
/*
* 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.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
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.transport.TransportAddress;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.node.Node;
import org.elasticsearch.test.ESTestCase;
public class EnoughShardsWaitStepTests extends ESTestCase {
public void testConditionMet() {
int numberOfShards = randomIntBetween(1, 10);
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT))
.numberOfShards(numberOfShards)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
Index index = indexMetadata.getIndex();
String nodeId = randomAlphaOfLength(10);
DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT)
.put(Node.NODE_MASTER_SETTING.getKey(), true).build(),
new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId);
IndexRoutingTable.Builder builder = IndexRoutingTable.builder(index);
for (int i = 0; i < numberOfShards; i++) {
builder.addShard(TestShardRouting.newShardRouting(new ShardId(index, i),
nodeId, true, ShardRoutingState.STARTED));
}
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.metaData(metaData)
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.routingTable(RoutingTable.builder().add(builder.build()).build()).build();
EnoughShardsWaitStep step = new EnoughShardsWaitStep(null, null, numberOfShards);
assertTrue(step.isConditionMet(indexMetadata.getIndex(), clusterState));
}
public void testConditionNotMetBecauseOfActive() {
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
Index index = indexMetadata.getIndex();
String nodeId = randomAlphaOfLength(10);
DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT)
.put(Node.NODE_MASTER_SETTING.getKey(), true).build(),
new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId);
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.metaData(metaData)
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.routingTable(RoutingTable.builder()
.add(IndexRoutingTable.builder(index).addShard(
TestShardRouting.newShardRouting(new ShardId(index, 0),
nodeId, true, ShardRoutingState.INITIALIZING)))
.build())
.build();
EnoughShardsWaitStep step = new EnoughShardsWaitStep(null, null, 1);
assertFalse(step.isConditionMet(indexMetadata.getIndex(), clusterState));
}
public void testConditionNotMetBecauseOfShardCount() {
int numberOfShards = randomIntBetween(1, 10);
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT))
.numberOfShards(numberOfShards)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
Index index = indexMetadata.getIndex();
String nodeId = randomAlphaOfLength(10);
DiscoveryNode masterNode = DiscoveryNode.createLocal(settings(Version.CURRENT)
.put(Node.NODE_MASTER_SETTING.getKey(), true).build(),
new TransportAddress(TransportAddress.META_ADDRESS, 9300), nodeId);
IndexRoutingTable.Builder builder = IndexRoutingTable.builder(index);
for (int i = 0; i < numberOfShards; i++) {
builder.addShard(TestShardRouting.newShardRouting(new ShardId(index, i),
nodeId, true, ShardRoutingState.INITIALIZING));
}
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT)
.metaData(metaData)
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.routingTable(RoutingTable.builder().add(builder.build()).build()).build();
EnoughShardsWaitStep step = new EnoughShardsWaitStep(null, null, 1);
assertFalse(step.isConditionMet(indexMetadata.getIndex(), clusterState));
}
}

View File

@ -8,8 +8,10 @@ package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractSerializingTestCase; import org.elasticsearch.test.AbstractSerializingTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -40,480 +42,26 @@ public class ShrinkActionTests extends AbstractSerializingTestCase<ShrinkAction>
assertThat(e.getMessage(), equalTo("[number_of_shards] must be greater than 0")); assertThat(e.getMessage(), equalTo("[number_of_shards] must be greater than 0"));
} }
// public void testExecuteSuccessfullyCompleted() { public void testToSteps() {
// String originalIndexName = randomAlphaOfLengthBetween(1, 20); ShrinkAction action = createTestInstance();
// Index index = new Index("shrunk-" + originalIndexName, randomAlphaOfLengthBetween(1, 20)); String phase = randomAlphaOfLengthBetween(1, 10);
// ClusterService clusterService = Mockito.mock(ClusterService.class); StepKey nextStepKey = new StepKey(randomAlphaOfLengthBetween(1, 10), randomAlphaOfLengthBetween(1, 10),
// IndexMetaData originalIndexMetaData = IndexMetaData.builder(originalIndexName) randomAlphaOfLengthBetween(1, 10));
// .settings(settings(Version.CURRENT)).numberOfReplicas(0).numberOfShards(1).build(); List<Step> steps = action.toSteps(null, phase, nextStepKey);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName()) assertThat(steps.size(), equalTo(4));
// .settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, originalIndexName)) StepKey expectedFirstKey = new StepKey(phase, ShrinkAction.NAME, ShrinkStep.NAME);
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build(); StepKey expectedSecondKey = new StepKey(phase, ShrinkAction.NAME, EnoughShardsWaitStep.NAME);
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(), StepKey expectedThirdKey = new StepKey(phase, ShrinkAction.NAME, AliasStep.NAME);
// indexMetadata).fPut(originalIndexName, originalIndexMetaData); StepKey expectedFourthKey = new StepKey(phase, ShrinkAction.NAME, ShrunkenIndexCheckStep.NAME);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build())) assertTrue(steps.get(0) instanceof ShrinkStep);
// .build(); assertThat(steps.get(0).getKey(), equalTo(expectedFirstKey));
// Mockito.when(clusterService.state()).thenReturn(clusterState); assertThat(((ShrinkStep) steps.get(0)).getNumberOfShards(), equalTo(action.getNumberOfShards()));
// Client client = Mockito.mock(Client.class); assertTrue(steps.get(1) instanceof EnoughShardsWaitStep);
// AdminClient adminClient = Mockito.mock(AdminClient.class); assertThat(steps.get(1).getKey(), equalTo(expectedSecondKey));
// IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); assertThat(((EnoughShardsWaitStep) steps.get(1)).getNumberOfShards(), equalTo(action.getNumberOfShards()));
// Mockito.when(client.admin()).thenReturn(adminClient); assertTrue(steps.get(2) instanceof AliasStep);
// Mockito.when(adminClient.indices()).thenReturn(indicesClient); assertThat(steps.get(2).getKey(), equalTo(expectedThirdKey));
// assertTrue(steps.get(3) instanceof ShrunkenIndexCheckStep);
// Mockito.doAnswer(invocationOnMock -> { assertThat(steps.get(3).getKey(), equalTo(expectedFourthKey));
// IndicesAliasesRequest request = (IndicesAliasesRequest) invocationOnMock.getArguments()[0]; }
// @SuppressWarnings("unchecked")
// ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocationOnMock.getArguments()[1];
// IndicesAliasesResponse response = IndicesAliasesAction.INSTANCE.newResponse();
// response.readFrom(StreamInput.wrap(new byte[] { 1 }));
//
// assertThat(request.getAliasActions().size(), equalTo(2));
// assertThat(request.getAliasActions().get(0).actionType(), equalTo(IndicesAliasesRequest.AliasActions.Type.REMOVE_INDEX));
// assertThat(request.getAliasActions().get(0).indices(), equalTo(new String[] { originalIndexName }));
// assertThat(request.getAliasActions().get(1).actionType(), equalTo(IndicesAliasesRequest.AliasActions.Type.ADD));
// assertThat(request.getAliasActions().get(1).indices(), equalTo(new String[] { index.getName() }));
// assertThat(request.getAliasActions().get(1).aliases(), equalTo(new String[] { originalIndexName }));
//
// listener.onResponse(response);
// return null;
// }).when(indicesClient).aliases(any(), any());
//
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertTrue(actionCompleted.get());
// Mockito.verify(client, Mockito.only()).admin();
// Mockito.verify(adminClient, Mockito.only()).indices();
// Mockito.verify(indicesClient, Mockito.only()).aliases(any(), any());
// }
//
// public void testExecuteAlreadyCompletedAndRunAgain() {
// String originalIndexName = randomAlphaOfLengthBetween(1, 20);
// Index index = new Index("shrunk-" + originalIndexName, randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .putAlias(AliasMetaData.builder(originalIndexName).build())
// .settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, originalIndexName))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertTrue(actionCompleted.get());
// Mockito.verify(client, Mockito.never()).admin();
// }
//
// public void testExecuteOriginalIndexAliasFailure() {
// String originalIndexName = randomAlphaOfLengthBetween(1, 20);
// Index index = new Index("shrunk-" + originalIndexName, randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, originalIndexName))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.STARTED)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// AdminClient adminClient = Mockito.mock(AdminClient.class);
// IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
// Mockito.when(client.admin()).thenReturn(adminClient);
// Mockito.when(adminClient.indices()).thenReturn(indicesClient);
//
// Mockito.doAnswer(invocationOnMock -> {
// @SuppressWarnings("unchecked")
// ActionListener<IndicesAliasesResponse> listener = (ActionListener<IndicesAliasesResponse>) invocationOnMock.getArguments()[1];
// listener.onFailure(new RuntimeException("failed"));
// return null;
// }).when(indicesClient).aliases(any(), any());
//
// SetOnce<Exception> onFailureException = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// throw new AssertionError("Unexpected method call");
// }
//
// @Override
// public void onFailure(Exception e) {
// onFailureException.set(e);
// }
// });
//
// assertThat(onFailureException.get().getMessage(), equalTo("failed"));
//
// Mockito.verify(client, Mockito.only()).admin();
// Mockito.verify(adminClient, Mockito.only()).indices();
// Mockito.verify(indicesClient, Mockito.only()).aliases(any(), any());
// }
//
// public void testExecuteWithIssuedResizeRequest() {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index("shrunk-" + index.getName(), randomAlphaOfLengthBetween(1, 20));
// int numberOfShards = randomIntBetween(1, 5);
// int numberOfReplicas = randomIntBetween(1, 5);
// long creationDate = randomNonNegativeLong();
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT))
// .putAlias(AliasMetaData.builder("my_alias"))
// .creationDate(creationDate)
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(numberOfReplicas).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.STARTED)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// AdminClient adminClient = Mockito.mock(AdminClient.class);
// IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
// Mockito.when(client.admin()).thenReturn(adminClient);
// Mockito.when(adminClient.indices()).thenReturn(indicesClient);
//
// Settings expectedSettings = Settings.builder().put(IndexMetaData.SETTING_BLOCKS_WRITE, true).build();
//
// Mockito.doAnswer(invocationOnMock -> {
// UpdateSettingsRequest request = (UpdateSettingsRequest) invocationOnMock.getArguments()[0];
// @SuppressWarnings("unchecked")
// ActionListener<UpdateSettingsResponse> listener = (ActionListener<UpdateSettingsResponse>) invocationOnMock.getArguments()[1];
// UpdateSettingsTestHelper.assertSettingsRequest(request, expectedSettings, index.getName());
// listener.onResponse(UpdateSettingsTestHelper.createMockResponse(true));
// return null;
// }).when(indicesClient).updateSettings(any(), any());
//
// Mockito.doAnswer(invocationOnMock -> {
// ResizeRequest request = (ResizeRequest) invocationOnMock.getArguments()[0];
// @SuppressWarnings("unchecked")
// ActionListener<AcknowledgedResponse> listener = (ActionListener<AcknowledgedResponse>) invocationOnMock.getArguments()[1];
// assertThat(request.getSourceIndex(), equalTo(index.getName()));
// assertThat(request.getTargetIndexRequest().aliases(), equalTo(Collections.singleton(new Alias("my_alias"))));
// assertThat(request.getTargetIndexRequest().settings(), equalTo(Settings.builder()
// .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, numberOfShards)
// .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, numberOfReplicas)
// .put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate).build()));
// assertThat(request.getTargetIndexRequest().index(), equalTo(targetIndex.getName()));
// ResizeResponse resizeResponse = ResizeAction.INSTANCE.newResponse();
// resizeResponse.readFrom(StreamInput.wrap(new byte[] { 1, 1, 1, 1, 1 }));
// listener.onResponse(resizeResponse);
// return null;
// }).when(indicesClient).resizeIndex(any(), any());
//
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(numberOfShards);
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertFalse(actionCompleted.get());
//
// Mockito.verify(client, Mockito.atLeast(1)).admin();
// Mockito.verify(adminClient, Mockito.atLeast(1)).indices();
// Mockito.verify(indicesClient, Mockito.atLeast(1)).updateSettings(any(), any());
// Mockito.verify(indicesClient, Mockito.atLeast(1)).resizeIndex(any(), any());
// }
//
// public void testExecuteWithIssuedResizeRequestFailure() {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.STARTED)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// AdminClient adminClient = Mockito.mock(AdminClient.class);
// IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
// Mockito.when(client.admin()).thenReturn(adminClient);
// Mockito.when(adminClient.indices()).thenReturn(indicesClient);
//
// Mockito.doAnswer(invocationOnMock -> {
// @SuppressWarnings("unchecked")
// ActionListener<UpdateSettingsResponse> listener = (ActionListener<UpdateSettingsResponse>) invocationOnMock.getArguments()[1];
// listener.onResponse(UpdateSettingsTestHelper.createMockResponse(true));
// return null;
// }).when(indicesClient).updateSettings(any(), any());
//
// Mockito.doAnswer(invocationOnMock -> {
// @SuppressWarnings("unchecked")
// ActionListener<AcknowledgedResponse> listener = (ActionListener<AcknowledgedResponse>) invocationOnMock.getArguments()[1];
// ResizeResponse resizeResponse = ResizeAction.INSTANCE.newResponse();
// resizeResponse.readFrom(StreamInput.wrap(new byte[] { 0, 1, 1, 1, 1 }));
// listener.onResponse(resizeResponse);
// return null;
// }).when(indicesClient).resizeIndex(any(), any());
//
// SetOnce<Exception> exceptionReturned = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// throw new AssertionError("Unexpected method call to onSuccess");
// }
//
// @Override
// public void onFailure(Exception e) {
// exceptionReturned.set(e);
// }
// });
//
// assertThat(exceptionReturned.get().getMessage(), equalTo("Shrink request failed to be acknowledged"));
//
// Mockito.verify(client, Mockito.atLeast(1)).admin();
// Mockito.verify(adminClient, Mockito.atLeast(1)).indices();
// Mockito.verify(indicesClient, Mockito.atLeast(1)).updateSettings(any(), any());
// Mockito.verify(indicesClient, Mockito.atLeast(1)).resizeIndex(any(), any());
// }
//
// public void testExecuteWithAllShardsAllocatedAndShrunkenIndexSetting() {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index("shrunk-" + index.getName(), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_PHASE, "phase1")
// .put(LifecycleSettings.LIFECYCLE_ACTION, "action1").put(LifecycleSettings.LIFECYCLE_NAME, "test"))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// IndexMetaData targetIndexMetaData = IndexMetaData.builder(targetIndex.getName())
// .settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, index.getName()))
// .numberOfShards(randomIntBetween(1, 3)).numberOfReplicas(indexMetadata.getNumberOfReplicas()).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder()
// .fPut(index.getName(), indexMetadata).fPut(targetIndex.getName(), targetIndexMetaData);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.STARTED)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// AdminClient adminClient = Mockito.mock(AdminClient.class);
// IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
// Mockito.when(client.admin()).thenReturn(adminClient);
// Mockito.when(adminClient.indices()).thenReturn(indicesClient);
//
// Settings expectedSettings = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, "test")
// .put(LifecycleSettings.LIFECYCLE_PHASE, "phase1").put(LifecycleSettings.LIFECYCLE_ACTION, "action1").build();
//
// Mockito.doAnswer(invocationOnMock -> {
// UpdateSettingsRequest request = (UpdateSettingsRequest) invocationOnMock.getArguments()[0];
// @SuppressWarnings("unchecked")
// ActionListener<UpdateSettingsResponse> listener = (ActionListener<UpdateSettingsResponse>) invocationOnMock.getArguments()[1];
// UpdateSettingsTestHelper.assertSettingsRequest(request, expectedSettings, targetIndex.getName());
// listener.onResponse(UpdateSettingsTestHelper.createMockResponse(true));
// return null;
// }).when(indicesClient).updateSettings(any(), any());
//
// Mockito.doAnswer(invocationOnMock -> {
// DeleteIndexRequest request = (DeleteIndexRequest) invocationOnMock.getArguments()[0];
// @SuppressWarnings("unchecked")
// ActionListener<DeleteIndexResponse> listener = (ActionListener<DeleteIndexResponse>) invocationOnMock.getArguments()[1];
// assertNotNull(request);
// assertEquals(1, request.indices().length);
// assertEquals(index.getName(), request.indices()[0]);
// listener.onResponse(null);
// return null;
// }).when(indicesClient).delete(any(), any());
//
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertFalse(actionCompleted.get());
// Mockito.verify(client, Mockito.atLeast(1)).admin();
// Mockito.verify(adminClient, Mockito.atLeast(1)).indices();
// Mockito.verify(indicesClient, Mockito.atLeast(1)).updateSettings(any(), any());
// }
//
// public void testExecuteWithAllShardsAllocatedAndShrunkenIndexConfigured() {
// String lifecycleName = randomAlphaOfLengthBetween(5, 10);
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index("shrunk-" + index.getName(), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_PHASE, "phase1")
// .put(LifecycleSettings.LIFECYCLE_ACTION, "action1").put(LifecycleSettings.LIFECYCLE_NAME, lifecycleName))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// IndexMetaData targetIndexMetaData = IndexMetaData.builder(targetIndex.getName())
// .settings(settings(Version.CURRENT)
// .put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, index.getName())
// .put(LifecycleSettings.LIFECYCLE_NAME_SETTING.getKey(), lifecycleName))
// .numberOfShards(randomIntBetween(1, 3)).numberOfReplicas(indexMetadata.getNumberOfReplicas()).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder()
// .fPut(index.getName(), indexMetadata).fPut(targetIndex.getName(), targetIndexMetaData);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.STARTED)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
//
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertFalse(actionCompleted.get());
// Mockito.verifyZeroInteractions(client);
// }
//
// public void testExecuteWaitingOnAllShardsActive() {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index("shrunk-" + index.getName(), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// IndexMetaData targetIndexMetadata = IndexMetaData.builder(targetIndex.getName())
// .settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, index.getName()))
// .numberOfShards(1).numberOfReplicas(randomIntBetween(0, 5)).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata).fPut(targetIndex.getName(), targetIndexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE).metaData(MetaData.builder().indices(indices.build()))
// .routingTable(RoutingTable.builder()
// .add(IndexRoutingTable.builder(targetIndex).addShard(
// TestShardRouting.newShardRouting(new ShardId(index, 0), "node1", true,
// ShardRoutingState.INITIALIZING)))
// .build())
// .build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
// SetOnce<Boolean> actionCompleted = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// actionCompleted.set(completed);
// }
//
// @Override
// public void onFailure(Exception e) {
// throw new AssertionError("Unexpected method call", e);
// }
// });
//
// assertFalse(actionCompleted.get());
// }
//
// public void testExecuteIndexAlreadyExists() {
// Index index = new Index(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
// Index targetIndex = new Index("shrunk-" + index.getName(), randomAlphaOfLengthBetween(1, 20));
// ClusterService clusterService = Mockito.mock(ClusterService.class);
// IndexMetaData indexMetadata = IndexMetaData.builder(index.getName())
// .settings(settings(Version.CURRENT))
// .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)).build();
// IndexMetaData targetIndexMetadata = IndexMetaData.builder(targetIndex.getName())
// .settings(settings(Version.CURRENT))
// .numberOfShards(1).numberOfReplicas(randomIntBetween(0, 5)).build();
// ImmutableOpenMap.Builder<String, IndexMetaData> indices = ImmutableOpenMap.<String, IndexMetaData> builder().fPut(index.getName(),
// indexMetadata).fPut(targetIndex.getName(), targetIndexMetadata);
// ClusterState clusterState = ClusterState.builder(ClusterState.EMPTY_STATE)
// .metaData(MetaData.builder().indices(indices.build())).build();
// Mockito.when(clusterService.state()).thenReturn(clusterState);
// Client client = Mockito.mock(Client.class);
//
// SetOnce<Exception> actionFailed = new SetOnce<>();
// ShrinkAction action = new ShrinkAction(randomIntBetween(1, 10));
//
// action.execute(index, client, clusterService, new LifecycleAction.Listener() {
// @Override
// public void onSuccess(boolean completed) {
// throw new AssertionError("Unexpected method call to onSuccess");
// }
//
// @Override
// public void onFailure(Exception e) {
// actionFailed.set(e);
// }
// });
//
// assertThat(actionFailed.get().getMessage(), equalTo("Cannot shrink index [" + index.getName() + "]" +
// " because target index [" + targetIndex.getName() + "] already exists."));
// }
} }

View File

@ -45,14 +45,14 @@ public class ShrinkStepTests extends ESTestCase {
public ShrinkStep createRandomInstance() { public ShrinkStep createRandomInstance() {
StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10)); StepKey stepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10)); StepKey nextStepKey = new StepKey(randomAlphaOfLength(10), randomAlphaOfLength(10), randomAlphaOfLength(10));
String shrunkenIndexName = randomAlphaOfLengthBetween(1, 20); int numberOfShards = randomIntBetween(1, 20);
return new ShrinkStep(stepKey, nextStepKey, client, shrunkenIndexName); return new ShrinkStep(stepKey, nextStepKey, client, numberOfShards);
} }
public ShrinkStep mutateInstance(ShrinkStep instance) { public ShrinkStep mutateInstance(ShrinkStep instance) {
StepKey key = instance.getKey(); StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey(); StepKey nextKey = instance.getNextStepKey();
String shrunkenIndexName = instance.getShrunkenIndexName(); int numberOfShards = instance.getNumberOfShards();
switch (between(0, 2)) { switch (between(0, 2)) {
case 0: case 0:
@ -62,32 +62,39 @@ public class ShrinkStepTests extends ESTestCase {
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5)); nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break; break;
case 2: case 2:
shrunkenIndexName = shrunkenIndexName + randomAlphaOfLengthBetween(1, 5); numberOfShards = numberOfShards + 1;
break; break;
default: default:
throw new AssertionError("Illegal randomisation branch"); throw new AssertionError("Illegal randomisation branch");
} }
return new ShrinkStep(key, nextKey, instance.getClient(), shrunkenIndexName); return new ShrinkStep(key, nextKey, instance.getClient(), numberOfShards);
} }
public void testHashcodeAndEquals() { public void testHashcodeAndEquals() {
EqualsHashCodeTestUtils EqualsHashCodeTestUtils
.checkEqualsAndHashCode(createRandomInstance(), .checkEqualsAndHashCode(createRandomInstance(),
instance -> new ShrinkStep(instance.getKey(), instance.getNextStepKey(), instance.getClient(), instance -> new ShrinkStep(instance.getKey(), instance.getNextStepKey(), instance.getClient(),
instance.getShrunkenIndexName()), instance.getNumberOfShards()),
this::mutateInstance); this::mutateInstance);
} }
public void testPerformAction() throws Exception { public void testPerformAction() throws Exception {
String lifecycleName = randomAlphaOfLength(5);
long creationDate = randomNonNegativeLong(); long creationDate = randomNonNegativeLong();
ShrinkStep step = createRandomInstance();
IndexMetaData sourceIndexMetaData = IndexMetaData.builder(randomAlphaOfLength(10)) IndexMetaData sourceIndexMetaData = IndexMetaData.builder(randomAlphaOfLength(10))
.settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate)) .settings(settings(Version.CURRENT)
.put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate)
.put(LifecycleSettings.LIFECYCLE_NAME, lifecycleName)
.put(LifecycleSettings.LIFECYCLE_PHASE, step.getKey().getPhase())
.put(LifecycleSettings.LIFECYCLE_ACTION, step.getKey().getAction())
.put(LifecycleSettings.LIFECYCLE_STEP, ShrunkenIndexCheckStep.NAME)
)
.numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5)) .numberOfShards(randomIntBetween(1, 5)).numberOfReplicas(randomIntBetween(0, 5))
.putAlias(AliasMetaData.builder("my_alias")) .putAlias(AliasMetaData.builder("my_alias"))
.build(); .build();
ShrinkStep step = createRandomInstance();
AdminClient adminClient = Mockito.mock(AdminClient.class); AdminClient adminClient = Mockito.mock(AdminClient.class);
IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class); IndicesAdminClient indicesClient = Mockito.mock(IndicesAdminClient.class);
@ -104,10 +111,16 @@ public class ShrinkStepTests extends ESTestCase {
assertThat(request.getSourceIndex(), equalTo(sourceIndexMetaData.getIndex().getName())); assertThat(request.getSourceIndex(), equalTo(sourceIndexMetaData.getIndex().getName()));
assertThat(request.getTargetIndexRequest().aliases(), equalTo(Collections.singleton(new Alias("my_alias")))); assertThat(request.getTargetIndexRequest().aliases(), equalTo(Collections.singleton(new Alias("my_alias"))));
assertThat(request.getTargetIndexRequest().settings(), equalTo(Settings.builder() assertThat(request.getTargetIndexRequest().settings(), equalTo(Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, sourceIndexMetaData.getNumberOfShards()) .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, step.getNumberOfShards())
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, sourceIndexMetaData.getNumberOfReplicas()) .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, sourceIndexMetaData.getNumberOfReplicas())
.put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate).build())); .put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate)
assertThat(request.getTargetIndexRequest().index(), equalTo(step.getShrunkenIndexName())); .put(LifecycleSettings.LIFECYCLE_NAME, lifecycleName)
.put(LifecycleSettings.LIFECYCLE_PHASE, step.getKey().getPhase())
.put(LifecycleSettings.LIFECYCLE_ACTION, step.getKey().getAction())
.put(LifecycleSettings.LIFECYCLE_STEP, ShrunkenIndexCheckStep.NAME)
.build()));
assertThat(request.getTargetIndexRequest().settings()
.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS, -1), equalTo(step.getNumberOfShards()));
ResizeResponse resizeResponse = ResizeAction.INSTANCE.newResponse(); ResizeResponse resizeResponse = ResizeAction.INSTANCE.newResponse();
resizeResponse.readFrom(StreamInput.wrap(new byte[] { 1, 1, 1, 1, 1 })); resizeResponse.readFrom(StreamInput.wrap(new byte[] { 1, 1, 1, 1, 1 }));
listener.onResponse(resizeResponse); listener.onResponse(resizeResponse);

View File

@ -0,0 +1,66 @@
/*
* 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.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.test.ESTestCase;
import static org.hamcrest.Matchers.equalTo;
public class ShrunkenIndexCheckStepTests extends ESTestCase {
public void testConditionMet() {
String sourceIndex = randomAlphaOfLengthBetween(1, 10);
IndexMetaData indexMetadata = IndexMetaData.builder(ShrinkStep.SHRUNKEN_INDEX_PREFIX + sourceIndex)
.settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, sourceIndex))
.numberOfShards(1)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
ShrunkenIndexCheckStep step = new ShrunkenIndexCheckStep(null, null);
assertTrue(step.isConditionMet(indexMetadata.getIndex(), clusterState));
}
public void testConditionNotMetBecauseNotSameShrunkenIndex() {
String sourceIndex = randomAlphaOfLengthBetween(1, 10);
IndexMetaData indexMetadata = IndexMetaData.builder(sourceIndex + "hello")
.settings(settings(Version.CURRENT).put(IndexMetaData.INDEX_SHRINK_SOURCE_NAME_KEY, sourceIndex))
.numberOfShards(1)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
ShrunkenIndexCheckStep step = new ShrunkenIndexCheckStep(null, null);
assertFalse(step.isConditionMet(indexMetadata.getIndex(), clusterState));
}
public void testIllegalState() {
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
ShrunkenIndexCheckStep step = new ShrunkenIndexCheckStep(null, null);
IllegalStateException exception = expectThrows(IllegalStateException.class,
() -> step.isConditionMet(indexMetadata.getIndex(), clusterState));
assertThat(exception.getMessage(),
equalTo("step[is-shrunken-index] is checking an un-shrunken index[" + indexMetadata.getIndex().getName() + "]"));
}
}