refactored ssh connections so that they can be shared across views

This commit is contained in:
Adrian Cole 2010-10-26 11:37:13 -07:00
parent c7c6e9eae1
commit b08abc6745
21 changed files with 335 additions and 148 deletions

View File

@ -37,12 +37,12 @@ import org.jclouds.aws.ec2.domain.Reservation;
import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.predicates.InstanceStateRunning;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.InetSocketAddressConnect;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.ScriptBuilder;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.ssh.jsch.predicates.InetSocketAddressConnect;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

View File

@ -21,9 +21,11 @@ package org.jclouds.compute;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.internal.UtilsImpl;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.inject.ImplementedBy;
/**
@ -37,4 +39,9 @@ public interface Utils extends org.jclouds.rest.Utils {
@Nullable
SshClient.Factory sshFactory();
/**
* @return function that gets an ssh client for a node that is available via ssh.
*/
Function<NodeMetadata, SshClient> sshForNode();
}

View File

@ -24,7 +24,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.compute.util.ComputeServiceUtils.SshCallable;
import org.jclouds.logging.Logger;
import org.jclouds.scriptbuilder.InitBuilder;
@ -32,6 +31,7 @@ import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import org.jclouds.util.Utils;
import com.google.common.collect.Iterables;
@ -93,7 +93,7 @@ public class InitAndStartScriptOnNode implements SshCallable<ExecResponse> {
String command;
if (node.getCredentials().identity.equals("root")) {
command = "./" + init.getInstanceName() + " " + action;
} else if (ComputeServiceUtils.isKeyAuth(node)) {
} else if (Utils.isPrivateKeyCredential(node.getCredentials())) {
command = "sudo ./" + init.getInstanceName() + " " + action;
} else {
command = String.format("echo '%s'|sudo -S ./%s %s", node.getCredentials().credential, init.getInstanceName(),

View File

@ -34,10 +34,13 @@ import org.jclouds.compute.LoadBalancerService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode;
import org.jclouds.domain.Location;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -47,6 +50,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Providers;
/**
@ -58,6 +62,8 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
protected void configure() {
install(new ComputeServiceTimeoutsModule());
bindLoadBalancerService();
bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() {
}).to(CreateSshClientOncePortIsListeningOnNode.class);
}
protected void bindLoadBalancerService() {

View File

@ -30,9 +30,7 @@ import org.jclouds.compute.predicates.NodeTerminated;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import com.google.common.base.Predicate;
import com.google.inject.AbstractModule;
@ -50,7 +48,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Named("NODE_RUNNING")
protected Predicate<NodeMetadata> nodeRunning(NodeRunning stateRunning, Timeouts timeouts) {
return timeouts.nodeRunning == 0 ? stateRunning : new RetryablePredicate<NodeMetadata>(stateRunning,
timeouts.nodeRunning);
timeouts.nodeRunning);
}
@Provides
@ -58,7 +56,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Named("NODE_TERMINATED")
protected Predicate<NodeMetadata> serverTerminated(NodeTerminated stateTerminated, Timeouts timeouts) {
return timeouts.nodeTerminated == 0 ? stateTerminated : new RetryablePredicate<NodeMetadata>(stateTerminated,
timeouts.nodeTerminated);
timeouts.nodeTerminated);
}
@Provides
@ -66,13 +64,7 @@ public class ComputeServiceTimeoutsModule extends AbstractModule {
@Named("SCRIPT_COMPLETE")
protected Predicate<CommandUsingClient> runScriptRunning(ScriptStatusReturnsZero stateRunning, Timeouts timeouts) {
return timeouts.scriptComplete == 0 ? not(stateRunning) : new RetryablePredicate<CommandUsingClient>(
not(stateRunning), timeouts.scriptComplete);
}
@Provides
@Singleton
protected Predicate<IPSocket> socketTester(SocketOpen open, Timeouts timeouts) {
return timeouts.portOpen == 0 ? open : new RetryablePredicate<IPSocket>(open, timeouts.portOpen);
not(stateRunning), timeouts.scriptComplete);
}
@Override

View File

@ -45,7 +45,7 @@ public class NodeMetadataBuilder extends ComputeMetadataBuilder {
private Credentials credentials;
@Nullable
private String tag;
private int loginPort;
private int loginPort = 22;
@Nullable
private String imageId;
@Nullable

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2010 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.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import javax.inject.Singleton;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.net.IPSocket;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.inject.Inject;
/**
*
* @author Adrian Cole
*
*/
@Singleton
public class CreateSshClientOncePortIsListeningOnNode implements Function<NodeMetadata, SshClient> {
@Inject(optional = true)
SshClient.Factory sshFactory;
private final RetryIfSocketNotYetOpen socketTester;
@Inject
public CreateSshClientOncePortIsListeningOnNode(RetryIfSocketNotYetOpen socketTester) {
this.socketTester = socketTester;
}
@Override
public SshClient apply(NodeMetadata node) {
checkState(sshFactory != null, "ssh requested, but no SshModule configured");
checkNotNull(node.getCredentials(), "credentials for node " + node.getName());
checkNotNull(node.getCredentials().credential, "credentials.credential for node " + node.getName());
IPSocket socket = ComputeServiceUtils.findReachableSocketOnNode(socketTester, node, node.getLoginPort());
return sshFactory.create(socket, node.getCredentials());
}
}

View File

@ -26,14 +26,17 @@ import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.compute.Utils;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.DateService;
import org.jclouds.json.Json;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rest.HttpAsyncClient;
import org.jclouds.rest.HttpClient;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshClient.Factory;
import com.google.common.base.Function;
import com.google.inject.Inject;
/**
@ -44,15 +47,15 @@ import com.google.inject.Inject;
public class UtilsImpl extends org.jclouds.rest.internal.UtilsImpl implements Utils {
@Inject(optional = true)
private Factory sshFactory;
private final Function<NodeMetadata, SshClient> sshForNode;
@Inject
UtilsImpl(Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient,
Crypto encryption, DateService date,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads,
LoggerFactory loggerFactory) {
super(json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads,
loggerFactory);
UtilsImpl(Json json, HttpClient simpleClient, HttpAsyncClient simpleAsyncClient, Crypto encryption,
DateService date, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ExecutorService ioThreads, LoggerFactory loggerFactory,
Function<NodeMetadata, SshClient> sshForNode) {
super(json, simpleClient, simpleAsyncClient, encryption, date, userThreads, ioThreads, loggerFactory);
this.sshForNode = sshForNode;
}
@Override
@ -65,4 +68,9 @@ public class UtilsImpl extends org.jclouds.rest.internal.UtilsImpl implements Ut
return sshFactory;
}
@Override
public Function<NodeMetadata, SshClient> sshForNode() {
return sshForNode;
}
}

View File

@ -0,0 +1,86 @@
/**
*
* Copyright (C) 2010 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.compute.predicates;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import com.google.common.base.Predicate;
/**
*
*
* Not singleton as seconds are mutable
*
* @author Adrian Cole
*
*/
public class RetryIfSocketNotYetOpen implements Predicate<IPSocket> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
private Logger logger = Logger.NULL;
private final SocketOpen socketTester;
private long seconds;
public RetryIfSocketNotYetOpen seconds(long seconds) {
this.seconds = seconds;
return this;
}
@Inject
public RetryIfSocketNotYetOpen(SocketOpen socketTester, Timeouts timeouts) {
this.socketTester = socketTester;
this.seconds = timeouts.portOpen;
}
public RetryIfSocketNotYetOpen(SocketOpen socketTester, Logger logger, long seconds) {
this.socketTester = socketTester;
this.logger = logger;
this.seconds = seconds;
}
@Override
public String toString() {
return "retryIfSocketNotYetOpen(" + seconds + ")";
}
@Override
public boolean apply(IPSocket socket) {
logger.debug(">> blocking on socket %s for %d seconds", socket, seconds);
RetryablePredicate<IPSocket> tester = new RetryablePredicate<IPSocket>(socketTester, seconds, 1, TimeUnit.SECONDS);
boolean passed = tester.apply(socket);
if (passed)
logger.debug("<< socket %s opened", socket);
else
logger.warn("<< socket %s didn't open after %d seconds", socket, seconds);
return passed;
}
}

View File

@ -19,10 +19,15 @@
package org.jclouds.compute.util;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getStackTraceAsString;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash;
import static org.jclouds.util.Utils.getSupportedProvidersOfType;
import java.net.URI;
import java.util.Formatter;
@ -33,6 +38,7 @@ import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jclouds.compute.ComputeServiceContextBuilder;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.Hardware;
@ -40,13 +46,15 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.http.HttpRequest;
import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
@ -212,13 +220,33 @@ public class ComputeServiceUtils {
void setConnection(SshClient ssh, Logger logger);
}
public static boolean isKeyAuth(NodeMetadata createdNode) {
return createdNode.getCredentials().credential != null
&& createdNode.getCredentials().credential.startsWith("-----BEGIN RSA PRIVATE KEY-----");
public static Iterable<String> getSupportedProviders() {
return getSupportedProvidersOfType(ComputeServiceContextBuilder.class);
}
public static Iterable<String> getSupportedProviders() {
return Utils.getSupportedProvidersOfType(ComputeServiceContextBuilder.class);
public static IPSocket findReachableSocketOnNode(RetryIfSocketNotYetOpen socketTester, final NodeMetadata node,
final int port) {
checkNodeHasIps(node);
IPSocket socket = null;
try {
socket = find(
transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()),
new Function<String, IPSocket>() {
@Override
public IPSocket apply(String from) {
return new IPSocket(from, port);
}
}), socketTester);
} catch (NoSuchElementException e) {
throw new RuntimeException(String.format("could not connect to any ip address port %d on node %s", port, node));
}
return socket;
}
public static void checkNodeHasIps(NodeMetadata node) {
checkState(size(concat(node.getPublicAddresses(), node.getPrivateAddresses())) > 0,
"node does not have IP addresses configured: " + node);
}
}

View File

@ -19,9 +19,12 @@
package org.jclouds.compute.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.compute.util.ComputeServiceUtils.isKeyAuth;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static org.jclouds.compute.util.ComputeServiceUtils.findReachableSocketOnNode;
import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
import java.util.List;
@ -31,11 +34,11 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
@ -45,14 +48,13 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.util.ComputeServiceUtils.SshCallable;
import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.scriptbuilder.domain.AuthorizeRSAPublicKey;
import org.jclouds.scriptbuilder.domain.InstallRSAPrivateKey;
import org.jclouds.scriptbuilder.domain.Statement;
@ -60,11 +62,8 @@ import org.jclouds.scriptbuilder.domain.StatementList;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
/**
@ -76,20 +75,20 @@ public class ComputeUtils {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
protected SshClient.Factory sshFactory;
protected final Function<NodeMetadata, SshClient> sshFactory;
protected final Predicate<CommandUsingClient> runScriptNotRunning;
protected final Predicate<IPSocket> socketTester;
protected final Provider<RetryIfSocketNotYetOpen> socketTester;
protected final ExecutorService executor;
protected final Predicate<NodeMetadata> nodeRunning;
protected final GetNodeMetadataStrategy getNode;
protected final Timeouts timeouts;
@Inject
public ComputeUtils(Predicate<IPSocket> socketTester,
public ComputeUtils(Provider<RetryIfSocketNotYetOpen> socketTester, Function<NodeMetadata, SshClient> sshFactory,
@Named("SCRIPT_COMPLETE") Predicate<CommandUsingClient> runScriptNotRunning, GetNodeMetadataStrategy getNode,
Timeouts timeouts, @Named("NODE_RUNNING") Predicate<NodeMetadata> nodeRunning,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.sshFactory = sshFactory;
this.nodeRunning = nodeRunning;
this.timeouts = timeouts;
this.getNode = getNode;
@ -101,7 +100,7 @@ public class ComputeUtils {
public Map<?, Future<Void>> runOptionsOnNodesAndAddToGoodSetOrPutExceptionIntoBadMap(final TemplateOptions options,
Iterable<NodeMetadata> runningNodes, final Set<NodeMetadata> goodNodes,
final Map<NodeMetadata, Exception> badNodes) {
Map<NodeMetadata, Future<Void>> responses = Maps.newHashMap();
Map<NodeMetadata, Future<Void>> responses = newHashMap();
for (final NodeMetadata node : runningNodes) {
responses.put(node, executor.submit(runOptionsOnNodeAndAddToGoodSetOrPutExceptionIntoBadMap(node, badNodes,
goodNodes, options)));
@ -119,8 +118,7 @@ public class ComputeUtils {
logger.debug("<< options applied node(%s)", node1.getId());
goodNodes.add(node1);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), Throwables.getRootCause(e)
.getMessage());
logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage());
badNodes.put(node, e);
}
return null;
@ -133,13 +131,13 @@ public class ComputeUtils {
return node;
if (nodeRunning.apply(node))
node = NodeMetadataBuilder.fromNodeMetadata(getNode.getNode(node.getId()))
.credentials(node.getCredentials()).build();
node = NodeMetadataBuilder.fromNodeMetadata(getNode.getNode(node.getId())).credentials(node.getCredentials())
.build();
else
throw new IllegalStateException(String.format(
"node didn't achieve the state running on node %s within %d seconds, final state: %s", node.getId(),
timeouts.nodeRunning / 1000, node.getState()));
List<Statement> bootstrap = Lists.newArrayList();
List<Statement> bootstrap = newArrayList();
if (options.getRunScript() != null)
bootstrap.add(options.getRunScript());
if (options.getPublicKey() != null)
@ -151,14 +149,10 @@ public class ComputeUtils {
return node;
}
public void checkNodeHasPublicIps(NodeMetadata node) {
checkState(node.getPublicAddresses().size() > 0, "node does not have IP addresses configured: " + node);
}
public ExecResponse runScriptOnNode(NodeMetadata node, Statement runScript, RunScriptOptions options) {
InitAndStartScriptOnNode callable = generateScript(node, runScript, options);
ExecResponse response;
SshClient ssh = createSshClientOncePortIsListeningOnNode(node);
SshClient ssh = sshFactory.apply(node);
try {
ssh.connect();
callable.setConnection(ssh, logger);
@ -168,24 +162,11 @@ public class ComputeUtils {
ssh.disconnect();
}
if (options.getPort() > 0) {
checkNodeHasPublicIps(node);
blockUntilPortIsListeningOnPublicIp(options.getPort(), options.getSeconds(),
Iterables.get(node.getPublicAddresses(), 0));
findReachableSocketOnNode(socketTester.get().seconds(options.getSeconds()), node, options.getPort());
}
return response;
}
public void blockUntilPortIsListeningOnPublicIp(int port, int seconds, String inetAddress) {
logger.debug(">> blocking on port %s:%d for %d seconds", inetAddress, port, seconds);
RetryablePredicate<IPSocket> tester = new RetryablePredicate<IPSocket>(socketTester, seconds, 1, TimeUnit.SECONDS);
IPSocket socket = new IPSocket(inetAddress, port);
boolean passed = tester.apply(socket);
if (passed)
logger.debug("<< port %s:%d opened", inetAddress, port);
else
logger.warn("<< port %s:%d didn't open after %d seconds", inetAddress, port, seconds);
}
public InitAndStartScriptOnNode generateScript(NodeMetadata node, Statement script, RunScriptOptions options) {
return options.shouldBlockOnComplete() ? new RunScriptOnNode(runScriptNotRunning, node, options.getTaskName(),
script, options.shouldRunAsRoot()) : new InitAndStartScriptOnNode(node, options.getTaskName(), script,
@ -194,11 +175,7 @@ public class ComputeUtils {
public Map<SshCallable<?>, ?> runCallablesOnNode(NodeMetadata node, Iterable<SshCallable<?>> parallel,
@Nullable SshCallable<?> last) {
checkState(this.sshFactory != null, "runScript requested, but no SshModule configured");
checkNodeHasPublicIps(node);
checkNotNull(node.getCredentials(), "credentials for node " + node.getName());
checkNotNull(node.getCredentials().credential, "credentials.credential for node " + node.getName());
SshClient ssh = createSshClientOncePortIsListeningOnNode(node);
SshClient ssh = sshFactory.apply(node);
try {
ssh.connect();
return runTasksUsingSshClient(parallel, last, ssh);
@ -210,8 +187,8 @@ public class ComputeUtils {
private Map<SshCallable<?>, ?> runTasksUsingSshClient(Iterable<SshCallable<?>> parallel, SshCallable<?> last,
SshClient ssh) {
Map<SshCallable<?>, Object> responses = Maps.newHashMap();
if (Iterables.size(parallel) > 0) {
Map<SshCallable<?>, Object> responses = newHashMap();
if (size(parallel) > 0) {
responses.putAll(runCallablesUsingSshClient(parallel, ssh));
}
if (last != null) {
@ -219,24 +196,15 @@ public class ComputeUtils {
try {
responses.put(last, last.call());
} catch (Exception e) {
Throwables.propagate(e);
propagate(e);
}
}
return responses;
}
public SshClient createSshClientOncePortIsListeningOnNode(NodeMetadata node) {
IPSocket socket = new IPSocket(Iterables.get(node.getPublicAddresses(), 0), 22);
socketTester.apply(socket);
SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().identity,
node.getCredentials().credential.getBytes()) : sshFactory.create(socket, node.getCredentials().identity,
node.getCredentials().credential);
return ssh;
}
// TODO refactor
private Map<SshCallable<?>, Object> runCallablesUsingSshClient(Iterable<SshCallable<?>> parallel, SshClient ssh) {
Map<SshCallable<?>, Future<?>> parallelResponses = Maps.newHashMap();
Map<SshCallable<?>, Future<?>> parallelResponses = newHashMap();
for (SshCallable<?> callable : parallel) {
callable.setConnection(ssh, logger);
@ -252,14 +220,14 @@ public class ComputeUtils {
@SuppressWarnings("unchecked")
public <T> Map<SshCallable<?>, T> transform(Map<SshCallable<?>, Future<?>> responses) {
Map<SshCallable<?>, T> actualResponses = Maps.newHashMap();
Map<SshCallable<?>, T> actualResponses = newHashMap();
for (Map.Entry<SshCallable<?>, Future<?>> entry : responses.entrySet()) {
try {
actualResponses.put(entry.getKey(), (T) entry.getValue().get());
} catch (InterruptedException e) {
throw Throwables.propagate(e);
throw propagate(e);
} catch (ExecutionException e) {
throw Throwables.propagate(e);
throw propagate(e);
}
}
return actualResponses;

View File

@ -564,20 +564,7 @@ public abstract class BaseComputeServiceLiveTest {
}
protected void doCheckJavaIsInstalledViaSsh(NodeMetadata node) throws IOException {
IPSocket socket = new IPSocket(get(node.getPublicAddresses(), 0), 22);
socketTester.apply(socket); // TODO add transitionTo option that accepts
// a socket conection
// state.
SshClient ssh = (node.getCredentials().credential != null && !node.getCredentials().credential
.startsWith("-----BEGIN RSA PRIVATE KEY-----")) ? context.utils().sshFactory()
.create(socket, node.getCredentials().identity, node.getCredentials().credential) : context
.utils()
.sshFactory()
.create(
socket,
node.getCredentials().identity,
node.getCredentials().credential != null ? node.getCredentials().credential.getBytes() : keyPair.get(
"private").getBytes());
SshClient ssh = context.utils().sshForNode().apply(node);
try {
ssh.connect();
ExecResponse hello = ssh.exec("echo hello");

View File

@ -19,7 +19,6 @@
package org.jclouds.compute;
import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.reportMatcher;
@ -41,6 +40,7 @@ import org.easymock.IArgumentMatcher;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template;
import org.jclouds.domain.Credentials;
import org.jclouds.io.Payload;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
@ -120,15 +120,14 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
SshClient client4 = createMock(SshClient.class);
SshClient client5 = createMock(SshClient.class);
expect(factory.create(new IPSocket("144.175.1.1", 22), "root", "password1")).andReturn(client1)
.atLeastOnce();
expect(factory.create(new IPSocket("144.175.1.1", 22), new Credentials("root", "password1"))).andReturn(
client1);
runScriptAndService(client1, 1);
expect(factory.create(new IPSocket("144.175.1.2", 22), "root", "romeo")).andThrow(
expect(factory.create(new IPSocket("144.175.1.2", 22), new Credentials("root", "password2"))).andReturn(
client2).times(2);
expect(factory.create(new IPSocket("144.175.1.2", 22), new Credentials("root", "romeo"))).andThrow(
new SshException("Auth fail"));
expect(factory.create(new IPSocket("144.175.1.2", 22), "root", "password2")).andReturn(client2)
.atLeastOnce();
client2.connect();
try {
runScript(client2, "runScriptWithCreds", Utils.toStringAndClose(StubComputeServiceIntegrationTest.class
@ -138,32 +137,32 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
}
client2.disconnect();
expect(factory.create(new IPSocket("144.175.1.3", 22), "root", "password3")).andReturn(client3)
.atLeastOnce();
expect(factory.create(new IPSocket("144.175.1.4", 22), "root", "password4")).andReturn(client4)
.atLeastOnce();
expect(factory.create(new IPSocket("144.175.1.5", 22), "root", "password5")).andReturn(client5)
.atLeastOnce();
expect(factory.create(new IPSocket("144.175.1.3", 22), new Credentials("root", "password3"))).andReturn(
client3).times(2);
expect(factory.create(new IPSocket("144.175.1.4", 22), new Credentials("root", "password4"))).andReturn(
client4).times(2);
expect(factory.create(new IPSocket("144.175.1.5", 22), new Credentials("root", "password5"))).andReturn(
client5).times(2);
runScriptAndInstallSsh(client3, "bootstrap", 3);
runScriptAndInstallSsh(client4, "bootstrap", 4);
runScriptAndInstallSsh(client5, "bootstrap", 5);
expect(
factory.create(eq(new IPSocket("144.175.1.1", 22)), eq("root"), aryEq(keyPair.get("private")
.getBytes()))).andReturn(client1).atLeastOnce();
factory.create(eq(new IPSocket("144.175.1.1", 22)),
eq(new Credentials("root", keyPair.get("private"))))).andReturn(client1);
expect(
factory.create(eq(new IPSocket("144.175.1.2", 22)), eq("root"), aryEq(keyPair.get("private")
.getBytes()))).andReturn(client2).atLeastOnce();
factory.create(eq(new IPSocket("144.175.1.2", 22)),
eq(new Credentials("root", keyPair.get("private"))))).andReturn(client2);
expect(
factory.create(eq(new IPSocket("144.175.1.3", 22)), eq("root"), aryEq(keyPair.get("private")
.getBytes()))).andReturn(client3).atLeastOnce();
factory.create(eq(new IPSocket("144.175.1.3", 22)),
eq(new Credentials("root", keyPair.get("private"))))).andReturn(client3);
expect(
factory.create(eq(new IPSocket("144.175.1.4", 22)), eq("root"), aryEq(keyPair.get("private")
.getBytes()))).andReturn(client4).atLeastOnce();
factory.create(eq(new IPSocket("144.175.1.4", 22)),
eq(new Credentials("root", keyPair.get("private"))))).andReturn(client4);
expect(
factory.create(eq(new IPSocket("155.175.1.5", 22)), eq("root"), aryEq(keyPair.get("private")
.getBytes()))).andReturn(client5).atLeastOnce();
factory.create(eq(new IPSocket("144.175.1.5", 22)),
eq(new Credentials("root", keyPair.get("private"))))).andReturn(client5);
helloAndJava(client2);
helloAndJava(client3);

View File

@ -17,7 +17,7 @@
* ====================================================================
*/
package org.jclouds.ssh.jsch.predicates;
package org.jclouds.predicates;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -29,7 +29,6 @@ import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.SocketOpen;
import com.google.inject.Inject;

View File

@ -58,6 +58,8 @@ import javax.annotation.Nullable;
import javax.annotation.Resource;
import org.jclouds.PropertiesBuilder;
import org.jclouds.crypto.Pems;
import org.jclouds.domain.Credentials;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContextBuilder;
@ -246,15 +248,14 @@ public class Utils {
}
/**
* Encode the given string with the given encoding, if possible. If the
* encoding fails with {@link UnsupportedEncodingException}, log a warning
* and fall back to the system's default encoding.
* Encode the given string with the given encoding, if possible. If the encoding fails with
* {@link UnsupportedEncodingException}, log a warning and fall back to the system's default
* encoding.
*
* @param str
* what to encode
* @param charsetName
* the name of a supported {@link java.nio.charset.Charset
* </code>charset<code>}
* the name of a supported {@link java.nio.charset.Charset </code>charset<code>}
* @return properly encoded String.
*/
public static byte[] encodeString(String str, String charsetName) {
@ -268,10 +269,9 @@ public class Utils {
}
/**
* Encode the given string with the UTF-8 encoding, the sane default. In the
* very unlikely event the encoding fails with
* {@link UnsupportedEncodingException}, log a warning and fall back to the
* system's default encoding.
* Encode the given string with the UTF-8 encoding, the sane default. In the very unlikely event
* the encoding fails with {@link UnsupportedEncodingException}, log a warning and fall back to
* the system's default encoding.
*
* @param str
* what to encode
@ -322,8 +322,7 @@ public class Utils {
}
/**
* Will throw an exception if the argument is null or empty. Accepts a custom
* error message.
* Will throw an exception if the argument is null or empty. Accepts a custom error message.
*
* @param nullableString
* string to verify. Can be null or empty.
@ -335,8 +334,8 @@ public class Utils {
}
/**
* Gets a set of supported providers. Idea stolen from pallets
* (supported-clouds). Uses rest.properties to populate the set.
* Gets a set of supported providers. Idea stolen from pallets (supported-clouds). Uses
* rest.properties to populate the set.
*
*/
public static Iterable<String> getSupportedProviders() {
@ -344,8 +343,8 @@ public class Utils {
}
/**
* Gets a set of supported providers. Idea stolen from pallets
* (supported-clouds). Uses rest.properties to populate the set.
* Gets a set of supported providers. Idea stolen from pallets (supported-clouds). Uses
* rest.properties to populate the set.
*
*/
@SuppressWarnings("unchecked")
@ -468,4 +467,24 @@ public class Utils {
}
return modules;
}
public static boolean isPrivateKeyCredential(Credentials credentials) {
return credentials != null
&& credentials.credential != null
&& (credentials.credential.startsWith(Pems.PRIVATE_PKCS1_MARKER) || credentials.credential
.startsWith(Pems.PRIVATE_PKCS8_MARKER));
}
public static Credentials overrideCredentialsIfSupplied(Credentials defaultCredentials,
@Nullable Credentials overridingCredentials) {
if (overridingCredentials == null)
return defaultCredentials;
String identity = overridingCredentials.identity != null ? overridingCredentials.identity : checkNotNull(
defaultCredentials, "defaultCredentials").identity;
String credential = overridingCredentials.credential != null ? overridingCredentials.credential : checkNotNull(
defaultCredentials, "defaultCredentials").credential;
return new Credentials(identity, credential);
}
}

View File

@ -25,6 +25,7 @@ import static org.testng.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeoutException;
import org.jclouds.domain.Credentials;
import org.jclouds.rest.AuthorizationException;
import org.testng.annotations.Test;
@ -42,6 +43,33 @@ import com.google.inject.spi.Message;
@Test(groups = "unit", testName = "jclouds.UtilsTest")
public class UtilsTest {
public void testOverridingCredentialsWhenOverridingIsNull() {
Credentials defaultCredentials = new Credentials("foo", "bar");
Credentials overridingCredentials = null;
assertEquals(Utils.overrideCredentialsIfSupplied(defaultCredentials, overridingCredentials), defaultCredentials);
}
public void testOverridingCredentialsWhenOverridingLoginIsNull() {
Credentials defaultCredentials = new Credentials("foo", "bar");
Credentials overridingCredentials = new Credentials(null, "baz");
assertEquals(Utils.overrideCredentialsIfSupplied(defaultCredentials, overridingCredentials), new Credentials(
"foo", "baz"));
}
public void testOverridingCredentialsWhenOverridingCredentialIsNull() {
Credentials defaultCredentials = new Credentials("foo", "bar");
Credentials overridingCredentials = new Credentials("fooble", null);
assertEquals(Utils.overrideCredentialsIfSupplied(defaultCredentials, overridingCredentials), new Credentials(
"fooble", "bar"));
}
public void testOverridingCredentialsWhenOverridingCredentialsAreNull() {
Credentials defaultCredentials = new Credentials("foo", "bar");
Credentials overridingCredentials = new Credentials(null, null);
assertEquals(Utils.overrideCredentialsIfSupplied(defaultCredentials, overridingCredentials), new Credentials(
"foo", "bar"));
}
public void testGetCause() {
AuthorizationException aex = createMock(AuthorizationException.class);
Message message = new Message(ImmutableList.of(), "test", aex);

View File

@ -59,11 +59,11 @@ import org.jclouds.gogrid.predicates.ServerLatestJobCompleted;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.InetSocketAddressConnect;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rest.RestContext;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.jsch.JschSshClient;
import org.jclouds.ssh.jsch.predicates.InetSocketAddressConnect;
import org.testng.SkipException;
import org.testng.TestException;
import org.testng.annotations.AfterTest;

View File

@ -117,7 +117,7 @@ public class RackspaceAuthenticationRestModule extends AbstractModule {
@Provides
@Singleton
@CloudFiles
protected URI provideStorageUrl(AuthenticationResponse response) {
protected URI providestroageUrl(AuthenticationResponse response) {
return response.getStorageUrl();
}

View File

@ -139,7 +139,7 @@ public interface RimuHostingAsyncClient {
ListenableFuture<ServerInfo> restartServer(@PathParam("id") Long id);
/**
* @see RimuHostingClient#destoryServer
* @see RimuHostingClient#destroyServer
*/
@DELETE
@Path("/orders/order-{id}-blah/vps")

View File

@ -20,7 +20,6 @@
package org.jclouds.tools.ant.taskdefs.compute;
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
import static org.jclouds.compute.util.ComputeServiceUtils.isKeyAuth;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.buildComputeMap;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.createTemplateFromElement;
import static org.jclouds.tools.ant.taskdefs.compute.ComputeTaskUtils.ipOrEmptyString;
@ -45,6 +44,7 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.domain.Location;
import org.jclouds.http.HttpUtils;
import org.jclouds.util.Utils;
import com.google.common.base.CaseFormat;
import com.google.common.base.Splitter;
@ -212,7 +212,7 @@ public class ComputeTask extends Task {
getProject().setProperty(nodeElement.getIdproperty(), createdNode.getProviderId());
if (nodeElement.getHostproperty() != null)
getProject().setProperty(nodeElement.getHostproperty(), ipOrEmptyString(createdNode.getPublicAddresses()));
if (nodeElement.getPasswordproperty() != null && !isKeyAuth(createdNode))
if (nodeElement.getPasswordproperty() != null && !Utils.isPrivateKeyCredential(createdNode.getCredentials()))
getProject().setProperty(nodeElement.getPasswordproperty(), createdNode.getCredentials().credential);
if (nodeElement.getUsernameproperty() != null)
getProject().setProperty(nodeElement.getUsernameproperty(), createdNode.getCredentials().identity);

View File

@ -35,11 +35,11 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.InetSocketAddressConnect;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshClient.Factory;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.jclouds.ssh.jsch.predicates.InetSocketAddressConnect;
import org.jclouds.vcloud.compute.options.VCloudTemplateOptions;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;