Skip to content

Commit ab06b13

Browse files
committed
Add notion of internal index settings (#31286)
We have some use cases for an index setting to only be manageable by dedicated APIs rather than be updateable via the update settings API. This commit adds the notion of an internal index setting. Such settings can be set on create index requests, they can not be changed via the update settings API, yet they can be changed by action on behalf of or triggered by the user via dedicated APIs.
1 parent 479a2eb commit ab06b13

File tree

6 files changed

+311
-11
lines changed

6 files changed

+311
-11
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataUpdateSettingsService.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,10 @@ public void updateSettings(final UpdateSettingsClusterStateUpdateRequest request
8282
Settings.Builder settingsForOpenIndices = Settings.builder();
8383
final Set<String> skippedSettings = new HashSet<>();
8484

85-
indexScopedSettings.validate(normalizedSettings.filter(s -> Regex.isSimpleMatchPattern(s) == false /* don't validate wildcards */),
86-
false); //don't validate dependencies here we check it below never allow to change the number of shards
85+
indexScopedSettings.validate(
86+
normalizedSettings.filter(s -> Regex.isSimpleMatchPattern(s) == false), // don't validate wildcards
87+
false, // don't validate dependencies here we check it below never allow to change the number of shards
88+
true); // validate internal index settings
8789
for (String key : normalizedSettings.keySet()) {
8890
Setting setting = indexScopedSettings.get(key);
8991
boolean isWildcard = setting == null && Regex.isSimpleMatchPattern(key);

server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java

+57-3
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,18 @@ public final void validate(final Settings settings, final boolean validateDepend
282282
validate(settings, validateDependencies, false, false);
283283
}
284284

285+
/**
286+
* Validates that all settings are registered and valid.
287+
*
288+
* @param settings the settings to validate
289+
* @param validateDependencies true if dependent settings should be validated
290+
* @param validateInternalIndex true if internal index settings should be validated
291+
* @see Setting#getSettingsDependencies(String)
292+
*/
293+
public final void validate(final Settings settings, final boolean validateDependencies, final boolean validateInternalIndex) {
294+
validate(settings, validateDependencies, false, false, validateInternalIndex);
295+
}
296+
285297
/**
286298
* Validates that all settings are registered and valid.
287299
*
@@ -296,6 +308,25 @@ public final void validate(
296308
final boolean validateDependencies,
297309
final boolean ignorePrivateSettings,
298310
final boolean ignoreArchivedSettings) {
311+
validate(settings, validateDependencies, ignorePrivateSettings, ignoreArchivedSettings, false);
312+
}
313+
314+
/**
315+
* Validates that all settings are registered and valid.
316+
*
317+
* @param settings the settings
318+
* @param validateDependencies true if dependent settings should be validated
319+
* @param ignorePrivateSettings true if private settings should be ignored during validation
320+
* @param ignoreArchivedSettings true if archived settings should be ignored during validation
321+
* @param validateInternalIndex true if index internal settings should be validated
322+
* @see Setting#getSettingsDependencies(String)
323+
*/
324+
public final void validate(
325+
final Settings settings,
326+
final boolean validateDependencies,
327+
final boolean ignorePrivateSettings,
328+
final boolean ignoreArchivedSettings,
329+
final boolean validateInternalIndex) {
299330
final List<RuntimeException> exceptions = new ArrayList<>();
300331
for (final String key : settings.keySet()) { // settings iterate in deterministic fashion
301332
if (isPrivateSetting(key) && ignorePrivateSettings) {
@@ -305,7 +336,7 @@ public final void validate(
305336
continue;
306337
}
307338
try {
308-
validate(key, settings, validateDependencies);
339+
validate(key, settings, validateDependencies, validateInternalIndex);
309340
} catch (final RuntimeException ex) {
310341
exceptions.add(ex);
311342
}
@@ -314,9 +345,27 @@ public final void validate(
314345
}
315346

316347
/**
317-
* Validates that the setting is valid
348+
* Validates that the settings is valid.
349+
*
350+
* @param key the key of the setting to validate
351+
* @param settings the settings
352+
* @param validateDependencies true if dependent settings should be validated
353+
* @throws IllegalArgumentException if the setting is invalid
318354
*/
319-
void validate(String key, Settings settings, boolean validateDependencies) {
355+
void validate(final String key, final Settings settings, final boolean validateDependencies) {
356+
validate(key, settings, validateDependencies, false);
357+
}
358+
359+
/**
360+
* Validates that the settings is valid.
361+
*
362+
* @param key the key of the setting to validate
363+
* @param settings the settings
364+
* @param validateDependencies true if dependent settings should be validated
365+
* @param validateInternalIndex true if internal index settings should be validated
366+
* @throws IllegalArgumentException if the setting is invalid
367+
*/
368+
void validate(final String key, final Settings settings, final boolean validateDependencies, final boolean validateInternalIndex) {
320369
Setting setting = getRaw(key);
321370
if (setting == null) {
322371
LevensteinDistance ld = new LevensteinDistance();
@@ -356,6 +405,11 @@ void validate(String key, Settings settings, boolean validateDependencies) {
356405
}
357406
}
358407
}
408+
// the only time that validateInternalIndex should be true is if this call is coming via the update settings API
409+
if (validateInternalIndex && setting.getProperties().contains(Setting.Property.InternalIndex)) {
410+
throw new IllegalArgumentException(
411+
"can not update internal setting [" + setting.getKey() + "]; this setting is managed via a dedicated API");
412+
}
359413
}
360414
setting.get(settings);
361415
}

server/src/main/java/org/elasticsearch/common/settings/Setting.java

+15-5
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,13 @@ public enum Property {
120120
* Mark this setting as not copyable during an index resize (shrink or split). This property can only be applied to settings that
121121
* also have {@link Property#IndexScope}.
122122
*/
123-
NotCopyableOnResize
123+
NotCopyableOnResize,
124+
125+
/**
126+
* Indicates an index-level setting that is managed internally. Such a setting can only be added to an index on index creation but
127+
* can not be updated via the update API.
128+
*/
129+
InternalIndex
124130
}
125131

126132
private final Key key;
@@ -152,14 +158,18 @@ private Setting(Key key, @Nullable Setting<T> fallbackSetting, Function<Settings
152158
if (propertiesAsSet.contains(Property.Dynamic) && propertiesAsSet.contains(Property.Final)) {
153159
throw new IllegalArgumentException("final setting [" + key + "] cannot be dynamic");
154160
}
155-
if (propertiesAsSet.contains(Property.NotCopyableOnResize) && propertiesAsSet.contains(Property.IndexScope) == false) {
156-
throw new IllegalArgumentException(
157-
"non-index-scoped setting [" + key + "] can not have property [" + Property.NotCopyableOnResize + "]");
158-
}
161+
checkPropertyRequiresIndexScope(propertiesAsSet, Property.NotCopyableOnResize);
162+
checkPropertyRequiresIndexScope(propertiesAsSet, Property.InternalIndex);
159163
this.properties = propertiesAsSet;
160164
}
161165
}
162166

167+
private void checkPropertyRequiresIndexScope(final EnumSet<Property> properties, final Property property) {
168+
if (properties.contains(property) && properties.contains(Property.IndexScope) == false) {
169+
throw new IllegalArgumentException("non-index-scoped setting [" + key + "] can not have property [" + property + "]");
170+
}
171+
}
172+
163173
/**
164174
* Creates a new Setting instance
165175
* @param key the settings key for this setting.

server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java

+24
Original file line numberDiff line numberDiff line change
@@ -876,4 +876,28 @@ public void testFinalSettingUpdateFail() {
876876
Settings.builder().put(currentSettings), Settings.builder(), "node"));
877877
assertThat(exc.getMessage(), containsString("final node setting [some.final.group.foo]"));
878878
}
879+
880+
public void testInternalIndexSettingsFailsValidation() {
881+
final Setting<String> indexInternalSetting = Setting.simpleString("index.internal", Property.InternalIndex, Property.IndexScope);
882+
final IndexScopedSettings indexScopedSettings =
883+
new IndexScopedSettings(Settings.EMPTY, Collections.singleton(indexInternalSetting));
884+
final IllegalArgumentException e = expectThrows(
885+
IllegalArgumentException.class,
886+
() -> {
887+
final Settings settings = Settings.builder().put("index.internal", "internal").build();
888+
indexScopedSettings.validate(settings, false, /* validateInternalIndex */ true);
889+
});
890+
final String message = "can not update internal setting [index.internal]; this setting is managed via a dedicated API";
891+
assertThat(e, hasToString(containsString(message)));
892+
}
893+
894+
public void testInternalIndexSettingsSkipValidation() {
895+
final Setting<String> internalIndexSetting = Setting.simpleString("index.internal", Property.InternalIndex, Property.IndexScope);
896+
final IndexScopedSettings indexScopedSettings =
897+
new IndexScopedSettings(Settings.EMPTY, Collections.singleton(internalIndexSetting));
898+
// nothing should happen, validation should not throw an exception
899+
final Settings settings = Settings.builder().put("index.internal", "internal").build();
900+
indexScopedSettings.validate(settings, false, /* validateInternalIndex */ false);
901+
}
902+
879903
}

server/src/test/java/org/elasticsearch/common/settings/SettingTests.java

+7
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,13 @@ public void testRejectNonIndexScopedNotCopyableOnResizeSetting() {
735735
assertThat(e, hasToString(containsString("non-index-scoped setting [foo.bar] can not have property [NotCopyableOnResize]")));
736736
}
737737

738+
public void testRejectNonIndexScopedIndexInternalSetting() {
739+
final IllegalArgumentException e = expectThrows(
740+
IllegalArgumentException.class,
741+
() -> Setting.simpleString("foo.bar", Property.InternalIndex));
742+
assertThat(e, hasToString(containsString("non-index-scoped setting [foo.bar] can not have property [InternalIndex]")));
743+
}
744+
738745
public void testTimeValue() {
739746
final TimeValue random = TimeValue.parseTimeValue(randomTimeValue(), "test");
740747

0 commit comments

Comments
 (0)