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 b090ee565ca IGNITE-26748 Add rolling upgrade commands for control.sh
(#12494)
b090ee565ca is described below
commit b090ee565ca7d3eada325e75585b0717bb1de6ca
Author: Aleksandr Chesnokov <[email protected]>
AuthorDate: Fri Nov 7 15:02:10 2025 +0300
IGNITE-26748 Add rolling upgrade commands for control.sh (#12494)
---
.../commandline/CommandHandlerParsingTest.java | 5 +
.../testsuites/IgniteControlUtilityTestSuite2.java | 2 +
.../ignite/util/RollingUpgradeCommandTest.java | 130 +++++++++++++++++++++
.../internal/management/IgniteCommandRegistry.java | 2 +
.../rollingupgrade/RollingUpgradeCommand.java | 31 +++++
.../RollingUpgradeDisableCommand.java | 67 +++++++++++
.../rollingupgrade/RollingUpgradeDisableTask.java | 75 ++++++++++++
.../RollingUpgradeEnableCommand.java | 74 ++++++++++++
.../RollingUpgradeEnableCommandArg.java | 58 +++++++++
.../rollingupgrade/RollingUpgradeEnableTask.java | 77 ++++++++++++
.../rollingupgrade/RollingUpgradeTaskResult.java | 102 ++++++++++++++++
...ridCommandHandlerClusterByClassTest_help.output | 11 ++
...andHandlerClusterByClassWithSSLTest_help.output | 11 ++
13 files changed, 645 insertions(+)
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
index ada5db81577..507d3bed706 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
@@ -76,6 +76,8 @@ import
org.apache.ignite.internal.management.meta.MetaUpdateCommand;
import org.apache.ignite.internal.management.metric.MetricCommand;
import
org.apache.ignite.internal.management.performancestatistics.PerformanceStatisticsCommand;
import org.apache.ignite.internal.management.property.PropertyCommand;
+import
org.apache.ignite.internal.management.rollingupgrade.RollingUpgradeCommand;
+import
org.apache.ignite.internal.management.rollingupgrade.RollingUpgradeEnableCommand;
import org.apache.ignite.internal.management.snapshot.SnapshotCommand;
import org.apache.ignite.internal.management.snapshot.SnapshotRestoreCommand;
import org.apache.ignite.internal.management.tx.TxCommand;
@@ -516,6 +518,8 @@ public class CommandHandlerParsingTest {
cmdText = F.concat(cmdText, "masterKeyName1");
else if (cmd.getClass() == EncryptionChangeCacheKeyCommand.class)
cmdText = F.concat(cmdText, "cacheGroup1");
+ else if (cmd.getClass() == RollingUpgradeEnableCommand.class)
+ cmdText = F.concat(cmdText, "2.18.0");
else if (cmd.getClass() == SnapshotRestoreCommand.class)
cmdText = F.concat(cmdText, "snp1");
else if (cmd.getClass() == MetaUpdateCommand.class)
@@ -1391,6 +1395,7 @@ public class CommandHandlerParsingTest {
cmd == MetaCommand.class ||
cmd == WarmUpCommand.class ||
cmd == PropertyCommand.class ||
+ cmd == RollingUpgradeCommand.class ||
cmd == SystemViewCommand.class ||
cmd == MetricCommand.class ||
cmd == DefragmentationCommand.class ||
diff --git
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
index 4d6feb57851..d7ed2b51246 100644
---
a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
+++
b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite2.java
@@ -37,6 +37,7 @@ import
org.apache.ignite.util.GridCommandHandlerTracingConfigurationTest;
import org.apache.ignite.util.IdleVerifyDumpTest;
import org.apache.ignite.util.MetricCommandTest;
import org.apache.ignite.util.PerformanceStatisticsCommandTest;
+import org.apache.ignite.util.RollingUpgradeCommandTest;
import org.apache.ignite.util.SystemViewCommandTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -63,6 +64,7 @@ import org.junit.runners.Suite;
GridCommandHandlerConsistencySensitiveTest.class,
GridCommandHandlerConsistencyRepairCorrectnessAtomicTest.class,
+ RollingUpgradeCommandTest.class,
SystemViewCommandTest.class,
MetricCommandTest.class,
PerformanceStatisticsCommandTest.class,
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
new file mode 100644
index 00000000000..6737103dbd4
--- /dev/null
+++
b/modules/control-utility/src/test/java/org/apache/ignite/util/RollingUpgradeCommandTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.util;
+
+import
org.apache.ignite.internal.management.rollingupgrade.RollingUpgradeCommand;
+import
org.apache.ignite.internal.management.rollingupgrade.RollingUpgradeTaskResult;
+import org.apache.ignite.lang.IgniteProductVersion;
+import org.junit.Test;
+
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_BUILD_VER;
+import static
org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
+
+/** Tests {@link RollingUpgradeCommand} command. */
+public class RollingUpgradeCommandTest extends
GridCommandHandlerClusterByClassAbstractTest {
+ /** */
+ public static final String ENABLE = "enable";
+
+ /** */
+ public static final String DISABLE = "disable";
+
+ /** */
+ public static final String ROLLING_UPGRADE = "--rolling-upgrade";
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ super.beforeTestsStarted();
+
+ autoConfirmation = true;
+ }
+
+ /** */
+ @Test
+ public void testEnableAndDisable() {
+ IgniteProductVersion curVer =
IgniteProductVersion.fromString(crd.localNode().attribute(ATTR_BUILD_VER));
+
+ String targetVerStr = curVer.major() + "." + (curVer.minor() + 1) +
".0";
+ IgniteProductVersion targetVer =
IgniteProductVersion.fromString(targetVerStr);
+
+ int res = execute(ROLLING_UPGRADE, ENABLE, targetVerStr);
+
+ assertEquals(EXIT_CODE_OK, res);
+
+ RollingUpgradeTaskResult taskRes =
(RollingUpgradeTaskResult)lastOperationResult;
+
+ assertNull(taskRes.errorMessage());
+ assertEquals(curVer, taskRes.currentVersion());
+ assertEquals(targetVer, taskRes.targetVersion());
+
+ assertTrue(crd.context().rollingUpgrade().enabled());
+
+ res = execute(ROLLING_UPGRADE, DISABLE);
+
+ assertEquals(EXIT_CODE_OK, res);
+
+ taskRes = (RollingUpgradeTaskResult)lastOperationResult;
+
+ assertNull(taskRes.errorMessage());
+ assertEquals(curVer, taskRes.currentVersion());
+ assertNull(taskRes.targetVersion());
+
+ assertFalse(crd.context().rollingUpgrade().enabled());
+ }
+
+ /** */
+ @Test
+ public void testDoubleDisable() {
+ IgniteProductVersion curVer =
IgniteProductVersion.fromString(crd.localNode().attribute(ATTR_BUILD_VER));
+
+ int res = execute(ROLLING_UPGRADE, DISABLE);
+
+ assertEquals(EXIT_CODE_OK, res);
+ RollingUpgradeTaskResult taskRes =
(RollingUpgradeTaskResult)lastOperationResult;
+
+ assertEquals(curVer, taskRes.currentVersion());
+ assertNull(taskRes.targetVersion());
+ assertNull(taskRes.errorMessage());
+
+ res = execute(ROLLING_UPGRADE, DISABLE);
+
+ assertEquals(EXIT_CODE_OK, res);
+ taskRes = (RollingUpgradeTaskResult)lastOperationResult;
+
+ assertNull(taskRes.errorMessage());
+ assertEquals(curVer, taskRes.currentVersion());
+ assertNull(taskRes.targetVersion());
+
+ assertFalse(crd.context().rollingUpgrade().enabled());
+ }
+
+ /** */
+ @Test
+ public void testEnableWithDifferentTargetVersions() {
+ IgniteProductVersion curVer =
IgniteProductVersion.fromString(crd.localNode().attribute(ATTR_BUILD_VER));
+
+ String targetVerStr = curVer.major() + "." + (curVer.minor() + 1) +
".0";
+ IgniteProductVersion targetVer =
IgniteProductVersion.fromString(targetVerStr);
+
+ execute(ROLLING_UPGRADE, ENABLE, targetVerStr);
+
+ String anotherTargetVerStr = curVer.major() + "." + curVer.minor() +
"." + (curVer.maintenance() + 1);
+
+ int res = execute(ROLLING_UPGRADE, ENABLE, anotherTargetVerStr);
+
+ assertEquals(EXIT_CODE_OK, res);
+ RollingUpgradeTaskResult 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/IgniteCommandRegistry.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java
index ae53c3e142e..4388486148a 100644
---
a/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/IgniteCommandRegistry.java
@@ -34,6 +34,7 @@ import
org.apache.ignite.internal.management.metric.MetricCommand;
import
org.apache.ignite.internal.management.performancestatistics.PerformanceStatisticsCommand;
import org.apache.ignite.internal.management.persistence.PersistenceCommand;
import org.apache.ignite.internal.management.property.PropertyCommand;
+import
org.apache.ignite.internal.management.rollingupgrade.RollingUpgradeCommand;
import org.apache.ignite.internal.management.snapshot.SnapshotCommand;
import
org.apache.ignite.internal.management.tracing.TracingConfigurationCommand;
import org.apache.ignite.internal.management.tx.TxCommand;
@@ -67,6 +68,7 @@ public class IgniteCommandRegistry extends
CommandRegistryImpl<NoArg, Void> {
new TracingConfigurationCommand(),
new WarmUpCommand(),
new PropertyCommand(),
+ new RollingUpgradeCommand(),
new SystemViewCommand(),
new MetricCommand(),
new PersistenceCommand(),
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeCommand.java
new file mode 100644
index 00000000000..c68f0378998
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeCommand.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import org.apache.ignite.internal.management.api.CommandRegistryImpl;
+
+/** Rolling upgrade commands. */
+public class RollingUpgradeCommand extends CommandRegistryImpl {
+ /** */
+ public RollingUpgradeCommand() {
+ super(
+ new RollingUpgradeEnableCommand(),
+ new RollingUpgradeDisableCommand()
+ );
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableCommand.java
new file mode 100644
index 00000000000..8bf3b948f07
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableCommand.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.management.api.ComputeCommand;
+import org.apache.ignite.internal.management.api.NoArg;
+import org.apache.ignite.lang.IgniteExperimental;
+
+import static
org.apache.ignite.internal.management.api.CommandUtils.coordinatorOrNull;
+
+/** Command to disable rolling upgrade mode. */
+@IgniteExperimental
+public class RollingUpgradeDisableCommand implements ComputeCommand<NoArg,
RollingUpgradeTaskResult> {
+ /** {@inheritDoc} */
+ @Override public String description() {
+ return "Disable rolling upgrade mode. All nodes in the cluster must be
running the same version";
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<NoArg> argClass() {
+ return NoArg.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<RollingUpgradeDisableTask> taskClass() {
+ return RollingUpgradeDisableTask.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printResult(NoArg arg, RollingUpgradeTaskResult res,
Consumer<String> printer) {
+ if (res.errorMessage() != null) {
+ printer.accept("Failed to disable rolling upgrade: " +
res.errorMessage());
+ return;
+ }
+
+ printer.accept("Rolling upgrade disabled [currentVersion=" +
res.currentVersion() + ']');
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<ClusterNode> nodes(Collection<ClusterNode>
nodes, NoArg arg) {
+ Collection<ClusterNode> coordinator = coordinatorOrNull(nodes);
+
+ if (coordinator == null)
+ throw new IgniteException("Could not find coordinator among nodes:
" + nodes);
+
+ return coordinator;
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableTask.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableTask.java
new file mode 100644
index 00000000000..8c913de58ab
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeDisableTask.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.management.api.NoArg;
+import
org.apache.ignite.internal.processors.rollingupgrade.RollingUpgradeProcessor;
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.util.lang.IgnitePair;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.lang.IgniteProductVersion;
+
+import static org.apache.ignite.internal.IgniteNodeAttributes.ATTR_BUILD_VER;
+
+/** Task to disable rolling upgrade. */
+@GridInternal
+public class RollingUpgradeDisableTask extends VisorOneNodeTask<NoArg,
RollingUpgradeTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** {@inheritDoc} */
+ @Override protected VisorJob<NoArg, RollingUpgradeTaskResult> job(NoArg
arg) {
+ return new RollingUpgradeDisableJob(arg, debug);
+ }
+
+ /** */
+ private static class RollingUpgradeDisableJob extends VisorJob<NoArg,
RollingUpgradeTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ protected RollingUpgradeDisableJob(NoArg arg, boolean debug) {
+ super(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected RollingUpgradeTaskResult run(NoArg arg) throws
IgniteException {
+ RollingUpgradeProcessor proc = ignite.context().rollingUpgrade();
+
+ try {
+ proc.disable();
+
+ String buildVer = ignite.localNode().attribute(ATTR_BUILD_VER);
+
+ return new
RollingUpgradeTaskResult(IgniteProductVersion.fromString(buildVer), null, null);
+ }
+ catch (IgniteCheckedException e) {
+ IgnitePair<IgniteProductVersion> rollUpVers = proc.versions();
+
+ return new RollingUpgradeTaskResult(
+ rollUpVers == null ? null : rollUpVers.get1(),
+ rollUpVers == null ? null : rollUpVers.get2(),
+ e.getMessage()
+ );
+ }
+ }
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommand.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommand.java
new file mode 100644
index 00000000000..94cfd7be2ab
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommand.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.management.api.ComputeCommand;
+import org.apache.ignite.lang.IgniteExperimental;
+
+import static
org.apache.ignite.internal.management.api.CommandUtils.coordinatorOrNull;
+
+/** Command to enable rolling upgrade mode. */
+@IgniteExperimental
+public class RollingUpgradeEnableCommand implements
ComputeCommand<RollingUpgradeEnableCommandArg, RollingUpgradeTaskResult> {
+ /** {@inheritDoc} */
+ @Override public String description() {
+ return "Enable rolling upgrade mode. It allows cluster with
mixed-version nodes";
+ }
+
+ /** {@inheritDoc} */
+ @Override public String confirmationPrompt(RollingUpgradeEnableCommandArg
arg) {
+ return "Warning: the command will enable rolling upgrade mode. "
+ + "It allows cluster with mixed-version nodes. You are responsible
for upgrading nodes manually. "
+ + "This mode can be disabled only when all nodes (including client
nodes) run the same version.";
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<RollingUpgradeEnableCommandArg> argClass() {
+ return RollingUpgradeEnableCommandArg.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Class<RollingUpgradeEnableTask> taskClass() {
+ return RollingUpgradeEnableTask.class;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printResult(RollingUpgradeEnableCommandArg arg,
RollingUpgradeTaskResult res, Consumer<String> printer) {
+ if (res.errorMessage() != null) {
+ printer.accept("Failed to enable rolling upgrade: " +
res.errorMessage());
+ return;
+ }
+
+ printer.accept("Rolling upgrade enabled "
+ + "[currentVersion=" + res.currentVersion() + ",
targetVersion=" + res.targetVersion() + ']');
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<ClusterNode> nodes(Collection<ClusterNode>
nodes, RollingUpgradeEnableCommandArg arg) {
+ Collection<ClusterNode> coordinator = coordinatorOrNull(nodes);
+
+ if (coordinator == null)
+ throw new IgniteException("Could not find coordinator among nodes:
" + nodes);
+
+ return coordinator;
+ }
+}
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
new file mode 100644
index 00000000000..180e7e39d76
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableCommandArg.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.management.api.Argument;
+import org.apache.ignite.internal.management.api.Positional;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/** Rolling upgrade enable command argument. */
+public class RollingUpgradeEnableCommandArg extends IgniteDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0;
+
+ /** Target version. */
+ @Positional
+ @Argument(description = "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)")
+ private String targetVersion;
+
+ /** */
+ public String targetVersion() {
+ return targetVersion;
+ }
+
+ /** */
+ public void targetVersion(String targetVersion) {
+ this.targetVersion = targetVersion;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws
IOException {
+ U.writeString(out, targetVersion);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(ObjectInput in) throws
IOException, ClassNotFoundException {
+ targetVersion = U.readString(in);
+ }
+}
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
new file mode 100644
index 00000000000..70b279f01de
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeEnableTask.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import
org.apache.ignite.internal.processors.rollingupgrade.RollingUpgradeProcessor;
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.util.lang.IgnitePair;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.lang.IgniteProductVersion;
+
+/** Task to enable rolling upgrade. */
+@GridInternal
+public class RollingUpgradeEnableTask extends
VisorOneNodeTask<RollingUpgradeEnableCommandArg, RollingUpgradeTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** {@inheritDoc} */
+ @Override protected VisorJob<RollingUpgradeEnableCommandArg,
RollingUpgradeTaskResult> job(RollingUpgradeEnableCommandArg arg) {
+ return new RollingUpgradeEnableJob(arg, debug);
+ }
+
+ /** */
+ private static class RollingUpgradeEnableJob extends
VisorJob<RollingUpgradeEnableCommandArg, RollingUpgradeTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ protected RollingUpgradeEnableJob(RollingUpgradeEnableCommandArg arg,
boolean debug) {
+ super(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected RollingUpgradeTaskResult
run(RollingUpgradeEnableCommandArg arg) throws IgniteException {
+ RollingUpgradeProcessor proc = ignite.context().rollingUpgrade();
+
+ try {
+
proc.enable(IgniteProductVersion.fromString(arg.targetVersion()));
+
+ IgnitePair<IgniteProductVersion> rollUpVers = proc.versions();
+
+ return new RollingUpgradeTaskResult(
+ rollUpVers == null ? null : rollUpVers.get1(),
+ rollUpVers == null ? null : rollUpVers.get2(),
+ null
+ );
+ }
+ catch (IgniteCheckedException e) {
+ IgnitePair<IgniteProductVersion> rollUpVers = proc.versions();
+
+ return new RollingUpgradeTaskResult(
+ rollUpVers == null ? null : rollUpVers.get1(),
+ rollUpVers == null ? null : rollUpVers.get2(),
+ e.getMessage()
+ );
+ }
+ }
+
+ }
+}
diff --git
a/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeTaskResult.java
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeTaskResult.java
new file mode 100644
index 00000000000..178120654c2
--- /dev/null
+++
b/modules/core/src/main/java/org/apache/ignite/internal/management/rollingupgrade/RollingUpgradeTaskResult.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.management.rollingupgrade;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteProductVersion;
+
+/** */
+public class RollingUpgradeTaskResult extends IgniteDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private IgniteProductVersion curVer;
+
+ /** */
+ private IgniteProductVersion targetVer;
+
+ /** */
+ private String errMsg;
+
+ /** */
+ public RollingUpgradeTaskResult(IgniteProductVersion curVer,
IgniteProductVersion targetVer, String errMsg) {
+ this.curVer = curVer;
+ this.targetVer = targetVer;
+ this.errMsg = errMsg;
+ }
+
+ /** */
+ public RollingUpgradeTaskResult() {
+ // No-op.
+ }
+
+ /** */
+ public IgniteProductVersion currentVersion() {
+ return curVer;
+ }
+
+ /** */
+ public void currentVersion(IgniteProductVersion curVer) {
+ this.curVer = curVer;
+ }
+
+ /** */
+ public IgniteProductVersion targetVersion() {
+ return targetVer;
+ }
+
+ /** */
+ public void targetVersion(IgniteProductVersion targetVer) {
+ this.targetVer = targetVer;
+ }
+
+ /** */
+ public String errorMessage() {
+ return errMsg;
+ }
+
+ /** */
+ public void errorMessage(String errMsg) {
+ this.errMsg = errMsg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws
IOException {
+ out.writeObject(curVer);
+ out.writeObject(targetVer);
+ U.writeString(out, errMsg);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(ObjectInput in) throws
IOException, ClassNotFoundException {
+ this.curVer = (IgniteProductVersion)in.readObject();
+ this.targetVer = (IgniteProductVersion)in.readObject();
+ this.errMsg = U.readString(in);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(RollingUpgradeTaskResult.class, this);
+ }
+}
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 35a0878fec5..06a5226d291 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
@@ -371,6 +371,17 @@ If the file name isn't specified the output file name is:
'<typeId>.bin':
Set the property value:
control.(sh|bat) --property set --name <property_name> --val
<property_value>
+ [EXPERIMENTAL]
+ Enable rolling upgrade mode. It allows cluster with mixed-version nodes:
+ control.(sh|bat) --rolling-upgrade enable target_version
+
+ 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).
+
+ [EXPERIMENTAL]
+ Disable rolling upgrade mode. All nodes in the cluster must be running the
same version:
+ control.(sh|bat) --rolling-upgrade disable
+
Print system view content:
control.(sh|bat) --system-view system_view_name [--node-id
node_id|--node-ids nodeId1,nodeId2,..|--all-nodes]
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 bd8712d6147..a3a7da449d8 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
@@ -371,6 +371,17 @@ If the file name isn't specified the output file name is:
'<typeId>.bin':
Set the property value:
control.(sh|bat) --property set --name <property_name> --val
<property_value>
+ [EXPERIMENTAL]
+ Enable rolling upgrade mode. It allows cluster with mixed-version nodes:
+ control.(sh|bat) --rolling-upgrade enable target_version
+
+ 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).
+
+ [EXPERIMENTAL]
+ Disable rolling upgrade mode. All nodes in the cluster must be running the
same version:
+ control.(sh|bat) --rolling-upgrade disable
+
Print system view content:
control.(sh|bat) --system-view system_view_name [--node-id
node_id|--node-ids nodeId1,nodeId2,..|--all-nodes]