From bfeb24f7dacb153975f782373da8ac9b7609bdd2 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 16 Nov 2017 10:53:18 +0100 Subject: [PATCH 1/4] [JENKINS-47896] - Introduce SerializableOnlyOverRemoting in classes. Due to the implementation specifics, some classes in the core are serializable only over Remoting. This change just marks these classes and utilizes the convenience method in the interface for serialization/deserialization operations. --- core/src/main/java/hudson/FilePath.java | 12 ++++++------ core/src/main/java/hudson/cli/CliManagerImpl.java | 12 +++++++----- core/src/main/java/hudson/util/ProcessTree.java | 9 +++++---- .../main/java/hudson/util/StreamTaskListener.java | 4 +++- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index ad13edf5f3..c9fbc43984 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -118,6 +118,7 @@ import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import org.jenkinsci.remoting.RoleChecker; import org.jenkinsci.remoting.RoleSensitive; +import org.jenkinsci.remoting.SerializableOnlyOverRemoting; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.Stapler; @@ -193,7 +194,7 @@ import java.util.Collections; * @author Kohsuke Kawaguchi * @see VirtualFile */ -public final class FilePath implements Serializable { +public final class FilePath implements SerializableOnlyOverRemoting { /** * Maximum http redirects we will follow. This defaults to the same number as Firefox/Chrome tolerates. */ @@ -2705,18 +2706,17 @@ public final class FilePath implements Serializable { } private void writeObject(ObjectOutputStream oos) throws IOException { - Channel target = Channel.current(); - - if(channel!=null && channel!=target) + Channel target = getChannelForSerialization(); + if(channel!=target) { throw new IllegalStateException("Can't send a remote FilePath to a different remote channel"); + } oos.defaultWriteObject(); oos.writeBoolean(channel==null); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - Channel channel = Channel.current(); - assert channel!=null; + Channel channel = getChannelForSerialization(); ois.defaultReadObject(); if(ois.readBoolean()) { diff --git a/core/src/main/java/hudson/cli/CliManagerImpl.java b/core/src/main/java/hudson/cli/CliManagerImpl.java index 750a38d210..6b8f606011 100644 --- a/core/src/main/java/hudson/cli/CliManagerImpl.java +++ b/core/src/main/java/hudson/cli/CliManagerImpl.java @@ -29,8 +29,10 @@ import hudson.remoting.Pipe; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; +import org.jenkinsci.remoting.SerializableOnlyOverRemoting; import java.io.InputStream; +import java.io.ObjectStreamException; import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; @@ -47,7 +49,7 @@ import java.util.logging.Logger; * @deprecated Specific to Remoting-based protocol. */ @Deprecated -public class CliManagerImpl implements CliEntryPoint, Serializable { +public class CliManagerImpl implements CliEntryPoint, SerializableOnlyOverRemoting { private transient final Channel channel; private Authentication transportAuth; @@ -87,10 +89,10 @@ public class CliManagerImpl implements CliEntryPoint, Serializable { String subCmd = args.get(0); CLICommand cmd = CLICommand.clone(subCmd); if(cmd!=null) { - cmd.channel = Channel.current(); + cmd.channel = Channel.currentOrFail(); final CLICommand old = CLICommand.setCurrent(cmd); try { - transportAuth = Channel.current().getProperty(CLICommand.TRANSPORT_AUTHENTICATION); + transportAuth = cmd.channel.getProperty(CLICommand.TRANSPORT_AUTHENTICATION); cmd.setTransportAuth(transportAuth); return cmd.main(args.subList(1,args.size()),locale, stdin, out, err); } finally { @@ -126,8 +128,8 @@ public class CliManagerImpl implements CliEntryPoint, Serializable { return VERSION; } - private Object writeReplace() { - return Channel.current().export(CliEntryPoint.class,this); + private Object writeReplace() throws ObjectStreamException { + return getChannelForSerialization().export(CliEntryPoint.class,this); } private static final Logger LOGGER = Logger.getLogger(CliManagerImpl.class.getName()); diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index 95fe237fc3..398e309415 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -40,6 +40,7 @@ import hudson.util.ProcessTree.OSProcess; import hudson.util.ProcessTreeRemoting.IOSProcess; import hudson.util.ProcessTreeRemoting.IProcessTree; import jenkins.security.SlaveToMasterCallable; +import org.jenkinsci.remoting.SerializableOnlyOverRemoting; import org.jvnet.winp.WinProcess; import org.jvnet.winp.WinpException; @@ -84,7 +85,7 @@ import javax.annotation.Nonnull; * @author Kohsuke Kawaguchi * @since 1.315 */ -public abstract class ProcessTree implements Iterable, IProcessTree, Serializable { +public abstract class ProcessTree implements Iterable, IProcessTree, SerializableOnlyOverRemoting { /** * To be filled in the constructor of the derived type. */ @@ -1317,7 +1318,7 @@ public abstract class ProcessTree implements Iterable, IProcessTree, /** * Represents a process tree over a channel. */ - public static class Remote extends ProcessTree implements Serializable { + public static class Remote extends ProcessTree { private final IProcessTree proxy; public Remote(ProcessTree proxy, Channel ch) { @@ -1388,8 +1389,8 @@ public abstract class ProcessTree implements Iterable, IProcessTree, /** * Use {@link Remote} as the serialized form. */ - /*package*/ Object writeReplace() { - return new Remote(this,Channel.current()); + /*package*/ Object writeReplace() throws ObjectStreamException { + return new Remote(this, getChannelForSerialization()); } // public static void main(String[] args) { diff --git a/core/src/main/java/hudson/util/StreamTaskListener.java b/core/src/main/java/hudson/util/StreamTaskListener.java index 9deea8fad0..2723aad5f4 100644 --- a/core/src/main/java/hudson/util/StreamTaskListener.java +++ b/core/src/main/java/hudson/util/StreamTaskListener.java @@ -48,6 +48,8 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.logging.Level; import java.util.logging.Logger; + +import org.jenkinsci.remoting.SerializableOnlyOverRemoting; import org.kohsuke.stapler.framework.io.WriterOutputStream; /** @@ -58,7 +60,7 @@ import org.kohsuke.stapler.framework.io.WriterOutputStream; * * @author Kohsuke Kawaguchi */ -public class StreamTaskListener extends AbstractTaskListener implements Serializable, Closeable { +public class StreamTaskListener extends AbstractTaskListener implements SerializableOnlyOverRemoting, Closeable { private PrintStream out; private Charset charset; From 09b9d227af324f1cad71ba39c8580abffb1a945b Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 28 Jan 2019 17:48:55 +0100 Subject: [PATCH 2/4] Add import java.io.ObjectStreamException; --- core/src/main/java/hudson/util/ProcessTree.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index 1bf9b90380..7397f98815 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -55,6 +55,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.Serializable; +import java.io.ObjectStreamException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; From 78423ca29290529e533b700843ae13ace3d3eb2c Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Thu, 31 Jan 2019 01:47:50 +0100 Subject: [PATCH 3/4] [JENKINS-47896] - Add some diagnostics for the failing channel comparison in FilePath --- core/src/main/java/hudson/FilePath.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 9cb3835dc9..5a02e2251e 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -2988,7 +2988,7 @@ public final class FilePath implements SerializableOnlyOverRemoting { private void writeObject(ObjectOutputStream oos) throws IOException { Channel target = getChannelForSerialization(); if(channel!=target) { - throw new IllegalStateException("Can't send a remote FilePath to a different remote channel"); + throw new IllegalStateException("Can't send a remote FilePath to a different remote channel (current=" + channel + ", target=" + target + ")"); } oos.defaultWriteObject(); From 34fb3c86c752d5b61f1b8c31988be31d63e5e7e2 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sun, 3 Feb 2019 02:06:41 +0100 Subject: [PATCH 4/4] [JENKINS-47896] - Allow FilePath with null channel to be serialized anywhere --- core/src/main/java/hudson/FilePath.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 5a02e2251e..e49a4e59b1 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -2987,7 +2987,7 @@ public final class FilePath implements SerializableOnlyOverRemoting { private void writeObject(ObjectOutputStream oos) throws IOException { Channel target = getChannelForSerialization(); - if(channel!=target) { + if (channel != null && channel != target) { throw new IllegalStateException("Can't send a remote FilePath to a different remote channel (current=" + channel + ", target=" + target + ")"); }