From 54a2ab9c0318926be106f06a2493cca5af667f6b Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Sat, 30 May 2015 17:36:58 -0400 Subject: [PATCH] add undocumented kill switch, to disable requiring units on byte size and time settings --- .../org/elasticsearch/common/Booleans.java | 2 +- .../common/settings/Settings.java | 15 ++++++++- .../common/unit/ByteSizeValue.java | 8 ++++- .../elasticsearch/common/unit/TimeValue.java | 10 ++++-- .../internal/InternalSettingsPreparer.java | 5 +++ .../settings/ClusterSettingsTests.java | 31 +++++++++++++++++++ 6 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/elasticsearch/common/Booleans.java b/src/main/java/org/elasticsearch/common/Booleans.java index e954ea5e813..a1315e30ba9 100644 --- a/src/main/java/org/elasticsearch/common/Booleans.java +++ b/src/main/java/org/elasticsearch/common/Booleans.java @@ -84,7 +84,7 @@ public class Booleans { * @return true/false * throws exception if string cannot be parsed to boolean */ - public static Boolean parseBooleanExact(String value){ + public static Boolean parseBooleanExact(String value) { boolean isFalse = isExplicitFalse(value); if (isFalse) { diff --git a/src/main/java/org/elasticsearch/common/settings/Settings.java b/src/main/java/org/elasticsearch/common/settings/Settings.java index 2bb7b3acafb..d19d47bde8a 100644 --- a/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -61,7 +61,20 @@ import static org.elasticsearch.common.unit.TimeValue.parseTimeValue; public final class Settings implements ToXContent { public static final Settings EMPTY = new Builder().build(); - private final static Pattern ARRAY_PATTERN = Pattern.compile("(.*)\\.\\d+$"); + private static final Pattern ARRAY_PATTERN = Pattern.compile("(.*)\\.\\d+$"); + + /** Name of the setting to use to disable required units for byte size, time settings. */ + public static final String SETTINGS_REQUIRE_UNITS = "settings_require_units"; + + private static boolean settingsRequireUnits = true; + + public static void setSettingsRequireUnits(boolean v) { + settingsRequireUnits = v; + } + + public static boolean getSettingsRequireUnits() { + return settingsRequireUnits; + } private ImmutableMap settings; private final ImmutableMap forcedUnderscoreSettings; diff --git a/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java b/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java index d858aa46882..04c340713fb 100644 --- a/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java +++ b/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; +import org.elasticsearch.common.settings.Settings; import java.io.IOException; import java.io.Serializable; @@ -213,7 +214,12 @@ public class ByteSizeValue implements Serializable, Streamable { bytes = 0; } else { // Missing units: - throw new ElasticsearchParseException("Failed to parse setting [" + settingName + "] with value [" + sValue + "] as a size in bytes: unit is missing or unrecognized") ; + if (Settings.getSettingsRequireUnits()) { + throw new ElasticsearchParseException("Failed to parse setting [" + settingName + "] with value [" + sValue + "] as a size in bytes: unit is missing or unrecognized") ; + } else { + // Leniency default to bytes: + bytes = Long.parseLong(sValue); + } } } catch (NumberFormatException e) { throw new ElasticsearchParseException("Failed to parse [" + sValue + "]", e); diff --git a/src/main/java/org/elasticsearch/common/unit/TimeValue.java b/src/main/java/org/elasticsearch/common/unit/TimeValue.java index 12464ebda55..c3e22c786c4 100644 --- a/src/main/java/org/elasticsearch/common/unit/TimeValue.java +++ b/src/main/java/org/elasticsearch/common/unit/TimeValue.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; +import org.elasticsearch.common.settings.Settings; import org.joda.time.Period; import org.joda.time.PeriodType; import org.joda.time.format.PeriodFormat; @@ -256,8 +257,13 @@ public class TimeValue implements Serializable, Streamable { // Allow this special value to be unit-less: millis = 0; } else { - // Missing units: - throw new ElasticsearchParseException("Failed to parse setting [" + settingName + "] with value [" + sValue + "] as a time value: unit is missing or unrecognized"); + if (Settings.getSettingsRequireUnits()) { + // Missing units: + throw new ElasticsearchParseException("Failed to parse setting [" + settingName + "] with value [" + sValue + "] as a time value: unit is missing or unrecognized"); + } else { + // Leniency default to msec for bwc: + millis = Long.parseLong(sValue); + } } return new TimeValue(millis, TimeUnit.MILLISECONDS); } catch (NumberFormatException e) { diff --git a/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java b/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java index 5b8cebc7547..9b470a680cd 100644 --- a/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java +++ b/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java @@ -20,6 +20,7 @@ package org.elasticsearch.node.internal; import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Names; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.Tuple; @@ -129,6 +130,10 @@ public class InternalSettingsPreparer { settingsBuilder.put(ClusterName.SETTING, ClusterName.DEFAULT.value()); } + String v = settingsBuilder.get(Settings.SETTINGS_REQUIRE_UNITS); + if (v != null) { + Settings.setSettingsRequireUnits(Booleans.parseBoolean(v, true)); + } Settings v1 = settingsBuilder.build(); environment = new Environment(v1); diff --git a/src/test/java/org/elasticsearch/cluster/settings/ClusterSettingsTests.java b/src/test/java/org/elasticsearch/cluster/settings/ClusterSettingsTests.java index 6a4546fcba3..97d8f33aaa5 100644 --- a/src/test/java/org/elasticsearch/cluster/settings/ClusterSettingsTests.java +++ b/src/test/java/org/elasticsearch/cluster/settings/ClusterSettingsTests.java @@ -21,10 +21,13 @@ package org.elasticsearch.cluster.settings; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequestBuilder; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.routing.allocation.decider.DisableAllocationDecider; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeUnit; +import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.discovery.DiscoverySettings; import org.elasticsearch.indices.store.IndicesStore; import org.elasticsearch.test.ElasticsearchIntegrationTest; @@ -189,4 +192,32 @@ public class ClusterSettingsTests extends ElasticsearchIntegrationTest { // Should fail (missing units for refresh_interval): client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder().put("index.refresh_interval", "10")).execute().actionGet(); } + + @Test + public void testMissingUnitsLenient() { + try { + createNode(Settings.builder().put(Settings.SETTINGS_REQUIRE_UNITS, "false").build()); + assertAcked(prepareCreate("test")); + client().admin().indices().prepareUpdateSettings("test").setSettings(Settings.builder().put("index.refresh_interval", "10")).execute().actionGet(); + } finally { + // Restore the default so subsequent tests require units: + assertFalse(Settings.getSettingsRequireUnits()); + Settings.setSettingsRequireUnits(true); + } + } + private void createNode(Settings settings) { + internalCluster().startNode(Settings.builder() + .put(ClusterName.SETTING, "ClusterSettingsTests") + .put("node.name", "ClusterSettingsTests") + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) + .put(EsExecutors.PROCESSORS, 1) // limit the number of threads created + .put("http.enabled", false) + .put("index.store.type", "ram") + .put("config.ignore_system_properties", true) // make sure we get what we set :) + .put("gateway.type", "none") + .put("indices.memory.interval", "100ms") + .put(settings) + ); + } }