From a49341ce2b8de604ac7498f2e90221b278895d78 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Tue, 13 Apr 2021 07:58:14 -0600 Subject: [PATCH] [7.x] Enforce data_frozen for partial searchable snapshot _tier_preference (#71155) (#71342) * Enforce data_frozen for partial searchable snapshot _tier_preference (#71155) We already set `data_frozen` for partial searchable snapshots when they are mounted (#70786), and automatically convert values other than the frozen role automatically for these snapshots when the metadata is loaded (#71014). This commit makes the `_tier_preference` setting validate that the setting is *only* `data_frozen` when set on a partial searchable snapshot index. * Handle mixed version clusters with pre-7.13.0 frozen SBIs * Fix checkstyyyyyyyyle * Pass index version in settings for test * Unconditionally return only data_frozen for setting Co-authored-by: Elastic Machine --- .../allocation/DataTierAllocationDecider.java | 43 ++++++++++++++++--- .../SearchableSnapshotsConstants.java | 5 +++ .../DataTierAllocationDeciderTests.java | 22 ++++++---- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java index 7c29cb348dc46..c82f033e29032 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import static org.elasticsearch.xpack.core.DataTier.DATA_FROZEN; @@ -65,8 +66,21 @@ public class DataTierAllocationDecider extends AllocationDecider { VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); public static final Setting INDEX_ROUTING_EXCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_EXCLUDE, VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); - public static final Setting INDEX_ROUTING_PREFER_SETTING = Setting.simpleString(INDEX_ROUTING_PREFER, - VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope); + public static final Setting INDEX_ROUTING_PREFER_SETTING = new Setting(new Setting.SimpleKey(INDEX_ROUTING_PREFER), + DataTierValidator::getDefaultTierPreference, Function.identity(), VALIDATOR, + Setting.Property.Dynamic, Setting.Property.IndexScope) { + @Override + public String get(Settings settings) { + if (SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex(settings)) { + // Partial searchable snapshot indices should be restricted to + // only data_frozen when reading the setting, or else validation fails. + return DATA_FROZEN; + } else { + // Otherwise pass through to the regular setting retrieval + return super.get(settings); + } + } + }; private static void validateTierSetting(String setting) { if (Strings.hasText(setting)) { @@ -84,17 +98,32 @@ private static class DataTierValidator implements Setting.Validator { org.elasticsearch.common.collect.List.of(IndexModule.INDEX_STORE_TYPE_SETTING, SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING); + public static String getDefaultTierPreference(Settings settings) { + if (SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex(settings)) { + return DATA_FROZEN; + } else { + return ""; + } + } + @Override public void validate(String value) { validateTierSetting(value); } @Override - public void validate(String value, Map, Object> settings) { - if (Strings.hasText(value) && SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex(settings) == false) { - String[] split = value.split(","); - if (Arrays.stream(split).anyMatch(DATA_FROZEN::equals)) { - throw new IllegalArgumentException("[" + DATA_FROZEN + "] tier can only be used for partial searchable snapshots"); + public void validate(String value, Map, Object> settings, boolean exists) { + if (exists && value != null) { + if (SearchableSnapshotsConstants.isPartialSearchableSnapshotIndex(settings)) { + if (value.equals(DATA_FROZEN) == false) { + throw new IllegalArgumentException("only the [" + DATA_FROZEN + + "] tier preference may be used for partial searchable snapshots (got: [" + value + "])"); + } + } else { + String[] split = value.split(","); + if (Arrays.stream(split).anyMatch(DATA_FROZEN::equals)) { + throw new IllegalArgumentException("[" + DATA_FROZEN + "] tier can only be used for partial searchable snapshots"); + } } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java index 5ad93d8955360..bc31b18f3ba78 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java @@ -42,6 +42,11 @@ public static boolean isPartialSearchableSnapshotIndex(Map, Object> i && (boolean) indexSettings.get(SNAPSHOT_PARTIAL_SETTING); } + public static boolean isPartialSearchableSnapshotIndex(Settings indexSettings) { + return SNAPSHOT_DIRECTORY_FACTORY_KEY.equals(INDEX_STORE_TYPE_SETTING.get(indexSettings)) + && SNAPSHOT_PARTIAL_SETTING.get(indexSettings); + } + public static final String CACHE_FETCH_ASYNC_THREAD_POOL_NAME = "searchable_snapshots_cache_fetch_async"; public static final String CACHE_FETCH_ASYNC_THREAD_POOL_SETTING = "xpack.searchable_snapshots.cache_fetch_async_thread_pool"; diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java index 1aa3ec1574587..b59747de4402d 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java @@ -730,22 +730,26 @@ public void testFrozenIllegalForRegularIndices() { } public void testFrozenLegalForPartialSnapshot() { - List tierList = new ArrayList<>(randomSubsetOf(DataTier.ALL_DATA_TIERS)); - if (tierList.contains(DATA_FROZEN) == false) { - tierList.add(DATA_FROZEN); - } - Randomness.shuffle(tierList); - - String value = Strings.join(tierList, ","); Setting setting = randomTierSetting(); - Settings.Builder builder = Settings.builder().put(setting.getKey(), value); + Settings.Builder builder = Settings.builder().put(setting.getKey(), DATA_FROZEN); builder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY); builder.put(SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.getKey(), true); Settings settings = builder.build(); // validate do not throw - assertThat(setting.get(settings), equalTo(value)); + assertThat(setting.get(settings), equalTo(DATA_FROZEN)); + } + + public void testDefaultValueForPreference() { + assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(Settings.EMPTY), equalTo("")); + + Settings.Builder builder = Settings.builder(); + builder.put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), SearchableSnapshotsConstants.SNAPSHOT_DIRECTORY_FACTORY_KEY); + builder.put(SearchableSnapshotsConstants.SNAPSHOT_PARTIAL_SETTING.getKey(), true); + + Settings settings = builder.build(); + assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings), equalTo(DATA_FROZEN)); } public Setting randomTierSetting() {