MapperService: check index.mapper.dynamic during index creation
The MapperService doesn't currently check the index.mapper.dynamic setting during index creation, so indices can be created with dynamic mappings even if this setting is false. Add a check that throws an exception in this case. Fixes #15381
This commit is contained in:
parent
4986817c6d
commit
3f9c0fbb58
|
@ -26,6 +26,7 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
|
||||
/**
|
||||
* Encapsulates the logic of whether a new index should be automatically created when
|
||||
|
@ -35,6 +36,7 @@ public final class AutoCreateIndex {
|
|||
|
||||
private final boolean needToCheck;
|
||||
private final boolean globallyDisabled;
|
||||
private final boolean dynamicMappingDisabled;
|
||||
private final String[] matches;
|
||||
private final String[] matches2;
|
||||
private final IndexNameExpressionResolver resolver;
|
||||
|
@ -42,6 +44,7 @@ public final class AutoCreateIndex {
|
|||
@Inject
|
||||
public AutoCreateIndex(Settings settings, IndexNameExpressionResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
dynamicMappingDisabled = !settings.getAsBoolean(MapperService.INDEX_MAPPER_DYNAMIC_SETTING, MapperService.INDEX_MAPPER_DYNAMIC_DEFAULT);
|
||||
String value = settings.get("action.auto_create_index");
|
||||
if (value == null || Booleans.isExplicitTrue(value)) {
|
||||
needToCheck = true;
|
||||
|
@ -82,7 +85,7 @@ public final class AutoCreateIndex {
|
|||
if (exists) {
|
||||
return false;
|
||||
}
|
||||
if (globallyDisabled) {
|
||||
if (globallyDisabled || dynamicMappingDisabled) {
|
||||
return false;
|
||||
}
|
||||
// matches not set, default value of "true"
|
||||
|
|
|
@ -78,6 +78,8 @@ import static org.elasticsearch.common.collect.MapBuilder.newMapBuilder;
|
|||
public class MapperService extends AbstractIndexComponent implements Closeable {
|
||||
|
||||
public static final String DEFAULT_MAPPING = "_default_";
|
||||
public static final String INDEX_MAPPER_DYNAMIC_SETTING = "index.mapper.dynamic";
|
||||
public static final boolean INDEX_MAPPER_DYNAMIC_DEFAULT = true;
|
||||
private static ObjectHashSet<String> META_FIELDS = ObjectHashSet.from(
|
||||
"_uid", "_id", "_type", "_all", "_parent", "_routing", "_index",
|
||||
"_size", "_timestamp", "_ttl"
|
||||
|
@ -124,7 +126,7 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
|
|||
this.searchQuoteAnalyzer = new MapperAnalyzerWrapper(analysisService.defaultSearchQuoteAnalyzer(), p -> p.searchQuoteAnalyzer());
|
||||
this.mapperRegistry = mapperRegistry;
|
||||
|
||||
this.dynamic = this.indexSettings.getSettings().getAsBoolean("index.mapper.dynamic", true);
|
||||
this.dynamic = this.indexSettings.getSettings().getAsBoolean(INDEX_MAPPER_DYNAMIC_SETTING, INDEX_MAPPER_DYNAMIC_DEFAULT);
|
||||
defaultPercolatorMappingSource = "{\n" +
|
||||
"\"_default_\":{\n" +
|
||||
"\"properties\" : {\n" +
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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.index.mapper;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.index.TransportIndexAction;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.AutoCreateIndex;
|
||||
import org.elasticsearch.cluster.action.shard.ShardStateAction;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.indices.IndicesService;
|
||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.transport.local.LocalTransport;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.test.cluster.TestClusterService;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class DynamicMappingDisabledTests extends ESSingleNodeTestCase {
|
||||
|
||||
private static ThreadPool THREAD_POOL;
|
||||
private TestClusterService clusterService;
|
||||
private LocalTransport transport;
|
||||
private TransportService transportService;
|
||||
private IndicesService indicesService;
|
||||
private ShardStateAction shardStateAction;
|
||||
private ActionFilters actionFilters;
|
||||
private IndexNameExpressionResolver indexNameExpressionResolver;
|
||||
private AutoCreateIndex autoCreateIndex;
|
||||
private Settings settings;
|
||||
|
||||
@BeforeClass
|
||||
public static void createThreadPool() {
|
||||
THREAD_POOL = new ThreadPool("DynamicMappingDisabledTests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
settings = Settings.builder()
|
||||
.put(MapperService.INDEX_MAPPER_DYNAMIC_SETTING, false)
|
||||
.build();
|
||||
clusterService = new TestClusterService(THREAD_POOL);
|
||||
transport = new LocalTransport(settings, THREAD_POOL, Version.CURRENT, new NamedWriteableRegistry());
|
||||
transportService = new TransportService(transport, THREAD_POOL);
|
||||
indicesService = getInstanceFromNode(IndicesService.class);
|
||||
shardStateAction = new ShardStateAction(settings, clusterService, transportService, null, null);
|
||||
actionFilters = new ActionFilters(Collections.emptySet());
|
||||
indexNameExpressionResolver = new IndexNameExpressionResolver(settings);
|
||||
autoCreateIndex = new AutoCreateIndex(settings, indexNameExpressionResolver);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroyThreadPool() {
|
||||
ThreadPool.terminate(THREAD_POOL, 30, TimeUnit.SECONDS);
|
||||
// since static must set to null to be eligible for collection
|
||||
THREAD_POOL = null;
|
||||
}
|
||||
|
||||
public void testDynamicDisabled() {
|
||||
TransportIndexAction action = new TransportIndexAction(settings, transportService, clusterService,
|
||||
indicesService, THREAD_POOL, shardStateAction, null, null, actionFilters, indexNameExpressionResolver,
|
||||
autoCreateIndex);
|
||||
|
||||
IndexRequest request = new IndexRequest("index", "type", "1");
|
||||
request.source("foo", 3);
|
||||
final AtomicBoolean onFailureCalled = new AtomicBoolean();
|
||||
|
||||
action.execute(request, new ActionListener<IndexResponse>() {
|
||||
@Override
|
||||
public void onResponse(IndexResponse indexResponse) {
|
||||
fail("Indexing request should have failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
onFailureCalled.set(true);
|
||||
assertThat(e, instanceOf(IndexNotFoundException.class));
|
||||
assertEquals(e.getMessage(), "no such index");
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(onFailureCalled.get());
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.indices.settings;
|
|||
|
||||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -40,7 +41,7 @@ public class GetSettingsBlocksIT extends ESIntegTestCase {
|
|||
.setSettings(Settings.settingsBuilder()
|
||||
.put("index.refresh_interval", -1)
|
||||
.put("index.merge.policy.expunge_deletes_allowed", "30")
|
||||
.put("index.mapper.dynamic", false)));
|
||||
.put(MapperService.INDEX_MAPPER_DYNAMIC_SETTING, false)));
|
||||
|
||||
for (String block : Arrays.asList(SETTING_BLOCKS_READ, SETTING_BLOCKS_WRITE, SETTING_READ_ONLY)) {
|
||||
try {
|
||||
|
@ -49,7 +50,7 @@ public class GetSettingsBlocksIT extends ESIntegTestCase {
|
|||
assertThat(response.getIndexToSettings().size(), greaterThanOrEqualTo(1));
|
||||
assertThat(response.getSetting("test", "index.refresh_interval"), equalTo("-1"));
|
||||
assertThat(response.getSetting("test", "index.merge.policy.expunge_deletes_allowed"), equalTo("30"));
|
||||
assertThat(response.getSetting("test", "index.mapper.dynamic"), equalTo("false"));
|
||||
assertThat(response.getSetting("test", MapperService.INDEX_MAPPER_DYNAMIC_SETTING), equalTo("false"));
|
||||
} finally {
|
||||
disableIndexBlock("test", block);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue