Browse Source

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.
Lee Hinman 4 years ago
parent
commit
b8b9ea0211

+ 23 - 7
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDecider.java

@@ -32,6 +32,7 @@ import java.util.List;
 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;
@@ -66,8 +67,8 @@ public class DataTierAllocationDecider extends AllocationDecider {
         VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope);
     public static final Setting<String> INDEX_ROUTING_EXCLUDE_SETTING = Setting.simpleString(INDEX_ROUTING_EXCLUDE,
         VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope);
-    public static final Setting<String> INDEX_ROUTING_PREFER_SETTING = Setting.simpleString(INDEX_ROUTING_PREFER,
-        VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope);
+    public static final Setting<String> INDEX_ROUTING_PREFER_SETTING = new Setting<>(new Setting.SimpleKey(INDEX_ROUTING_PREFER),
+        DataTierValidator::getDefaultTierPreference, Function.identity(), VALIDATOR, Setting.Property.Dynamic, Setting.Property.IndexScope);
 
     private static void validateTierSetting(String setting) {
         if (Strings.hasText(setting)) {
@@ -84,17 +85,32 @@ public class DataTierAllocationDecider extends AllocationDecider {
         private static final Collection<Setting<?>> dependencies = 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<Setting<?>, 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<Setting<?>, 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");
+                    }
                 }
             }
         }

+ 5 - 0
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/searchablesnapshots/SearchableSnapshotsConstants.java

@@ -42,6 +42,11 @@ public class SearchableSnapshotsConstants {
             && (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";
 

+ 62 - 8
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/cluster/routing/allocation/DataTierAllocationDeciderTests.java

@@ -47,6 +47,7 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
+import static org.elasticsearch.xpack.core.DataTier.DATA_COLD;
 import static org.elasticsearch.xpack.core.DataTier.DATA_FROZEN;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
@@ -731,22 +732,75 @@ public class DataTierAllocationDeciderTests extends ESAllocationTestCase {
     }
 
     public void testFrozenLegalForPartialSnapshot() {
+        Setting<String> setting = randomTierSetting();
+        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(DATA_FROZEN));
+    }
+
+    public void testNonFrozenIllegalForPartialSnapshot() {
         List<String> tierList = new ArrayList<>(randomSubsetOf(DataTier.ALL_DATA_TIERS));
-        if (tierList.contains(DATA_FROZEN) == false) {
-            tierList.add(DATA_FROZEN);
+        if (tierList.contains(DATA_FROZEN)) {
+            tierList.remove(DATA_FROZEN);
+            tierList.add(DATA_COLD);
         }
         Randomness.shuffle(tierList);
 
-        String value = Strings.join(tierList, ",");
-        Setting<String> setting = randomTierSetting();
-        Settings.Builder builder = Settings.builder().put(setting.getKey(), value);
+        {
+            String value = Strings.join(tierList, ",");
+            Settings.Builder builder = Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, value);
+            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();
+
+            IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
+                () -> DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings));
+            assertThat(e.getMessage(),
+                containsString("only the [data_frozen] tier preference may be used for partial searchable snapshots"));
+        }
+
+        {
+            Settings.Builder builder = Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "");
+            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();
+
+            IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
+                () -> DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings));
+            assertThat(e.getMessage(),
+                containsString("only the [data_frozen] tier preference may be used for partial searchable snapshots"));
+        }
+
+        {
+            Settings.Builder builder = Settings.builder().put(DataTierAllocationDecider.INDEX_ROUTING_PREFER, "  ");
+            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();
+
+            IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
+                () -> DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings));
+            assertThat(e.getMessage(),
+                containsString("only the [data_frozen] tier preference may be used for partial searchable snapshots"));
+        }
+    }
+
+    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();
-
-        // validate do not throw
-        assertThat(setting.get(settings), equalTo(value));
+        assertThat(DataTierAllocationDecider.INDEX_ROUTING_PREFER_SETTING.get(settings), equalTo(DATA_FROZEN));
     }
 
     public Setting<String> randomTierSetting() {