【问题标题】:sshexec ant task: environment variablessshexec 蚂蚁任务:环境变量
【发布时间】:2009-07-02 13:37:01
【问题描述】:

我正在使用 SSHExec ant 任务连接到远程主机,并且我依赖于在远程主机上设置的环境变量才能成功执行某些命令。

<sshexec host="somehost"
    username="${username}"
    password="${password}"
    command="set"/>

使用环境中的任务。输出的变量与我使用 SSH 客户端登录时得到的变量不同。

如何制作环境。会话可用的远程主机的变量?

【问题讨论】:

    标签: ant build ssh


    【解决方案1】:

    实际上,您可以对它不启动 shell 的事实采取一些措施。使用以下内容:

    <ssshexec command="/bin/bash -l yourScript.sh" .../>
    

    使用 /bin/bash -l 将启动一个登录 shell,然后在该 shell 中执行您的脚本。就好像您有一个可以正确启动登录 shell 的 sshexec 版本一样。它必须是一个脚本。如果你想运行单个可执行命令,你可以这样做:

    <sshexec command="/bin/bash -l -c 'echo $CATALINA_HOME'" .../>
    

    【讨论】:

      【解决方案2】:

      我发现当前的 SSHExeceec 任务实现是使用 JSCh 的 ChannelExec(远程执行命令)而不是 ChannelShell(远程 shell)作为连接通道。

      这意味着显然根据 JSCh 的当前实现,ChannelExec 不会加载环境。变量。

      我仍然不确定这是对协议还是 API 的限制。

      结论是,目前还没有解决问题的办法,除非你实现自己的 Ant 任务。

      一份工作草案:

      package org.apache.tools.ant.taskdefs.optional.ssh;
      
      import java.io.BufferedReader;
      import java.io.ByteArrayOutputStream;
      import java.io.File;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.io.PipedInputStream;
      import java.io.PipedOutputStream;
      import java.io.StringReader;
      
      import org.apache.tools.ant.BuildException;
      import org.apache.tools.ant.Project;
      import org.apache.tools.ant.types.Resource;
      import org.apache.tools.ant.types.resources.FileResource;
      import org.apache.tools.ant.util.FileUtils;
      import org.apache.tools.ant.util.KeepAliveOutputStream;
      import org.apache.tools.ant.util.TeeOutputStream;
      
      import com.jcraft.jsch.Channel;
      import com.jcraft.jsch.ChannelExec;
      import com.jcraft.jsch.JSchException;
      import com.jcraft.jsch.Session;
      
      /**
       * Executes a command on a remote machine via ssh.
       * @since     Ant 1.6 (created February 2, 2003)
       */
      public class SSHExecShellSupport extends SSHBase {
      
          private static final String COMMAND_SEPARATOR = System.getProperty("line.separator");
          private static final int BUFFER_SIZE = 8192;
          private static final int RETRY_INTERVAL = 500;
      
          /** the command to execute via ssh */
          private String command = null;
      
          /** units are milliseconds, default is 0=infinite */
          private long maxwait = 0;
      
          /** for waiting for the command to finish */
          private Thread thread = null;
      
          private String outputProperty = null;   // like <exec>
          private File outputFile = null;   // like <exec>
          private boolean append = false;   // like <exec>
      
          private Resource commandResource = null;
          private boolean isShellMode;
          private long maxTimeWithoutAnyData = 1000*10;
      
          private static final String TIMEOUT_MESSAGE =
              "Timeout period exceeded, connection dropped.";
      
          public long getMaxTimeWithoutAnyData() {
              return maxTimeWithoutAnyData;
          }
      
          public void setMaxTimeWithoutAnyData(long maxTimeWithoutAnyData) {
              this.maxTimeWithoutAnyData = maxTimeWithoutAnyData;
          }
      
          public boolean isShellMode() {
              return isShellMode;
          }
      
          public void setShellMode(boolean isShellMode) {
              this.isShellMode = isShellMode;
          }
      
          /**
           * Constructor for SSHExecTask.
           */
          public SSHExecShellSupport() {
              super();
          }
      
          /**
           * Sets the command to execute on the remote host.
           *
           * @param command  The new command value
           */
          public void setCommand(String command) {
              this.command = command;
          }
      
          /**
           * Sets a commandResource from a file
           * @param f the value to use.
           * @since Ant 1.7.1
           */
          public void setCommandResource(String f) {
              this.commandResource = new FileResource(new File(f));
          }
      
          /**
           * The connection can be dropped after a specified number of
           * milliseconds. This is sometimes useful when a connection may be
           * flaky. Default is 0, which means &quot;wait forever&quot;.
           *
           * @param timeout  The new timeout value in seconds
           */
          public void setTimeout(long timeout) {
              maxwait = timeout;
          }
      
          /**
           * If used, stores the output of the command to the given file.
           *
           * @param output  The file to write to.
           */
          public void setOutput(File output) {
              outputFile = output;
          }
      
          /**
           * Determines if the output is appended to the file given in
           * <code>setOutput</code>. Default is false, that is, overwrite
           * the file.
           *
           * @param append  True to append to an existing file, false to overwrite.
           */
          public void setAppend(boolean append) {
              this.append = append;
          }
      
          /**
           * If set, the output of the command will be stored in the given property.
           *
           * @param property  The name of the property in which the command output
           *      will be stored.
           */
          public void setOutputproperty(String property) {
              outputProperty = property;
          }
      
          /**
           * Execute the command on the remote host.
           *
           * @exception BuildException  Most likely a network error or bad parameter.
           */
          public void execute() throws BuildException {
              if (getHost() == null) {
                  throw new BuildException("Host is required.");
              }
              if (getUserInfo().getName() == null) {
                  throw new BuildException("Username is required.");
              }
              if (getUserInfo().getKeyfile() == null
                  && getUserInfo().getPassword() == null) {
                  throw new BuildException("Password or Keyfile is required.");
              }
              if (command == null && commandResource == null) {
                  throw new BuildException("Command or commandResource is required.");
              }
      
              if(isShellMode){
                  shellMode();
              } else {
                  commandMode();
              }
      
          }
      
          private void shellMode() {
              final Object lock = new Object();
              Session session = null;
              try {
                  session = openSession();
                  final Channel channel=session.openChannel("shell");
      
                  final PipedOutputStream pipedOS = new PipedOutputStream();
                  PipedInputStream pipedIS = new PipedInputStream(pipedOS);
      
                  final Thread commandProducerThread = new Thread("CommandsProducerThread"){
                      public void run() {
                          BufferedReader br = null;
                          try {
                              br = new BufferedReader(new InputStreamReader(commandResource.getInputStream()));                       
                              String singleCmd;
      
                              synchronized (lock) {
                                  lock.wait(); // waits for the reception of the very first data (before commands are issued)
                                  while ((singleCmd = br.readLine()) != null) {
                                      singleCmd += COMMAND_SEPARATOR;
                                      log("cmd : " + singleCmd, Project.MSG_INFO);
                                      pipedOS.write(singleCmd.getBytes());
                                      lock.notify();
                                      try {
                                          lock.wait();
                                      } catch (InterruptedException e) {
                                          log(e, Project.MSG_VERBOSE);
                                          break;
                                      }
                                  }
                                  log("Finished producing commands", Project.MSG_VERBOSE);
                              }
                          } catch (IOException e) {
                              log(e, Project.MSG_VERBOSE);
                          } catch (InterruptedException e) {
                              log(e, Project.MSG_VERBOSE);
                          } finally {
                              FileUtils.close(br);
                          }
                      }
                  };
      
                  ByteArrayOutputStream out = new ByteArrayOutputStream();
                  final TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
                  channel.setOutputStream(tee);
                  channel.setExtOutputStream(tee);
                  channel.setInputStream(pipedIS);
                  channel.connect();
      
                  // waits for it to finish receiving data response and then ask for another the producer to issue one more command
                  thread = new Thread("DataReceiverThread") {
                      public void run() {
                          long lastTimeConsumedData = System.currentTimeMillis(); // initializes the watch
                          try {
                              InputStream in = channel.getInputStream();
                              byte[] tmp = new byte[1024];
      
                              while (true) {
      
                                  if(thread == null){ // works with maxTimeout (for the whole task to complete)
                                      break;
                                  }
      
                                  while (in.available() > 0) {
                                      int i = in.read(tmp, 0, 1024);
                                      lastTimeConsumedData = System.currentTimeMillis();
                                      if (i < 0){
                                          break;
                                      }
                                      tee.write(tmp, 0, i);
                                  }
      
                                  if (channel.isClosed()) {
                                      log("exit-status: " + channel.getExitStatus(), Project.MSG_INFO);
                                      log("channel.isEOF(): " + channel.isEOF(), Project.MSG_VERBOSE);
                                      log("channel.isConnected(): " + channel.isConnected(), Project.MSG_VERBOSE);
                                      throw new BuildException("Connection lost."); // NOTE: it also can happen that if one of the command are "exit" the channel will be closed!
                                  }
                                  synchronized(lock){
                                      long elapsedTimeWithoutData = (System.currentTimeMillis() - lastTimeConsumedData);
                                      if (elapsedTimeWithoutData > maxTimeWithoutAnyData) {
                                          log(elapsedTimeWithoutData / 1000 + " secs elapsed without any data reception. Notifying command producer.", Project.MSG_VERBOSE);
                                          lock.notify(); // command producer is waiting for this
                                          try {
                                              lock.wait(500); // wait til we have new commands.
                                              Thread.yield();
                                              log("Continuing consumer loop. commandProducerThread.isAlive()?" + commandProducerThread.isAlive(), Project.MSG_VERBOSE);
                                              if(!commandProducerThread.isAlive()){
                                                  log("No more commands to be issued and it's been too long without data reception. Exiting consumer.", Project.MSG_VERBOSE);
                                                  break;
                                              }
                                          } catch (InterruptedException e) {
                                              log(e, Project.MSG_VERBOSE);                                                
                                              break;
                                          }
                                          lastTimeConsumedData = System.currentTimeMillis(); // resets watch
                                      }
                                  }
                              }
                          } catch (IOException e) {
                              throw new BuildException(e);
                          }
                      }
                  };
      
                  thread.start();
                  commandProducerThread.start();
                  thread.join(maxwait);
      
                  if (thread.isAlive()) {
                      // ran out of time
                      thread = null;
                      if (getFailonerror()) {
                          throw new BuildException(TIMEOUT_MESSAGE);
                      } else {
                          log(TIMEOUT_MESSAGE, Project.MSG_ERR);
                      }
                  } else {
                      //success
                      if (outputFile != null) {
                          writeToFile(out.toString(), append, outputFile);
                      }
      
                      // this is the wrong test if the remote OS is OpenVMS,
                      // but there doesn't seem to be a way to detect it.
                      log("Exit status (not reliable): " + channel.getExitStatus(), Project.MSG_INFO);
      //                int ec = channel.getExitStatus(); FIXME
      //                if (ec != 0) {
      //                    String msg = "Remote command failed with exit status " + ec;
      //                    if (getFailonerror()) {
      //                        throw new BuildException(msg);
      //                    } else {
      //                        log(msg, Project.MSG_ERR);
      //                    }
      //                }
                  }
              } catch (Exception e){
                  throw new BuildException(e);
              } finally {
                  if (session != null && session.isConnected()) {
                      session.disconnect();
                  }
              }
          }
      
          private void commandMode() {
              Session session = null;
              try {
                  session = openSession();
                  /* called once */
                  if (command != null) {
                      log("cmd : " + command, Project.MSG_INFO);
                      ByteArrayOutputStream out = executeCommand(session, command);
                      if (outputProperty != null) {
                          //#bugzilla 43437
                          getProject().setNewProperty(outputProperty, command + " : " + out);
                      }
                  } else { // read command resource and execute for each command
                      try {
                          BufferedReader br = new BufferedReader(
                                  new InputStreamReader(commandResource.getInputStream()));
                          String cmd;
                          String output = "";
                          while ((cmd = br.readLine()) != null) {
                              log("cmd : " + cmd, Project.MSG_INFO);
                              ByteArrayOutputStream out = executeCommand(session, cmd);
                              output += cmd + " : " + out + "\n";
                          }
                          if (outputProperty != null) {
                              //#bugzilla 43437
                              getProject().setNewProperty(outputProperty, output);
                          }
                          FileUtils.close(br);
                      } catch (IOException e) {
                          throw new BuildException(e);
                      }
                  }
              } catch (JSchException e) {
                  throw new BuildException(e);
              } finally {
                  if (session != null && session.isConnected()) {
                      session.disconnect();
                  }
              }
          }
      
          private ByteArrayOutputStream executeCommand(Session session, String cmd)
              throws BuildException {
              ByteArrayOutputStream out = new ByteArrayOutputStream();
              TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
      
              try {
                  final ChannelExec channel;
                  session.setTimeout((int) maxwait);
                  /* execute the command */
                  channel = (ChannelExec) session.openChannel("exec");
                  channel.setCommand(cmd);
                  channel.setOutputStream(tee);
                  channel.setExtOutputStream(tee);
                  channel.connect();
                  // wait for it to finish
                  thread =
                      new Thread() {
                          public void run() {
                              while (!channel.isClosed()) {
                                  if (thread == null) {
                                      return;
                                  }
                                  try {
                                      sleep(RETRY_INTERVAL);
                                  } catch (Exception e) {
                                      // ignored
                                  }
                              }
                          }
                      };
      
                  thread.start();
                  thread.join(maxwait);
      
                  if (thread.isAlive()) {
                      // ran out of time
                      thread = null;
                      if (getFailonerror()) {
                          throw new BuildException(TIMEOUT_MESSAGE);
                      } else {
                          log(TIMEOUT_MESSAGE, Project.MSG_ERR);
                      }
                  } else {
                      //success
                      if (outputFile != null) {
                          writeToFile(out.toString(), append, outputFile);
                      }
      
                      // this is the wrong test if the remote OS is OpenVMS,
                      // but there doesn't seem to be a way to detect it.
                      int ec = channel.getExitStatus();
                      if (ec != 0) {
                          String msg = "Remote command failed with exit status " + ec;
                          if (getFailonerror()) {
                              throw new BuildException(msg);
                          } else {
                              log(msg, Project.MSG_ERR);
                          }
                      }
                  }
              } catch (BuildException e) {
                  throw e;
              } catch (JSchException e) {
                  if (e.getMessage().indexOf("session is down") >= 0) {
                      if (getFailonerror()) {
                          throw new BuildException(TIMEOUT_MESSAGE, e);
                      } else {
                          log(TIMEOUT_MESSAGE, Project.MSG_ERR);
                      }
                  } else {
                      if (getFailonerror()) {
                          throw new BuildException(e);
                      } else {
                          log("Caught exception: " + e.getMessage(),
                              Project.MSG_ERR);
                      }
                  }
              } catch (Exception e) {
                  if (getFailonerror()) {
                      throw new BuildException(e);
                  } else {
                      log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
                  }
              }
              return out;
          }
      
          /**
           * Writes a string to a file. If destination file exists, it may be
           * overwritten depending on the "append" value.
           *
           * @param from           string to write
           * @param to             file to write to
           * @param append         if true, append to existing file, else overwrite
           * @exception Exception  most likely an IOException
           */
          private void writeToFile(String from, boolean append, File to)
              throws IOException {
              FileWriter out = null;
              try {
                  out = new FileWriter(to.getAbsolutePath(), append);
                  StringReader in = new StringReader(from);
                  char[] buffer = new char[BUFFER_SIZE];
                  int bytesRead;
                  while (true) {
                      bytesRead = in.read(buffer);
                      if (bytesRead == -1) {
                          break;
                      }
                      out.write(buffer, 0, bytesRead);
                  }
                  out.flush();
              } finally {
                  if (out != null) {
                      out.close();
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        另一个简单的解决方法是在运行命令之前获取用户的.bash_profile

        <sshexec host="somehost"
            username="${username}"
            password="${password}"
            command="source ~/.bash_profile &amp;&amp; set"/>
        

        【讨论】:

        • 当我使用 command="source ~/.bash_profile && set"/> 时,出现类似 [sshexec] Connecting to somehost:22 [sshexec] sh: source [sshexec] 的错误: 未找到 当我运行像 command="/home/aykut/myscript" 这样的 shell 脚本时,ant 冻结了。是什么原因造成的?
        【解决方案4】:

        很棒的帖子 chubbsondubs。我需要设置 ORACLE SID,然后执行一个没有正确出口的 PLSQL 脚本。因此,回声出口通过管道传输。

                <sshexec host="${db.ipaddr}"
        
                    verbose="true"
                    trust="true"
                    username="${scp.oracle.userid}"
                    password="${scp.oracle.password}"
                    command="echo exit | /bin/bash -l -c 'export ORACLE_SID=${db.name} ; sqlplus ${db.dbo.userid}/${db.dbo.password} @./INSTALL_REVPORT/CreateDatabase/gengrant.sql'"
        
                />
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-04-17
          • 1970-01-01
          • 2011-12-29
          • 2013-12-04
          • 1970-01-01
          • 2011-10-15
          • 2015-05-30
          相关资源
          最近更新 更多