OpenSearch/server/src/test/java/org/elasticsearch/indices/IndicesServiceTests.java
Like b8be6cb5c7
Reject index.optimize_auto_generated_id setting (#28895)
This commit rejects the index.optmize_auto_generated_id setting for
indices created on or after 7.0.0. This setting was deprecated in 6.7.0.
2019-02-10 13:46:09 -05:00

690 lines
34 KiB
Java

/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.indices;
import org.apache.lucene.search.similarities.BM25Similarity;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.store.AlreadyClosedException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.stats.CommonStatsFlags;
import org.elasticsearch.action.admin.indices.stats.IndexShardStats;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
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.service.ClusterService;
import org.elasticsearch.cluster.shards.ClusterShardLimitIT;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.env.ShardLockObtainFailedException;
import org.elasticsearch.gateway.GatewayMetaState;
import org.elasticsearch.gateway.LocalAllocateDangledIndices;
import org.elasticsearch.gateway.MetaStateService;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.engine.EngineConfig;
import org.elasticsearch.index.engine.EngineFactory;
import org.elasticsearch.index.engine.InternalEngine;
import org.elasticsearch.index.engine.InternalEngineFactory;
import org.elasticsearch.index.mapper.KeywordFieldMapper;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.shard.IllegalIndexShardStateException;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.index.shard.IndexShardState;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.ShardPath;
import org.elasticsearch.index.similarity.NonNegativeScoresSimilarity;
import org.elasticsearch.indices.IndicesService.ShardDeletionCheckResult;
import org.elasticsearch.plugins.EnginePlugin;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.test.IndexSettingsModule;
import org.elasticsearch.test.VersionUtils;
import org.elasticsearch.test.hamcrest.RegexMatcher;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.elasticsearch.cluster.shards.ClusterShardLimitIT.ShardCounts.forDataNodeCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class IndicesServiceTests extends ESSingleNodeTestCase {
public IndicesService getIndicesService() {
return getInstanceFromNode(IndicesService.class);
}
public NodeEnvironment getNodeEnvironment() {
return getInstanceFromNode(NodeEnvironment.class);
}
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Stream.concat(
super.getPlugins().stream(),
Stream.of(TestPlugin.class, FooEnginePlugin.class, BarEnginePlugin.class))
.collect(Collectors.toList());
}
public static class FooEnginePlugin extends Plugin implements EnginePlugin {
static class FooEngineFactory implements EngineFactory {
@Override
public Engine newReadWriteEngine(final EngineConfig config) {
return new InternalEngine(config);
}
}
private static final Setting<Boolean> FOO_INDEX_SETTING =
Setting.boolSetting("index.foo_index", false, Setting.Property.IndexScope);
@Override
public List<Setting<?>> getSettings() {
return Collections.singletonList(FOO_INDEX_SETTING);
}
@Override
public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
if (FOO_INDEX_SETTING.get(indexSettings.getSettings())) {
return Optional.of(new FooEngineFactory());
} else {
return Optional.empty();
}
}
}
public static class BarEnginePlugin extends Plugin implements EnginePlugin {
static class BarEngineFactory implements EngineFactory {
@Override
public Engine newReadWriteEngine(final EngineConfig config) {
return new InternalEngine(config);
}
}
private static final Setting<Boolean> BAR_INDEX_SETTING =
Setting.boolSetting("index.bar_index", false, Setting.Property.IndexScope);
@Override
public List<Setting<?>> getSettings() {
return Collections.singletonList(BAR_INDEX_SETTING);
}
@Override
public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
if (BAR_INDEX_SETTING.get(indexSettings.getSettings())) {
return Optional.of(new BarEngineFactory());
} else {
return Optional.empty();
}
}
}
public static class TestPlugin extends Plugin implements MapperPlugin {
public TestPlugin() {}
@Override
public Map<String, Mapper.TypeParser> getMappers() {
return Collections.singletonMap("fake-mapper", new KeywordFieldMapper.TypeParser());
}
@Override
public void onIndexModule(IndexModule indexModule) {
super.onIndexModule(indexModule);
indexModule.addSimilarity("fake-similarity",
(settings, indexCreatedVersion, scriptService) -> new BM25Similarity());
}
}
@Override
protected boolean resetNodeAfterTest() {
return true;
}
public void testCanDeleteShardContent() {
IndicesService indicesService = getIndicesService();
IndexMetaData meta = IndexMetaData.builder("test").settings(settings(Version.CURRENT)).numberOfShards(1).numberOfReplicas(
1).build();
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("test", meta.getSettings());
ShardId shardId = new ShardId(meta.getIndex(), 0);
assertEquals("no shard location", indicesService.canDeleteShardContent(shardId, indexSettings),
ShardDeletionCheckResult.NO_FOLDER_FOUND);
IndexService test = createIndex("test");
shardId = new ShardId(test.index(), 0);
assertTrue(test.hasShard(0));
assertEquals("shard is allocated", indicesService.canDeleteShardContent(shardId, test.getIndexSettings()),
ShardDeletionCheckResult.STILL_ALLOCATED);
test.removeShard(0, "boom");
assertEquals("shard is removed", indicesService.canDeleteShardContent(shardId, test.getIndexSettings()),
ShardDeletionCheckResult.FOLDER_FOUND_CAN_DELETE);
ShardId notAllocated = new ShardId(test.index(), 100);
assertEquals("shard that was never on this node should NOT be deletable",
indicesService.canDeleteShardContent(notAllocated, test.getIndexSettings()), ShardDeletionCheckResult.NO_FOLDER_FOUND);
}
public void testDeleteIndexStore() throws Exception {
IndicesService indicesService = getIndicesService();
IndexService test = createIndex("test");
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
IndexMetaData firstMetaData = clusterService.state().metaData().index("test");
assertTrue(test.hasShard(0));
try {
indicesService.deleteIndexStore("boom", firstMetaData, clusterService.state());
fail();
} catch (IllegalStateException ex) {
// all good
}
GatewayMetaState gwMetaState = getInstanceFromNode(GatewayMetaState.class);
MetaData meta = gwMetaState.getMetaData();
assertNotNull(meta);
assertNotNull(meta.index("test"));
assertAcked(client().admin().indices().prepareDelete("test"));
meta = gwMetaState.getMetaData();
assertNotNull(meta);
assertNull(meta.index("test"));
test = createIndex("test");
client().prepareIndex("test", "type", "1").setSource("field", "value").setRefreshPolicy(IMMEDIATE).get();
client().admin().indices().prepareFlush("test").get();
assertHitCount(client().prepareSearch("test").get(), 1);
IndexMetaData secondMetaData = clusterService.state().metaData().index("test");
assertAcked(client().admin().indices().prepareClose("test"));
ShardPath path = ShardPath.loadShardPath(logger, getNodeEnvironment(), new ShardId(test.index(), 0), test.getIndexSettings());
assertTrue(path.exists());
try {
indicesService.deleteIndexStore("boom", secondMetaData, clusterService.state());
fail();
} catch (IllegalStateException ex) {
// all good
}
assertTrue(path.exists());
// now delete the old one and make sure we resolve against the name
try {
indicesService.deleteIndexStore("boom", firstMetaData, clusterService.state());
fail();
} catch (IllegalStateException ex) {
// all good
}
assertAcked(client().admin().indices().prepareOpen("test"));
ensureGreen("test");
}
public void testPendingTasks() throws Exception {
IndicesService indicesService = getIndicesService();
IndexService test = createIndex("test");
assertTrue(test.hasShard(0));
ShardPath path = test.getShardOrNull(0).shardPath();
assertTrue(test.getShardOrNull(0).routingEntry().started());
ShardPath shardPath = ShardPath.loadShardPath(logger, getNodeEnvironment(), new ShardId(test.index(), 0), test.getIndexSettings());
assertEquals(shardPath, path);
try {
indicesService.processPendingDeletes(test.index(), test.getIndexSettings(), new TimeValue(0, TimeUnit.MILLISECONDS));
fail("can't get lock");
} catch (ShardLockObtainFailedException ex) {
}
assertTrue(path.exists());
int numPending = 1;
if (randomBoolean()) {
indicesService.addPendingDelete(new ShardId(test.index(), 0), test.getIndexSettings());
} else {
if (randomBoolean()) {
numPending++;
indicesService.addPendingDelete(new ShardId(test.index(), 0), test.getIndexSettings());
}
indicesService.addPendingDelete(test.index(), test.getIndexSettings());
}
assertAcked(client().admin().indices().prepareClose("test"));
assertTrue(path.exists());
assertEquals(indicesService.numPendingDeletes(test.index()), numPending);
assertTrue(indicesService.hasUncompletedPendingDeletes());
// shard lock released... we can now delete
indicesService.processPendingDeletes(test.index(), test.getIndexSettings(), new TimeValue(0, TimeUnit.MILLISECONDS));
assertEquals(indicesService.numPendingDeletes(test.index()), 0);
assertFalse(indicesService.hasUncompletedPendingDeletes());
assertFalse(path.exists());
if (randomBoolean()) {
indicesService.addPendingDelete(new ShardId(test.index(), 0), test.getIndexSettings());
indicesService.addPendingDelete(new ShardId(test.index(), 1), test.getIndexSettings());
indicesService.addPendingDelete(new ShardId("bogus", "_na_", 1), test.getIndexSettings());
assertEquals(indicesService.numPendingDeletes(test.index()), 2);
assertTrue(indicesService.hasUncompletedPendingDeletes());
// shard lock released... we can now delete
indicesService.processPendingDeletes(test.index(), test.getIndexSettings(), new TimeValue(0, TimeUnit.MILLISECONDS));
assertEquals(indicesService.numPendingDeletes(test.index()), 0);
assertTrue(indicesService.hasUncompletedPendingDeletes()); // "bogus" index has not been removed
}
assertAcked(client().admin().indices().prepareOpen("test").setTimeout(TimeValue.timeValueSeconds(1)));
}
public void testVerifyIfIndexContentDeleted() throws Exception {
final Index index = new Index("test", UUIDs.randomBase64UUID());
final IndicesService indicesService = getIndicesService();
final NodeEnvironment nodeEnv = getNodeEnvironment();
final MetaStateService metaStateService = getInstanceFromNode(MetaStateService.class);
final ClusterService clusterService = getInstanceFromNode(ClusterService.class);
final Settings idxSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID())
.build();
final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(idxSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.build();
metaStateService.writeIndex("test index being created", indexMetaData);
final MetaData metaData = MetaData.builder(clusterService.state().metaData()).put(indexMetaData, true).build();
final ClusterState csWithIndex = new ClusterState.Builder(clusterService.state()).metaData(metaData).build();
try {
indicesService.verifyIndexIsDeleted(index, csWithIndex);
fail("Should not be able to delete index contents when the index is part of the cluster state.");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("Cannot delete index"));
}
final ClusterState withoutIndex = new ClusterState.Builder(csWithIndex)
.metaData(MetaData.builder(csWithIndex.metaData()).remove(index.getName()))
.build();
indicesService.verifyIndexIsDeleted(index, withoutIndex);
assertFalse("index files should be deleted", FileSystemUtils.exists(nodeEnv.indexPaths(index)));
}
public void testDanglingIndicesWithAliasConflict() throws Exception {
final String indexName = "test-idx1";
final String alias = "test-alias";
final ClusterService clusterService = getInstanceFromNode(ClusterService.class);
createIndex(indexName);
// create the alias for the index
client().admin().indices().prepareAliases().addAlias(indexName, alias).get();
final ClusterState originalState = clusterService.state();
// try to import a dangling index with the same name as the alias, it should fail
final LocalAllocateDangledIndices dangling = getInstanceFromNode(LocalAllocateDangledIndices.class);
final Settings idxSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
.build();
final IndexMetaData indexMetaData = new IndexMetaData.Builder(alias)
.settings(idxSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.build();
DanglingListener listener = new DanglingListener();
dangling.allocateDangled(Arrays.asList(indexMetaData), listener);
listener.latch.await();
assertThat(clusterService.state(), equalTo(originalState));
// remove the alias
client().admin().indices().prepareAliases().removeAlias(indexName, alias).get();
// now try importing a dangling index with the same name as the alias, it should succeed.
listener = new DanglingListener();
dangling.allocateDangled(Arrays.asList(indexMetaData), listener);
listener.latch.await();
assertThat(clusterService.state(), not(originalState));
assertNotNull(clusterService.state().getMetaData().index(alias));
}
/**
* This test checks an edge case where, if a node had an index (lets call it A with UUID 1), then
* deleted it (so a tombstone entry for A will exist in the cluster state), then created
* a new index A with UUID 2, then shutdown, when the node comes back online, it will look at the
* tombstones for deletions, and it should proceed with trying to delete A with UUID 1 and not
* throw any errors that the index still exists in the cluster state. This is a case of ensuring
* that tombstones that have the same name as current valid indices don't cause confusion by
* trying to delete an index that exists.
* See https://github.com/elastic/elasticsearch/issues/18054
*/
public void testIndexAndTombstoneWithSameNameOnStartup() throws Exception {
final String indexName = "test";
final Index index = new Index(indexName, UUIDs.randomBase64UUID());
final IndicesService indicesService = getIndicesService();
final Settings idxSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID())
.build();
final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(idxSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.build();
final Index tombstonedIndex = new Index(indexName, UUIDs.randomBase64UUID());
final IndexGraveyard graveyard = IndexGraveyard.builder().addTombstone(tombstonedIndex).build();
final MetaData metaData = MetaData.builder().put(indexMetaData, true).indexGraveyard(graveyard).build();
final ClusterState clusterState = new ClusterState.Builder(new ClusterName("testCluster")).metaData(metaData).build();
// if all goes well, this won't throw an exception, otherwise, it will throw an IllegalStateException
indicesService.verifyIndexIsDeleted(tombstonedIndex, clusterState);
}
private static class DanglingListener implements LocalAllocateDangledIndices.Listener {
final CountDownLatch latch = new CountDownLatch(1);
@Override
public void onResponse(LocalAllocateDangledIndices.AllocateDangledResponse response) {
latch.countDown();
}
@Override
public void onFailure(Throwable e) {
latch.countDown();
}
}
/**
* Tests that teh {@link MapperService} created by {@link IndicesService#createIndexMapperService(IndexMetaData)} contains
* custom types and similarities registered by plugins
*/
public void testStandAloneMapperServiceWithPlugins() throws IOException {
final String indexName = "test";
final Index index = new Index(indexName, UUIDs.randomBase64UUID());
final IndicesService indicesService = getIndicesService();
final Settings idxSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID())
.put(IndexModule.SIMILARITY_SETTINGS_PREFIX + ".test.type", "fake-similarity")
.build();
final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(idxSettings)
.numberOfShards(1)
.numberOfReplicas(0)
.build();
MapperService mapperService = indicesService.createIndexMapperService(indexMetaData);
assertNotNull(mapperService.documentMapperParser().parserContext("type").typeParser("fake-mapper"));
Similarity sim = mapperService.documentMapperParser().parserContext("type").getSimilarity("test").get();
assertThat(sim, instanceOf(NonNegativeScoresSimilarity.class));
sim = ((NonNegativeScoresSimilarity) sim).getDelegate();
assertThat(sim, instanceOf(BM25Similarity.class));
}
public void testStatsByShardDoesNotDieFromExpectedExceptions() {
final int shardCount = randomIntBetween(2, 5);
final int failedShardId = randomIntBetween(0, shardCount - 1);
final Index index = new Index("test-index", "abc123");
// the shard that is going to fail
final ShardId shardId = new ShardId(index, failedShardId);
final List<IndexShard> shards = new ArrayList<>(shardCount);
final List<IndexShardStats> shardStats = new ArrayList<>(shardCount - 1);
final IndexShardState state = randomFrom(IndexShardState.values());
final String message = "TEST - expected";
final RuntimeException expectedException =
randomFrom(new IllegalIndexShardStateException(shardId, state, message), new AlreadyClosedException(message));
// this allows us to control the indices that exist
final IndicesService mockIndicesService = mock(IndicesService.class);
final IndexService indexService = mock(IndexService.class);
// generate fake shards and their responses
for (int i = 0; i < shardCount; ++i) {
final IndexShard shard = mock(IndexShard.class);
shards.add(shard);
if (failedShardId != i) {
final IndexShardStats successfulShardStats = mock(IndexShardStats.class);
shardStats.add(successfulShardStats);
when(mockIndicesService.indexShardStats(mockIndicesService, shard, CommonStatsFlags.ALL)).thenReturn(successfulShardStats);
} else {
when(mockIndicesService.indexShardStats(mockIndicesService, shard, CommonStatsFlags.ALL)).thenThrow(expectedException);
}
}
when(mockIndicesService.iterator()).thenReturn(Collections.singleton(indexService).iterator());
when(indexService.iterator()).thenReturn(shards.iterator());
when(indexService.index()).thenReturn(index);
// real one, which has a logger defined
final IndicesService indicesService = getIndicesService();
final Map<Index, List<IndexShardStats>> indexStats = indicesService.statsByShard(mockIndicesService, CommonStatsFlags.ALL);
assertThat(indexStats.isEmpty(), equalTo(false));
assertThat("index not defined", indexStats.containsKey(index), equalTo(true));
assertThat("unexpected shard stats", indexStats.get(index), equalTo(shardStats));
}
public void testIsMetaDataField() {
IndicesService indicesService = getIndicesService();
final Version randVersion = VersionUtils.randomVersionBetween(random(), Version.V_6_0_0, Version.CURRENT);
assertFalse(indicesService.isMetaDataField(randVersion, randomAlphaOfLengthBetween(10, 15)));
for (String builtIn : IndicesModule.getBuiltInMetaDataFields()) {
assertTrue(indicesService.isMetaDataField(randVersion, builtIn));
}
}
public void testGetEngineFactory() throws IOException {
final IndicesService indicesService = getIndicesService();
final Boolean[] values = new Boolean[] { true, false, null };
for (final Boolean value : values) {
final String indexName = "foo-" + value;
final Index index = new Index(indexName, UUIDs.randomBase64UUID());
final Settings.Builder builder = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID());
if (value != null) {
builder.put(FooEnginePlugin.FOO_INDEX_SETTING.getKey(), value);
}
final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(builder.build())
.numberOfShards(1)
.numberOfReplicas(0)
.build();
final IndexService indexService = indicesService.createIndex(indexMetaData, Collections.emptyList());
if (value != null && value) {
assertThat(indexService.getEngineFactory(), instanceOf(FooEnginePlugin.FooEngineFactory.class));
} else {
assertThat(indexService.getEngineFactory(), instanceOf(InternalEngineFactory.class));
}
}
}
public void testConflictingEngineFactories() throws IOException {
final String indexName = "foobar";
final Index index = new Index(indexName, UUIDs.randomBase64UUID());
final Settings settings = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID())
.put(FooEnginePlugin.FOO_INDEX_SETTING.getKey(), true)
.put(BarEnginePlugin.BAR_INDEX_SETTING.getKey(), true)
.build();
final IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(settings)
.numberOfShards(1)
.numberOfReplicas(0)
.build();
final IndicesService indicesService = getIndicesService();
final IllegalStateException e =
expectThrows(IllegalStateException.class, () -> indicesService.createIndex(indexMetaData, Collections.emptyList()));
final String pattern =
".*multiple engine factories provided for \\[foobar/.*\\]: \\[.*FooEngineFactory\\],\\[.*BarEngineFactory\\].*";
assertThat(e, hasToString(new RegexMatcher(pattern)));
}
public void testOverShardLimit() {
int nodesInCluster = randomIntBetween(1,100);
ClusterShardLimitIT.ShardCounts counts = forDataNodeCount(nodesInCluster);
Settings clusterSettings = Settings.builder()
.put(MetaData.SETTING_CLUSTER_MAX_SHARDS_PER_NODE.getKey(), counts.getShardsPerNode())
.build();
ClusterState state = createClusterForShardLimitTest(nodesInCluster, counts.getFirstIndexShards(), counts.getFirstIndexReplicas(),
clusterSettings);
int shardsToAdd = counts.getFailingIndexShards() * (1 + counts.getFailingIndexReplicas());
Optional<String> errorMessage = IndicesService.checkShardLimit(shardsToAdd, state);
int totalShards = counts.getFailingIndexShards() * (1 + counts.getFailingIndexReplicas());
int currentShards = counts.getFirstIndexShards() * (1 + counts.getFirstIndexReplicas());
int maxShards = counts.getShardsPerNode() * nodesInCluster;
assertTrue(errorMessage.isPresent());
assertEquals("this action would add [" + totalShards + "] total shards, but this cluster currently has [" + currentShards
+ "]/[" + maxShards + "] maximum shards open", errorMessage.get());
}
public void testUnderShardLimit() {
int nodesInCluster = randomIntBetween(2,100);
// Calculate the counts for a cluster 1 node smaller than we have to ensure we have headroom
ClusterShardLimitIT.ShardCounts counts = forDataNodeCount(nodesInCluster - 1);
Settings clusterSettings = Settings.builder()
.put(MetaData.SETTING_CLUSTER_MAX_SHARDS_PER_NODE.getKey(), counts.getShardsPerNode())
.build();
ClusterState state = createClusterForShardLimitTest(nodesInCluster, counts.getFirstIndexShards(), counts.getFirstIndexReplicas(),
clusterSettings);
int existingShards = counts.getFirstIndexShards() * (1 + counts.getFirstIndexReplicas());
int shardsToAdd = randomIntBetween(1, (counts.getShardsPerNode() * nodesInCluster) - existingShards);
Optional<String> errorMessage = IndicesService.checkShardLimit(shardsToAdd, state);
assertFalse(errorMessage.isPresent());
}
public static ClusterState createClusterForShardLimitTest(int nodesInCluster, int shardsInIndex, int replicas,
Settings clusterSettings) {
ImmutableOpenMap.Builder<String, DiscoveryNode> dataNodes = ImmutableOpenMap.builder();
for (int i = 0; i < nodesInCluster; i++) {
dataNodes.put(randomAlphaOfLengthBetween(5,15), mock(DiscoveryNode.class));
}
DiscoveryNodes nodes = mock(DiscoveryNodes.class);
when(nodes.getDataNodes()).thenReturn(dataNodes.build());
IndexMetaData.Builder indexMetaData = IndexMetaData.builder(randomAlphaOfLengthBetween(5, 15))
.settings(Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT))
.creationDate(randomLong())
.numberOfShards(shardsInIndex)
.numberOfReplicas(replicas);
MetaData.Builder metaData = MetaData.builder().put(indexMetaData);
if (randomBoolean()) {
metaData.transientSettings(clusterSettings);
} else {
metaData.persistentSettings(clusterSettings);
}
return ClusterState.builder(ClusterName.DEFAULT)
.metaData(metaData)
.nodes(nodes)
.build();
}
public void testOptimizeAutoGeneratedIdsSettingRemoval() throws Exception {
final IndicesService indicesService = getIndicesService();
final Index index = new Index("foo-index", UUIDs.randomBase64UUID());
Settings.Builder builder = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_7_0_0)
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID());
IndexMetaData indexMetaData = new IndexMetaData.Builder(index.getName())
.settings(builder.build())
.numberOfShards(1)
.numberOfReplicas(0)
.build();
IndexService indexService = indicesService.createIndex(indexMetaData, Collections.emptyList());
assertNotNull(indexService);
final Index index2 = new Index("bar-index", UUIDs.randomBase64UUID());
Settings.Builder builder2 = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_7_0_0)
.put(IndexMetaData.SETTING_INDEX_UUID, index2.getUUID())
.put(EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS.getKey(), randomBoolean());
IndexMetaData indexMetaData2 = new IndexMetaData.Builder(index2.getName())
.settings(builder2.build())
.numberOfShards(1)
.numberOfReplicas(0)
.build();
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
() -> indicesService.createIndex(indexMetaData2, Collections.emptyList()));
assertEquals("Setting [" + EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS.getKey() + "] was removed in version 7.0.0",
ex.getMessage());
Version version = randomFrom(Version.V_6_0_0_rc1, Version.V_6_0_0, Version.V_6_2_0, Version.V_6_3_0, Version.V_6_4_0);
builder = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, version)
.put(IndexMetaData.SETTING_INDEX_UUID, index2.getUUID())
.put(EngineConfig.INDEX_OPTIMIZE_AUTO_GENERATED_IDS.getKey(), randomBoolean());
IndexMetaData indexMetaData3 = new IndexMetaData.Builder(index2.getName())
.settings(builder.build())
.numberOfShards(1)
.numberOfReplicas(0)
.build();
IndexService indexService2 = indicesService.createIndex(indexMetaData3, Collections.emptyList());
assertNotNull(indexService2);
}
}