Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ public abstract class IgniteDataTransferObject implements Externalizable {
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(MAGIC);

try (IgniteDataTransferObjectOutput dtout = new IgniteDataTransferObjectOutput(out)) {
IgniteDataTransferObjectSerializer serializer = IDTOSerializerFactory.getInstance().serializer(getClass());

serializer.writeExternal(this, dtout);
}
writeIgniteDataTransferObject(out);
}

/** {@inheritDoc} */
Expand All @@ -68,6 +64,20 @@ public abstract class IgniteDataTransferObject implements Externalizable {
throw new IOException("Unexpected IgniteDataTransferObject header " +
"[actual=" + Integer.toHexString(hdr) + ", expected=" + Integer.toHexString(MAGIC) + "]");

readIgniteDataTransferObject(in);
}

/** */
protected void writeIgniteDataTransferObject(ObjectOutput out) throws IOException {
try (IgniteDataTransferObjectOutput dtout = new IgniteDataTransferObjectOutput(out)) {
IgniteDataTransferObjectSerializer serializer = IDTOSerializerFactory.getInstance().serializer(getClass());

serializer.writeExternal(this, dtout);
}
}

/** */
protected void readIgniteDataTransferObject(ObjectInput in) throws IOException, ClassNotFoundException {
try (IgniteDataTransferObjectInput dtin = new IgniteDataTransferObjectInput(in)) {
IgniteDataTransferObjectSerializer serializer = IDTOSerializerFactory.getInstance().serializer(getClass());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class IgniteCoreFeatureSet extends IgniteComponentFeatureSet {
private static final long serialVersionUID = 0L;

/** */
private static final IgniteCoreFeatureSet INSTANCE = new IgniteCoreFeatureSet(
static IgniteCoreFeatureSet INSTANCE = new IgniteCoreFeatureSet(
IgniteVersionUtils.VER,
IgniteFeatureSet.buildFrom(SupportedFeatureRegistry.class)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,17 @@

package org.apache.ignite.internal.visor;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.apache.ignite.internal.Order;
import org.apache.ignite.internal.dto.IgniteDataTransferObject;
import org.apache.ignite.internal.processors.metastorage.persistence.DistributedMetaStorageVersion;
import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteCoreFeatureSet;
import org.apache.ignite.internal.util.typedef.internal.S;

/**
Expand All @@ -32,6 +37,20 @@ public class VisorTaskArgument<A> extends IgniteDataTransferObject {
/** */
private static final long serialVersionUID = 0L;

/**
* Magic header used for Management API argument serialization.
*
* <p>This value differs from the magic header defined in the parent class because
* some {@link IgniteDataTransferObject} implementations (for example,
* {@link DistributedMetaStorageVersion}) are stored in the PDS, which requires full backward compatibility.
* A separate magic header is required to distinguish Management API arguments serialized by pre-Rolling Upgrade
* clients and handle them correctly.</p>
*/
private static final int MAGIC = 0xBAA55F5E;

/** */
transient IgniteCoreFeatureSet cmdInitiatorFeatures = IgniteCoreFeatureSet.local();

/** Node IDs task should be mapped to. */
@Order(0)
List<UUID> nodes;
Expand Down Expand Up @@ -119,6 +138,40 @@ public boolean isDebug() {
return debug;
}

/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(MAGIC);

cmdInitiatorFeatures.writeExternal(out);

writeIgniteDataTransferObject(out);
}

/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
int hdr = in.readInt();

if ((hdr & MAGIC) != MAGIC) {
throw new IOException("Unexpected Ignite DTO message header. The input stream is malformed or was generated " +
"by an incompatible Ignite version [actual=" + Integer.toHexString(hdr) +
", expected=" + Integer.toHexString(MAGIC) + ']'
);
}

cmdInitiatorFeatures = new IgniteCoreFeatureSet();
cmdInitiatorFeatures.readExternal(in);

if (!cmdInitiatorFeatures.isUpgradableTo(IgniteCoreFeatureSet.local())) {
throw new IOException("Failed to deserialize the Ignite Management API command argument. The data was " +
"serialized by an incompatible Ignite version " +
" [remoteVersion=" + cmdInitiatorFeatures.version() +
", localVersion=" + IgniteCoreFeatureSet.local().version() + ']'
);
}

readIgniteDataTransferObject(in);
}

/** {@inheritDoc} */
@Override public String toString() {
return S.toString(VisorTaskArgument.class, this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
/**
*
*/
public class TestManagementVisorOneNodeTask extends VisorOneNodeTask<String, Object> {
public class TestManagementVisorOneNodeTask extends VisorOneNodeTask<Object, Object> {
/** */
private static final long serialVersionUID = 0L;

/** {@inheritDoc} */
@Override protected VisorValidOneNodeJob job(String arg) {
@Override protected VisorValidOneNodeJob job(Object arg) {
return new VisorValidOneNodeJob(arg, debug);
}

Expand All @@ -43,20 +43,20 @@ public class TestManagementVisorOneNodeTask extends VisorOneNodeTask<String, Obj
/**
* Valid Management one node visor job.
*/
private static class VisorValidOneNodeJob extends VisorJob<String, Object> {
private static class VisorValidOneNodeJob extends VisorJob<Object, Object> {
/** */
private static final long serialVersionUID = 0L;

/**
* @param arg Argument.
* @param debug Debug flag.
*/
protected VisorValidOneNodeJob(String arg, boolean debug) {
protected VisorValidOneNodeJob(Object arg, boolean debug) {
super(arg, debug);
}

/** {@inheritDoc} */
@Override protected Object run(String arg) {
@Override protected Object run(Object arg) {
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,7 @@ protected void checkVersionUpgradeInProgress(String logicalVer, String srcVer, S
protected void checkPreviousClusterFeatures(@Nullable String expVer) throws Exception {
TestVersions expVersions = expVer == null ? null : TestVersions.parse(expVer);

IgniteCoreFeatureSet expPrevCoreFeatures = expVersions != null
? new IgniteCoreFeatureSet(
IgniteProductVersion.fromString(expVersions.coreVersion()),
IgniteFeatureSet.buildFrom(readDeclaredCoreFeatures(expVersions.coreVersion())))
: null;
IgniteCoreFeatureSet expPrevCoreFeatures = expVersions != null ? createCoreFeatureSet(expVersions.coreVersion()) : null;

IgnitePluginFeatureSet expPrevPluginFeatures = expVersions != null && expVersions.containsPlugin()
? new IgnitePluginFeatureSet(
Expand All @@ -417,6 +413,13 @@ protected void checkPreviousClusterFeatures(@Nullable String expVer) throws Exce
}
}

/** */
public static IgniteCoreFeatureSet createCoreFeatureSet(String ver) throws Exception {
return new IgniteCoreFeatureSet(
IgniteProductVersion.fromString(ver),
IgniteFeatureSet.buildFrom(readDeclaredCoreFeatures(ver)));
}

/** */
protected void checkVersionUpgradeInactive(String expVer) throws Exception {
checkVersionUpgradeEnabledStatus(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* 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;

import java.util.concurrent.Callable;
import org.apache.ignite.Ignition;
import org.apache.ignite.client.ClientConnectionException;
import org.apache.ignite.client.Config;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.TestManagementVisorOneNodeTask;
import org.apache.ignite.internal.processors.rollingupgrade.AbstractRollingUpgradeTest;
import org.apache.ignite.internal.visor.VisorTaskArgument;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.ListeningTestLogger;
import org.apache.ignite.testframework.LogListener;
import org.junit.Test;

/** */
public class ManagementApiVersionValidationTest extends AbstractRollingUpgradeTest {
/** */
public static final LogListener DESERIALIZATION_FAILED_LSNR = LogListener.builder().andMatches(
"Failed to deserialize the Ignite Management API command argument"
).build();

/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName, String ver) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName, ver);

cfg.setGridLogger(new ListeningTestLogger(log, DESERIALIZATION_FAILED_LSNR));

return cfg;
}

/** */
@Test
public void testVersionValidation() throws Exception {
withCoreVersion("2.21.0", () -> {
startGrid(0);

checkCommandArgumentDeserializationFailed(0, "2.21.1");
checkCommandArgumentDeserializationFailed(0, "2.19.0");

executeCommand(createCommandArgument(0, "2.21.0"));
executeCommand(createCommandArgument(0, "2.20.0"));

return null;
});
}

/** */
private void checkCommandArgumentDeserializationFailed(int destNodeIdx, String ver) throws Exception {
DESERIALIZATION_FAILED_LSNR.reset();

GridTestUtils.assertThrowsAnyCause(
log,
() -> {
executeCommand(createCommandArgument(destNodeIdx, ver));

return null;
},
ClientConnectionException.class,
"Channel is closed");

DESERIALIZATION_FAILED_LSNR.check(getTestTimeout());
}

/** */
private void executeCommand(VisorTaskArgument<Object> arg) throws Exception {
try (IgniteClient cli = Ignition.startClient(new ClientConfiguration().setAddresses(Config.SERVER))) {
cli.compute().execute(TestManagementVisorOneNodeTask.class.getName(), arg);
}
}

/** */
private VisorTaskArgument<Object> createCommandArgument(int destNodeIdx, String ver) throws Exception {
return withCoreVersion(ver, () -> new VisorTaskArgument<>(nodeId(destNodeIdx), "", false));
}

/** */
private static <R> R withCoreVersion(String ver, Callable<R> action) throws Exception {
IgniteCoreFeatureSet prev = IgniteCoreFeatureSet.INSTANCE;
IgniteCoreFeatureSet.INSTANCE = createCoreFeatureSet(ver);

try {
return action.call();
}
finally {
IgniteCoreFeatureSet.INSTANCE = prev;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.apache.ignite.internal.processors.rollingupgrade.CoreVersionRollingUpgradeTest;
import org.apache.ignite.internal.processors.rollingupgrade.PluginVersionRollingUpgradeTest;
import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeatureSetTest;
import org.apache.ignite.internal.processors.rollingupgrade.feature.ManagementApiVersionValidationTest;
import org.apache.ignite.internal.product.GridProductVersionSelfTest;
import org.apache.ignite.internal.util.nio.IgniteExceptionInNioWorkerSelfTest;
import org.apache.ignite.messaging.GridMessagingNoPeerClassLoadingSelfTest;
Expand Down Expand Up @@ -108,6 +109,7 @@

CoreVersionRollingUpgradeTest.class,
PluginVersionRollingUpgradeTest.class,
ManagementApiVersionValidationTest.class,
GridProductVersionSelfTest.class,
GridAffinityAssignmentV2Test.class,
GridAffinityAssignmentV2TestNoOptimizations.class,
Expand Down
Loading