Index: src/main/java/hudson/plugins/sshslaves/SSHLauncher.java =================================================================== --- src/main/java/hudson/plugins/sshslaves/SSHLauncher.java (revision 30747) +++ src/main/java/hudson/plugins/sshslaves/SSHLauncher.java (working copy) @@ -32,6 +32,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.StringWriter; @@ -51,6 +52,7 @@ import org.kohsuke.stapler.DataBoundConstructor; import com.trilead.ssh2.Connection; +import com.trilead.ssh2.SCPClient; import com.trilead.ssh2.SFTPv3Client; import com.trilead.ssh2.SFTPv3FileAttributes; import com.trilead.ssh2.Session; @@ -345,11 +347,11 @@ * Method copies the slave jar to the remote system. * * @param listener The listener. - * @param workingDirectory The directory into whihc the slave jar will be copied. + * @param workingDirectory The directory into which the slave jar will be copied. * * @throws IOException If something goes wrong. */ - private void copySlaveJar(TaskListener listener, String workingDirectory) throws IOException { + private void copySlaveJar(TaskListener listener, String workingDirectory) throws IOException, InterruptedException { String fileName = workingDirectory + "/slave.jar"; listener.getLogger().println(Messages.SSHLauncher_StartingSFTPClient(getTimestamp())); @@ -389,6 +391,15 @@ } catch (Exception e) { throw new IOException2(Messages.SSHLauncher_ErrorCopyingSlaveJar(), e); } + } catch (IOException e) { + listener.getLogger().println(Messages.SSHLauncher_SFTPFailure(getTimestamp())); + // lets try to recover if the slave doesn't have an SFTP server running + if (sftpClient == null) { + copySlaveJarUsingSCP(listener, workingDirectory); + } else + { + throw e; + } } finally { if (sftpClient != null) { sftpClient.close(); @@ -396,6 +407,73 @@ } } + /** + * Method copies the slave jar to the remote system using scp. + * + * @param listener The listener. + * @param workingDirectory The directory into which the slave jar will be copied. + * + * @throws IOException If something goes wrong. + * @throws InterruptedException If something goes wrong. + */ + private void copySlaveJarUsingSCP(TaskListener listener, String workingDirectory) throws IOException, InterruptedException { + listener.getLogger().println(Messages.SSHLauncher_StartingSCPClient(getTimestamp())); + SCPClient scp = new SCPClient(connection); + try + { + // check if the working directory exists + StringWriter output = new StringWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + connection.exec("! " + workingDirectory ,out); + BufferedReader r = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(out.toByteArray()))); + final boolean exists = checkIfDirectoryExists(listener.getLogger(), r, output); + listener.getLogger().println(output); + if (!exists) { + listener.getLogger().println(Messages.SSHLauncher_RemoteFSDoesNotExist(getTimestamp(), + workingDirectory)); + // working directory doesn't exist, lets make it. + connection.exec("mkdir " + workingDirectory, listener.getLogger()); + } // TODO check if the working directory is a file + + // delete the slave jar as we do with SFTP + connection.exec("rm " + workingDirectory + "/slave.jar", listener.getLogger()); + // SCP it to the slave. hudson.Util.ByteArrayOutputStream2 doesn't work for this. It pads the byte array. + InputStream is = Hudson.getInstance().servletContext.getResourceAsStream("/WEB-INF/slave.jar"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int size=0; + byte[] chunk = new byte[4096]; + while ( (size = is.read(chunk)) > 0) + { + baos.write(chunk,0,size); + } + byte[] result = baos.toByteArray(); + listener.getLogger().println(Messages.SSHLauncher_CopyingSlaveJar(getTimestamp())); + scp.put(result, "slave.jar", workingDirectory, "0700"); + } + catch (IOException e) + { + throw new IOException2(Messages.SSHLauncher_ErrorCopyingSlaveJar(), e); + } + } + + /** + * Given the output of "! /some/directory" in r, determine if the directory exists. + * + */ + private boolean checkIfDirectoryExists(final PrintStream logger, + final BufferedReader r, final StringWriter output) throws IOException { + String line; + while (null != (line = r.readLine())) { + output.write(line); + output.write("\n"); + line = line.toLowerCase(); + if (line.indexOf("No such file or directory") != -1) { + return false; + } + } + return true; + } + private void reportEnvironment(TaskListener listener) throws IOException, InterruptedException { listener.getLogger().println(Messages._SSHLauncher_RemoteUserEnvironment(getTimestamp())); connection.exec("set",listener.getLogger()); Index: src/main/resources/hudson/plugins/sshslaves/Messages.properties =================================================================== --- src/main/resources/hudson/plugins/sshslaves/Messages.properties (revision 30273) +++ src/main/resources/hudson/plugins/sshslaves/Messages.properties (working copy) @@ -24,3 +24,7 @@ SSHLauncher.UnexpectedError=Unexpected error in launching a slave. This is probably a bug in Hudson. SSHLauncher.StartingSlaveProcess={0} [SSH] Starting slave process: {1} SSHLauncher.RemoteUserEnvironment={0} [SSH] The remote user's environment is: +SSHLauncher.SFTPFailure={0} [SSH] Could not copy slave.jar via SFTP. +SSHLauncher_StartingSCPClient={0} [SSH] Starting scp client. + +