diff --git a/src/main/java/org/jvnet/hudson/test/SimpleCommandLauncher.java b/src/main/java/org/jvnet/hudson/test/SimpleCommandLauncher.java index b8eea25e9..64143a74d 100644 --- a/src/main/java/org/jvnet/hudson/test/SimpleCommandLauncher.java +++ b/src/main/java/org/jvnet/hudson/test/SimpleCommandLauncher.java @@ -24,6 +24,7 @@ package org.jvnet.hudson.test; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.AbortException; import hudson.EnvVars; import hudson.Extension; @@ -31,12 +32,10 @@ import hudson.model.Descriptor; import hudson.model.Slave; import hudson.model.TaskListener; -import hudson.remoting.Channel; import hudson.slaves.ComputerLauncher; import hudson.slaves.SlaveComputer; import hudson.util.ProcessTree; import hudson.util.StreamCopyThread; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -52,6 +51,8 @@ public class SimpleCommandLauncher extends ComputerLauncher { public final String cmd; private final Map env; + private transient Process proc; + private transient EnvVars cookie; @DataBoundConstructor // in case anyone needs to configRoundtrip such a node public SimpleCommandLauncher(String cmd) { @@ -72,29 +73,37 @@ public void launch(SlaveComputer computer, final TaskListener listener) { } listener.getLogger().println("$ " + cmd); ProcessBuilder pb = new ProcessBuilder(Util.tokenize(cmd)); - final EnvVars cookie = EnvVars.createCookie(); + cookie = EnvVars.createCookie(); pb.environment().putAll(cookie); if (env != null) { pb.environment().putAll(env); } - final Process proc = pb.start(); + proc = pb.start(); new StreamCopyThread("stderr copier for remote agent on " + computer.getDisplayName(), proc.getErrorStream(), listener.getLogger()).start(); - computer.setChannel(proc.getInputStream(), proc.getOutputStream(), listener.getLogger(), new Channel.Listener() { - @Override - public void onClosed(Channel channel, IOException cause) { - try { - ProcessTree.get().killAll(proc, cookie); - } catch (Exception x) { - LOGGER.log(Level.WARNING, null, x); - } - } - }); + computer.setChannel(proc.getInputStream(), proc.getOutputStream(), listener, null); LOGGER.log(Level.INFO, "agent launched for {0}", computer.getName()); } catch (Exception x) { LOGGER.log(Level.WARNING, null, x); } } + @SuppressFBWarnings(value = "IS2_INCONSISTENT_SYNC", justification = "test code, close enough") + @Override + public synchronized void afterDisconnect(SlaveComputer computer, TaskListener listener) { + if (proc != null) { + try { + ProcessTree.get().killAll(proc, cookie); + LOGGER.info(() -> "killed " + proc + " with " + cookie + " for " + computer.getName()); + } catch (Exception x) { + LOGGER.log(Level.WARNING, "failed to kill " + proc + " with " + cookie + " for " + computer.getName(), x); + } + proc = null; + cookie = null; + } else { + LOGGER.info(() -> "no process for " + computer.getName()); + } + } + @Extension public static class DescriptorImpl extends Descriptor {} }