Browse Source

Adjust RolloverAction serialization of maxPrimaryShardSize during an upgrade (#70076)

If node doesn't support maxPrimaryShardSize then serialize maxPrimaryShardSize as maxSize.
This should fix a problematic situation if an older node doesn't support maxPrimaryShardSize
and this is the only condition specified then the older node ends up with a instance without
any conditions. This could lead to upgrade failures, new nodes not able to start because
local cluster state can't be read.

Relates to #69918
Martijn van Groningen 4 years ago
parent
commit
80d486f8b8

+ 12 - 2
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ilm/RolloverAction.java

@@ -96,12 +96,22 @@ public class RolloverAction implements LifecycleAction {
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         boolean hasMaxSize = maxSize != null;
-        out.writeBoolean(hasMaxSize);
+        boolean hasMaxPrimaryShardSize = maxPrimaryShardSize != null;
         if (hasMaxSize) {
+            out.writeBoolean(true);
             maxSize.writeTo(out);
+        } else if (hasMaxPrimaryShardSize && out.getVersion().before(Version.V_7_13_0)) {
+            // In the case that the outgoing node is on a version that doesn't support maxPrimaryShardSize then
+            // serialize it as maxSize. When the outgoing node receives that node-to-node response there is no validation
+            // taking place (see constructors_ and otherwise we could end up with a rollover action instance without any conditions.
+            // If the node is rebooted then it would be unable to read the cluster state and fail starting up.
+            // (ilm policies are part of cluster state)
+            out.writeBoolean(true);
+            maxPrimaryShardSize.writeTo(out);
+        } else {
+            out.writeBoolean(false);
         }
         if (out.getVersion().onOrAfter(Version.V_7_13_0)) {
-            boolean hasMaxPrimaryShardSize = maxPrimaryShardSize != null;
             out.writeBoolean(hasMaxPrimaryShardSize);
             if (hasMaxPrimaryShardSize) {
                 maxPrimaryShardSize.writeTo(out);

+ 18 - 0
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ilm/RolloverActionTests.java

@@ -6,6 +6,7 @@
  */
 package org.elasticsearch.xpack.core.ilm;
 
+import org.elasticsearch.Version;
 import org.elasticsearch.common.io.stream.Writeable.Reader;
 import org.elasticsearch.common.unit.ByteSizeUnit;
 import org.elasticsearch.common.unit.ByteSizeValue;
@@ -16,6 +17,9 @@ import org.elasticsearch.xpack.core.ilm.Step.StepKey;
 import java.io.IOException;
 import java.util.List;
 
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+
 public class RolloverActionTests extends AbstractActionTestCase<RolloverAction> {
 
     @Override
@@ -118,4 +122,18 @@ public class RolloverActionTests extends AbstractActionTestCase<RolloverAction>
         assertEquals(action.getMaxDocs(), firstStep.getMaxDocs());
         assertEquals(nextStepKey, fifthStep.getNextStepKey());
     }
+
+    public void testBwcSerializationWithMaxPrimaryShardSize() throws Exception {
+        // In case of serializing to node with older version, replace maxPrimaryShardSize with maxSize.
+        RolloverAction instance = new RolloverAction(null, new ByteSizeValue(1L), null, null);
+        RolloverAction deserializedInstance = copyInstance(instance, Version.V_7_11_2);
+        assertThat(deserializedInstance.getMaxPrimaryShardSize(), nullValue());
+        assertThat(deserializedInstance.getMaxSize(), equalTo(instance.getMaxPrimaryShardSize()));
+
+        // But not if maxSize is also specified:
+        instance = new RolloverAction(new ByteSizeValue(1L), new ByteSizeValue(2L), null, null);
+        deserializedInstance = copyInstance(instance, Version.V_7_11_2);
+        assertThat(deserializedInstance.getMaxPrimaryShardSize(), nullValue());
+        assertThat(deserializedInstance.getMaxSize(), equalTo(instance.getMaxSize()));
+    }
 }