mirror of https://github.com/apache/jclouds.git
Issue 632:enhance and automatically work around nodes with sftp problems
This commit is contained in:
parent
b09c81177b
commit
f3a0e6d0bd
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.ssh;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class ChannelNotOpenException extends SshException {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 129347129837129837l;
|
||||
|
||||
public ChannelNotOpenException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ChannelNotOpenException(String arg0, Throwable arg1) {
|
||||
super(arg0, arg1);
|
||||
}
|
||||
|
||||
public ChannelNotOpenException(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
public ChannelNotOpenException(Throwable arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,7 @@ import org.jclouds.io.Payload;
|
|||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.net.IPSocket;
|
||||
import org.jclouds.ssh.ChannelNotOpenException;
|
||||
import org.jclouds.ssh.SshClient;
|
||||
import org.jclouds.ssh.SshException;
|
||||
import org.jclouds.util.Strings2;
|
||||
|
@ -58,6 +59,7 @@ import com.google.inject.Inject;
|
|||
import com.jcraft.jsch.ChannelExec;
|
||||
import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
/**
|
||||
|
@ -114,7 +116,7 @@ public class JschSshClient implements SshClient {
|
|||
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
|
||||
|
||||
public JschSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, IPSocket socket, int timeout,
|
||||
String username, String password, byte[] privateKey) {
|
||||
String username, String password, byte[] privateKey) {
|
||||
this.host = checkNotNull(socket, "socket").getAddress();
|
||||
checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort());
|
||||
checkArgument(password != null || privateKey != null, "you must specify a password or a key");
|
||||
|
@ -222,10 +224,15 @@ public class JschSshClient implements SshClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ChannelSftp create() throws Exception {
|
||||
public ChannelSftp create() throws JSchException {
|
||||
checkConnected();
|
||||
sftp = (ChannelSftp) session.openChannel("sftp");
|
||||
sftp.connect();
|
||||
String channel = "sftp";
|
||||
sftp = (ChannelSftp) session.openChannel(channel);
|
||||
try {
|
||||
sftp.connect();
|
||||
} catch (JSchException e) {
|
||||
throwChannelNotOpenExceptionOrPropagate(channel, e);
|
||||
}
|
||||
return sftp;
|
||||
}
|
||||
|
||||
|
@ -235,6 +242,11 @@ public class JschSshClient implements SshClient {
|
|||
}
|
||||
};
|
||||
|
||||
public void throwChannelNotOpenExceptionOrPropagate(String channel, JSchException e) throws JSchException {
|
||||
if (e.getMessage().indexOf("channel is not opened") != -1)
|
||||
throw new ChannelNotOpenException(String.format("(%s) channel %s is not open", toString() , channel), e);
|
||||
}
|
||||
|
||||
class GetConnection implements Connection<Payload> {
|
||||
private final String path;
|
||||
private ChannelSftp sftp;
|
||||
|
@ -285,7 +297,7 @@ public class JschSshClient implements SshClient {
|
|||
public Void create() throws Exception {
|
||||
sftp = acquire(sftpConnection);
|
||||
try {
|
||||
sftp.put(contents.getInput(), path);
|
||||
sftp.put(checkNotNull(contents.getInput(), "inputstream for path %s", path), path);
|
||||
} finally {
|
||||
Closeables.closeQuietly(contents);
|
||||
clear();
|
||||
|
@ -307,15 +319,17 @@ public class JschSshClient implements SshClient {
|
|||
@VisibleForTesting
|
||||
boolean shouldRetry(Exception from) {
|
||||
final String rootMessage = getRootCause(from).getMessage();
|
||||
if (rootMessage == null)
|
||||
return false;
|
||||
return any(getCausalChain(from), retryPredicate)
|
||||
|| Iterables.any(Splitter.on(",").split(retryableMessages), new Predicate<String>() {
|
||||
|| Iterables.any(Splitter.on(",").split(retryableMessages), new Predicate<String>() {
|
||||
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return rootMessage.indexOf(input) != -1;
|
||||
}
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
return rootMessage.indexOf(input) != -1;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void backoffForAttempt(int retryAttempt, String message) {
|
||||
|
@ -325,7 +339,8 @@ public class JschSshClient implements SshClient {
|
|||
private SshException propagate(Exception e, String message) {
|
||||
message += ": " + e.getMessage();
|
||||
logger.error(e, "<< " + message);
|
||||
throw new SshException(message, e);
|
||||
throw e instanceof SshException ? SshException.class.cast(e) : new SshException(
|
||||
"(" + toString() + ") " + message, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -338,30 +353,42 @@ public class JschSshClient implements SshClient {
|
|||
sessionConnection.clear();
|
||||
}
|
||||
|
||||
Connection<ChannelExec> execConnection = new Connection<ChannelExec>() {
|
||||
protected Connection<ChannelExec> execConnection(final String command) {
|
||||
checkNotNull(command, "command");
|
||||
return new Connection<ChannelExec>() {
|
||||
|
||||
private ChannelExec executor = null;
|
||||
private ChannelExec executor = null;
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (executor != null)
|
||||
executor.disconnect();
|
||||
}
|
||||
@Override
|
||||
public void clear() {
|
||||
if (executor != null)
|
||||
executor.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelExec create() throws Exception {
|
||||
checkConnected();
|
||||
executor = (ChannelExec) session.openChannel("exec");
|
||||
executor.setPty(true);
|
||||
return executor;
|
||||
}
|
||||
@Override
|
||||
public ChannelExec create() throws Exception {
|
||||
checkConnected();
|
||||
String channel = "exec";
|
||||
executor = (ChannelExec) session.openChannel(channel);
|
||||
executor.setPty(true);
|
||||
executor.setCommand(command);
|
||||
ByteArrayOutputStream error = new ByteArrayOutputStream();
|
||||
executor.setErrStream(error);
|
||||
try {
|
||||
executor.connect();
|
||||
} catch (JSchException e) {
|
||||
throwChannelNotOpenExceptionOrPropagate("exec", e);
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChannelExec(" + JschSshClient.this.toString() + ")";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChannelExec(" + JschSshClient.this.toString() + ")";
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class ExecConnection implements Connection<ExecResponse> {
|
||||
private final String command;
|
||||
|
@ -379,14 +406,10 @@ public class JschSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public ExecResponse create() throws Exception {
|
||||
executor = acquire(execConnection);
|
||||
executor.setCommand(command);
|
||||
ByteArrayOutputStream error = new ByteArrayOutputStream();
|
||||
executor.setErrStream(error);
|
||||
executor = acquire(execConnection(command));
|
||||
try {
|
||||
executor.connect();
|
||||
String outputString = Strings2.toStringAndClose(executor.getInputStream());
|
||||
String errorString = error.toString();
|
||||
String errorString = executor.getErrStream().toString();
|
||||
int errorStatus = executor.getExitStatus();
|
||||
int i = 0;
|
||||
String message = String.format("bad status -1 %s", toString());
|
||||
|
@ -407,8 +430,7 @@ public class JschSshClient implements SshClient {
|
|||
public String toString() {
|
||||
return "ExecResponse(" + JschSshClient.this.toString() + ")[" + command + "]";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public ExecResponse exec(String command) {
|
||||
return acquire(new ExecConnection(command));
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.jclouds.vcloud.terremark;
|
|||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
|
||||
import static org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh.PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP;
|
||||
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED;
|
||||
import static org.jclouds.vcloud.terremark.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NAME;
|
||||
import static org.jclouds.vcloud.terremark.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_VERSION;
|
||||
|
@ -44,8 +43,6 @@ public class TerremarkECloudPropertiesBuilder extends TerremarkVCloudPropertiesB
|
|||
properties.setProperty(PROPERTY_TERREMARK_EXTENSION_VERSION, "2.8");
|
||||
// default for ubuntu
|
||||
properties.setProperty(PROPERTY_VCLOUD_TIMEOUT_TASK_COMPLETED, 360l * 1000l + "");
|
||||
// ubuntu image has a problem with sftp
|
||||
properties.setProperty(PROPERTY_PUSH_INIT_SCRIPT_VIA_SFTP, "false");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue