You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2016/12/13 15:58:57 UTC
[03/13] brooklyn-server git commit: bump sshj version
bump sshj version
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/c3de6287
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/c3de6287
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/c3de6287
Branch: refs/heads/master
Commit: c3de62874f04f74bc3b542ff8f4db7e1a9a96010
Parents: 9f8a3aa
Author: Andrea Turli <an...@gmail.com>
Authored: Fri Sep 16 17:50:03 2016 +0200
Committer: Andrea Turli <an...@gmail.com>
Committed: Tue Dec 6 15:29:57 2016 +0100
----------------------------------------------------------------------
core/pom.xml | 2 +-
.../util/core/internal/ssh/sshj/SshjTool.java | 206 +++++++++----------
parent/pom.xml | 2 +-
pom.xml | 2 +-
4 files changed, 102 insertions(+), 110 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c3de6287/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index f133515..02c6cbf 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -58,7 +58,7 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>net.schmizz</groupId>
+ <groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c3de6287/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java b/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java
index fa46af0..1ee02da 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjTool.java
@@ -38,17 +38,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
-import net.schmizz.sshj.connection.ConnectionException;
-import net.schmizz.sshj.connection.channel.direct.PTYMode;
-import net.schmizz.sshj.connection.channel.direct.Session;
-import net.schmizz.sshj.connection.channel.direct.Session.Command;
-import net.schmizz.sshj.connection.channel.direct.Session.Shell;
-import net.schmizz.sshj.connection.channel.direct.SessionChannel;
-import net.schmizz.sshj.sftp.FileAttributes;
-import net.schmizz.sshj.sftp.SFTPClient;
-import net.schmizz.sshj.transport.TransportException;
-import net.schmizz.sshj.xfer.InMemorySourceFile;
-
import org.apache.brooklyn.core.BrooklynFeatureEnablement;
import org.apache.brooklyn.util.core.internal.ssh.BackoffLimitedRetryHandler;
import org.apache.brooklyn.util.core.internal.ssh.ShellTool;
@@ -56,11 +45,9 @@ import org.apache.brooklyn.util.core.internal.ssh.SshAbstractTool;
import org.apache.brooklyn.util.core.internal.ssh.SshTool;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.exceptions.RuntimeTimeoutException;
-import org.apache.brooklyn.util.io.FileUtil;
import org.apache.brooklyn.util.repeat.Repeater;
import org.apache.brooklyn.util.stream.KnownSizeInputStream;
import org.apache.brooklyn.util.stream.StreamGobbler;
-import org.apache.brooklyn.util.stream.Streams;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
@@ -80,6 +67,19 @@ import com.google.common.io.CountingOutputStream;
import com.google.common.net.HostAndPort;
import com.google.common.primitives.Ints;
+import net.schmizz.sshj.connection.ConnectionException;
+import net.schmizz.sshj.connection.channel.direct.PTYMode;
+import net.schmizz.sshj.connection.channel.direct.Session;
+import net.schmizz.sshj.connection.channel.direct.Session.Command;
+import net.schmizz.sshj.connection.channel.direct.Session.Shell;
+import net.schmizz.sshj.connection.channel.direct.SessionChannel;
+import net.schmizz.sshj.sftp.FileAttributes;
+import net.schmizz.sshj.sftp.SFTPClient;
+import net.schmizz.sshj.transport.TransportException;
+import net.schmizz.sshj.xfer.FileSystemFile;
+import net.schmizz.sshj.xfer.InMemorySourceFile;
+import net.schmizz.sshj.xfer.LocalDestFile;
+
/**
* For ssh and scp-style commands, using the sshj library.
*/
@@ -95,7 +95,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
* Having multiple threads call connect/disconnect is going to be brittle. With
* our retries we can get away with it usually, but it's not good!
*
- * TODO need to upgrade sshj version from 0.8.1 to 0.9, but jclouds 1.7.2 still
+ * TODO need to upgrade sshj version from 0.8.1 to 0.9, but jclouds 1.7.2 still
* relies on 0.8.1. In 0.9, it fixes the https://github.com/shikhar/sshj/issues/89
* so does not throw AssertionError.
*/
@@ -108,7 +108,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
/** Terminal type name for {@code allocatePTY} option. */
final static String TERM = "vt100"; // "dumb"
-
+
private class CloseFtpChannelOnCloseInputStream extends ProxyInputStream {
private final SFTPClient sftp;
@@ -129,17 +129,17 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public static SshjToolBuilder builder() {
return new SshjToolBuilder();
}
-
+
public static class SshjToolBuilder extends Builder<SshjTool, SshjToolBuilder> {
}
-
+
public static class Builder<T extends SshjTool, B extends Builder<T,B>> extends AbstractSshToolBuilder<T,B> {
protected long connectTimeout;
protected long sessionTimeout;
protected int sshTries = 4; //allow 4 tries by default, much safer
protected long sshTriesTimeout = 2*60*1000; //allow 2 minutes by default (so if too slow trying sshTries times, abort anyway)
protected long sshRetryDelay = 50L;
-
+
@Override
public B from(Map<String,?> props) {
super.from(props);
@@ -175,10 +175,10 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public SshjTool(Map<String,?> map) {
this(builder().from(map));
}
-
+
protected SshjTool(Builder<?,?> builder) {
super(builder);
-
+
sshTries = builder.sshTries;
sshTriesTimeout = builder.sshTriesTimeout;
backoffLimitedRetryHandler = new BackoffLimitedRetryHandler(sshTries, builder.sshRetryDelay);
@@ -194,10 +194,10 @@ public class SshjTool extends SshAbstractTool implements SshTool {
.connectTimeout(builder.connectTimeout)
.sessionTimeout(builder.sessionTimeout)
.build();
-
+
if (LOG.isTraceEnabled()) LOG.trace("Created SshTool {} ({})", this, System.identityHashCode(this));
}
-
+
@Override
public void connect() {
try {
@@ -231,19 +231,19 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public boolean isConnected() {
return sshClientConnection.isConnected() && sshClientConnection.isAuthenticated();
}
-
+
@Override
public int copyToServer(java.util.Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer) {
return copyToServer(props, newInputStreamSupplier(contents), contents.length, pathAndFileOnRemoteServer);
}
-
+
@Override
public int copyToServer(Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer) {
/* sshj needs to:
* 1) to know the length of the InputStream to copy the file to perform copy; and
* 2) re-read the input stream on retry if the first attempt fails.
* For now, write it to a file, unless caller supplies a KnownSizeInputStream
- *
+ *
* (We could have a switch where we hold it in memory if less than some max size,
* but most the routines should supply a string or byte array or similar,
* so we probably don't come here too often.)
@@ -259,12 +259,12 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
}
}
-
+
@Override
public int copyToServer(Map<String,?> props, File localFile, String pathAndFileOnRemoteServer) {
return copyToServer(props, newInputStreamSupplier(localFile), (int)localFile.length(), pathAndFileOnRemoteServer);
}
-
+
private int copyToServer(Map<String,?> props, Supplier<InputStream> contentsSupplier, long length, String pathAndFileOnRemoteServer) {
acquire(new PutFileAction(props, pathAndFileOnRemoteServer, contentsSupplier, length));
return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
@@ -273,13 +273,8 @@ public class SshjTool extends SshAbstractTool implements SshTool {
@Override
public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File localFile) {
- InputStream contents = acquire(new GetFileAction(pathAndFileOnRemoteServer));
- try {
- FileUtil.copyTo(contents, localFile);
- return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
- } finally {
- Streams.closeQuietly(contents);
- }
+ LocalDestFile localDestFile = acquire(new GetFileAction(pathAndFileOnRemoteServer));
+ return 0;
}
/**
@@ -304,11 +299,11 @@ public class SshjTool extends SshAbstractTool implements SshTool {
* e.g. by putting every second command as "echo <uid>", and waiting for the stdout.
* This gets fiddly...
* </ul>
- *
+ *
* So on balance, the script-based approach seems most reliable, even if there is an overhead
* of separate message(s) for copying the file!
- *
- * Another consideration is long-running scripts. On some clouds when executing a script that takes
+ *
+ * Another consideration is long-running scripts. On some clouds when executing a script that takes
* several minutes, we have seen it fail with -1 (e.g. 1 in 20 times). This suggests the ssh connection
* is being dropped. To avoid this problem, we can execute the script asynchronously, writing to files
* the stdout/stderr/pid/exitStatus. We then periodically poll to retrieve the contents of these files.
@@ -337,17 +332,17 @@ public class SshjTool extends SshAbstractTool implements SshTool {
/**
* Executes the script in the background (`nohup ... &`), and then executes other ssh commands to poll for the
* stdout, stderr and exit code of that original process (which will each have been written to separate files).
- *
+ *
* The polling is a "long poll". That is, it executes a long-running ssh command to retrieve the stdout, etc.
* If that long-poll command fails, then we just execute another one to pick up from where it left off.
* This means we do not need to execute many ssh commands (which are expensive), but can still return promptly
* when the command completes.
- *
+ *
* Much of this was motivated by https://issues.apache.org/jira/browse/BROOKLYN-106, which is no longer
* an issue. The retries (e.g. in the upload-script) are arguably overkill given that {@link #acquire(SshAction)}
* will already retry. However, leaving this in place as it could prove useful when working with flakey
* networks in the future.
- *
+ *
* TODO There are (probably) issues with this method when using {@link ShellTool#PROP_RUN_AS_ROOT}.
* I (Aled) saw the .pid file having an owner of root:root, and a failure message in stderr of:
* -bash: line 3: /tmp/brooklyn-20150113-161203056-XMEo-move_install_dir_from_user_to_.pid: Permission denied
@@ -362,12 +357,12 @@ public class SshjTool extends SshAbstractTool implements SshTool {
private int stdoutCount = 0;
private int stderrCount = 0;
private Stopwatch timer;
-
+
public int run() {
timer = Stopwatch.createStarted();
final String scriptContents = toScript(props, commands, env);
if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as async script: {}", host, scriptContents);
-
+
// Upload script; try repeatedly because have seen timeout intermittently on vcloud-director (BROOKLYN-106 related).
boolean uploadSuccess = Repeater.create("async script upload on "+SshjTool.this.toString()+" (for "+getSummary()+")")
.backoffTo(maxDelayBetweenPolls)
@@ -389,14 +384,14 @@ public class SshjTool extends SshAbstractTool implements SshTool {
return true;
}})
.run();
-
+
if (!uploadSuccess) {
// Unexpected! Should have either returned true or have rethrown the exception; should never get false.
String msg = "Unexpected state: repeated failure for async script upload on "+SshjTool.this.toString()+" ("+getSummary()+")";
LOG.warn(msg+"; rethrowing");
throw new IllegalStateException(msg);
}
-
+
// Execute script asynchronously
int execResult = asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
if (execResult != 0) return execResult;
@@ -417,16 +412,16 @@ public class SshjTool extends SshAbstractTool implements SshTool {
return exitstatus != null;
}})
.run();
-
+
if (!success) {
// Timed out
String msg = "Timeout for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")";
LOG.warn(msg+"; rethrowing");
throw new TimeoutException(msg);
}
-
+
return result.get();
-
+
} catch (Exception e) {
LOG.debug("Problem polling for async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); rethrowing after deleting temporary files", e);
throw Exceptions.propagate(e);
@@ -445,13 +440,13 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
}
}
-
+
Integer longPoll() throws IOException {
// Long-polling to get stdout, stderr + exit status of async task.
// If our long-poll disconnects, we will just re-execute.
- // We wrap the stdout/stderr so that we can get the size count.
+ // We wrap the stdout/stderr so that we can get the size count.
// If we disconnect, we will pick up from that char of the stream.
- // TODO Additional stdout/stderr written by buildLongPollCommand() could interfere,
+ // TODO Additional stdout/stderr written by buildLongPollCommand() could interfere,
// causing us to miss some characters.
Duration nextPollTimeout = Duration.min(pollTimeout, Duration.millis(execTimeout.toMilliseconds()-timer.elapsed(TimeUnit.MILLISECONDS)));
CountingOutputStream countingOut = (out == null) ? null : new CountingOutputStream(out);
@@ -459,7 +454,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
List<String> pollCommand = buildLongPollCommand(stdoutCount, stderrCount, nextPollTimeout);
Duration sshJoinTimeout = nextPollTimeout.add(Duration.TEN_SECONDS);
ShellAction action = new ShellAction(pollCommand, countingOut, countingErr, sshJoinTimeout);
-
+
int longPollResult;
try {
longPollResult = asInt(acquire(action, 3, nextPollTimeout), -1);
@@ -469,11 +464,11 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
stdoutCount += (countingOut == null) ? 0 : countingOut.getCount();
stderrCount += (countingErr == null) ? 0 : countingErr.getCount();
-
+
if (longPollResult == 0) {
if (LOG.isDebugEnabled()) LOG.debug("Long-poll succeeded (exit status 0) on "+SshjTool.this.toString()+" (for "+getSummary()+")");
return longPollResult; // success
-
+
} else if (longPollResult == -1) {
// probably a connection failure; try again
if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
@@ -495,7 +490,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
return result;
}
}
-
+
consecutiveSshFailures++;
if (consecutiveSshFailures > maxConsecutiveSshFailures) {
LOG.warn("Aborting on "+consecutiveSshFailures+" consecutive ssh connection errors (return -1) when polling for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")");
@@ -505,14 +500,14 @@ public class SshjTool extends SshAbstractTool implements SshTool {
return null;
}
}
-
+
Integer retrieveStatusCommand() throws IOException {
// want to double-check whether this is the exit-code from the async process, or
// some unexpected failure in our long-poll command.
ByteArrayOutputStream statusOut = new ByteArrayOutputStream();
ByteArrayOutputStream statusErr = new ByteArrayOutputStream();
int statusResult = asInt(acquire(new ShellAction(buildRetrieveStatusCommand(), statusOut, statusErr, execTimeout)), -1);
-
+
if (statusResult == 0) {
// The status we retrieved really is valid; return it.
// TODO How to ensure no additional output in stdout/stderr when parsing below?
@@ -531,7 +526,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
// probably a connection failure; try again with long-poll
if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status directly received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
return null;
-
+
} else {
if (out != null) {
out.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stdout follow)"));
@@ -541,28 +536,28 @@ public class SshjTool extends SshAbstractTool implements SshTool {
err.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stderr follow)"));
err.write(statusErr.toByteArray());
}
-
+
if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status failed; returning "+statusResult+" on "+SshjTool.this.toString()+" (for "+getSummary()+")");
return statusResult;
}
}
}.run();
}
-
+
public int execShellDirect(Map<String,?> props, List<String> commands, Map<String,?> env) {
OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
Duration execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
-
+
List<String> cmdSequence = toCommandSequence(commands, env);
List<String> allcmds = ImmutableList.<String>builder()
.add(getOptionalVal(props, PROP_DIRECT_HEADER))
.addAll(cmdSequence)
.add("exit $?")
.build();
-
+
if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {}: {}", host, allcmds);
-
+
Integer result = acquire(new ShellAction(allcmds, out, err, execTimeout));
if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} completed: return status {}", host, result);
return asInt(result, -1);
@@ -573,7 +568,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
if (Boolean.FALSE.equals(props.get("blocks"))) {
throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
}
-
+
// If async is set, then do it as execScript
Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
@@ -591,14 +586,14 @@ public class SshjTool extends SshAbstractTool implements SshTool {
if (Boolean.TRUE.equals(getOptionalVal(props, PROP_RUN_AS_ROOT))) {
LOG.warn("Cannot run as root when executing as command; run as a script instead (will run as normal user): "+singlecmd);
}
-
+
if (LOG.isTraceEnabled()) LOG.trace("Running command at {}: {}", host, singlecmd);
-
+
Command result = acquire(new ExecAction(singlecmd, out, err, execTimeout));
if (LOG.isTraceEnabled()) LOG.trace("Running command at {} completed: exit code {}", host, result.getExitStatus());
// can be null if no exit status is received (observed on kill `ps aux | grep thing-to-grep-for | awk {print $2}`
if (result.getExitStatus()==null) LOG.warn("Null exit status running at {}: {}", host, singlecmd);
-
+
return asInt(result.getExitStatus(), -1);
}
@@ -615,16 +610,16 @@ public class SshjTool extends SshAbstractTool implements SshTool {
protected <T, C extends SshAction<T>> T acquire(C action) {
return acquire(action, sshTries, sshTriesTimeout == 0 ? Duration.PRACTICALLY_FOREVER : Duration.millis(sshTriesTimeout));
}
-
+
protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
Stopwatch stopwatch = Stopwatch.createStarted();
-
+
for (int i = 0; i < sshTries; i++) {
try {
action.clear();
if (LOG.isTraceEnabled()) LOG.trace(">> ({}) acquiring {}", toString(), action);
Stopwatch perfStopwatch = Stopwatch.createStarted();
-
+
T returnVal;
try {
returnVal = action.create();
@@ -633,25 +628,25 @@ public class SshjTool extends SshAbstractTool implements SshTool {
* TODO In net.schmizz.sshj.SSHClient.auth(SSHClient.java:204) throws AssertionError
* if not connected. This can happen if another thread has called disconnect
* concurrently. This is changed in sshj v0.9.0 to instead throw an IllegalStateException.
- *
+ *
* For now, we'll retry. See "TODO" at top of class about synchronization.
*/
throw new IllegalStateException("Problem in "+toString()+" for "+action, e);
}
-
+
if (LOG.isTraceEnabled()) LOG.trace("<< ({}) acquired {}", toString(), returnVal);
if (LOG.isTraceEnabled()) LOG.trace("SSH Performance: {} {} took {}", new Object[] {
- sshClientConnection.getHostAndPort(),
- action.getClass().getSimpleName() != null ? action.getClass().getSimpleName() : action,
+ sshClientConnection.getHostAndPort(),
+ action.getClass().getSimpleName() != null ? action.getClass().getSimpleName() : action,
Time.makeTimeStringRounded(perfStopwatch)});
return returnVal;
} catch (Exception e) {
- // uninformative net.schmizz.sshj.connection.ConnectionException:
+ // uninformative net.schmizz.sshj.connection.ConnectionException:
// Request failed (reason=UNKNOWN) may mean remote Subsytem is disabled (e.g. for FTP)
// if key is missing, get a UserAuth error
String errorMessage = String.format("(%s) error acquiring %s", toString(), action);
- String fullMessage = String.format("%s (attempt %s/%s, in time %s/%s)",
- errorMessage, (i+1), sshTries, Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)),
+ String fullMessage = String.format("%s (attempt %s/%s, in time %s/%s)",
+ errorMessage, (i+1), sshTries, Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)),
(sshTriesTimeout.equals(Duration.PRACTICALLY_FOREVER) ? "unlimited" : Time.makeTimeStringRounded(sshTriesTimeout)));
try {
disconnect();
@@ -700,7 +695,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
};
- private class GetFileAction implements SshAction<InputStream> {
+ private class GetFileAction implements SshAction<LocalDestFile> {
private final String path;
private SFTPClient sftp;
@@ -715,10 +710,11 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
@Override
- public InputStream create() throws Exception {
+ public LocalDestFile create() throws Exception {
sftp = acquire(sftpConnection);
- return new CloseFtpChannelOnCloseInputStream(
- sftp.getSFTPEngine().open(path).getInputStream(), sftp);
+ LocalDestFile localDestFile = new FileSystemFile(path);
+ sftp.get(path, localDestFile);
+ return localDestFile;
}
@Override
@@ -729,7 +725,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
private class PutFileAction implements SshAction<Void> {
// TODO support backup as a property?
-
+
private SFTPClient sftp;
private final String path;
private final int permissionsMask;
@@ -738,7 +734,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
private final int uid;
private final Supplier<InputStream> contentsSupplier;
private final Integer length;
-
+
PutFileAction(Map<String,?> props, String path, Supplier<InputStream> contentsSupplier, long length) {
String permissions = getOptionalVal(props, PROP_PERMISSIONS);
long lastModificationDateVal = getOptionalVal(props, PROP_LAST_MODIFICATION_DATE);
@@ -817,7 +813,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
};
}
-
+
protected SshAction<Session> newSessionAction() {
return new SshAction<Session>() {
@@ -853,18 +849,18 @@ public class SshjTool extends SshAbstractTool implements SshTool {
private final OutputStream out;
private final OutputStream err;
private final Duration timeout;
-
+
private Session session;
private Shell shell;
private StreamGobbler outgobbler;
private StreamGobbler errgobbler;
-
+
ExecAction(String command, OutputStream out, OutputStream err, Duration timeout) {
this.command = checkNotNull(command, "command");
this.out = out;
this.err = err;
- Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0)
- ? Duration.PRACTICALLY_FOREVER
+ Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0)
+ ? Duration.PRACTICALLY_FOREVER
: Duration.millis(sshClientConnection.getSessionTimeout());
this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
}
@@ -883,9 +879,9 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public Command create() throws Exception {
try {
session = acquire(newSessionAction());
-
+
Command output = session.exec(checkNotNull(command, "command"));
-
+
if (out != null) {
outgobbler = new StreamGobbler(output.getInputStream(), out, (Logger)null);
outgobbler.start();
@@ -897,7 +893,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
try {
output.join((int)Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE), TimeUnit.MILLISECONDS);
return output;
-
+
} finally {
// wait for all stdout/stderr to have been re-directed
try {
@@ -910,7 +906,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
Thread.currentThread().interrupt();
}
}
-
+
} finally {
clear();
}
@@ -929,7 +925,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
final OutputStream out;
@VisibleForTesting
final OutputStream err;
-
+
private Session session;
private Shell shell;
private StreamGobbler outgobbler;
@@ -940,8 +936,8 @@ public class SshjTool extends SshAbstractTool implements SshTool {
this.commands = checkNotNull(commands, "commands");
this.out = out;
this.err = err;
- Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0)
- ? Duration.PRACTICALLY_FOREVER
+ Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0)
+ ? Duration.PRACTICALLY_FOREVER
: Duration.millis(sshClientConnection.getSessionTimeout());
this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
}
@@ -960,9 +956,9 @@ public class SshjTool extends SshAbstractTool implements SshTool {
public Integer create() throws Exception {
try {
session = acquire(newSessionAction());
-
+
shell = session.startShell();
-
+
if (out != null) {
InputStream outstream = shell.getInputStream();
outgobbler = new StreamGobbler(outstream, out, (Logger)null);
@@ -973,7 +969,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
errgobbler = new StreamGobbler(errstream, err, (Logger)null);
errgobbler.start();
}
-
+
OutputStream output = shell.getOutputStream();
for (CharSequence cmd : commands) {
@@ -990,12 +986,8 @@ public class SshjTool extends SshAbstractTool implements SshTool {
}
}
}
- // workaround attempt for SSHJ deadlock - https://github.com/shikhar/sshj/issues/105
- synchronized (shell.getOutputStream()) {
- shell.sendEOF();
- }
closeWhispering(output, this);
-
+
boolean timedOut = false;
try {
long timeoutMillis = Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE);
@@ -1006,8 +998,8 @@ public class SshjTool extends SshAbstractTool implements SshTool {
// shell closed, and exit status returned
break;
boolean endBecauseReturned =
- // if either condition is satisfied, then wait 1s in hopes the other does, then return
- (!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
+ // if either condition is satisfied, then wait 1s in hopes the other does, then return
+ (!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
try {
shell.join(1000, TimeUnit.MILLISECONDS);
} catch (ConnectionException e) {
@@ -1016,7 +1008,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
if (endBecauseReturned) {
// shell is still open, ie some process is running
// but we have a result code, so main shell is finished
- // we waited one second extra to allow any background process
+ // we waited one second extra to allow any background process
// which is nohupped to really be in the background (#162)
// now let's bail out
break;
@@ -1051,7 +1043,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
Thread.currentThread().interrupt();
}
}
-
+
} finally {
clear();
}
@@ -1066,7 +1058,7 @@ public class SshjTool extends SshAbstractTool implements SshTool {
private byte[] toUTF8ByteArray(String string) {
return org.bouncycastle.util.Strings.toUTF8ByteArray(string);
}
-
+
private Supplier<InputStream> newInputStreamSupplier(final byte[] contents) {
return new Supplier<InputStream>() {
@Override public InputStream get() {
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c3de6287/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index fea6e19..3cf38b2 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -430,7 +430,7 @@
<version>${commons-compress.version}</version>
</dependency>
<dependency>
- <groupId>net.schmizz</groupId>
+ <groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>${sshj.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c3de6287/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 9ca5234..7e7e0d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -120,7 +120,7 @@
<ivy.version>2.2.0</ivy.version>
<mx4j.version>3.0.1</mx4j.version>
<bouncycastle.version>1.49</bouncycastle.version>
- <sshj.version>0.8.1</sshj.version>
+ <sshj.version>0.12.0</sshj.version>
<felix.framework.version>5.4.0</felix.framework.version>
<reflections.version>0.9.9-RC1</reflections.version>
<jetty.version>9.2.13.v20150730</jetty.version>