diff --git a/src/main/java/org/elasticsearch/action/admin/cluster/settings/TransportClusterUpdateSettingsAction.java b/src/main/java/org/elasticsearch/action/admin/cluster/settings/TransportClusterUpdateSettingsAction.java index b75b88a0ff7..f1ea7d40645 100644 --- a/src/main/java/org/elasticsearch/action/admin/cluster/settings/TransportClusterUpdateSettingsAction.java +++ b/src/main/java/org/elasticsearch/action/admin/cluster/settings/TransportClusterUpdateSettingsAction.java @@ -95,8 +95,13 @@ public class TransportClusterUpdateSettingsAction extends TransportMasterNodeOpe transientSettings.put(currentState.metaData().transientSettings()); for (Map.Entry entry : request.transientSettings().getAsMap().entrySet()) { if (dynamicSettings.hasDynamicSetting(entry.getKey()) || entry.getKey().startsWith("logger.")) { - transientSettings.put(entry.getKey(), entry.getValue()); - changed = true; + String error = dynamicSettings.validateDynamicSetting(entry.getKey(), entry.getValue()); + if (error == null) { + transientSettings.put(entry.getKey(), entry.getValue()); + changed = true; + } else { + logger.warn("ignoring transient setting [{}], [{}]", entry.getKey(), error); + } } else { logger.warn("ignoring transient setting [{}], not dynamically updateable", entry.getKey()); } @@ -106,8 +111,13 @@ public class TransportClusterUpdateSettingsAction extends TransportMasterNodeOpe persistentSettings.put(currentState.metaData().persistentSettings()); for (Map.Entry entry : request.persistentSettings().getAsMap().entrySet()) { if (dynamicSettings.hasDynamicSetting(entry.getKey()) || entry.getKey().startsWith("logger.")) { - changed = true; - persistentSettings.put(entry.getKey(), entry.getValue()); + String error = dynamicSettings.validateDynamicSetting(entry.getKey(), entry.getValue()); + if (error == null) { + persistentSettings.put(entry.getKey(), entry.getValue()); + changed = true; + } else { + logger.warn("ignoring persistent setting [{}], [{}]", entry.getKey(), error); + } } else { logger.warn("ignoring persistent setting [{}], not dynamically updateable", entry.getKey()); } diff --git a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataUpdateSettingsService.java b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataUpdateSettingsService.java index d93971d28c7..cd6be27cdf7 100644 --- a/src/main/java/org/elasticsearch/cluster/metadata/MetaDataUpdateSettingsService.java +++ b/src/main/java/org/elasticsearch/cluster/metadata/MetaDataUpdateSettingsService.java @@ -143,11 +143,23 @@ public class MetaDataUpdateSettingsService extends AbstractComponent implements final Settings closeSettings = updatedSettingsBuilder.build(); final Set removedSettings = Sets.newHashSet(); - for (String key : updatedSettingsBuilder.internalMap().keySet()) { - if (!dynamicSettings.hasDynamicSetting(key)) { - removedSettings.add(key); + final Set errors = Sets.newHashSet(); + for (Map.Entry setting : updatedSettingsBuilder.internalMap().entrySet()) { + if (!dynamicSettings.hasDynamicSetting(setting.getKey())) { + removedSettings.add(setting.getKey()); + } else { + String error = dynamicSettings.validateDynamicSetting(setting.getKey(), setting.getValue()); + if (error != null) { + errors.add("[" + setting.getKey() + "] - " + error); + } } } + + if (!errors.isEmpty()) { + listener.onFailure(new ElasticSearchIllegalArgumentException("can't process the settings: " + errors.toString())); + return; + } + if (!removedSettings.isEmpty()) { for (String removedSetting : removedSettings) { updatedSettingsBuilder.remove(removedSetting); diff --git a/src/main/java/org/elasticsearch/cluster/settings/ClusterDynamicSettingsModule.java b/src/main/java/org/elasticsearch/cluster/settings/ClusterDynamicSettingsModule.java index ee752a9d955..014c8c0c01d 100644 --- a/src/main/java/org/elasticsearch/cluster/settings/ClusterDynamicSettingsModule.java +++ b/src/main/java/org/elasticsearch/cluster/settings/ClusterDynamicSettingsModule.java @@ -71,10 +71,15 @@ public class ClusterDynamicSettingsModule extends AbstractModule { ); } - public void addDynamicSetting(String... settings) { + public void addDynamicSettings(String... settings) { clusterDynamicSettings.addDynamicSettings(settings); } + public void addDynamicSetting(String setting, Validator validator) { + clusterDynamicSettings.addDynamicSetting(setting, validator); + } + + @Override protected void configure() { bind(DynamicSettings.class).annotatedWith(ClusterDynamicSettings.class).toInstance(clusterDynamicSettings); diff --git a/src/main/java/org/elasticsearch/cluster/settings/DynamicSettings.java b/src/main/java/org/elasticsearch/cluster/settings/DynamicSettings.java index 61c3e1f9037..cdb758b0fe4 100644 --- a/src/main/java/org/elasticsearch/cluster/settings/DynamicSettings.java +++ b/src/main/java/org/elasticsearch/cluster/settings/DynamicSettings.java @@ -19,20 +19,20 @@ package org.elasticsearch.cluster.settings; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap; +import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.regex.Regex; -import java.util.Arrays; -import java.util.HashSet; +import java.util.Map; /** */ public class DynamicSettings { - private ImmutableSet dynamicSettings = ImmutableSet.of(); + private ImmutableMap dynamicSettings = ImmutableMap.of(); public boolean hasDynamicSetting(String key) { - for (String dynamicSetting : dynamicSettings) { + for (String dynamicSetting : dynamicSettings.keySet()) { if (Regex.simpleMatch(dynamicSetting, key)) { return true; } @@ -40,10 +40,32 @@ public class DynamicSettings { return false; } + public String validateDynamicSetting(String dynamicSetting, String value) { + for (Map.Entry setting : dynamicSettings.entrySet()) { + if (Regex.simpleMatch(dynamicSetting, setting.getKey())) { + return setting.getValue().validate(dynamicSetting, value); + } + } + return null; + } + + public synchronized void addDynamicSetting(String setting, Validator validator) { + MapBuilder updatedSettings = MapBuilder.newMapBuilder(dynamicSettings); + updatedSettings.put(setting, validator); + dynamicSettings = updatedSettings.immutableMap(); + } + + public synchronized void addDynamicSetting(String setting) { + addDynamicSetting(setting, Validator.EmptyValidator.INSTANCE); + } + + public synchronized void addDynamicSettings(String... settings) { - HashSet updatedSettings = new HashSet(dynamicSettings); - updatedSettings.addAll(Arrays.asList(settings)); - dynamicSettings = ImmutableSet.copyOf(updatedSettings); + MapBuilder updatedSettings = MapBuilder.newMapBuilder(dynamicSettings); + for (String setting : settings) { + updatedSettings.put(setting, Validator.EmptyValidator.INSTANCE); + } + dynamicSettings = updatedSettings.immutableMap(); } } diff --git a/src/main/java/org/elasticsearch/cluster/settings/Validator.java b/src/main/java/org/elasticsearch/cluster/settings/Validator.java new file mode 100644 index 00000000000..dc62eb8f93f --- /dev/null +++ b/src/main/java/org/elasticsearch/cluster/settings/Validator.java @@ -0,0 +1,64 @@ +/* + * Licensed to ElasticSearch and Shay Banon 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.cluster.settings; + +import org.elasticsearch.ElasticSearchParseException; +import org.elasticsearch.common.unit.TimeValue; + +/** + */ +public interface Validator { + String validate(String setting, String value); + + public static class EmptyValidator implements Validator { + + public static final EmptyValidator INSTANCE = new EmptyValidator(); + + private EmptyValidator() { + + } + + @Override + public String validate(String setting, String value) { + return null; + } + } + + public static class TimeValueValidator implements Validator { + + public static final TimeValueValidator INSTANCE = new TimeValueValidator(); + + private TimeValueValidator() { + + } + + @Override + public String validate(String setting, String value) { + try { + if (TimeValue.parseTimeValue(value, null) == null) { + return "cannot parse value [" + value + "] as time"; + } + } catch (ElasticSearchParseException ex) { + return "cannot parse value [" + value + "] as time"; + } + return null; + } + } +} diff --git a/src/main/java/org/elasticsearch/index/settings/IndexDynamicSettingsModule.java b/src/main/java/org/elasticsearch/index/settings/IndexDynamicSettingsModule.java index 017f6ed0a71..1de8724e459 100644 --- a/src/main/java/org/elasticsearch/index/settings/IndexDynamicSettingsModule.java +++ b/src/main/java/org/elasticsearch/index/settings/IndexDynamicSettingsModule.java @@ -23,6 +23,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider; import org.elasticsearch.cluster.routing.allocation.decider.ShardsLimitAllocationDecider; import org.elasticsearch.cluster.settings.DynamicSettings; +import org.elasticsearch.cluster.settings.Validator; import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.gateway.local.LocalGatewayAllocator; import org.elasticsearch.index.engine.robin.RobinEngine; @@ -46,75 +47,78 @@ public class IndexDynamicSettingsModule extends AbstractModule { public IndexDynamicSettingsModule() { indexDynamicSettings = new DynamicSettings(); - indexDynamicSettings.addDynamicSettings( - AbstractIndexStore.INDEX_STORE_THROTTLE_MAX_BYTES_PER_SEC, - AbstractIndexStore.INDEX_STORE_THROTTLE_TYPE, - FilterAllocationDecider.INDEX_ROUTING_REQUIRE_GROUP + "*", - FilterAllocationDecider.INDEX_ROUTING_INCLUDE_GROUP + "*", - FilterAllocationDecider.INDEX_ROUTING_EXCLUDE_GROUP + "*", - FsTranslog.INDEX_TRANSLOG_FS_TYPE, - FsTranslog.INDEX_TRANSLOG_FS_BUFFER_SIZE, - FsTranslog.INDEX_TRANSLOG_FS_TRANSIENT_BUFFER_SIZE, - IndexMetaData.SETTING_NUMBER_OF_REPLICAS, - IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, - IndexMetaData.SETTING_READ_ONLY, - IndexMetaData.SETTING_BLOCKS_READ, - IndexMetaData.SETTING_BLOCKS_WRITE, - IndexMetaData.SETTING_BLOCKS_METADATA, - IndexShardGatewayService.INDEX_GATEWAY_SNAPSHOT_INTERVAL, - IndicesTTLService.INDEX_TTL_DISABLE_PURGE, - InternalIndexShard.INDEX_REFRESH_INTERVAL, - LocalGatewayAllocator.INDEX_RECOVERY_INITIAL_SHARDS, - LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MIN_MERGE_SIZE, - LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_SIZE, - LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_DOCS, - LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MERGE_FACTOR, - LogByteSizeMergePolicyProvider.INDEX_COMPOUND_FORMAT, - LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MIN_MERGE_DOCS, - LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_DOCS, - LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MERGE_FACTOR, - LogDocMergePolicyProvider.INDEX_COMPOUND_FORMAT, - RobinEngine.INDEX_TERM_INDEX_INTERVAL, - RobinEngine.INDEX_TERM_INDEX_DIVISOR, - RobinEngine.INDEX_INDEX_CONCURRENCY, - RobinEngine.INDEX_GC_DELETES, - RobinEngine.INDEX_CODEC, - RobinEngine.INDEX_FAIL_ON_MERGE_FAILURE, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_WARN, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_INFO, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_DEBUG, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_TRACE, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_REFORMAT, - ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_LEVEL, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_INFO, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_DEBUG, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_TRACE, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_WARN, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_INFO, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_DEBUG, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_TRACE, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_REFORMAT, - ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_LEVEL, - ShardsLimitAllocationDecider.INDEX_TOTAL_SHARDS_PER_NODE, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_EXPUNGE_DELETES_ALLOWED, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_FLOOR_SEGMENT, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_EXPLICIT, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGED_SEGMENT, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_SEGMENTS_PER_TIER, - TieredMergePolicyProvider.INDEX_MERGE_POLICY_RECLAIM_DELETES_WEIGHT, - TieredMergePolicyProvider.INDEX_COMPOUND_FORMAT, - TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_OPS, - TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE, - TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_PERIOD, - TranslogService.INDEX_TRANSLOG_DISABLE_FLUSH); + indexDynamicSettings.addDynamicSetting(AbstractIndexStore.INDEX_STORE_THROTTLE_MAX_BYTES_PER_SEC); + indexDynamicSettings.addDynamicSetting(AbstractIndexStore.INDEX_STORE_THROTTLE_TYPE); + indexDynamicSettings.addDynamicSetting(FilterAllocationDecider.INDEX_ROUTING_REQUIRE_GROUP + "*"); + indexDynamicSettings.addDynamicSetting(FilterAllocationDecider.INDEX_ROUTING_INCLUDE_GROUP + "*"); + indexDynamicSettings.addDynamicSetting(FilterAllocationDecider.INDEX_ROUTING_EXCLUDE_GROUP + "*"); + indexDynamicSettings.addDynamicSetting(FsTranslog.INDEX_TRANSLOG_FS_TYPE); + indexDynamicSettings.addDynamicSetting(FsTranslog.INDEX_TRANSLOG_FS_BUFFER_SIZE); + indexDynamicSettings.addDynamicSetting(FsTranslog.INDEX_TRANSLOG_FS_TRANSIENT_BUFFER_SIZE); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_NUMBER_OF_REPLICAS); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_READ_ONLY); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_BLOCKS_READ); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_BLOCKS_WRITE); + indexDynamicSettings.addDynamicSetting(IndexMetaData.SETTING_BLOCKS_METADATA); + indexDynamicSettings.addDynamicSetting(IndexShardGatewayService.INDEX_GATEWAY_SNAPSHOT_INTERVAL); + indexDynamicSettings.addDynamicSetting(IndicesTTLService.INDEX_TTL_DISABLE_PURGE); + indexDynamicSettings.addDynamicSetting(InternalIndexShard.INDEX_REFRESH_INTERVAL, Validator.TimeValueValidator.INSTANCE); + indexDynamicSettings.addDynamicSetting(LocalGatewayAllocator.INDEX_RECOVERY_INITIAL_SHARDS); + indexDynamicSettings.addDynamicSetting(LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MIN_MERGE_SIZE); + indexDynamicSettings.addDynamicSetting(LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_SIZE); + indexDynamicSettings.addDynamicSetting(LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_DOCS); + indexDynamicSettings.addDynamicSetting(LogByteSizeMergePolicyProvider.INDEX_MERGE_POLICY_MERGE_FACTOR); + indexDynamicSettings.addDynamicSetting(LogByteSizeMergePolicyProvider.INDEX_COMPOUND_FORMAT); + indexDynamicSettings.addDynamicSetting(LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MIN_MERGE_DOCS); + indexDynamicSettings.addDynamicSetting(LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_DOCS); + indexDynamicSettings.addDynamicSetting(LogDocMergePolicyProvider.INDEX_MERGE_POLICY_MERGE_FACTOR); + indexDynamicSettings.addDynamicSetting(LogDocMergePolicyProvider.INDEX_COMPOUND_FORMAT); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_TERM_INDEX_INTERVAL); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_TERM_INDEX_DIVISOR); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_INDEX_CONCURRENCY); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_GC_DELETES); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_CODEC); + indexDynamicSettings.addDynamicSetting(RobinEngine.INDEX_FAIL_ON_MERGE_FAILURE); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_WARN); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_INFO); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_DEBUG); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_THRESHOLD_INDEX_TRACE); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_REFORMAT); + indexDynamicSettings.addDynamicSetting(ShardSlowLogIndexingService.INDEX_INDEXING_SLOWLOG_LEVEL); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_WARN); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_INFO); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_DEBUG); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_QUERY_TRACE); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_WARN); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_INFO); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_DEBUG); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_THRESHOLD_FETCH_TRACE); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_REFORMAT); + indexDynamicSettings.addDynamicSetting(ShardSlowLogSearchService.INDEX_SEARCH_SLOWLOG_LEVEL); + indexDynamicSettings.addDynamicSetting(ShardsLimitAllocationDecider.INDEX_TOTAL_SHARDS_PER_NODE); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_EXPUNGE_DELETES_ALLOWED); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_FLOOR_SEGMENT); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGE_AT_ONCE_EXPLICIT); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_MAX_MERGED_SEGMENT); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_SEGMENTS_PER_TIER); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_MERGE_POLICY_RECLAIM_DELETES_WEIGHT); + indexDynamicSettings.addDynamicSetting(TieredMergePolicyProvider.INDEX_COMPOUND_FORMAT); + indexDynamicSettings.addDynamicSetting(TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_OPS); + indexDynamicSettings.addDynamicSetting(TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_SIZE); + indexDynamicSettings.addDynamicSetting(TranslogService.INDEX_TRANSLOG_FLUSH_THRESHOLD_PERIOD); + indexDynamicSettings.addDynamicSetting(TranslogService.INDEX_TRANSLOG_DISABLE_FLUSH); } - public void addDynamicSetting(String... settings) { + public void addDynamicSettings(String... settings) { indexDynamicSettings.addDynamicSettings(settings); } + public void addDynamicSetting(String setting, Validator validator) { + indexDynamicSettings.addDynamicSetting(setting, validator); + } + @Override protected void configure() { bind(DynamicSettings.class).annotatedWith(IndexDynamicSettings.class).toInstance(indexDynamicSettings); diff --git a/src/test/java/org/elasticsearch/test/integration/cluster/UpdateSettingsValidationTests.java b/src/test/java/org/elasticsearch/test/integration/cluster/UpdateSettingsValidationTests.java new file mode 100644 index 00000000000..257236301e6 --- /dev/null +++ b/src/test/java/org/elasticsearch/test/integration/cluster/UpdateSettingsValidationTests.java @@ -0,0 +1,66 @@ +/* + * Licensed to ElasticSearch and Shay Banon 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.test.integration.cluster; + +import org.elasticsearch.ElasticSearchIllegalArgumentException; +import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.common.Priority; +import org.elasticsearch.test.integration.AbstractNodesTests; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.Test; + +import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +/** + */ +public class UpdateSettingsValidationTests extends AbstractNodesTests { + + @AfterMethod + public void closeNodes() { + closeAllNodes(); + } + + @Test + public void testUpdateSettingsValidation() throws Exception { + startNode("master", settingsBuilder().put("node.data", false).build()); + startNode("node1", settingsBuilder().put("node.master", false).build()); + startNode("node2", settingsBuilder().put("node.master", false).build()); + + client("master").admin().indices().prepareCreate("test") + .setSettings(settingsBuilder().put("index.number_of_shards", 5).put("index.number_of_replicas", 1)).execute().actionGet(); + ClusterHealthResponse healthResponse = client("master").admin().cluster().prepareHealth("test").setWaitForEvents(Priority.LANGUID).setWaitForNodes("3").setWaitForGreenStatus().execute().actionGet(); + assertThat(healthResponse.isTimedOut(), equalTo(false)); + assertThat(healthResponse.getIndices().get("test").getActiveShards(), equalTo(10)); + + client("master").admin().indices().prepareUpdateSettings("test").setSettings(settingsBuilder().put("index.number_of_replicas", 0)).execute().actionGet(); + healthResponse = client("master").admin().cluster().prepareHealth("test").setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet(); + assertThat(healthResponse.isTimedOut(), equalTo(false)); + assertThat(healthResponse.getIndices().get("test").getActiveShards(), equalTo(5)); + + try { + client("master").admin().indices().prepareUpdateSettings("test").setSettings(settingsBuilder().put("index.refresh_interval", "")).execute().actionGet(); + assert false; + } catch (ElasticSearchIllegalArgumentException ex) { + logger.info("Error message: [{}]", ex.getMessage()); + } + } +}