From ea874483b0d33269b6d605be0c3ae4a0e88cca5a Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Tue, 21 Jul 2009 12:45:08 +0000 Subject: [PATCH] Issue 79: added ssh exec feature git-svn-id: http://jclouds.googlecode.com/svn/trunk@1824 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../java/org/jclouds/ssh/ExecResponse.java | 23 +++++++++++++ .../java/org/jclouds/ssh/SshConnection.java | 4 ++- .../jclouds/ssh/jsch/JschSshConnection.java | 33 ++++++++++++++++++- .../ssh/jsch/JschSshConnectionLiveTest.java | 20 +++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/jclouds/ssh/ExecResponse.java diff --git a/core/src/main/java/org/jclouds/ssh/ExecResponse.java b/core/src/main/java/org/jclouds/ssh/ExecResponse.java new file mode 100644 index 0000000000..bca47127c9 --- /dev/null +++ b/core/src/main/java/org/jclouds/ssh/ExecResponse.java @@ -0,0 +1,23 @@ +package org.jclouds.ssh; + +/** + * @author Adrian Cole + */ +public class ExecResponse { + private final String error; + private final String output; + + public ExecResponse(String output, String error) { + this.output = output; + this.error = error; + } + + public String getError() { + return error; + } + + public String getOutput() { + return output; + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/ssh/SshConnection.java b/core/src/main/java/org/jclouds/ssh/SshConnection.java index 24317c85ae..67683014b4 100644 --- a/core/src/main/java/org/jclouds/ssh/SshConnection.java +++ b/core/src/main/java/org/jclouds/ssh/SshConnection.java @@ -12,7 +12,7 @@ import com.google.inject.assistedinject.Assisted; * @author Adrian Cole */ public interface SshConnection { - + public interface Factory { SshConnection create(InetAddress host, int port, @Assisted("username") String username, @Assisted("password") String password); @@ -20,6 +20,8 @@ public interface SshConnection { InputStream get(String path); + ExecResponse exec(String command); + @PostConstruct void connect(); diff --git a/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshConnection.java b/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshConnection.java index 87256bb1c7..951f8b4a85 100644 --- a/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshConnection.java +++ b/extensions/ssh/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshConnection.java @@ -11,13 +11,17 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.jclouds.logging.Logger; +import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.SshConnection; import org.jclouds.ssh.SshException; +import org.jclouds.util.Utils; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; @@ -37,6 +41,7 @@ public class JschSshConnection implements SshConnection { private ChannelSftp sftp; @Resource protected Logger logger = Logger.NULL; + private Session session; @Inject public JschSshConnection(@Assisted InetAddress host, @Assisted int port, @@ -69,7 +74,7 @@ public class JschSshConnection implements SshConnection { if (sftp != null && sftp.isConnected()) return; JSch jsch = new JSch(); - Session session = null; + session = null; Channel channel = null; try { session = jsch.getSession(username, host.getHostAddress(), port); @@ -106,4 +111,30 @@ public class JschSshConnection implements SshConnection { sftp.quit(); } + public ExecResponse exec(String command) { + ChannelExec executor = null; + try { + try { + executor = (ChannelExec) session.openChannel("exec"); + } catch (JSchException e) { + throw new SshException(String.format("%s@%s:%d: Error connecting to exec.", username, + host.getHostAddress(), port), e); + } + executor.setCommand(command); + ByteArrayOutputStream error = new ByteArrayOutputStream(); + executor.setErrStream(error); + try { + executor.connect(); + return new ExecResponse(Utils.toStringAndClose(executor.getInputStream()), error + .toString()); + } catch (Exception e) { + throw new SshException(String.format("%s@%s:%d: Error executing command: ", username, + host.getHostAddress(), port, command), e); + } + } finally { + if (executor != null) + executor.disconnect(); + } + } + } diff --git a/extensions/ssh/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshConnectionLiveTest.java b/extensions/ssh/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshConnectionLiveTest.java index 02c2ef0dce..0050661979 100644 --- a/extensions/ssh/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshConnectionLiveTest.java +++ b/extensions/ssh/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshConnectionLiveTest.java @@ -1,11 +1,14 @@ package org.jclouds.ssh.jsch; +import static org.testng.Assert.assertEquals; + import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.UnknownHostException; import org.apache.commons.io.IOUtils; +import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.SshConnection; import org.jclouds.ssh.jsch.config.JschSshConnectionModule; import org.jclouds.util.Utils; @@ -54,6 +57,17 @@ public class JschSshConnectionLiveTest { throw new RuntimeException("path " + path + " not stubbed"); } + public ExecResponse exec(String command) { + if (command.equals("hostname")) { + try { + return new ExecResponse(InetAddress.getLocalHost().getHostName(), ""); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + throw new RuntimeException("command " + command + " not stubbed"); + } + }; } else { Injector i = Guice.createInjector(new JschSshConnectionModule()); @@ -69,4 +83,10 @@ public class JschSshConnectionLiveTest { assert contents.indexOf("root") >= 0 : "no root in " + contents; } + public void testExecHostname() throws IOException { + ExecResponse response = connection.exec("hostname"); + assertEquals(response.getError(), ""); + assertEquals(response.getOutput().trim(), InetAddress.getLocalHost().getHostName()); + } + } \ No newline at end of file