/*
* Copyright (c) 2010 Ecole des Mines de Nantes.
*
* This file is part of Entropy.
*
* Entropy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Entropy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Entropy. If not, see <http://www.gnu.org/licenses/>.
*/
package entropy.execution.driver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* Tool to execute remote shell command on a SSH server.
* The tool support authentification through password or identity file.
*
* @author Fabien Hermenier
*/
public class SSHExec {
/**
* Default listening port of the ssh server.
*/
public static final int DEFAULT_PORT = 22;
/**
* The port of the ssh server.
*/
private int port;
/**
* The user used to log on the node.
*/
private String user;
/**
* The hostname of the server.
*/
private String hostname;
/**
* The current SSH session.
*/
private Session session;
/**
* The buffer that contains all the standard output.
*/
private StringBuilder outputBuffer;
/**
* The buffer that contains all the standard error.
*/
private StringBuilder errorBuffer;
/**
* The SSH toolkit.
*/
private JSch jsch;
/**
* Get the port of the server.
*
* @return the port
*/
public final int getPort() {
return this.port;
}
/**
* Get the username on the server.
*
* @return the login of the user
*/
public final String getUsername() {
return this.user;
}
/**
* Make a new instance with the current user.
*
* @param host the hostname of the SSH server
* @throws JSchException If an error occurs
*/
public SSHExec(String host) throws JSchException {
this(host, DEFAULT_PORT, System.getenv("user.name"));
}
/**
* Make a new instance.
*
* @param host the hostname of the server
* @param username the login of the user
* @param p the listening port
* @throws JSchException If an error occurs
*/
public SSHExec(String host, int p, String username) throws JSchException {
this.hostname = host;
this.user = username;
this.port = p;
this.outputBuffer = new StringBuilder();
this.errorBuffer = new StringBuilder();
jsch = new JSch();
session = jsch.getSession(this.getUsername(), this.getHostname(), this.getPort());
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
}
/**
* Use an identity file as authentification.
*
* @param filename The absolute pathname of the private key
* @throws JSchException if an error occurs.
*/
public void useIdentity(String filename) throws JSchException {
this.jsch.addIdentity(filename);
}
/**
* Use an identity file and a passphrase as authentification.
*
* @param filename The absolute pathname of the private key
* @param passPhrase the passphrase
* @throws JSchException if an error occurs
*/
public void useIdentity(String filename, String passPhrase) throws JSchException {
this.jsch.addIdentity(filename, passPhrase);
}
/**
* Use a password as authentification.
*
* @param password the password
*/
public void usePassword(String password) {
this.session.setPassword(password);
}
/**
* Get the hostname of the server.
*
* @return the hostname
*/
public final String getHostname() {
return this.hostname;
}
/**
* Return the standard output after the execution of the command.
*
* @return the content of the standard output, may be empty
*/
public String getStandartOutput() {
return this.outputBuffer.toString();
}
/**
* Return the standard error output after the execution of the command.
*
* @return the content of the standard error output, may be empty
*/
public String getStandardError() {
return this.errorBuffer.toString();
}
/**
* Execute a command through a SSH session.
*
* @param command the command to execute
* @return the exit code
* @throws JSchException if an error occurs
* @throws IOException if an error occurs
*/
public int executeCommand(String command) throws JSchException, IOException {
session.connect();
int exitCode = -1;
ChannelExec channel = null;
BufferedReader stdoutReader = null;
BufferedReader stderrReader = null;
outputBuffer = new StringBuilder();
errorBuffer = new StringBuilder();
try {
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command + "\n");
InputStream stdout = channel.getInputStream();
InputStream stderr = channel.getErrStream();
channel.connect();
stdoutReader = new BufferedReader(new InputStreamReader(stdout));
stderrReader = new BufferedReader(new InputStreamReader(stderr));
while (stdoutReader.read() != -1) {
outputBuffer.append(stdoutReader.readLine());
}
while (stderrReader.read() != -1) {
errorBuffer.append(stderrReader.readLine());
}
exitCode = channel.getExitStatus();
return exitCode;
} finally {
if (stdoutReader != null) {
stdoutReader.close();
}
if (stderrReader != null) {
stderrReader.close();
}
if (channel != null) {
channel.disconnect();
session.disconnect();
}
}
}
}