Issue 721:Connect errors not automatically retried in sshj

This commit is contained in:
Adrian Cole 2011-10-14 10:39:50 -07:00
parent 9018bdafa2
commit 3a9ac55e4a
3 changed files with 20 additions and 4 deletions

View File

@ -30,6 +30,7 @@ import static org.jclouds.crypto.SshKeys.sha1PrivateKey;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.ConnectException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@ -58,6 +59,7 @@ import org.jclouds.net.IPSocket;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
import org.jclouds.util.Throwables2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -71,6 +73,7 @@ import com.google.inject.Inject;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@SuppressWarnings("unchecked")
public class SshjSshClient implements SshClient { public class SshjSshClient implements SshClient {
private final class CloseFtpChannelOnCloseInputStream extends ProxyInputStream { private final class CloseFtpChannelOnCloseInputStream extends ProxyInputStream {
@ -115,7 +118,7 @@ public class SshjSshClient implements SshClient {
@Named("jclouds.ssh.retry-predicate") @Named("jclouds.ssh.retry-predicate")
// NOTE cannot retry io exceptions, as SSHException is a part of the chain // NOTE cannot retry io exceptions, as SSHException is a part of the chain
private Predicate<Throwable> retryPredicate = or(instanceOf(ConnectionException.class), private Predicate<Throwable> retryPredicate = or(instanceOf(ConnectionException.class),
instanceOf(TransportException.class)); instanceOf(ConnectException.class), instanceOf(TransportException.class));
@Resource @Resource
@Named("jclouds.ssh") @Named("jclouds.ssh")
@ -222,11 +225,21 @@ public class SshjSshClient implements SshClient {
logger.warn(from, "<< (%s) error closing connection", toString()); logger.warn(from, "<< (%s) error closing connection", toString());
} }
if (i + 1 == sshRetries) { if (i + 1 == sshRetries) {
logger.error(from, "<< " + errorMessage + ": out of retries %d", sshRetries);
throw propagate(from, errorMessage); throw propagate(from, errorMessage);
} else if (Throwables2.getFirstThrowableOfType(from, IllegalStateException.class) != null) {
logger.warn(from, "<< " + errorMessage + ": " + from.getMessage());
disconnect();
backoffForAttempt(i + 1, errorMessage + ": " + from.getMessage());
connect();
continue;
} else if (shouldRetry(from)) { } else if (shouldRetry(from)) {
logger.warn(from, "<< " + errorMessage + ": " + from.getMessage()); logger.warn(from, "<< " + errorMessage + ": " + from.getMessage());
backoffForAttempt(i + 1, errorMessage + ": " + from.getMessage()); backoffForAttempt(i + 1, errorMessage + ": " + from.getMessage());
continue; continue;
} else {
logger.error(from, "<< " + errorMessage + ": exception not retryable");
throw propagate(from, errorMessage);
} }
} }
} }

View File

@ -127,7 +127,7 @@ public class SshjSshClientLiveTest {
temp.deleteOnExit(); temp.deleteOnExit();
SshClient client = setupClient(); SshClient client = setupClient();
client.put(temp.getAbsolutePath(), Payloads.newStringPayload("rabbit")); client.put(temp.getAbsolutePath(), Payloads.newStringPayload("rabbit"));
Payload input = setupClient().get(temp.getAbsolutePath()); Payload input = client.get(temp.getAbsolutePath());
String contents = Strings2.toStringAndClose(input.getInput()); String contents = Strings2.toStringAndClose(input.getInput());
assertEquals(contents, "rabbit"); assertEquals(contents, "rabbit");
} }
@ -138,8 +138,9 @@ public class SshjSshClientLiveTest {
assert contents.indexOf("root") >= 0 : "no root in " + contents; assert contents.indexOf("root") >= 0 : "no root in " + contents;
} }
public void testExecHostname() throws IOException { public void testExecHostname() throws IOException, InterruptedException {
ExecResponse response = setupClient().exec("hostname"); SshClient client = setupClient();
ExecResponse response = client.exec("hostname");
assertEquals(response.getError(), ""); assertEquals(response.getError(), "");
assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName() assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName()
: sshHost); : sshHost);

View File

@ -21,6 +21,7 @@ package org.jclouds.sshj;
import static com.google.inject.name.Names.bindProperties; import static com.google.inject.name.Names.bindProperties;
import java.io.IOException; import java.io.IOException;
import java.net.ConnectException;
import java.util.Properties; import java.util.Properties;
import net.schmizz.sshj.common.SSHException; import net.schmizz.sshj.common.SSHException;
@ -87,6 +88,7 @@ public class SshjSshClientTest {
public void testExceptionClassesRetry() { public void testExceptionClassesRetry() {
assert ssh.shouldRetry(new TransportException("socket closed")); assert ssh.shouldRetry(new TransportException("socket closed"));
assert ssh.shouldRetry(new ConnectionException("problem")); assert ssh.shouldRetry(new ConnectionException("problem"));
assert ssh.shouldRetry(new ConnectException("Connection refused"));
assert !ssh.shouldRetry(new IOException("channel %s is not open", new NullPointerException())); assert !ssh.shouldRetry(new IOException("channel %s is not open", new NullPointerException()));
} }