From c9672b7c16ee662ff452fff8405a67cac091a15e Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 23 Feb 2010 19:23:00 +0000 Subject: [PATCH] Improve JSCH support git-svn-id: https://svn.argeo.org/slc/trunk@3392 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../slc/core/deploy/MultiResourceSet.java | 26 ++++++++++ .../slc/core/execution/tasks/SystemCall.java | 9 ++++ .../org/argeo/slc/jsch/AbstractJschTask.java | 29 ++++++++++- .../argeo/slc/jsch/JschContextSession.java | 50 +++++++++++++++++++ .../java/org/argeo/slc/jsch/RemoteExec.java | 33 ++++++++++++ .../main/java/org/argeo/slc/jsch/ScpFrom.java | 6 ++- .../main/java/org/argeo/slc/jsch/ScpTo.java | 8 +-- .../java/org/argeo/slc/jsch/SshTarget.java | 12 +++++ 8 files changed, 166 insertions(+), 7 deletions(-) create mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/deploy/MultiResourceSet.java create mode 100644 runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschContextSession.java diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/deploy/MultiResourceSet.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/deploy/MultiResourceSet.java new file mode 100644 index 000000000..d08e56ced --- /dev/null +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/deploy/MultiResourceSet.java @@ -0,0 +1,26 @@ +package org.argeo.slc.core.deploy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.io.Resource; + +public class MultiResourceSet implements ResourceSet { + private List resourceSets = new ArrayList(); + + public Map listResources() { + Map res = new HashMap(); + for (ResourceSet resourceSet : resourceSets) { + res.putAll(resourceSet.listResources()); + } + return res; + } + + /** Last listed override previous for the same relative paths. */ + public void setResourceSets(List resourceSets) { + this.resourceSets = resourceSets; + } + +} diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java index e5df71ab1..2e5b14116 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java @@ -202,6 +202,15 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable { } + public String asCommand() { + return createCommandLine().toString(); + } + + @Override + public String toString() { + return asCommand(); + } + /** * Build a command line based on the properties. Can be overridden by * specific command wrappers. diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/AbstractJschTask.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/AbstractJschTask.java index 8a58c357f..1fff474ee 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/AbstractJschTask.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/AbstractJschTask.java @@ -3,6 +3,8 @@ package org.argeo.slc.jsch; import java.io.IOException; import java.io.InputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; import com.jcraft.jsch.JSch; @@ -10,9 +12,21 @@ import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; public abstract class AbstractJschTask implements Runnable { + private final static Log log = LogFactory.getLog(AbstractJschTask.class); + private SshTarget sshTarget; protected Session openSession() { + if (sshTarget.getSession() != null) { + Session session = sshTarget.getSession(); + if (session.isConnected()) { + if (log.isDebugEnabled()) + log.debug("Using cached sesison to " + getSshTarget() + + " via SSH"); + return session; + } + } + try { JSch jsch = new JSch(); if (sshTarget.getUsePrivateKey() @@ -24,6 +38,14 @@ public abstract class AbstractJschTask implements Runnable { session.setUserInfo(getSshTarget().getUserInfo()); session.connect(); + if (log.isDebugEnabled()) + log.debug("Connected to " + getSshTarget() + " via SSH"); + if (sshTarget.getSession() != null) { + if (log.isDebugEnabled()) + log.debug("The cached session to " + getSshTarget() + + " was disconnected and was reste."); + sshTarget.setSession(session); + } return session; } catch (JSchException e) { throw new SlcException("Could not open session to " @@ -36,7 +58,12 @@ public abstract class AbstractJschTask implements Runnable { try { run(session); } finally { - session.disconnect(); + if (sshTarget.getSession() == null) { + session.disconnect(); + if (log.isDebugEnabled()) + log.debug("Disconnected from " + getSshTarget() + + " via SSH"); + } } } diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschContextSession.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschContextSession.java new file mode 100644 index 000000000..b127afbc7 --- /dev/null +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschContextSession.java @@ -0,0 +1,50 @@ +package org.argeo.slc.jsch; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +import com.jcraft.jsch.Session; + +/** Caches a JSCH session in the the ssh target. */ +public class JschContextSession extends AbstractJschTask implements + InitializingBean, DisposableBean { + private final static Log log = LogFactory.getLog(JschContextSession.class); + private Boolean autoconnect = false; + + @Override + void run(Session session) { + clear(); + getSshTarget().setSession(session); + if (log.isDebugEnabled()) + log.debug("Cached SSH context session to " + getSshTarget()); + } + + public void afterPropertiesSet() throws Exception { + if (autoconnect) + run(); + } + + public void destroy() throws Exception { + clear(); + } + + public void clear() { + SshTarget sshTarget = getSshTarget(); + synchronized (sshTarget) { + if (sshTarget.getSession() != null) { + sshTarget.getSession().disconnect(); + sshTarget.setSession(null); + if (log.isDebugEnabled()) + log.debug("Cleared cached SSH context session to " + + getSshTarget()); + } + } + } + + public void setAutoconnect(Boolean autoconnect) { + this.autoconnect = autoconnect; + } + +} diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java index b163ca911..129520986 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java @@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.tasks.SystemCall; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; @@ -22,8 +23,26 @@ public class RemoteExec extends AbstractJschTask { private List commands = new ArrayList(); private String command; + private SystemCall systemCall; + private List systemCalls = new ArrayList(); public void run(Session session) { + // convert system calls + if (systemCall != null) { + if (command != null) + throw new SlcException("Cannot specify command AND systemCall"); + command = convertSystemCall(systemCall); + } + + if (systemCalls.size() != 0) { + if (commands.size() != 0) + throw new SlcException( + "Cannot specify commands AND systemCalls"); + for (SystemCall systemCall : systemCalls) + commands.add(convertSystemCall(systemCall)); + } + + // execute command(s) if (command != null) { if (commands.size() != 0) throw new SlcException( @@ -40,6 +59,12 @@ public class RemoteExec extends AbstractJschTask { } } + protected String convertSystemCall(SystemCall systemCall) { + // TODO: prepend environemnt variables + // TODO: deal with exec dir + return systemCall.asCommand(); + } + protected void remoteExec(Session session, String command) { BufferedReader execIn = null; try { @@ -113,4 +138,12 @@ public class RemoteExec extends AbstractJschTask { this.failOnBadExitStatus = failOnBadExitStatus; } + public void setSystemCall(SystemCall systemCall) { + this.systemCall = systemCall; + } + + public void setSystemCalls(List systemCalls) { + this.systemCalls = systemCalls; + } + } diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpFrom.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpFrom.java index d88fda172..ced80eee0 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpFrom.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpFrom.java @@ -104,8 +104,6 @@ public class ScpFrom extends AbstractJschTask { String localPath = localFile.isDirectory() ? localFile .getPath() + File.separator + remoteFileName : localFile.getPath(); - if (log.isDebugEnabled()) - log.debug("Download " + remoteFile + " to " + localPath); out = new FileOutputStream(localPath); int foo; @@ -131,6 +129,10 @@ public class ScpFrom extends AbstractJschTask { buf[0] = 0; channelOut.write(buf, 0, 1); channelOut.flush(); + + if (log.isDebugEnabled()) + log.debug("Finished downloading " + remoteFile + " on " + + getSshTarget() + " to " + localPath); } channel.disconnect(); diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpTo.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpTo.java index 554b9b6f0..07f428c4d 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpTo.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/ScpTo.java @@ -190,13 +190,13 @@ public class ScpTo extends AbstractJschTask { channelOut.flush(); checkAck(channelIn); - if (log.isDebugEnabled()) - log.info((cycleCount) + " KB sent to server. (" + if (log.isTraceEnabled()) + log.debug((cycleCount) + " KB sent to server. (" + (cycleCount / oneMB + " MB)")); if (log.isDebugEnabled()) - log.debug("Finished copy of " + localFile + " to " + remoteFile - + " on " + getSshTarget() + "..."); + log.debug("Finished copy to " + remoteFile + " on " + + getSshTarget() + " from " + localFile); IOUtils.closeQuietly(channelOut); diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshTarget.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshTarget.java index 17f042651..03f6990f5 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshTarget.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/SshTarget.java @@ -2,6 +2,7 @@ package org.argeo.slc.jsch; import java.io.File; +import com.jcraft.jsch.Session; import com.jcraft.jsch.UserInfo; public class SshTarget { @@ -14,6 +15,9 @@ public class SshTarget { private File localPrivateKey = new File(System.getProperty("user.home") + File.separator + ".ssh" + File.separator + "id_rsa"); + /** cached session */ + private Session session; + public String getHost() { return host; } @@ -65,4 +69,12 @@ public class SshTarget { public String toString() { return "ssh:" + getUser() + "@" + getHost() + ":" + getPort(); } + + public Session getSession() { + return session; + } + + public void setSession(Session session) { + this.session = session; + } } -- 2.39.5