diff --git a/core/src/main/java/org/elasticsearch/common/settings/Settings.java b/core/src/main/java/org/elasticsearch/common/settings/Settings.java index 374d923d30a37..b4ab00267c524 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -57,6 +57,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; @@ -442,6 +443,20 @@ public String[] getAsArray(String settingPrefix, String[] defaultArray) throws S public String[] getAsArray(String settingPrefix, String[] defaultArray, Boolean commaDelimited) throws SettingsException { List result = new ArrayList<>(); + final String valueFromPrefix = get(settingPrefix); + final String valueFromPreifx0 = get(settingPrefix + ".0"); + + if (valueFromPrefix != null && valueFromPreifx0 != null) { + final String message = String.format( + Locale.ROOT, + "settings object contains values for [%s=%s] and [%s=%s]", + settingPrefix, + valueFromPrefix, + settingPrefix + ".0", + valueFromPreifx0); + throw new IllegalStateException(message); + } + if (get(settingPrefix) != null) { if (commaDelimited) { String[] strings = Strings.splitStringByCommaToArray(get(settingPrefix)); diff --git a/core/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java b/core/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java index f5501437bcc46..5261268bd4bd3 100644 --- a/core/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java +++ b/core/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java @@ -125,14 +125,21 @@ public static Environment prepareEnvironment(Settings input, Terminal terminal, } /** - * Initializes the builder with the given input settings, and loads system properties settings if allowed. - * If loadDefaults is true, system property default settings are loaded. + * Initializes the builder with the given input settings, and applies settings and default settings from the specified map (these + * settings typically come from the command line). The default settings are applied only if the setting does not exist in the specified + * output. + * + * @param output the settings builder to apply the input and default settings to + * @param input the input settings + * @param esSettings a map from which to apply settings and default settings */ - private static void initializeSettings(Settings.Builder output, Settings input, Map esSettings) { + static void initializeSettings(final Settings.Builder output, final Settings input, final Map esSettings) { output.put(input); output.putProperties(esSettings, - PROPERTY_DEFAULTS_PREDICATE.and(key -> output.get(STRIP_PROPERTY_DEFAULTS_PREFIX.apply(key)) == null), - STRIP_PROPERTY_DEFAULTS_PREFIX); + PROPERTY_DEFAULTS_PREDICATE + .and(key -> output.get(STRIP_PROPERTY_DEFAULTS_PREFIX.apply(key)) == null) + .and(key -> output.get(STRIP_PROPERTY_DEFAULTS_PREFIX.apply(key) + ".0") == null), + STRIP_PROPERTY_DEFAULTS_PREFIX); output.putProperties(esSettings, PROPERTY_DEFAULTS_PREDICATE.negate(), Function.identity()); output.replacePropertyPlaceholders(); } diff --git a/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java b/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java index c1dc07116ecf1..6eec34a90e981 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java @@ -562,4 +562,16 @@ public void testSecureSettingConflict() { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> setting.get(settings)); assertTrue(e.getMessage().contains("must be stored inside the Elasticsearch keystore")); } + + public void testGetAsArrayFailsOnDuplicates() { + final Settings settings = + Settings.builder() + .put("foobar.0", "bar") + .put("foobar.1", "baz") + .put("foobar", "foo") + .build(); + final IllegalStateException e = expectThrows(IllegalStateException.class, () -> settings.getAsArray("foobar")); + assertThat(e, hasToString(containsString("settings object contains values for [foobar=foo] and [foobar.0=bar]"))); + } + } diff --git a/core/src/test/java/org/elasticsearch/node/internal/InternalSettingsPreparerTests.java b/core/src/test/java/org/elasticsearch/node/InternalSettingsPreparerTests.java similarity index 93% rename from core/src/test/java/org/elasticsearch/node/internal/InternalSettingsPreparerTests.java rename to core/src/test/java/org/elasticsearch/node/InternalSettingsPreparerTests.java index daaeab8014369..44c4b880fb68f 100644 --- a/core/src/test/java/org/elasticsearch/node/internal/InternalSettingsPreparerTests.java +++ b/core/src/test/java/org/elasticsearch/node/InternalSettingsPreparerTests.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.node.internal; +package org.elasticsearch.node; import org.elasticsearch.cli.MockTerminal; import org.elasticsearch.cluster.ClusterName; @@ -196,4 +196,15 @@ public void testDefaultPropertiesOverride() throws Exception { Environment env = InternalSettingsPreparer.prepareEnvironment(baseEnvSettings, null, props); assertEquals("bar", env.settings().get("setting")); } + + public void testDefaultWithArray() { + final Settings.Builder output = Settings.builder().put("foobar.0", "bar").put("foobar.1", "baz"); + final Map esSettings = Collections.singletonMap("default.foobar", "foo"); + InternalSettingsPreparer.initializeSettings(output, Settings.EMPTY, esSettings); + final Settings settings = output.build(); + assertThat(settings.get("foobar.0"), equalTo("bar")); + assertThat(settings.get("foobar.1"), equalTo("baz")); + assertNull(settings.get("foobar")); + } + }