in deploy-runner-agent/src/main/java/jetbrains/buildServer/deployer/agent/ssh/SSHExecProcessAdapter.java [73:156]
private BuildFinishedStatus executeCommand(Session session, String pty, String command) throws JSchException {
ChannelExec channel = null;
BuildFinishedStatus result = BuildFinishedStatus.FINISHED_SUCCESS;
myLogger.message("Executing commands:\n" + command + "\non host [" + session.getHost() + "]");
try {
channel = (ChannelExec) session.openChannel("exec");
if (!StringUtil.isEmpty(pty)) {
channel.setPty(true);
channel.setPtyType(pty);
}
channel.setAgentForwarding(myOptions.enableSshAgentForwarding());
channel.setCommand(command);
final AtomicLong lastOutputTimeStamp = new AtomicLong(System.currentTimeMillis());
final LineAwareByteArrayOutputStream.LineListener lineListener = new LineAwareByteArrayOutputStream.LineListener() {
@Override
public void newLineDetected(@NotNull String line) {
myLogger.message(line);
lastOutputTimeStamp.set(System.currentTimeMillis());
}
};
final LineAwareByteArrayOutputStream outputStream = new LineAwareByteArrayOutputStream(Charset.forName("UTF-8"), lineListener);
final StreamGobbler outputGobbler = new StreamGobbler(channel.getInputStream(), null, "SSH session to [" + session.getHost() + "]", outputStream);
final LineAwareByteArrayOutputStream errStream = new LineAwareByteArrayOutputStream(Charset.forName("UTF-8"), lineListener);
final StreamGobbler errGobbler = new StreamGobbler(channel.getErrStream(), null, "Unknown", errStream);
outputGobbler.start();
errGobbler.start();
channel.connect(CONNECTION_OPEN_TIMEOUT_MS);
while (!isInterrupted()
&& channel.isConnected()
&& !channel.isEOF()
&& !channel.isClosed()) {
try {
Thread.sleep(500);
// sometimes no newline chars are present, but still some output may be pending
final boolean hasSomePendingOutput = outputGobbler.getLastActivityTimestamp() > lastOutputTimeStamp.get();
final boolean waitingForTooLong = System.currentTimeMillis() - outputGobbler.getLastActivityTimestamp() > CONNECTION_SILENCE_THRESHOLD_MS;
if (waitingForTooLong && hasSomePendingOutput) {
// force dump of current pending output
outputStream.write("\n".getBytes(Charset.forName("UTF-8")));
}
} catch (InterruptedException e) {
checkIsInterrupted();
}
}
outputGobbler.notifyProcessExit();
errGobbler.notifyProcessExit();
try {
outputGobbler.join();
errGobbler.join();
} catch (InterruptedException e) {
LOG.warnAndDebugDetails("SSH command interrupted", e);
}
if (isInterrupted()) {
myLogger.message("Interrupted.");
}
} catch (IOException e) {
myLogger.error(e.toString());
LOG.warnAndDebugDetails(e.getMessage(), e);
result = BuildFinishedStatus.FINISHED_FAILED;
} finally {
if (channel != null) {
channel.disconnect();
int exitCode = channel.getExitStatus();
if (exitCode != 0) {
if (myOptions.shouldFailBuildOnExitCode()) {
logExitCodeBuildProblem(exitCode);
result = BuildFinishedStatus.FINISHED_WITH_PROBLEMS;
} else {
logBuildProblem(myLogger, "SSH exit-code [" + exitCode + "]");
}
} else {
myLogger.message("SSH exit-code [" + exitCode + "]");
}
}
}
return result;
}