Don't omit default values when updating routing exclusions (#33638)
Exclusion setting `cluster.routing.allocation.exclude._host` default value is an empty string. When an exclusion setting is sent with a null value the o.e.c.s.Setting#innerGetRaw API return an empty string (probably to avoid a NullPointerException to be raised). The o.e.c.r.a.d.FilterAllocationDecider class is developed to omit updates of default values for exclusion setting. That's why a null exclusion setting value is translated to an empty string which is equals to the exclusion default value which is configured to be ignored. A simple fix would be to not omit default values for exclusion setting and keep the NullPointerException guard. This is the purpose of this commit. Closes #32721
This commit is contained in:
parent
aeb3cda585
commit
3036ab1048
|
@ -101,9 +101,9 @@ public class FilterAllocationDecider extends AllocationDecider {
|
|||
setClusterRequireFilters(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING.getAsMap(settings));
|
||||
setClusterExcludeFilters(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING.getAsMap(settings));
|
||||
setClusterIncludeFilters(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING.getAsMap(settings));
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING, this::setClusterRequireFilters, (a,b)-> {}, true);
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING, this::setClusterExcludeFilters, (a,b)-> {}, true);
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING, this::setClusterIncludeFilters, (a,b)-> {}, true);
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_REQUIRE_GROUP_SETTING, this::setClusterRequireFilters, (a, b) -> {});
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_EXCLUDE_GROUP_SETTING, this::setClusterExcludeFilters, (a, b) -> {});
|
||||
clusterSettings.addAffixMapUpdateConsumer(CLUSTER_ROUTING_INCLUDE_GROUP_SETTING, this::setClusterIncludeFilters, (a, b) -> {});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -301,13 +301,13 @@ public abstract class AbstractScopedSettings extends AbstractComponent {
|
|||
* consumer in order to be processed correctly. This consumer will get a namespace to value map instead of each individual namespace
|
||||
* and value as in {@link #addAffixUpdateConsumer(Setting.AffixSetting, BiConsumer, BiConsumer)}
|
||||
*/
|
||||
public synchronized <T> void addAffixMapUpdateConsumer(Setting.AffixSetting<T> setting, Consumer<Map<String, T>> consumer,
|
||||
BiConsumer<String, T> validator, boolean omitDefaults) {
|
||||
public synchronized <T> void addAffixMapUpdateConsumer(Setting.AffixSetting<T> setting, Consumer<Map<String, T>> consumer,
|
||||
BiConsumer<String, T> validator) {
|
||||
final Setting<?> registeredSetting = this.complexMatchers.get(setting.getKey());
|
||||
if (setting != registeredSetting) {
|
||||
throw new IllegalArgumentException("Setting is not registered for key [" + setting.getKey() + "]");
|
||||
}
|
||||
addSettingsUpdater(setting.newAffixMapUpdater(consumer, logger, validator, omitDefaults));
|
||||
addSettingsUpdater(setting.newAffixMapUpdater(consumer, logger, validator));
|
||||
}
|
||||
|
||||
synchronized void addSettingsUpdater(SettingUpdater<?> updater) {
|
||||
|
|
|
@ -700,7 +700,7 @@ public class Setting<T> implements ToXContentObject {
|
|||
}
|
||||
|
||||
AbstractScopedSettings.SettingUpdater<Map<String, T>> newAffixMapUpdater(Consumer<Map<String, T>> consumer, Logger logger,
|
||||
BiConsumer<String, T> validator, boolean omitDefaults) {
|
||||
BiConsumer<String, T> validator) {
|
||||
return new AbstractScopedSettings.SettingUpdater<Map<String, T>>() {
|
||||
|
||||
@Override
|
||||
|
@ -721,9 +721,7 @@ public class Setting<T> implements ToXContentObject {
|
|||
// only the ones that have changed otherwise we might get too many updates
|
||||
// the hasChanged above checks only if there are any changes
|
||||
T value = updater.getValue(current, previous);
|
||||
if ((omitDefaults && value.equals(concreteSetting.getDefault(current))) == false) {
|
||||
result.put(namespace, value);
|
||||
}
|
||||
result.put(namespace, value);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
|
|
|
@ -371,9 +371,8 @@ public class ScopedSettingsTests extends ESTestCase {
|
|||
listResults.clear();
|
||||
listResults.putAll(map);
|
||||
};
|
||||
boolean omitDefaults = randomBoolean();
|
||||
service.addAffixMapUpdateConsumer(listSetting, listConsumer, (s, k) -> {}, omitDefaults);
|
||||
service.addAffixMapUpdateConsumer(intSetting, intConsumer, (s, k) -> {}, omitDefaults);
|
||||
service.addAffixMapUpdateConsumer(listSetting, listConsumer, (s, k) -> {});
|
||||
service.addAffixMapUpdateConsumer(intSetting, intConsumer, (s, k) -> {});
|
||||
assertEquals(0, listResults.size());
|
||||
assertEquals(0, intResults.size());
|
||||
service.applySettings(Settings.builder()
|
||||
|
@ -403,7 +402,6 @@ public class ScopedSettingsTests extends ESTestCase {
|
|||
assertEquals(2, listResults.size());
|
||||
assertEquals(2, intResults.size());
|
||||
|
||||
|
||||
listResults.clear();
|
||||
intResults.clear();
|
||||
|
||||
|
@ -416,17 +414,9 @@ public class ScopedSettingsTests extends ESTestCase {
|
|||
assertNull("test wasn't changed", intResults.get("test"));
|
||||
assertEquals(8, intResults.get("test_1").intValue());
|
||||
assertNull("test_list wasn't changed", listResults.get("test_list"));
|
||||
if (omitDefaults) {
|
||||
assertNull(listResults.get("test_list_1"));
|
||||
assertFalse(listResults.containsKey("test_list_1"));
|
||||
assertEquals(0, listResults.size());
|
||||
assertEquals(1, intResults.size());
|
||||
} else {
|
||||
assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
|
||||
assertEquals(1, listResults.size());
|
||||
assertEquals(1, intResults.size());
|
||||
}
|
||||
|
||||
assertEquals(Arrays.asList(1), listResults.get("test_list_1")); // reset to default
|
||||
assertEquals(1, listResults.size());
|
||||
assertEquals(1, intResults.size());
|
||||
}
|
||||
|
||||
public void testAffixMapConsumerNotCalledWithNull() {
|
||||
|
@ -442,7 +432,7 @@ public class ScopedSettingsTests extends ESTestCase {
|
|||
affixResults.clear();
|
||||
affixResults.putAll(map);
|
||||
};
|
||||
service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {}, randomBoolean());
|
||||
service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {});
|
||||
assertEquals(0, affixResults.size());
|
||||
service.applySettings(Settings.builder()
|
||||
.put("eggplant._name", 2)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.elasticsearch.common.settings;
|
||||
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.settings.AbstractScopedSettings.SettingUpdater;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.unit.ByteSizeUnit;
|
||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||
|
@ -33,6 +34,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -890,4 +893,39 @@ public class SettingTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testAffixMapUpdateWithNullSettingValue() {
|
||||
// GIVEN an affix setting changed from "prefix._foo"="bar" to "prefix._foo"=null
|
||||
final Settings current = Settings.builder()
|
||||
.put("prefix._foo", (String) null)
|
||||
.build();
|
||||
|
||||
final Settings previous = Settings.builder()
|
||||
.put("prefix._foo", "bar")
|
||||
.build();
|
||||
|
||||
final Setting.AffixSetting<String> affixSetting =
|
||||
Setting.prefixKeySetting("prefix" + ".",
|
||||
(key) -> Setting.simpleString(key, (value, map) -> {}, Property.Dynamic, Property.NodeScope));
|
||||
|
||||
final Consumer<Map<String, String>> consumer = (map) -> {};
|
||||
final BiConsumer<String, String> validator = (s1, s2) -> {};
|
||||
|
||||
// WHEN creating an affix updater
|
||||
final SettingUpdater<Map<String, String>> updater = affixSetting.newAffixMapUpdater(consumer, logger, validator);
|
||||
|
||||
// THEN affix updater is always expected to have changed (even when defaults are omitted)
|
||||
assertTrue(updater.hasChanged(current, previous));
|
||||
|
||||
// THEN changes are expected when defaults aren't omitted
|
||||
final Map<String, String> updatedSettings = updater.getValue(current, previous);
|
||||
assertNotNull(updatedSettings);
|
||||
assertEquals(1, updatedSettings.size());
|
||||
|
||||
// THEN changes are reported when defaults aren't omitted
|
||||
final String key = updatedSettings.keySet().iterator().next();
|
||||
final String value = updatedSettings.get(key);
|
||||
assertEquals("_foo", key);
|
||||
assertEquals("", value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue