X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.support.simple%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fjsch%2FRemoteExec.java;h=094b77fc183e0118723ce03686dbf22a59176d6e;hb=82da8aeebe37e93f26158678590f94341f8ea325;hp=1295209867bcc84bb6fdd6f72c0780c7c2701c7d;hpb=c9672b7c16ee662ff452fff8405a67cac091a15e;p=gpl%2Fargeo-slc.git 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 129520986..094b77fc1 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 @@ -1,22 +1,32 @@ package org.argeo.slc.jsch; import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; import java.util.List; +import java.util.Map; 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 org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelShell; import com.jcraft.jsch.Session; -public class RemoteExec extends AbstractJschTask { +public class RemoteExec extends AbstractJschTask implements InitializingBean { private final static Log log = LogFactory.getLog(RemoteExec.class); private Boolean failOnBadExitStatus = true; @@ -25,105 +35,220 @@ public class RemoteExec extends AbstractJschTask { private String command; private SystemCall systemCall; private List systemCalls = new ArrayList(); + private Resource script; + private Boolean xForwarding = false; + private Boolean agentForwarding = false; + private Boolean forceShell = false; + private Map env = new HashMap(); public void run(Session session) { + List commandsToUse = new ArrayList(commands); + String commandToUse = command; // convert system calls if (systemCall != null) { if (command != null) throw new SlcException("Cannot specify command AND systemCall"); - command = convertSystemCall(systemCall); + commandToUse = convertSystemCall(systemCall); } if (systemCalls.size() != 0) { - if (commands.size() != 0) + if (commandsToUse.size() != 0) throw new SlcException( "Cannot specify commands AND systemCalls"); for (SystemCall systemCall : systemCalls) - commands.add(convertSystemCall(systemCall)); + commandsToUse.add(convertSystemCall(systemCall)); + } + + if (script != null) { + if (commandsToUse.size() != 0) + throw new SlcException("Cannot specify commands and script"); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(script + .getInputStream())); + String line = null; + while ((line = reader.readLine()) != null) { + if (!StringUtils.hasText(line)) + continue; + commandsToUse.add(line); + } + } catch (IOException e) { + throw new SlcException("Cannot read script " + script, e); + } finally { + IOUtils.closeQuietly(reader); + } + } + + if (forceShell) { + commandsToUse.add(commandToUse); + commandToUse = null; } // execute command(s) - if (command != null) { - if (commands.size() != 0) + if (commandToUse != null) { + if (commandsToUse.size() != 0) throw new SlcException( "Specify either a single command or a list of commands."); - remoteExec(session, command); + remoteExec(session, commandToUse); } else { - if (commands.size() == 0) + if (commandsToUse.size() == 0) throw new SlcException( "Neither a single command or a list of commands has been specified."); - for (String cmd : commands) { - remoteExec(session, cmd); - } + remoteExec(session, commandsToUse); } } protected String convertSystemCall(SystemCall systemCall) { - // TODO: prepend environemnt variables + // TODO: prepend environment variables // TODO: deal with exec dir return systemCall.asCommand(); } - protected void remoteExec(Session session, String command) { - BufferedReader execIn = null; + protected void remoteExec(Session session, final List commands) { try { - Channel channel = session.openChannel("exec"); - ((ChannelExec) channel).setCommand(command); + final ChannelShell channel = (ChannelShell) session + .openChannel("shell"); + channel.setInputStream(null); + channel.setXForwarding(xForwarding); + channel.setAgentForwarding(agentForwarding); + channel.setEnv(new Hashtable(env)); - // X Forwarding - // channel.setXForwarding(true); + /* + * // Choose the pty-type "vt102". + * ((ChannelShell)channel).setPtyType("vt102"); + */ + // Writer thread + final BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(channel.getOutputStream())); - // channel.setInputStream(System.in); - channel.setInputStream(null); + channel.connect(); - ((ChannelExec) channel).setErrStream(System.err); + // write commands to shell + Thread writerThread = new Thread("Shell writer " + getSshTarget()) { + @Override + public void run() { + try { + for (String line : commands) { + if (!StringUtils.hasText(line)) + continue; + writer.write(line); + writer.newLine(); + } + writer.append("exit"); + writer.newLine(); + writer.flush(); + // channel.disconnect(); + } catch (IOException e) { + throw new SlcException("Cannot write to shell on " + + getSshTarget(), e); + } finally { + IOUtils.closeQuietly(writer); + } + } + }; + writerThread.start(); - InputStream in = channel.getInputStream(); + readStdOut(channel); + checkExitStatus(channel); + channel.disconnect(); - if (log.isDebugEnabled()) - log.debug("Run '" + command + "' on " + getSshTarget() + "..."); + } catch (Exception e) { + throw new SlcException("Cannot use SSH shell on " + getSshTarget(), + e); + } - channel.connect(); + } - // byte[] tmp = new byte[1024]; - while (true) { - execIn = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = execIn.readLine()) != null) { - if (!line.trim().equals("")) - log.info(line); - } + protected void remoteExec(Session session, String command) { + try { + final ChannelExec channel = (ChannelExec) session + .openChannel("exec"); + channel.setCommand(command); - if (channel.isClosed()) { - int exitStatus = channel.getExitStatus(); - if (exitStatus == 0) { - if (log.isTraceEnabled()) - log.trace("Remote execution exit status: " - + exitStatus); - } else { - String msg = "Remote execution failed with " - + " exit status: " + exitStatus; - if (failOnBadExitStatus) - throw new SlcException(msg); - else - log.error(msg); - } + channel.setInputStream(null); + channel.setXForwarding(xForwarding); + channel.setAgentForwarding(agentForwarding); + channel.setEnv(new Hashtable(env)); + channel.setErrStream(null); - break; - } - try { - Thread.sleep(1000); - } catch (Exception ee) { - } - } + // Standard Error + readStdErr(channel); + + if (log.isDebugEnabled()) + log.debug("Run '" + command + "' on " + getSshTarget() + "..."); + channel.connect(); + readStdOut(channel); + checkExitStatus(channel); channel.disconnect(); } catch (Exception e) { throw new SlcException("Cannot execute remotely '" + command + "' on " + getSshTarget(), e); + } + } + + protected void readStdErr(final ChannelExec channel) { + new Thread("stderr " + getSshTarget()) { + public void run() { + BufferedReader stdErr = null; + try { + InputStream in = channel.getErrStream(); + stdErr = new BufferedReader(new InputStreamReader(in)); + String line = null; + while ((line = stdErr.readLine()) != null) { + if (!line.trim().equals("")) + log.error(line); + } + } catch (IOException e) { + if (log.isDebugEnabled()) + log.error("Cannot read stderr from " + getSshTarget(), + e); + } finally { + IOUtils.closeQuietly(stdErr); + } + } + }.start(); + } + + protected void readStdOut(Channel channel) { + BufferedReader stdOut = null; + try { + InputStream in = channel.getInputStream(); + stdOut = new BufferedReader(new InputStreamReader(in)); + String line = null; + while ((line = stdOut.readLine()) != null) { + if (!line.trim().equals("")) + log.info(line); + } + } catch (IOException e) { + if (log.isDebugEnabled()) + log.error("Cannot read stdout from " + getSshTarget(), e); } finally { - IOUtils.closeQuietly(execIn); + IOUtils.closeQuietly(stdOut); + } + } + + protected void checkExitStatus(Channel channel) { + if (channel.isClosed()) { + int exitStatus = channel.getExitStatus(); + if (exitStatus == 0) { + if (log.isTraceEnabled()) + log.trace("Remote execution exit status: " + exitStatus); + } else { + String msg = "Remote execution failed with " + " exit status: " + + exitStatus; + if (failOnBadExitStatus) + throw new SlcException(msg); + else + log.error(msg); + } } + + } + + public void afterPropertiesSet() throws Exception { + // TODO Auto-generated method stub + } public void setCommand(String command) { @@ -146,4 +271,28 @@ public class RemoteExec extends AbstractJschTask { this.systemCalls = systemCalls; } + public void setScript(Resource script) { + this.script = script; + } + + public void setxForwarding(Boolean xForwarding) { + this.xForwarding = xForwarding; + } + + public void setAgentForwarding(Boolean agentForwarding) { + this.agentForwarding = agentForwarding; + } + + public void setEnv(Map env) { + this.env = env; + } + + public void setForceShell(Boolean forceShell) { + this.forceShell = forceShell; + } + + public List getCommands() { + return commands; + } + }