Skip to content

Commit 377242f

Browse files
author
Piyush Kumar
committed
test: Add unit tests for internal vs user ignore settings separation
Add tests to verify that internal ignore patterns can filter protected settings while user ignore patterns respect protection. Also optimize the predicate to use Set.contains() instead of iteration. Signed-off-by: Piyush Kumar <piykumab@amazon.com>
1 parent 1dfa515 commit 377242f

File tree

2 files changed

+114
-41
lines changed

2 files changed

+114
-41
lines changed

server/src/main/java/org/opensearch/snapshots/RestoreService.java

Lines changed: 82 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,78 @@ public class RestoreService implements ClusterStateApplier {
173173
USER_UNREMOVABLE_SETTINGS = unmodifiableSet(unremovable);
174174
}
175175

176+
/**
177+
* Creates a settings filter predicate that separates internal ignore patterns from user ignore patterns.
178+
* Internal ignore patterns override protection and can filter any setting.
179+
* User ignore patterns respect protected settings and cannot filter them.
180+
*
181+
* @param userIgnoreSettings array of user-provided settings to ignore
182+
* @param internalIgnoreSettings array of internal settings to ignore (override protection)
183+
* @param protectedSettings set of settings that user cannot remove
184+
* @return a predicate that returns true if the setting should be kept, false if it should be filtered out
185+
*/
186+
static Predicate<String> createSettingsFilterPredicate(
187+
String[] userIgnoreSettings,
188+
String[] internalIgnoreSettings,
189+
Set<String> protectedSettings
190+
) {
191+
Set<String> userKeyFilters = new HashSet<>();
192+
List<String> userSimpleMatchPatterns = new ArrayList<>();
193+
Set<String> internalKeyFilters = new HashSet<>();
194+
List<String> internalSimpleMatchPatterns = new ArrayList<>();
195+
196+
// Process user ignore settings
197+
for (String ignoredSetting : userIgnoreSettings) {
198+
if (!Regex.isSimpleMatchPattern(ignoredSetting)) {
199+
userKeyFilters.add(ignoredSetting);
200+
} else {
201+
userSimpleMatchPatterns.add(ignoredSetting);
202+
}
203+
}
204+
205+
// Process internal ignore settings
206+
for (String ignoredSetting : internalIgnoreSettings) {
207+
if (!Regex.isSimpleMatchPattern(ignoredSetting)) {
208+
internalKeyFilters.add(ignoredSetting);
209+
} else {
210+
internalSimpleMatchPatterns.add(ignoredSetting);
211+
}
212+
}
213+
214+
return k -> {
215+
// Check internal ignore patterns first (they override protection)
216+
if (internalKeyFilters.contains(k)) {
217+
return false;
218+
}
219+
for (String pattern : internalSimpleMatchPatterns) {
220+
if (Regex.simpleMatch(pattern, k)) {
221+
return false;
222+
}
223+
}
224+
225+
// Check user ignore patterns only for non-protected settings
226+
if (!protectedSettings.contains(k)) {
227+
if (userKeyFilters.contains(k)) {
228+
return false;
229+
}
230+
for (String pattern : userSimpleMatchPatterns) {
231+
if (Regex.simpleMatch(pattern, k)) {
232+
return false;
233+
}
234+
}
235+
}
236+
return true;
237+
};
238+
}
239+
240+
/**
241+
* Returns the set of settings that users cannot remove during restore.
242+
* Exposed for testing purposes.
243+
*/
244+
static Set<String> getUserUnremovableSettings() {
245+
return USER_UNREMOVABLE_SETTINGS;
246+
}
247+
176248
private final ClusterService clusterService;
177249

178250
private final RepositoriesService repositoriesService;
@@ -818,10 +890,6 @@ private IndexMetadata updateIndexSettings(
818890
}
819891
IndexMetadata.Builder builder = IndexMetadata.builder(indexMetadata);
820892
Settings settings = indexMetadata.getSettings();
821-
Set<String> keyFilters = new HashSet<>();
822-
List<String> simpleMatchPatterns = new ArrayList<>();
823-
Set<String> internalKeyFilters = new HashSet<>();
824-
List<String> internalSimpleMatchPatterns = new ArrayList<>();
825893

826894
for (String ignoredSetting : ignoreSettings) {
827895
if (!Regex.isSimpleMatchPattern(ignoredSetting)) {
@@ -835,51 +903,24 @@ private IndexMetadata updateIndexSettings(
835903
snapshot,
836904
"cannot remove UnmodifiableOnRestore setting [" + ignoredSetting + "] on restore"
837905
);
838-
} else {
839-
keyFilters.add(ignoredSetting);
840906
}
841-
} else {
842-
simpleMatchPatterns.add(ignoredSetting);
843907
}
844908
}
845909

846-
// add internal settings to separate ignore lists
847-
for (String ignoredSetting : ignoreSettingsInternal) {
848-
if (!Regex.isSimpleMatchPattern(ignoredSetting)) {
849-
internalKeyFilters.add(ignoredSetting);
850-
} else {
851-
internalSimpleMatchPatterns.add(ignoredSetting);
910+
// Build combined protected settings set including dynamic unmodifiable settings
911+
Set<String> protectedSettings = new HashSet<>(USER_UNREMOVABLE_SETTINGS);
912+
for (String key : settings.keySet()) {
913+
if (indexScopedSettings.isUnmodifiableOnRestoreSetting(key)) {
914+
protectedSettings.add(key);
852915
}
853916
}
854917

855-
Predicate<String> settingsFilter = k -> {
856-
// Check internal ignore patterns first (they override protection)
857-
for (String filterKey : internalKeyFilters) {
858-
if (k.equals(filterKey)) {
859-
return false;
860-
}
861-
}
862-
for (String pattern : internalSimpleMatchPatterns) {
863-
if (Regex.simpleMatch(pattern, k)) {
864-
return false;
865-
}
866-
}
918+
Predicate<String> settingsFilter = createSettingsFilterPredicate(
919+
ignoreSettings,
920+
ignoreSettingsInternal,
921+
protectedSettings
922+
);
867923

868-
// Check user ignore patterns only for non-protected settings
869-
if (USER_UNREMOVABLE_SETTINGS.contains(k) == false && !indexScopedSettings.isUnmodifiableOnRestoreSetting(k)) {
870-
for (String filterKey : keyFilters) {
871-
if (k.equals(filterKey)) {
872-
return false;
873-
}
874-
}
875-
for (String pattern : simpleMatchPatterns) {
876-
if (Regex.simpleMatch(pattern, k)) {
877-
return false;
878-
}
879-
}
880-
}
881-
return true;
882-
};
883924
Settings.Builder settingsBuilder = Settings.builder()
884925
.put(settings.filter(settingsFilter))
885926
.put(normalizedChangeSettings.filter(k -> {

server/src/test/java/org/opensearch/snapshots/RestoreServiceTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,36 @@ public void testValidateReplicationTypeRestoreSettings_WhenSnapshotIsSegment_Res
159159
() -> RestoreService.validateReplicationTypeRestoreSettings(snapshot, ReplicationType.SEGMENT.toString(), indexMetadata)
160160
);
161161
}
162+
163+
// Tests for internal vs user ignore settings filter separation (PR #20494)
164+
165+
public void testInternalIgnoreOverridesProtection() {
166+
var filter = RestoreService.createSettingsFilterPredicate(
167+
new String[] {},
168+
new String[] { "index.remote_store.*" },
169+
RestoreService.getUserUnremovableSettings()
170+
);
171+
// Internal pattern can filter protected settings
172+
assertFalse(filter.test("index.remote_store.enabled"));
173+
}
174+
175+
public void testUserIgnoreRespectsProtection() {
176+
var filter = RestoreService.createSettingsFilterPredicate(
177+
new String[] { "index.number_of_replicas" },
178+
new String[] {},
179+
RestoreService.getUserUnremovableSettings()
180+
);
181+
// User cannot filter protected settings
182+
assertTrue(filter.test("index.number_of_replicas"));
183+
}
184+
185+
public void testUserIgnoreWorksForNonProtected() {
186+
var filter = RestoreService.createSettingsFilterPredicate(
187+
new String[] { "index.custom.*" },
188+
new String[] {},
189+
RestoreService.getUserUnremovableSettings()
190+
);
191+
// User can filter non-protected settings
192+
assertFalse(filter.test("index.custom.setting"));
193+
}
162194
}

0 commit comments

Comments
 (0)