Skip to content
Snippets Groups Projects
Commit 26f24b7f authored by Jan Kožusznik's avatar Jan Kožusznik
Browse files

support for ssh commands

parent e556d485
Branches
No related tags found
No related merge requests found
package cz.it4i.fiji.scpclient;
import com.jcraft.jsch.Identity;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import java.io.Closeable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cz.it4i.fiji.commons.DoActionEventualy;
public class AbstractBaseSshClient implements Closeable {
protected static final int MAX_NUMBER_OF_CONNECTION_ATTEMPTS = 5;
protected static final long TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS = 500;
private final static Logger log = LoggerFactory.getLogger(
AbstractBaseSshClient.class);
private String hostName;
private String username;
private final JSch jsch = new JSch();
private Session session;
private int port = 22;
public AbstractBaseSshClient(String hostName, String username,
byte[] privateKeyFile) throws JSchException
{
init(hostName, username, new ByteIdentity(jsch, privateKeyFile));
}
public AbstractBaseSshClient(String hostName, String username,
Identity privateKeyFile) throws JSchException
{
init(hostName, username, privateKeyFile);
}
public AbstractBaseSshClient(String hostName, String userName, String keyFile,
String pass) throws JSchException
{
Identity id = IdentityFile.newInstance(keyFile, null, jsch);
try {
if (pass != null) {
id.setPassphrase(pass.getBytes("UTF-8"));
}
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
init(hostName, userName, id);
}
public void setPort(int port) {
this.port = port;
}
@Override
public void close() {
if (session != null && session.isConnected()) {
// log.info("disconnect");
try (DoActionEventualy actionEventualy = new DoActionEventualy(
TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS, this::interruptSessionThread))
{
session.disconnect();
}
}
session = null;
}
protected Session getConnectedSession() throws JSchException {
if (session == null) {
session = jsch.getSession(username, hostName, port);
UserInfo ui = new P_UserInfo();
session.setUserInfo(ui);
}
int connectRetry = 0;
long timoutBetweenRetry = TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS;
while (!session.isConnected()) {
try {
session.connect();
}
catch (JSchException e) {
if (e.getMessage().contains("Auth fail") || e.getMessage().contains(
"Packet corrupt"))
{
if (connectRetry < MAX_NUMBER_OF_CONNECTION_ATTEMPTS) {
connectRetry++;
try {
Thread.sleep(timoutBetweenRetry);
timoutBetweenRetry *= 2;
}
catch (InterruptedException exc) {
log.info("Interruption detected");
throw new JSchException(exc.getMessage(), exc);
}
continue;
}
e = new AuthFailException(e.getMessage(), e);
}
throw e;
}
}
return session;
}
private void interruptSessionThread() {
try {
Field f = session.getClass().getDeclaredField("connectThread");
if (!f.isAccessible()) {
f.setAccessible(true);
Thread thread = (Thread) f.get(session);
thread.interrupt();
}
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException exc)
{
log.error(exc.getMessage(), exc);
}
}
private void init(String initHostName, String initUsername,
Identity privateKeyFile) throws JSchException
{
this.hostName = initHostName;
this.username = initUsername;
jsch.addIdentity(privateKeyFile, null);
}
private class P_UserInfo implements UserInfo {
@Override
public String getPassphrase() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean promptPassword(String message) {
return false;
}
@Override
public boolean promptPassphrase(String message) {
return false;
}
@Override
public boolean promptYesNo(String message) {
return true;
}
@Override
public void showMessage(String message) {}
}
}
......@@ -6,19 +6,13 @@ import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.Identity;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.channels.ClosedByInterruptException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
......@@ -30,31 +24,20 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cz.it4i.fiji.commons.DoActionEventualy;
public class ScpClient extends AbstractBaseSshClient {
public class ScpClient implements Closeable {
public static final Logger log = LoggerFactory.getLogger(ScpClient.class);
private static final String NO_SUCH_FILE_OR_DIRECTORY_ERROR_TEXT =
"No such file or directory";
public static final Logger log = LoggerFactory.getLogger(
cz.it4i.fiji.scpclient.ScpClient.class);
private static String constructExceptionText(AckowledgementChecker ack) {
return "Check acknowledgement failed with status: " + ack.getLastStatus() +
" and message: " + ack.getLastMessage();
}
private static final int MAX_NUMBER_OF_CONNECTION_ATTEMPTS = 5;
private static final long TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS = 500;
private static final int BUFFER_SIZE = 4 * 1024 * 1024; // 4 MB
private String hostName;
private String username;
private final JSch jsch = new JSch();
private Session session;
private final TransferFileProgress dummyProgress =
new TransferFileProgress()
{
......@@ -65,45 +48,22 @@ public class ScpClient implements Closeable {
}
};
private int port = 22;
public ScpClient(String hostName, String username, byte[] privateKeyFile)
throws JSchException
{
init(hostName, username, new ByteIdentity(jsch, privateKeyFile));
super(hostName, username, privateKeyFile);
}
public ScpClient(String hostName, String username, Identity privateKeyFile)
throws JSchException
{
init(hostName, username, privateKeyFile);
super(hostName, username, privateKeyFile);
}
public ScpClient(String hostName, String userName, String keyFile,
String pass) throws JSchException
{
Identity id = IdentityFile.newInstance(keyFile, null, jsch);
try {
if (pass != null) {
id.setPassphrase(pass.getBytes("UTF-8"));
}
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
init(hostName, userName, id);
}
public void setPort(int port) {
this.port = port;
}
private void init(String initHostName, String initUsername,
Identity privateKeyFile) throws JSchException
{
this.hostName = initHostName;
this.username = initUsername;
jsch.addIdentity(privateKeyFile, null);
super(hostName, userName, keyFile, pass);
}
public void download(String lfile, Path rFile) throws JSchException,
......@@ -112,8 +72,8 @@ public class ScpClient implements Closeable {
download(lfile, rFile, dummyProgress);
}
public void download(String lfile, Path rfile,
TransferFileProgress progress) throws JSchException, IOException
public void download(String lfile, Path rfile, TransferFileProgress progress)
throws JSchException, IOException
{
if (!Files.exists(rfile.getParent())) {
Files.createDirectories(rfile.getParent());
......@@ -236,8 +196,8 @@ public class ScpClient implements Closeable {
throws JSchException, IOException
{
try (InputStream is = Files.newInputStream(file)) {
upload(is, rfile, file.toFile().length(), file.toFile()
.lastModified(), progress);
upload(is, rfile, file.toFile().length(), file.toFile().lastModified(),
progress);
}
}
......@@ -250,7 +210,8 @@ public class ScpClient implements Closeable {
try {
scp2Server(is, fileName, length, lastModified, progress);
break;
} catch (NoSuchFileException e) {
}
catch (NoSuchFileException e) {
if (noSuchFileExceptionThrown > MAX_NUMBER_OF_CONNECTION_ATTEMPTS) {
throw new JSchException(e.getReason());
}
......@@ -258,14 +219,14 @@ public class ScpClient implements Closeable {
try {
Thread.sleep(TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS);
}
catch (InterruptedException exc) {
}
catch (InterruptedException exc) {}
}
mkdir(e.getFile());
noSuchFileExceptionThrown++;
continue;
}
} while(true);
}
while (true);
}
public long size(String lfile) throws JSchException, IOException {
......@@ -346,73 +307,10 @@ public class ScpClient implements Closeable {
return null;
}
@Override
public void close() {
if (session != null && session.isConnected()) {
// log.info("disconnect");
try(DoActionEventualy actionEventualy = new DoActionEventualy(TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS, this::interruptSessionThread)){
session.disconnect();
}
}
session = null;
}
private void interruptSessionThread() {
try {
Field f= session.getClass().getDeclaredField("connectThread");
if(!f.isAccessible()) {
f.setAccessible(true);
Thread thread = (Thread) f.get(session);
thread.interrupt();
}
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException
| IllegalAccessException exc)
{
log.error(exc.getMessage(), exc);
}
}
private int getBufferSize() {
return BUFFER_SIZE;
}
private Session getConnectedSession() throws JSchException {
if (session == null) {
session = jsch.getSession(username, hostName, port);
UserInfo ui = new P_UserInfo();
session.setUserInfo(ui);
}
int connectRetry = 0;
long timoutBetweenRetry = TIMEOUT_BETWEEN_CONNECTION_ATTEMPTS;
while (!session.isConnected()) {
try {
session.connect();
}
catch(JSchException e) {
if(e.getMessage().contains("Auth fail") || e.getMessage().contains("Packet corrupt")) {
if(connectRetry < MAX_NUMBER_OF_CONNECTION_ATTEMPTS) {
connectRetry++;
try {
Thread.sleep(timoutBetweenRetry);
timoutBetweenRetry *= 2;
}
catch (InterruptedException exc) {
log.info("Interruption detected");
throw new JSchException(exc.getMessage(), exc);
}
continue;
}
e = new AuthFailException(e.getMessage(), e);
}
throw e;
}
}
return session;
}
private void scp2Server(InputStream is, String fileName, long length,
long lastModified, TransferFileProgress progress) throws JSchException,
IOException, InterruptedIOException
......@@ -423,7 +321,8 @@ public class ScpClient implements Closeable {
fileName = fileName.replace("'", "'\"'\"'");
String command = "scp " + (ptimestamp ? "-p" : "") + " -t '" + fileName + "'";
String command = "scp " + (ptimestamp ? "-p" : "") + " -t '" + fileName +
"'";
Channel channel = getConnectedSession().openChannel("exec");
((ChannelExec) channel).setCommand(command);
// get I/O streams for remote scp
......@@ -491,12 +390,14 @@ public class ScpClient implements Closeable {
}
private int mkdir(String file) throws JSchException {
ChannelExec channel = (ChannelExec) getConnectedSession().openChannel("exec");
ChannelExec channel = (ChannelExec) getConnectedSession().openChannel(
"exec");
channel.setCommand("mkdir -p '" + file + "'");
try {
channel.connect();
return channel.getExitStatus();
} finally {
}
finally {
channel.disconnect();
}
}
......@@ -509,38 +410,4 @@ public class ScpClient implements Closeable {
return fileName.substring(0, index);
}
private class P_UserInfo implements UserInfo {
@Override
public String getPassphrase() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public boolean promptPassword(String message) {
return false;
}
@Override
public boolean promptPassphrase(String message) {
return false;
}
@Override
public boolean promptYesNo(String message) {
return true;
}
@Override
public void showMessage(String message) {}
}
}
package cz.it4i.fiji.scpclient;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.Identity;
import com.jcraft.jsch.JSchException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SshCommandClient extends AbstractBaseSshClient {
private final static Logger log = LoggerFactory.getLogger(
SshCommandClient.class);
public SshCommandClient(String hostName, String username,
byte[] privateKeyFile) throws JSchException
{
super(hostName, username, privateKeyFile);
}
public SshCommandClient(String hostName, String username,
Identity privateKeyFile) throws JSchException
{
super(hostName, username, privateKeyFile);
}
public SshCommandClient(String hostName, String userName, String keyFile,
String pass) throws JSchException
{
super(hostName, userName, keyFile, pass);
}
public String executeCommand(String command) {
StringBuilder sb = new StringBuilder();
try {
ChannelExec channelExec = (ChannelExec) getConnectedSession().openChannel(
"exec");
InputStream in = channelExec.getInputStream();
channelExec.setCommand(command);
channelExec.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append('\n');
}
int exitStatus = channelExec.getExitStatus();
channelExec.disconnect();
if (exitStatus < 0) {
log.debug("Done, but exit status not set!");
}
else if (exitStatus > 0) {
log.debug("Done, but with error!");
}
else {
log.debug("Done!");
}
}
catch (Exception e) {
log.error("Error: ", e);
throw new RuntimeException(e);
}
return sb.toString();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment