2009-10-02 5 views
2

J'ai un programme Java qui s'exécute dans Tomcat et qui doit exécuter plusieurs commandes ssh et scp, ainsi que quelques commandes simples telles que ls sur la machine locale. J'ai des problèmes avec mon approche actuelle en ce sens que je reçois un temps d'arrêt chaque fois que j'exécute une commande ssh. Je peux exécuter la commande ssh sur la ligne de commande sans problème, mais lorsqu'elle est exécutée à partir de mon programme Java, elle expire. J'exécute l'application web dans laquelle les commandes ssh sont exécutées en tant que root (ie je lance Tomcat en tant qu'utilisateur root, avec mon code d'application web déployé en fichier WAR), et autant que je sache, les clés de certification correctes sont configurées les machines locales et distantes, au moins je peux exécuter les commandes ssh à la ligne de commande en tant que root sans avoir à entrer un nom d'utilisateur ou un mot de passe. Je ne spécifie pas le nom d'utilisateur ou le mot de passe dans la commande ssh qui est exécutée par mon programme Java car je suppose que je peux exécuter la même commande ssh dans mon code Java que je peux exécuter en ligne de commande, mais c'est peut-être faux hypothèse et est la cause de mes ennuis.Délai d'exécution de la commande ssh depuis mon programme Java

Le code Java j'ai développé pour effectuer l'exécution de la commande est la suivante:

public class ProcessUtility 
{ 

    static Log log = LogFactory.getLog(ProcessUtility.class); 

    /** 
    * Thread class to be used as a worker 
    */ 
    private static class Worker 
     extends Thread 
    { 
     private final Process process; 
     private volatile Integer exitValue; 

     Worker(final Process process) 
     { 
      this.process = process; 
     } 

     public Integer getExitValue() 
     { 
      return exitValue; 
     } 

     @Override 
     public void run() 
     { 
      try 
      { 
       exitValue = process.waitFor(); 
      } 
      catch (InterruptedException ignore) 
      { 
       return; 
      } 
     } 
    } 

    /** 
    * Executes a command. 
    * 
    * @param args command + arguments 
    */ 
    public static void execCommand(final String[] args) 
    { 
     try 
     { 
      Runtime.getRuntime().exec(args); 
     } 
     catch (IOException e) 
     { 
      // swallow it 
     } 

    } 

    /** 
    * Executes a command. 
    * 
    * @param command 
    * @param printOutput 
    * @param printError 
    * @param timeOut 
    * @return 
    * @throws java.io.IOException 
    * @throws java.lang.InterruptedException 
    */ 
    public static int executeCommand(final String command, 
            final boolean printOutput, 
            final boolean printError, 
            final long timeOut) 
    { 
     return executeCommandWithWorker(command, printOutput, printError, timeOut); 
    } 

    /** 
    * Executes a command and returns its output or error stream. 
    * 
    * @param command 
    * @return the command's resulting output or error stream 
    */ 
    public static String executeCommandReceiveOutput(final String command) 
    { 
     try 
     { 
      // create the process which will run the command 
      Runtime runtime = Runtime.getRuntime(); 
      final Process process = runtime.exec(command); 

      try 
      { 
       // consume the error and output streams 
       StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", false); 
       StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", false); 
       outputGobbler.start(); 
       errorGobbler.start(); 

       // execute the command 
       if (process.waitFor() == 0) 
       { 
        return outputGobbler.getInput(); 
       } 
       return errorGobbler.getInput(); 
      } 
      finally 
      { 
       process.destroy(); 
      } 
     } 
     catch (InterruptedException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
     catch (IOException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an IO error."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
    } 

    /** 
    * Executes a command. 
    * 
    * @param command 
    * @param printOutput 
    * @param printError 
    * @param timeOut 
    * @return 
    * @throws java.io.IOException 
    * @throws java.lang.InterruptedException 
    */ 
    @SuppressWarnings("unused") 
    private static int executeCommandWithExecutors(final String command, 
                final boolean printOutput, 
                final boolean printError, 
                final long timeOut) 
    { 
     // validate the system and command line and get a system-appropriate command line 
     String massagedCommand = validateSystemAndMassageCommand(command); 

     try 
     { 
      // create the process which will run the command 
      Runtime runtime = Runtime.getRuntime(); 
      final Process process = runtime.exec(massagedCommand); 

      // consume and display the error and output streams 
      StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput); 
      StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError); 
      outputGobbler.start(); 
      errorGobbler.start(); 

      // create a Callable for the command's Process which can be called by an Executor 
      Callable<Integer> call = new Callable<Integer>() 
      { 
       public Integer call() 
        throws Exception 
       { 
        process.waitFor(); 
        return process.exitValue(); 
       } 
      }; 

      // submit the command's call via an Executor and get the result from a Future 
      ExecutorService executorService = Executors.newSingleThreadExecutor(); 
      try 
      { 
       Future<Integer> futureResultOfCall = executorService.submit(call); 
       int exitValue = futureResultOfCall.get(timeOut, TimeUnit.MILLISECONDS); 
       return exitValue; 
      } 
      catch (TimeoutException ex) 
      { 
       String errorMessage = "The command [" + command + "] timed out."; 
       log.error(errorMessage, ex); 
       throw new RuntimeException(errorMessage, ex); 
      } 
      catch (ExecutionException ex) 
      { 
       String errorMessage = "The command [" + command + "] did not complete due to an execution error."; 
       log.error(errorMessage, ex); 
       throw new RuntimeException(errorMessage, ex); 
      } 
      finally 
      { 
       executorService.shutdown(); 
       process.destroy(); 
      } 
     } 
     catch (InterruptedException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
     catch (IOException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an IO error."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
    } 

    /** 
    * Executes a command. 
    * 
    * @param command 
    * @param printOutput 
    * @param printError 
    * @param timeOut 
    * @return 
    * @throws java.io.IOException 
    * @throws java.lang.InterruptedException 
    */ 
    private static int executeCommandWithWorker(final String command, 
               final boolean printOutput, 
               final boolean printError, 
               final long timeOut) 
    { 
     // validate the system and command line and get a system-appropriate command line 
     String massagedCommand = validateSystemAndMassageCommand(command); 

     try 
     { 
      // create the process which will run the command 
      Runtime runtime = Runtime.getRuntime(); 
      Process process = runtime.exec(massagedCommand); 

      // consume and display the error and output streams 
      StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT", printOutput); 
      StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR", printError); 
      outputGobbler.start(); 
      errorGobbler.start(); 

      // create and start a Worker thread which this thread will join for the timeout period 
      Worker worker = new Worker(process); 
      worker.start(); 
      try 
      { 
       worker.join(timeOut); 
       Integer exitValue = worker.getExitValue(); 
       if (exitValue != null) 
       { 
        // the worker thread completed within the timeout period 

        // stop the output and error stream gobblers 
        outputGobbler.stopGobbling(); 
        errorGobbler.stopGobbling(); 

        return exitValue; 
       } 

       // if we get this far then we never got an exit value from the worker thread as a result of a timeout 
       String errorMessage = "The command [" + command + "] timed out."; 
       log.error(errorMessage); 
       throw new RuntimeException(errorMessage); 
      } 
      catch (InterruptedException ex) 
      { 
       worker.interrupt(); 
       Thread.currentThread().interrupt(); 
       throw ex; 
      } 
      finally 
      { 
       process.destroy(); 
      } 
     } 
     catch (InterruptedException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an unexpected interruption."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
     catch (IOException ex) 
     { 
      String errorMessage = "The command [" + command + "] did not complete due to an IO error."; 
      log.error(errorMessage, ex); 
      throw new RuntimeException(errorMessage, ex); 
     } 
    } 

    /** 
    * Validates that the system is running a supported OS and returns a system-appropriate command line. 
    * 
    * @param originalCommand 
    * @return 
    */ 
    private static String validateSystemAndMassageCommand(final String originalCommand) 
    { 
     // make sure that we have a command 
     if (originalCommand.isEmpty() || (originalCommand.length() < 1)) 
     { 
      String errorMessage = "Missing or empty command line parameter."; 
      log.error(errorMessage); 
      throw new RuntimeException(errorMessage); 
     } 

     // make sure that we are running on a supported system, and if so set the command line appropriately 
     String massagedCommand; 
     String osName = System.getProperty("os.name"); 
     if (osName.equals("Windows XP")) 
     { 
      massagedCommand = "cmd.exe /C " + originalCommand; 
     } 
     else if (osName.equals("Solaris") || osName.equals("SunOS") || osName.equals("Linux")) 
     { 
      massagedCommand = originalCommand; 
     } 
     else 
     { 
      String errorMessage = "Unable to run on this system which is not Solaris, Linux, or Windows XP (actual OS type: \'" + 
            osName + "\')."; 
      log.error(errorMessage); 
      throw new RuntimeException(errorMessage); 
     } 

     return massagedCommand; 
    } 
} 

class StreamGobbler 
    extends Thread 
{ 
    static private Log log = LogFactory.getLog(StreamGobbler.class); 
    private InputStream inputStream; 
    private String streamType; 
    private boolean displayStreamOutput; 
    private final StringBuffer inputBuffer = new StringBuffer(); 
    private boolean keepGobbling = true; 

    /** 
    * Constructor. 
    * 
    * @param inputStream the InputStream to be consumed 
    * @param streamType the stream type (should be OUTPUT or ERROR) 
    * @param displayStreamOutput whether or not to display the output of the stream being consumed 
    */ 
    StreamGobbler(final InputStream inputStream, 
        final String streamType, 
        final boolean displayStreamOutput) 
    { 
     this.inputStream = inputStream; 
     this.streamType = streamType; 
     this.displayStreamOutput = displayStreamOutput; 
    } 

    /** 
    * Returns the output stream of the 
    * 
    * @return 
    */ 
    public String getInput() 
    { 
     return inputBuffer.toString(); 
    } 

    /** 
    * Consumes the output from the input stream and displays the lines consumed if configured to do so. 
    */ 
    @Override 
    public void run() 
    { 
     InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 
     BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
     try 
     { 
      String line = null; 
      while (keepGobbling && inputStreamReader.ready() && ((line = bufferedReader.readLine()) != null)) 
      { 
       inputBuffer.append(line); 
       if (displayStreamOutput) 
       { 
        System.out.println(streamType + ">" + line); 
       } 
      } 
     } 
     catch (IOException ex) 
     { 
      log.error("Failed to successfully consume and display the input stream of type " + streamType + ".", ex); 
      ex.printStackTrace(); 
     } 
     finally 
     { 
      try 
      { 
       bufferedReader.close(); 
       inputStreamReader.close(); 
      } 
      catch (IOException e) 
      { 
       // swallow it 
      } 
     } 
    } 

    public void stopGobbling() 
    { 
     keepGobbling = false; 
    } 
} 

J'exécute les commandes ssh dans mon programme Java comme ceci:

ProcessUtility.executeCommand ("ssh" + physicalHostIpAddress + "liste vierge \ | grep" + nouveauDomUName, faux, faux, 3600000)

Quelqu'un peut-il voir ce que je fais mal? BTW le code ci-dessus a été développé en utilisant cet article comme un guide: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html. Je ne suis pas très expert en programmation simultanée, alors peut-être que je fais quelque chose de stupide - n'hésitez pas à le signaler si c'est le cas.

Merci beaucoup à l'avance pour des suggestions, des idées, etc.

--James

Mise à jour: J'ai maintenant pris l'avis des gens utiles qui ont répondu à ma question initiale et ont écrit une classe qui fournit des méthodes pour faire des appels ssh et scp, implémentés en utilisant deux bibliothèques Java ssh jsch (jsch-0.1.31) et sshtools (j2ssh-core-0.2.9). Cependant, aucune de ces implémentations ne fonctionne en ce sens qu'elles échouent toutes les deux à l'étape de connexion, avant même que j'aie la chance d'effectuer l'authentification. Je pense que je suis confronté à une sorte de problème de configuration sur les serveurs où j'exécute les codes, bien que cela ne soit pas évident car je peux exécuter des commandes ssh et scp sur ces serveurs sans problème lorsque j'émets les commandes ssh ou scp ligne de commande. Les serveurs Solaris que je teste mon code sur montrent les éléments suivants à la suite de ssh -v:

Sun_SSH_1.3, les protocoles SSH 1.5/2.0, OpenSSL 0x0090801f

Voici le code Java j'ai écrit à cet effet - si quelqu'un peut voir ce que je fais de mal au niveau du code Java alors s'il vous plaît faites le moi savoir, et si oui, merci beaucoup d'avance pour votre aide.

public class SecureCommandUtility 
{ 
    static Log log = LogFactory.getLog(SecureCommandUtility.class); 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param username 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    * @param timeout 
    */ 
    public static void secureCopySingleFile(final String localFilePathName, 
              final String username, 
              final String password, 
              final String remoteHost, 
              final String remoteFilePathName, 
              final int timeout) 
    { 
     // basic validation of the parameters 
     if ((localFilePathName == null) || localFilePathName.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied local file path name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((username == null) || username.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied user name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((password == null) || password.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied password parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteHost == null) || remoteHost.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied remote host parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteFilePathName == null) || remoteFilePathName.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied remote file path name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if (timeout < 1000) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the secure copy -- the supplied timeout parameter is less than one second."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 

     //secureCopySingleFileJSch(localFilePathName, username, password, remoteHost, remoteFilePathName); 
     secureCopySingleFileJ2Ssh(localFilePathName, username, password, remoteHost, remoteFilePathName, timeout); 
    } 

    /** 
    * 
    * @param user 
    * @param password 
    * @param remoteHost 
    * @param command 
    * @return exit status of the command 
    */ 
    public static int secureShellCommand(final String user, 
             final String password, 
             final String remoteHost, 
             final String command, 
             final int timeout) 
    { 
     // basic validation of the parameters 
     if ((user == null) || user.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied user name parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((password == null) || password.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied password parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((remoteHost == null) || remoteHost.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied remote host parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if ((command == null) || command.isEmpty()) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command: the supplied command parameter is null or empty."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
     if (timeout < 1000) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Error executing the ssh command \'" + command + 
            "\': the supplied timeout parameter is less than one second."; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 

     //return secureShellCommandJsch(user, password, remoteHost, command, timeout); 
     return secureShellCommandJ2Ssh(user, password, remoteHost, command, timeout); 
    } 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param username 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    * @param timeout 
    */ 
    private static void secureCopySingleFileJ2Ssh(final String localFilePathName, 
                final String username, 
                final String password, 
                final String remoteHost, 
                final String remoteFilePathName, 
                final int timeout) 
    { 
     SshClient sshClient = null; 
     try 
     { 
      // create and connect client 
      sshClient = new SshClient(); 
      sshClient.setSocketTimeout(timeout); 
      sshClient.connect(remoteHost, 22, new IgnoreHostKeyVerification()); 

      // perform password-based authentication 
      PasswordAuthenticationClient passwordAuthenticationClient = new PasswordAuthenticationClient(); 
      passwordAuthenticationClient.setUsername(username); 
      passwordAuthenticationClient.setPassword(password); 
      if (sshClient.authenticate(passwordAuthenticationClient) != AuthenticationProtocolState.COMPLETE) 
      { 
       // log the error and throw an exception 
       String errorMessage = "Failed to copy \'" + localFilePathName + "\' to \'" + remoteHost + ":" + 
             remoteFilePathName + "\' -- failed to authenticate using username/password \'" + 
             username + "\'/\'" + password + "\'."; 
       log.error(errorMessage); 
       throw new LifecycleException(errorMessage); 
      } 

      // perform the copy 
      sshClient.openScpClient().put(localFilePathName, remoteFilePathName, false); 
     } 
     catch (Exception ex) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Failed to copy \'" + localFilePathName + "\' to \'" + remoteHost + ":" + 
            remoteFilePathName + "\'."; 
      log.error(errorMessage, ex); 
      throw new LifecycleException(errorMessage, ex); 
     } 
     finally 
     { 
      if ((sshClient != null) && sshClient.isConnected()) 
      { 
       sshClient.disconnect(); 
      } 
     } 
    } 

    /** 
    * Performs a secure copy of a single file (using scp). 
    * 
    * @param localFilePathName 
    * @param user 
    * @param password 
    * @param remoteHost 
    * @param remoteFilePathName 
    */ 
    @SuppressWarnings("unused") 
    private static void secureCopySingleFileJSch(final String localFilePathName, 
               final String user, 
               final String password, 
               final String remoteHost, 
               final String remoteFilePathName) 
    { 
     Session session = null; 
     Channel channel = null; 
     FileInputStream fileInputStream = null; 
     try 
     { 
      // create and connect Jsch session 
      JSch jsch = new JSch(); 
      session = jsch.getSession(user, remoteHost, 22); 
      session.setPassword(password); 
      session.connect(); 

      // exec 'scp -p -t remoteFilePathName' remotely 
      String command = "scp -p -t " + remoteFilePathName; 
      channel = session.openChannel("exec"); 
      ((ChannelExec) channel).setCommand(command); 

      // get the I/O streams for the remote scp 
      OutputStream outputStream = channel.getOutputStream(); 
      InputStream inputStream = channel.getInputStream(); 

      // connect the channel 
      channel.connect(); 

      int ackCheck = checkAck(inputStream); 
      if (checkAck(inputStream) != 0) 
      { 
       // log the error and throw an exception 
       String errorMessage = "The scp command failed -- input stream ACK check failed with the following result: " + 
             ackCheck; 
       log.error(errorMessage); 
       throw new LifecycleException(errorMessage); 
      } 

      // send "C0644 filesize filename", where filename should not include '/' 
      long filesize = (new File(localFilePathName)).length(); 
      command = "C0644 " + filesize + " "; 
      if (localFilePathName.lastIndexOf('/') > 0) 
      { 
       command += localFilePathName.substring(localFilePathName.lastInde 
+0

Où exactement obtenez-vous un temps mort? '' process.waitFor(); '' ?? Spécifiez-le. – NawaMan

Répondre

1

J'ai abandonné mes tentatives d'utilisation de bibliothèques ssh pour cela et j'ai plutôt utilisé une approche Runtime.exec() pour lancer des commandes ssh et scp. Voici le code que j'utilise maintenant ce qui fonctionne bien:

public static void executeSecureCommand(final String user, 
             final String remoteHost, 
             final String command) 
{ 
    // basic validation of the parameters 
    if ((user == null) || user.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command \'" + command + 
           "\': the supplied user name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteHost == null) || remoteHost.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command \'" + command + 
           "\': the supplied remote host parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((command == null) || command.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the ssh command: the supplied command parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 

    // create and execute a corresponding ssh command 
    String sshCommand = "ssh " + user + "@" + remoteHost + " " + command; 
    try 
    { 
     executeShellCommand(sshCommand); 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure shell command \'" + sshCommand + "\'"; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

public static void executeSecureFileCopy(final String localFilePathName, 
             final String user, 
             final String remoteHost, 
             final String remoteFilePathName) 
{ 
    // basic validation of the parameters 
    if ((localFilePathName == null) || localFilePathName.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied local file path name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((user == null) || user.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied user name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteHost == null) || remoteHost.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied remote host parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 
    if ((remoteFilePathName == null) || remoteFilePathName.isEmpty()) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Error executing the secure copy -- the supplied remote file path name parameter is null or empty."; 
     log.error(errorMessage); 
     throw new LifecycleException(errorMessage); 
    } 

    try 
    { 
     // create an scp command we'll use to perform the secure file copy 
     String scpCommand = "scp -B -C -q " + localFilePathName + " " + user + "@" + remoteHost + ":" + 
          remoteFilePathName; 

     // execute the scp command 
     executeShellCommand(scpCommand); 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Failed to copy local file \'" + localFilePathName + "\' to remote host:file \'" + 
           remoteHost + ":" + remoteFilePathName + "\'."; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

public static void executeShellCommand(final String command) 
{ 
    try 
    { 
     // create and execute a runtime process which runs the command 
     Process process = Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command }); 

     // gobble the input stream 
     InputStream processInputStream = process.getInputStream(); 
     BufferedReader processInputStreamReader = new BufferedReader(new InputStreamReader(processInputStream)); 
     String inputStreamLine = processInputStreamReader.readLine(); 
     while (inputStreamLine != null) 
     { 
      inputStreamLine = processInputStreamReader.readLine(); 
     } 

     // capture the error stream 
     InputStream processErrorStream = process.getErrorStream(); 
     BufferedReader processErrorStreamReader = new BufferedReader(new InputStreamReader(processErrorStream)); 
     String errorStreamLine = processErrorStreamReader.readLine(); 
     StringBuffer errorBuffer = new StringBuffer(); 
     while (errorStreamLine != null) 
     { 
      errorBuffer.append(errorStreamLine); 
      errorStreamLine = processErrorStreamReader.readLine(); 
     } 

     // close the streams 
     processInputStream.close(); 
     processErrorStream.close(); 

     // wait for the process to finish and return the exit code 
     process.waitFor(); 
     if (process.exitValue() != 0) 
     { 
      // log the error and throw an exception 
      String errorMessage = "Failed to execute the shell command \'" + command + "\' -- Error: \'" + 
            errorBuffer.toString() + "\'"; 
      log.error(errorMessage); 
      throw new LifecycleException(errorMessage); 
     } 
    } 
    catch (Exception ex) 
    { 
     // log the error and throw an exception 
     String errorMessage = "Failed to execute the shell command \'" + command + "\'."; 
     log.error(errorMessage, ex); 
     throw new LifecycleException(errorMessage, ex); 
    } 
} 

Si quelqu'un voit des problèmes avec ce code, à savoir les erreurs possibles, je ne suis pas Attraper, etc. alors s'il vous plaît les signaler. Mon code original était assez compliqué et alambiqué pour aborder toutes les questions soulevées dans cet article (http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html) mais ce n'est que récemment qu'il m'a été signalé que cet article a presque 8 ans et que beaucoup des problèmes qu'il met en garde à propos de ne sont plus applicables dans les versions actuelles de Java. Je suis donc de retour à une solution de base qui utilise Runtime.exec() et tout semble bien.

Merci encore à tous ceux qui ont essayé de m'aider à résoudre ce problème.

2

Vous pourriez avoir plus de chance traiter avec délai d'attente et les erreurs si vous utilisez jsch plutôt que d'essayer de débourser. Il existe des exemples d'utilisation here.

Dans la plupart des cas, les erreurs que vous obtiendrez de JSch seront beaucoup plus utiles pour diagnostiquer s'il s'agit d'un problème de connexion ou d'un problème de logique.

De même, vous ne savez pas pourquoi vous devez utiliser ls de cette façon.Vous pouvez obtenir un tableau de fichiers ainsi

File dir = new File("directory"); 
String[] children = dir.list(); 

Sans avoir à analyser la sortie de ls. Ce sera beaucoup plus portable.

+0

Merci pour votre réponse, et pour les bonnes suggestions. –

+0

J'ai aussi eu une bonne expérience avec jsch –

+0

je reçois l'exception suivante lors de la connexion à l'hôte: JSchException: négociation algorithme échec Cela se produit à l'étape de connexion: JSch jsch = new JSch(); session = jsch.getSession (utilisateur, remoteHost, 22); session.setPassword (mot de passe); session.connect(); Quelqu'un peut-il commenter ce qui pourrait être la cause de cette erreur? (BTW Je reçois aussi ce que je suppose être une erreur similaire à l'étape de connexion lors de l'utilisation j2ssh, IOException: socket est EOF) –

0

Cela ne répond pas à votre question, mais vous pouvez essayer sshtools lib qui gère ssh gentiment.

Quelques exemples:

SshClient ssh = = new SshClient(); 
ssh.connect(server, port, new IgnoreHostKeyVerification()); 
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient(); 
pwd.setUsername(uid); 
pwd.setPassword(password); 
int result = ssh.authenticate(pwd); 
if (result == AuthenticationProtocolState.COMPLETE) { 
    SessionChannelClient session = ssh.openSessionChannel(); 
    session.executeCommand("sh test.sh"); 
} 
+0

Je reçois une exception IOException lors de la connexion à l'aide de cette bibliothèque: java.io.IOException: le socket est EOF Cela se produit lors de l'appel connect(): SshClient sshClient = new SshClient(); sshClient.setSocketTimeout (timeout); sshClient.connect (RemoteHost, 22); Quelqu'un peut-il commenter ce que cette exception indique? –

+0

J'ai ajouté un exemple rapide. Encore une fois, je ne sais pas comment cela est lié à votre problème, désolé. – serg

+0

Merci serg555. S'il vous plaît voir ma mise à jour à ma question d'origine qui répertorie le code que j'utilise pour faire la commande ssh. Mon code est exactement comme vous l'avez démontré ci-dessus sauf que je n'utilisais pas une IgnoreHostKeyVerification dans mon étape de connexion, mais maintenant je l'ai ajouté et cela ne fonctionne toujours pas, échouant à l'appel connect() avec cette erreur:

SEVERE: le thread de protocole de transport a échoué
java.io.IOException: le socket est EOF –

0

Je pense: Qu'est-ce que l'utilisateur exécute tomcat comme? Et comment SSH fait-il la gestion des clés? Je soupçonne l'utilisateur qu'il est en cours d'exécution, car les touches ne sont pas configurées correctement.

+0

Merci, soyeux. Je cours Tomcat en tant que root. Je ne pense pas que ce soit vraiment important car dans mon code j'obtiens un utilisateur et un mot de passe et je les utilise pour m'authentifier, et je n'arrive même pas à cette étape puisque le code lance une exception à l'étape connect() dans les deux implémentations (en utilisant sshtools/j2ssh et jsch), ce qui se produit avant l'étape d'authentification (voir la mise à jour de mon message original pour les deux implémentations que j'ai trouvées en utilisant sshtools/j2ssh et jsch). –

Questions connexes