diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java index 3d92dfa0d566e..0dee5ba767484 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java @@ -68,6 +68,7 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.IgniteRestProcessor; import org.apache.ignite.internal.processors.rollingupgrade.RollingUpgradeProcessor; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; @@ -140,6 +141,9 @@ public interface GridKernalContext extends Iterable { */ public GridKernalGateway gateway(); + /** @return Local node features. */ + public IgniteNodeFeatureSet localNodeFeatures(); + /** * Gets grid instance managed by kernal. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java index 8981207abf2ff..9892823a0917f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java @@ -90,6 +90,7 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.IgniteRestProcessor; import org.apache.ignite.internal.processors.rollingupgrade.RollingUpgradeProcessor; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.segmentation.GridSegmentationProcessor; @@ -632,6 +633,11 @@ else if (!(comp instanceof DiscoveryNodeValidationProcessor return gw; } + /** {@inheritDoc} */ + @Override public IgniteNodeFeatureSet localNodeFeatures() { + return rollUpProc.features().localVersionFeatures(); + } + /** {@inheritDoc} */ @Override public IgniteEx grid() { return grid; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java index 3b0acf2e65eb7..44a5bdabcf5f6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java @@ -91,6 +91,8 @@ import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.rest.IgniteRestProcessor; import org.apache.ignite.internal.processors.rollingupgrade.RollingUpgradeProcessor; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteCoreFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.processors.schedule.IgniteScheduleProcessorAdapter; import org.apache.ignite.internal.processors.security.IgniteSecurity; import org.apache.ignite.internal.processors.security.NoOpIgniteSecurityProcessor; @@ -177,6 +179,9 @@ public class StandaloneGridKernalContext implements GridKernalContext { /** Operation context dispacther. */ private final OperationContextDispatcher opCtxDispatcher = new OperationContextDispatcher(); + /** */ + private final IgniteNodeFeatureSet locNodeFeatures = new IgniteNodeFeatureSet(IgniteCoreFeatureSet.local()); + /** * @param log Logger. * @param ft Node file tree. @@ -317,6 +322,11 @@ protected IgniteConfiguration prepareIgniteConfiguration() { return null; } + /** {@inheritDoc} */ + @Override public IgniteNodeFeatureSet localNodeFeatures() { + return locNodeFeatures; + } + /** {@inheritDoc} */ @Override public IgniteEx grid() { final IgniteEx kernal = new IgniteKernal() { diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index 43d4f1b4867a3..1849f5c91f149 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -88,6 +88,7 @@ import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNodesRing; +import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAuthFailedMessage; @@ -708,7 +709,7 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws TcpDiscoveryIoSession ses = createSession(sock); - TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(locNodeId); + TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(locNodeId, spi.localNodeFeatures()); req.client(true); req.dcId(locNode.dataCenterId()); @@ -717,6 +718,8 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws TcpDiscoveryHandshakeResponse res = spi.readHandshakeResponse(ses, ackTimeout0); + spi.validateRemoteFeatures(res.nodeFeatures()); + // Convert the addresses once. Collection redirectAddrs = res.redirectAddresses(); @@ -791,6 +794,16 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws errs.add(e); + if (e instanceof UnsupportedNodeVersionException) { + LT.error(log, e, "Failed to initialize a connection with the remote node. The remote node is running" + + " components with an incompatible versions, so the nodes cannot agree on serialization protocol" + + " [rmtAddr=" + addr + ']'); + + throw new IgniteSpiException("Failed to initialize a connection with the remote node. The remote node" + + " is running components with an incompatible versions, so the nodes cannot agree on serialization" + + " protocol [rmtAddr=" + addr + ']', e); + } + if (X.hasCause(e, SSLException.class)) { if (--sslConnectAttempts == 0) throw new IgniteSpiException("Unable to establish secure connection. " + diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 1d70baed0aa48..8df9d2c748520 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -130,6 +130,7 @@ import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNodesRing; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState; +import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAuthFailedMessage; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryCheckFailedMessage; @@ -1512,13 +1513,15 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout) openSock = true; - TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(locNodeId); + TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(locNodeId, spi.localNodeFeatures()); // Handshake. spi.writeMessage(ses, req, timeoutHelper.nextTimeoutChunk(spi.getSocketTimeout())); TcpDiscoveryHandshakeResponse res = spi.readHandshakeResponse(ses, timeoutHelper.nextTimeoutChunk(ackTimeout0)); + spi.validateRemoteFeatures(res.nodeFeatures()); + if (msg instanceof TcpDiscoveryJoinRequestMessage) { boolean ignore = false; @@ -1597,6 +1600,16 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout) errs.add(e); + if (e instanceof UnsupportedNodeVersionException) { + LT.error(log, e, "Failed to initialize a connection with the remote node. The remote node is running" + + " components with an incompatible versions, so the nodes cannot agree on serialization protocol" + + " [rmtAddr=" + addr + ']'); + + throw new IgniteException("Failed to initialize a connection with the remote node. The remote node" + + " is running components with an incompatible versions, so the nodes cannot agree on a serialization" + + " protocol [rmtAddr=" + addr + ']', e); + } + if (X.hasCause(e, SSLException.class)) { if (--sslConnectAttempts == 0) throw new IgniteException("Unable to establish secure connection. " + @@ -3412,7 +3425,7 @@ else if (log.isTraceEnabled()) openSock = true; // Handshake. - TcpDiscoveryHandshakeRequest hndMsg = new TcpDiscoveryHandshakeRequest(locNodeId); + TcpDiscoveryHandshakeRequest hndMsg = new TcpDiscoveryHandshakeRequest(locNodeId, spi.localNodeFeatures()); if (sndState != null) { // If want a forced connection, we set the change-topology node flag to current node id. @@ -3441,6 +3454,8 @@ else if (!sndState.isStartingPoint()) if (log.isDebugEnabled()) log.debug("Handshake response: " + res); + spi.validateRemoteFeatures(res.nodeFeatures()); + // We should take previousNodeAlive flag into account // only if we received the response from the correct node. if (res.creatorNodeId().equals(next.id()) && res.previousNodeAlive() && sndState != null) { @@ -6593,8 +6608,11 @@ else if (log.isDebugEnabled()) U.enhanceThreadName(U.id8(nodeId) + ' ' + sock.getInetAddress().getHostAddress() + ":" + sock.getPort() + (req.client() ? " client" : "")); - TcpDiscoveryHandshakeResponse res = - new TcpDiscoveryHandshakeResponse(locNodeId, locNode.internalOrder()); + TcpDiscoveryHandshakeResponse res = new TcpDiscoveryHandshakeResponse( + locNodeId, + locNode.internalOrder(), + spi.localNodeFeatures() + ); if (req.client()) { if (req.dcId() != null && !Objects.equals(req.dcId(), locNode.dataCenterId())) { @@ -6708,6 +6726,8 @@ else if (log.isInfoEnabled()) { spi.writeMessage(ses, res, spi.getEffectiveSocketTimeout(srvSock)); + spi.validateRemoteFeatures(req.nodeFeatures()); + // It can happen if a remote node is stopped and it has a loopback address in the list of addresses, // the local node sends a handshake request message on the loopback address, so we get here. if (locNodeId.equals(nodeId)) { @@ -6804,21 +6824,26 @@ else if ((X.hasCause(e, ObjectStreamException.class) || !sock.isClosed()) onException("Caught exception on handshake [err=" + e + ", sock=" + sock + ']', e); - if (e.hasCause(SocketTimeoutException.class)) + if (e instanceof UnsupportedNodeVersionException) { + LT.warn(log, "Failed to initialize a connection with the remote node. The remote node is running" + + " components with an incompatible versions, so the nodes cannot agree on serialization protocol" + + " [rmtAddr=" + rmtAddr + ']', e); + } + else if (e.hasCause(SocketTimeoutException.class)) { LT.warn(log, "Socket operation timed out on handshake " + "(consider increasing 'networkTimeout' configuration property) " + "[netTimeout=" + spi.netTimeout + ']'); - - else if (e.hasCause(ClassNotFoundException.class)) + } + else if (e.hasCause(ClassNotFoundException.class)) { LT.warn(log, "Failed to read message due to ClassNotFoundException " + "(make sure same versions of all classes are available on all nodes) " + "[rmtAddr=" + rmtAddr + ", err=" + X.cause(e, ClassNotFoundException.class).getMessage() + ']'); - + } + else if (e.hasCause(ObjectStreamException.class) || (!sock.isClosed() && !e.hasCause(IOException.class))) { // Always report marshalling problems. - else if (e.hasCause(ObjectStreamException.class) || - (!sock.isClosed() && !e.hasCause(IOException.class))) LT.error(log, e, "Failed to initialize connection [sock=" + sock + ']'); + } return; } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java index b1cc53cbee551..122861cc4206d 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java @@ -60,6 +60,8 @@ import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpi; import org.apache.ignite.internal.processors.failure.FailureProcessor; import org.apache.ignite.internal.processors.metric.MetricRegistryImpl; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteComponentFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; @@ -99,6 +101,7 @@ import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryStatistics; +import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder; @@ -468,6 +471,9 @@ public class TcpDiscoverySpi extends IgniteSpiAdapter implements IgniteDiscovery /** For test purposes. */ private boolean skipAddrsRandomization = false; + /** */ + private IgniteNodeFeatureSet locNodeFeatures; + /** * Gets current SPI state. * @@ -1189,6 +1195,8 @@ protected void initLocalNode(int srvPort, boolean addExtAddrAttr) { // Init local node. initAddresses(); + locNodeFeatures = ((IgniteEx)ignite).context().localNodeFeatures(); + locNode = new TcpDiscoveryNode( ignite.configuration().getNodeId(), addrs.get1(), @@ -1686,6 +1694,40 @@ Socket createSocket() throws IOException { } } + /** */ + IgniteNodeFeatureSet localNodeFeatures() { + return locNodeFeatures; + } + + /** */ + void validateRemoteFeatures(IgniteNodeFeatureSet rmtFeatures) throws IgniteCheckedException { + if (rmtFeatures == null) + throw new UnsupportedNodeVersionException("Remote node component versions are not supported" + + " [locComponents=" + locNodeFeatures + + ", rmtComponents=" + rmtFeatures + ']'); + + for (IgniteComponentFeatureSet rmtCmpFeatures : rmtFeatures.values()) { + IgniteComponentFeatureSet locCmpFeatures = locNodeFeatures.componentFeatures(rmtCmpFeatures.componentName()); + + if (locCmpFeatures == null) + continue; + + int c = locCmpFeatures.version().compareTo(rmtCmpFeatures.version()); + + if (c == 0) + continue; + + IgniteComponentFeatureSet src = c > 0 ? rmtCmpFeatures : locCmpFeatures; + IgniteComponentFeatureSet target = c > 0 ? locCmpFeatures : rmtCmpFeatures; + + if (!src.isUpgradableTo(target)) { + throw new UnsupportedNodeVersionException("Remote node component versions are not supported" + + " [locComponents=" + locNodeFeatures + + ", rmtComponents=" + rmtFeatures + ']'); + } + } + } + /** * Writes message to the socket. * diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/UnsupportedNodeVersionException.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/UnsupportedNodeVersionException.java new file mode 100644 index 0000000000000..ca46b73cc2055 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/UnsupportedNodeVersionException.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.spi.discovery.tcp.internal; + +import org.apache.ignite.IgniteCheckedException; + +/** */ +public class UnsupportedNodeVersionException extends IgniteCheckedException { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + public UnsupportedNodeVersionException(String message) { + super(message); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeRequest.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeRequest.java index 6ce9f16a7bcd9..d2a33c6d059e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeRequest.java @@ -19,6 +19,8 @@ import java.util.UUID; import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteComponentFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.jetbrains.annotations.Nullable; @@ -35,6 +37,10 @@ public class TcpDiscoveryHandshakeRequest extends TcpDiscoveryAbstractMessage { @Order(1) @Nullable String dcId; + /** */ + @Order(2) + IgniteComponentFeatureSet[] nodeFeatures; + /** * Default constructor for {@link MessageFactory}. */ @@ -46,9 +52,12 @@ public TcpDiscoveryHandshakeRequest() { * Constructor. * * @param creatorNodeId Creator node ID. + * @param locNodeFeatures Local node features. */ - public TcpDiscoveryHandshakeRequest(UUID creatorNodeId) { + public TcpDiscoveryHandshakeRequest(UUID creatorNodeId, IgniteNodeFeatureSet locNodeFeatures) { super(creatorNodeId); + + this.nodeFeatures = locNodeFeatures.values(); } /** @@ -79,6 +88,11 @@ public void dcId(String dcId) { this.dcId = dcId; } + /** @return Features supported by the sender node. */ + public IgniteNodeFeatureSet nodeFeatures() { + return nodeFeatures == null ? null : new IgniteNodeFeatureSet(nodeFeatures); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(TcpDiscoveryHandshakeRequest.class, this, "super", super.toString(), diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeResponse.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeResponse.java index b5ca363ae01e0..d11e0814ef88c 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryHandshakeResponse.java @@ -21,6 +21,8 @@ import java.util.Collection; import java.util.UUID; import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteComponentFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.plugin.extensions.communication.MessageFactory; @@ -42,6 +44,10 @@ public class TcpDiscoveryHandshakeResponse extends TcpDiscoveryAbstractMessage { @Order(2) @Nullable Collection redirectAddrsMsgs; + /** */ + @Order(3) + IgniteComponentFeatureSet[] nodeFeatures; + /** * Default constructor for {@link MessageFactory}. */ @@ -54,11 +60,14 @@ public TcpDiscoveryHandshakeResponse() { * * @param creatorNodeId Creator node ID. * @param locNodeOrder Local node order. + * @param locNodeFeatures Local node features. */ - public TcpDiscoveryHandshakeResponse(UUID creatorNodeId, long locNodeOrder) { + public TcpDiscoveryHandshakeResponse(UUID creatorNodeId, long locNodeOrder, IgniteNodeFeatureSet locNodeFeatures) { super(creatorNodeId); order = locNodeOrder; + + this.nodeFeatures = locNodeFeatures.values(); } /** @@ -104,6 +113,11 @@ public void redirectAddresses(@Nullable Collection sockAddrs) : F.viewReadOnly(sockAddrs, addr -> new InetSocketAddressMessage(addr.getAddress(), addr.getPort())); } + /** @return Features supported by the sender node. */ + public IgniteNodeFeatureSet nodeFeatures() { + return nodeFeatures == null ? null : new IgniteNodeFeatureSet(nodeFeatures); + } + /** {@inheritDoc} */ @Override public String toString() { return S.toString(TcpDiscoveryHandshakeResponse.class, this, "super", super.toString(), diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/AbstractRollingUpgradeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/AbstractRollingUpgradeTest.java index 1802069a95af2..0bbdb9824a57d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/AbstractRollingUpgradeTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/AbstractRollingUpgradeTest.java @@ -71,6 +71,7 @@ import org.apache.ignite.spi.IgniteSpiException; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.TestBlockingTcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.jspecify.annotations.Nullable; @@ -148,8 +149,7 @@ public abstract class AbstractRollingUpgradeTest extends GridCommonAbstractTest "One or more component versions on the joining node differ from the corresponding versions active in the cluster"; /** */ - protected static final String RU_UNAVAILABLE_BETWEEN_VER_ERR = "Ignite component Rolling Upgrade is not supported" + - " between the component version active in the cluster and the version running on the joining node"; + protected static final String NOT_SUPPORTED_VER_ERR = "Remote node component versions are not supported"; /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { @@ -346,10 +346,14 @@ protected void checkJoinFailed(int nodeIdx, String ver, String msg) { protected void checkJoinFailed(int nodeIdx, String ver, boolean checkClientNode, String msg) { int expClusterSize = clusterNode().cluster().nodes().size(); - GridTestUtils.assertThrowsAnyCause(log, () -> startGrid(nodeIdx, ver), IgniteSpiException.class, msg); + Class errCls = Objects.equals(msg, NOT_SUPPORTED_VER_ERR) + ? UnsupportedNodeVersionException.class + : IgniteSpiException.class; + + GridTestUtils.assertThrowsAnyCause(log, () -> startGrid(nodeIdx, ver), errCls, msg); if (checkClientNode) - GridTestUtils.assertThrowsAnyCause(log, () -> startClientGrid(nodeIdx, ver), IgniteSpiException.class, msg); + GridTestUtils.assertThrowsAnyCause(log, () -> startClientGrid(nodeIdx, ver), errCls, msg); assertEquals(expClusterSize, clusterNode().cluster().nodes().size()); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/CoreVersionRollingUpgradeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/CoreVersionRollingUpgradeTest.java index e3f65fd356530..fa609093f7e95 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/CoreVersionRollingUpgradeTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/CoreVersionRollingUpgradeTest.java @@ -311,6 +311,22 @@ public void testProductVersionChangeDuringClusterVersionUpgrade() throws Excepti finalizeClusterVersion(1, "2.19.3"); } + /** */ + @Test + public void testJoinOfNodeWithGreaterUnsupportedVersion() throws Exception { + startCluster("2.19.0"); + + checkJoinFailed(3, "2.21.0", NOT_SUPPORTED_VER_ERR); + } + + /** */ + @Test + public void testJoinOfNodeWithSmallerUnsupportedVersion() throws Exception { + startCluster("2.21.0"); + + checkJoinFailed(3, "2.19.0", NOT_SUPPORTED_VER_ERR); + } + /** */ @Test public void testUpgradeBetweenVersionsWithCherryPicks() throws Exception { @@ -318,7 +334,7 @@ public void testUpgradeBetweenVersionsWithCherryPicks() throws Exception { ru(1).enableVersionUpgrade(); - checkJoinFailed(3, "2.20.0", RU_UNAVAILABLE_BETWEEN_VER_ERR); + checkJoinFailed(3, "2.20.0", NOT_SUPPORTED_VER_ERR); forAllNodes(nodeIdx -> upgradeNodeVersion(nodeIdx, "2.19.3", "2.20.1")); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/PluginVersionRollingUpgradeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/PluginVersionRollingUpgradeTest.java index 0f7291a966558..68b404de6f3ae 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/PluginVersionRollingUpgradeTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/PluginVersionRollingUpgradeTest.java @@ -131,11 +131,11 @@ public void testNodeValidationDuringUpgrade() throws Exception { checkJoinFailed(3, "2.20.0", false, "Some components active in the cluster are not configured on the joining server node"); checkJoinSuccess(3, "2.20.0", true); - checkJoinFailed(4, "2.20.0 | 3.0.0", RU_UNAVAILABLE_BETWEEN_VER_ERR); + checkJoinFailed(4, "2.20.0 | 3.0.0", NOT_SUPPORTED_VER_ERR); checkJoinSuccess(4, "2.20.0 | 2.0.0", true); - checkJoinFailed(5, "2.20.0 | 3.0.0", VER_INCOMPATIBLE_ERR); + checkJoinFailed(5, "2.20.0 | 2.1.0", VER_INCOMPATIBLE_ERR); upgradeNodeVersion(0, "2.19.0 | 1.0.0", "2.20.0 | 2.0.0"); upgradeNodeVersion(1, "2.19.0 | 1.0.0", "2.20.0 | 2.0.0"); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java new file mode 100644 index 0000000000000..edb4b3b3646ac --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java @@ -0,0 +1,27 @@ +/* + * 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.processors.rollingupgrade.feature; + +/** */ +public class TestPluginReleaseFeatures_2_1_0 { + /** */ + public static final IgniteFeature VER_2_1_0_ID_1_FEATURE = new TestPluginFeature(1); + + /** */ + public static final IgniteFeature VER_2_1_0_ID_2_FEATURE = new TestPluginFeature(2); +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_3_0_0.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_3_0_0.java index b40cea1590d2b..d5c7b4f2e23b9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_3_0_0.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_3_0_0.java @@ -21,4 +21,7 @@ public class TestPluginReleaseFeatures_3_0_0 { /** */ public static final IgniteFeature VER_3_0_0_ID_2_FEATURE = new TestPluginFeature(2); + + /** */ + public static final IgniteFeature VER_3_0_0_ID_3_FEATURE = new TestPluginFeature(3); }