This is an automated email from the ASF dual-hosted git repository.

timoninmaxim pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new b20fe87b897 IGNITE-27030 Add force flag for enabling rolling upgrade 
(#12513)
b20fe87b897 is described below

commit b20fe87b89765482a4a714974069e620a4c58045
Author: Aleksandr Chesnokov <[email protected]>
AuthorDate: Thu Nov 13 17:42:59 2025 +0300

    IGNITE-27030 Add force flag for enabling rolling upgrade (#12513)
---
 .../ignite/util/RollingUpgradeCommandTest.java     | 50 ++++++++++++++++++++++
 .../RollingUpgradeEnableCommandArg.java            | 17 ++++++++
 .../rollingupgrade/RollingUpgradeEnableTask.java   |  2 +-
 .../rollingupgrade/RollingUpgradeProcessor.java    | 22 ++++++++--
 .../ignite/internal/GridReleaseTypeSelfTest.java   | 44 +++++++++++++------
 ...ridCommandHandlerClusterByClassTest_help.output |  3 +-
 ...andHandlerClusterByClassWithSSLTest_help.output |  3 +-
 7 files changed, 120 insertions(+), 21 deletions(-)

diff --git 
a/modules/control-utility/src/test/java/org/apache/ignite/util/RollingUpgradeCommandTest.java
 
b/modules/control-utility/src/test/java/org/apache/ignite/util/RollingUpgradeCommandTest.java
index 6737103dbd4..b924fb4186f 100644
--- 
a/modules/control-utility/src/test/java/org/apache/ignite/util/RollingUpgradeCommandTest.java
+++ 
b/modules/control-utility/src/test/java/org/apache/ignite/util/RollingUpgradeCommandTest.java
@@ -33,6 +33,9 @@ public class RollingUpgradeCommandTest extends 
GridCommandHandlerClusterByClassA
     /** */
     public static final String DISABLE = "disable";
 
+    /** */
+    public static final String FORCE = "--force";
+
     /** */
     public static final String ROLLING_UPGRADE = "--rolling-upgrade";
 
@@ -43,6 +46,14 @@ public class RollingUpgradeCommandTest extends 
GridCommandHandlerClusterByClassA
         autoConfirmation = true;
     }
 
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        if (crd.context().rollingUpgrade().enabled())
+            crd.context().rollingUpgrade().disable();
+    }
+
     /** */
     @Test
     public void testEnableAndDisable() {
@@ -127,4 +138,43 @@ public class RollingUpgradeCommandTest extends 
GridCommandHandlerClusterByClassA
 
         assertTrue(crd.context().rollingUpgrade().enabled());
     }
+
+    /** */
+    @Test
+    public void testForceEnable() {
+        IgniteProductVersion curVer = 
IgniteProductVersion.fromString(crd.localNode().attribute(ATTR_BUILD_VER));
+
+        String targetVerStr = curVer.major() + "." + (curVer.minor() + 1) + 
"." + (curVer.maintenance() + 1);
+        IgniteProductVersion targetVer = 
IgniteProductVersion.fromString(targetVerStr);
+
+        int res = execute(ROLLING_UPGRADE, ENABLE, targetVerStr);
+
+        assertEquals(EXIT_CODE_OK, res);
+
+        RollingUpgradeTaskResult taskRes = 
(RollingUpgradeTaskResult)lastOperationResult;
+
+        assertNotNull(taskRes.errorMessage());
+        assertTrue(taskRes.errorMessage().contains("Minor version can only be 
incremented by 1"));
+        assertNull(taskRes.targetVersion());
+
+        String anotherTargetVerStr = curVer.major() + "." + curVer.minor() + 
"." + (curVer.maintenance() + 1);
+
+        execute(ROLLING_UPGRADE, ENABLE, targetVerStr, FORCE);
+
+        taskRes = (RollingUpgradeTaskResult)lastOperationResult;
+        assertNull(taskRes.errorMessage());
+
+        res = execute(ROLLING_UPGRADE, ENABLE, anotherTargetVerStr, FORCE);
+
+        assertEquals(EXIT_CODE_OK, res);
+        taskRes = (RollingUpgradeTaskResult)lastOperationResult;
+
+        assertNotNull(taskRes.errorMessage());
+        assertTrue(taskRes.errorMessage().contains("Rolling upgrade is already 
enabled with a different current and target version"));
+
+        assertEquals(curVer, taskRes.currentVersion());
+        assertEquals(targetVer, taskRes.targetVersion());
+
+        assertTrue(crd.context().rollingUpgrade().enabled());
+    }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommandArg.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommandArg.java
index 180e7e39d76..16cccf4eafe 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommandArg.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommandArg.java
@@ -36,6 +36,11 @@ public class RollingUpgradeEnableCommandArg extends 
IgniteDataTransferObject {
         + "or one maintenance version higher (e.g. 2.18.0 -> 2.18.1 or 2.18.1 
-> 2.19.0)")
     private String targetVersion;
 
+    /** Force flag. */
+    @Argument(description = "Enable rolling upgrade without target version 
checks."
+        + " Use only when required, if the upgrade cannot proceed otherwise", 
optional = true)
+    private boolean force;
+
     /** */
     public String targetVersion() {
         return targetVersion;
@@ -46,13 +51,25 @@ public class RollingUpgradeEnableCommandArg extends 
IgniteDataTransferObject {
         this.targetVersion = targetVersion;
     }
 
+    /** */
+    public boolean force() {
+        return force;
+    }
+
+    /** */
+    public void force(boolean force) {
+        this.force = force;
+    }
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws 
IOException {
         U.writeString(out, targetVersion);
+        out.writeBoolean(force);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(ObjectInput in) throws 
IOException, ClassNotFoundException {
         targetVersion = U.readString(in);
+        force = in.readBoolean();
     }
 }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableTask.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableTask.java
index 70b279f01de..113e0dc659c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableTask.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableTask.java
@@ -52,7 +52,7 @@ public class RollingUpgradeEnableTask extends 
VisorOneNodeTask<RollingUpgradeEna
             RollingUpgradeProcessor proc = ignite.context().rollingUpgrade();
 
             try {
-                
proc.enable(IgniteProductVersion.fromString(arg.targetVersion()));
+                
proc.enable(IgniteProductVersion.fromString(arg.targetVersion()), arg.force());
 
                 IgnitePair<IgniteProductVersion> rollUpVers = proc.versions();
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/RollingUpgradeProcessor.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/RollingUpgradeProcessor.java
index 14af99193ab..7e5be3b10a5 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/RollingUpgradeProcessor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/RollingUpgradeProcessor.java
@@ -155,6 +155,8 @@ public class RollingUpgradeProcessor extends 
GridProcessorAdapter implements Dis
      * This method can only be called on coordinator node with {@link 
TcpDiscoverySpi}.
      *
      * @param target Target version.
+     * @param force If {@code true}, skips target version compatibility checks 
and forcibly enables rolling upgrade.
+     *              This flag does not override an already active upgrade 
configuration.
      * @throws IgniteCheckedException If:
      *     <ul>
      *         <li>The current and target versions are incompatible;</li>
@@ -163,7 +165,7 @@ public class RollingUpgradeProcessor extends 
GridProcessorAdapter implements Dis
      *         <li>The distributed metastorage is not ready;</li>
      *     </ul>
      */
-    public void enable(IgniteProductVersion target) throws 
IgniteCheckedException {
+    public void enable(IgniteProductVersion target, boolean force) throws 
IgniteCheckedException {
         if (startLatch.getCount() > 0)
             throw new IgniteCheckedException("Cannot enable rolling upgrade: 
processor has not been started yet");
 
@@ -179,7 +181,7 @@ public class RollingUpgradeProcessor extends 
GridProcessorAdapter implements Dis
         String curBuildVer = 
ctx.discovery().localNode().attribute(ATTR_BUILD_VER);
         IgniteProductVersion curVer = 
IgniteProductVersion.fromString(curBuildVer);
 
-        if (!checkVersionsForEnabling(curVer, target))
+        if (!checkVersionsForEnabling(curVer, target, force))
             return;
 
         IgnitePair<IgniteProductVersion> newPair = F.pair(curVer, target);
@@ -278,10 +280,14 @@ public class RollingUpgradeProcessor extends 
GridProcessorAdapter implements Dis
      *
      * @param cur Current cluster version.
      * @param target Target cluster version.
-     * @return {@code false} if there is no need to update versions {@code 
true} otherwise.
+     * @param force Force flag to skip version checks.
      * @throws IgniteCheckedException If versions are incorrect.
      */
-    private boolean checkVersionsForEnabling(IgniteProductVersion cur, 
IgniteProductVersion target) throws IgniteCheckedException {
+    private boolean checkVersionsForEnabling(
+        IgniteProductVersion cur,
+        IgniteProductVersion target,
+        boolean force
+    ) throws IgniteCheckedException {
         IgnitePair<IgniteProductVersion> oldVerPair = rollUpVers;
         if (oldVerPair != null) {
             if (oldVerPair.get1().equals(cur) && 
oldVerPair.get2().equals(target))
@@ -291,6 +297,14 @@ public class RollingUpgradeProcessor extends 
GridProcessorAdapter implements Dis
                 oldVerPair.get1() + " , " + oldVerPair.get2());
         }
 
+        if (force) {
+            if (log.isInfoEnabled())
+                log.info("Skipping version compatibility check for rolling 
upgrade due to force flag "
+                    + "[currentVer=" + cur + ", targetVer=" + target + ']');
+
+            return true;
+        }
+
         if (cur.major() != target.major())
             throw new IgniteCheckedException("Major versions are different");
 
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/GridReleaseTypeSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/GridReleaseTypeSelfTest.java
index 36035e32b81..afbfef1bd75 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/GridReleaseTypeSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/GridReleaseTypeSelfTest.java
@@ -145,16 +145,26 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
     /** */
     @Test
     public void testForwardRollingUpgrade() throws Exception {
-        cleanPersistenceDir();
-        IgniteEx ign0 = startGrid(0, "2.18.0", false);
-        IgniteEx ign1 = startGrid(1, "2.18.0", client);
-        IgniteEx ign2 = startGrid(2, "2.18.0", client);
+        doTestRollingUpgrade("2.18.0", "2.18.1", false);
+    }
+
+    /** */
+    @Test
+    public void testForceRollingUpgrade() throws Exception {
+        doTestRollingUpgrade("2.18.0", "2.19.1", true);
+    }
+
+    /** Performs full rolling upgrade scenario. */
+    private void doTestRollingUpgrade(String curVer, String targetVer, boolean 
force) throws Exception {
+        IgniteEx ign0 = startGrid(0, curVer, false);
+        IgniteEx ign1 = startGrid(1, curVer, client);
+        IgniteEx ign2 = startGrid(2, curVer, client);
 
         assertClusterSize(3);
 
-        assertRemoteRejected(() -> startGrid(3, "2.18.1", client));
+        assertRemoteRejected(() -> startGrid(3, targetVer, client));
 
-        configureRollingUpgradeVersion(ign0, "2.18.1");
+        configureRollingUpgradeVersion(ign0, targetVer, force);
 
         for (int i = 0; i < 3; i++) {
             int finalI = i;
@@ -165,7 +175,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
 
         assertClusterSize(2);
 
-        startGrid(2, "2.18.1", client);
+        startGrid(2, targetVer, client);
 
         assertClusterSize(3);
 
@@ -173,7 +183,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
 
         assertClusterSize(2);
 
-        startGrid(1, "2.18.1", client);
+        startGrid(1, targetVer, client);
 
         assertClusterSize(3);
 
@@ -181,7 +191,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
 
         assertClusterSize(2);
 
-        startGrid(0, "2.18.1", false);
+        startGrid(0, targetVer, false);
 
         assertClusterSize(3);
 
@@ -195,7 +205,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
                 assertFalse(grid(i).context().rollingUpgrade().enabled());
         }
 
-        assertRemoteRejected(() -> startGrid(3, "2.18.0", client));
+        assertRemoteRejected(() -> startGrid(3, curVer, client));
     }
 
     /** */
@@ -315,7 +325,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
         IgnitePair<IgniteProductVersion> newPair = 
F.pair(IgniteProductVersion.fromString("2.18.0"),
             IgniteProductVersion.fromString("2.19.0"));
 
-        grid0.context().rollingUpgrade().enable(newPair.get2());
+        grid0.context().rollingUpgrade().enable(newPair.get2(), false);
 
         assertEnablingFails(grid0, "2.18.1", "Rolling upgrade is already 
enabled with a different current and target version");
 
@@ -335,7 +345,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
      */
     private void assertEnablingFails(IgniteEx ex, String ver, String errMsg) {
         Throwable e = assertThrows(log,
-            () -> 
ex.context().rollingUpgrade().enable(IgniteProductVersion.fromString(ver)),
+            () -> 
ex.context().rollingUpgrade().enable(IgniteProductVersion.fromString(ver), 
false),
             IgniteException.class,
             null);
 
@@ -470,10 +480,16 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
         return ign;
     }
 
+    /** */
+    private void configureRollingUpgradeVersion(IgniteEx grid, String ver) 
throws IgniteCheckedException {
+        configureRollingUpgradeVersion(grid, ver, false);
+    }
+
     /**
      * @param ver Version for rolling upgrade support.
+     * @param force Force rolling upgrade.
      */
-    private void configureRollingUpgradeVersion(IgniteEx grid, String ver) 
throws IgniteCheckedException {
+    private void configureRollingUpgradeVersion(IgniteEx grid, String ver, 
boolean force) throws IgniteCheckedException {
         if (ver == null) {
             grid.context().rollingUpgrade().disable();
             return;
@@ -481,7 +497,7 @@ public class GridReleaseTypeSelfTest extends 
GridCommonAbstractTest {
 
         IgniteProductVersion target = IgniteProductVersion.fromString(ver);
 
-        grid.context().rollingUpgrade().enable(target);
+        grid.context().rollingUpgrade().enable(target, force);
     }
 
     /**
diff --git 
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
 
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
index 06a5226d291..9bf90f38eac 100644
--- 
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
+++ 
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
@@ -373,10 +373,11 @@ If the file name isn't specified the output file name is: 
'<typeId>.bin':
 
   [EXPERIMENTAL]
   Enable rolling upgrade mode. It allows cluster with mixed-version nodes:
-      control.(sh|bat) --rolling-upgrade enable target_version
+      control.(sh|bat) --rolling-upgrade enable target_version [--force]
 
       Parameters:
         target_version  - Target Ignite version. The target version can be one 
minor higher if its maintenance version is zero, or one maintenance version 
higher (e.g. 2.18.0 -> 2.18.1 or 2.18.1 -> 2.19.0).
+        --force         - Enable rolling upgrade without target version 
checks. Use only when required, if the upgrade cannot proceed otherwise.
 
   [EXPERIMENTAL]
   Disable rolling upgrade mode. All nodes in the cluster must be running the 
same version:
diff --git 
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
 
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
index a3a7da449d8..21cef2d908e 100644
--- 
a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
+++ 
b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
@@ -373,10 +373,11 @@ If the file name isn't specified the output file name is: 
'<typeId>.bin':
 
   [EXPERIMENTAL]
   Enable rolling upgrade mode. It allows cluster with mixed-version nodes:
-      control.(sh|bat) --rolling-upgrade enable target_version
+      control.(sh|bat) --rolling-upgrade enable target_version [--force]
 
       Parameters:
         target_version  - Target Ignite version. The target version can be one 
minor higher if its maintenance version is zero, or one maintenance version 
higher (e.g. 2.18.0 -> 2.18.1 or 2.18.1 -> 2.19.0).
+        --force         - Enable rolling upgrade without target version 
checks. Use only when required, if the upgrade cannot proceed otherwise.
 
   [EXPERIMENTAL]
   Disable rolling upgrade mode. All nodes in the cluster must be running the 
same version:

Reply via email to