fixed templateBuilder logger and also fixed copyright headers

This commit is contained in:
Adrian Cole 2010-04-13 23:40:56 -07:00
parent d08b359956
commit dedd8f8270
27 changed files with 1092 additions and 1150 deletions

View File

@ -107,11 +107,8 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule {
} }
@Provides @Provides
TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.architecture(Architecture.X86_32).osFamily(UBUNTU);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).architecture(
Architecture.X86_32).osFamily(UBUNTU);
} }
@Singleton @Singleton

View File

@ -65,14 +65,13 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
@Test @Test
public void testScriptExecution() throws Exception { public void testScriptExecution() throws Exception {
Template simpleTemplate = client.templateBuilder().smallest().build(); Template simpleTemplate = client.templateBuilder().smallest().build();
client.runNodesWithTag("ec2", 1, simpleTemplate); client.runNodesWithTag("ec2", 1, simpleTemplate);
Map<String, ? extends NodeMetadata> map = client.getNodesWithTag("ec2"); Map<String, ? extends NodeMetadata> map = client.getNodesWithTag("ec2");
NodeMetadata node = map.values().iterator().next(); map.values().iterator().next();
Credentials creds = new Credentials("ubuntu", keyPair.get("public")); Credentials creds = new Credentials("ubuntu", keyPair.get("public"));
client.runScriptOnNodesWithTag("ec2", creds, client.runScriptOnNodesWithTag("ec2", creds, "mkdir ~/ahha; sleep 3".getBytes());
"mkdir ~/ahha; sleep 3".getBytes()); client.destroyNodesWithTag("ec2");
client.destroyNodesWithTag("ec2");
} }
@Override @Override

View File

@ -119,7 +119,8 @@ public class EC2ComputeServiceTest {
return new TemplateBuilderImpl(ImmutableMap.of("us-east-1", location), ImmutableMap.of( return new TemplateBuilderImpl(ImmutableMap.of("us-east-1", location), ImmutableMap.of(
"ami-image", image), Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM, "ami-image", image), Maps.uniqueIndex(ImmutableSet.of(EC2Size.C1_MEDIUM,
EC2Size.C1_XLARGE, EC2Size.M1_LARGE, EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, EC2Size.M1_SMALL, EC2Size.M1_XLARGE,
EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE), indexer()), location); EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, EC2Size.M2_4XLARGE), indexer()), location) {
};
} }
Function<ComputeMetadata, String> indexer() { Function<ComputeMetadata, String> indexer() {

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.blobstore (ns org.jclouds.blobstore
"A clojure binding for the jclouds BlobStore. "A clojure binding for the jclouds BlobStore.

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.blobstore-test (ns org.jclouds.blobstore-test
(:use [org.jclouds.blobstore] :reload-all) (:use [org.jclouds.blobstore] :reload-all)
(:use [clojure.test]) (:use [clojure.test])

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.compute (ns org.jclouds.compute
"A clojure binding to the jclouds ComputeService. "A clojure binding to the jclouds ComputeService.

View File

@ -18,16 +18,15 @@
*/ */
package org.jclouds.compute; package org.jclouds.compute;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import org.jclouds.compute.config.ResolvesImages; import org.jclouds.compute.config.ResolvesImages;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.rest.RestContextBuilder; import org.jclouds.rest.RestContextBuilder;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ -48,18 +47,18 @@ public abstract class ComputeServiceContextBuilder<A, S> extends RestContextBuil
} }
@Override @Override
public Injector buildInjector() { public Injector buildInjector() {
addImageResolutionModuleIfNotPresent(); addImageResolutionModuleIfNotPresent();
return super.buildInjector(); return super.buildInjector();
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public ComputeServiceContextBuilder<A, S> withModules(Module... modules) { public ComputeServiceContextBuilder<A, S> withModules(Module... modules) {
return (ComputeServiceContextBuilder<A, S>) super.withModules(modules); return (ComputeServiceContextBuilder<A, S>) super.withModules(modules);
} }
public ComputeServiceContext buildComputeServiceContext() { public ComputeServiceContext buildComputeServiceContext() {
@ -70,7 +69,7 @@ public abstract class ComputeServiceContextBuilder<A, S> extends RestContextBuil
} }
protected void addImageResolutionModuleIfNotPresent() { protected void addImageResolutionModuleIfNotPresent() {
if (!Iterables.any(modules, new Predicate<Module>() { if (!Iterables.any(modules, new Predicate<Module>() {
public boolean apply(Module input) { public boolean apply(Module input) {
return input.getClass().isAnnotationPresent(ResolvesImages.class); return input.getClass().isAnnotationPresent(ResolvesImages.class);
} }
@ -80,9 +79,8 @@ public abstract class ComputeServiceContextBuilder<A, S> extends RestContextBuil
} }
} }
@SuppressWarnings({"UnusedDeclaration"})
protected void addImageResolutionModule() { protected void addImageResolutionModule() {
// do nothing; // do nothing;
// this is to be overridden when needed // this is to be overridden when needed
} }
} }

View File

@ -61,6 +61,7 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy;
import org.jclouds.compute.util.ComputeUtils; import org.jclouds.compute.util.ComputeUtils;
import org.jclouds.compute.util.ComputeUtils.SshCallable;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
@ -75,304 +76,311 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.ssh.ExecResponse; import org.jclouds.ssh.ExecResponse;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BaseComputeService implements ComputeService { public class BaseComputeService implements ComputeService {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final ComputeServiceContext context; protected final ComputeServiceContext context;
protected final Provider<Map<String, ? extends Image>> images; protected final Provider<Map<String, ? extends Image>> images;
protected final Provider<Map<String, ? extends Size>> sizes; protected final Provider<Map<String, ? extends Size>> sizes;
protected final Provider<Map<String, ? extends Location>> locations; protected final Provider<Map<String, ? extends Location>> locations;
protected final ListNodesStrategy listNodesStrategy; protected final ListNodesStrategy listNodesStrategy;
protected final GetNodeMetadataStrategy getNodeMetadataStrategy; protected final GetNodeMetadataStrategy getNodeMetadataStrategy;
protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy; protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy;
protected final RebootNodeStrategy rebootNodeStrategy; protected final RebootNodeStrategy rebootNodeStrategy;
protected final DestroyNodeStrategy destroyNodeStrategy; protected final DestroyNodeStrategy destroyNodeStrategy;
protected final Provider<TemplateBuilder> templateBuilderProvider; protected final Provider<TemplateBuilder> templateBuilderProvider;
protected final ComputeUtils utils; protected final ComputeUtils utils;
protected final ExecutorService executor; protected final ExecutorService executor;
private static class NodeMatchesTag implements Predicate<NodeMetadata> { private static class NodeMatchesTag implements Predicate<NodeMetadata> {
private final String tag; private final String tag;
public NodeMatchesTag(String tag) { public NodeMatchesTag(String tag) {
this.tag = tag; this.tag = tag;
} }
@Override @Override
public boolean apply(NodeMetadata from) { public boolean apply(NodeMetadata from) {
return from.getTag().equals(tag); return from.getTag().equals(tag);
} }
}; };
public static Function<ComputeMetadata, String> METADATA_TO_ID = new Function<ComputeMetadata, String>() { public static Function<ComputeMetadata, String> METADATA_TO_ID = new Function<ComputeMetadata, String>() {
@Override @Override
public String apply(ComputeMetadata from) { public String apply(ComputeMetadata from) {
return from.getId(); return from.getId();
} }
}; };
public static Function<ComputeMetadata, String> METADATA_TO_NAME = new Function<ComputeMetadata, String>() { public static Function<ComputeMetadata, String> METADATA_TO_NAME = new Function<ComputeMetadata, String>() {
@Override @Override
public String apply(ComputeMetadata from) { public String apply(ComputeMetadata from) {
return from.getName(); return from.getName();
} }
}; };
@Inject @Inject
protected BaseComputeService(ComputeServiceContext context, protected BaseComputeService(ComputeServiceContext context,
Provider<Map<String, ? extends Image>> images, Provider<Map<String, ? extends Image>> images,
Provider<Map<String, ? extends Size>> sizes, Provider<Map<String, ? extends Size>> sizes,
Provider<Map<String, ? extends Location>> locations, Provider<Map<String, ? extends Location>> locations,
ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy,
RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy, RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy,
RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy,
Provider<TemplateBuilder> templateBuilderProvider, ComputeUtils utils, Provider<TemplateBuilder> templateBuilderProvider, ComputeUtils utils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.context = checkNotNull(context, "context"); this.context = checkNotNull(context, "context");
this.images = checkNotNull(images, "images"); this.images = checkNotNull(images, "images");
this.sizes = checkNotNull(sizes, "sizes"); this.sizes = checkNotNull(sizes, "sizes");
this.locations = checkNotNull(locations, "locations"); this.locations = checkNotNull(locations, "locations");
this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy"); this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy");
this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy, this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy,
"getNodeMetadataStrategy"); "getNodeMetadataStrategy");
this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy,
"runNodesAndAddToSetStrategy"); "runNodesAndAddToSetStrategy");
this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy"); this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy");
this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy"); this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy");
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, this.templateBuilderProvider = checkNotNull(templateBuilderProvider,
"templateBuilderProvider"); "templateBuilderProvider");
this.utils = checkNotNull(utils, "utils"); this.utils = checkNotNull(utils, "utils");
this.executor = checkNotNull(executor, "executor"); this.executor = checkNotNull(executor, "executor");
} }
@Override @Override
public ComputeServiceContext getContext() { public ComputeServiceContext getContext() {
return context; return context;
} }
@Override @Override
public Map<String, ? extends NodeMetadata> runNodesWithTag(final String tag, int count, public Map<String, ? extends NodeMetadata> runNodesWithTag(final String tag, int count,
final Template template) { final Template template) {
checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens"); checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens");
checkNotNull(template.getLocation(), "location"); checkNotNull(template.getLocation(), "location");
logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)", logger.debug(">> running %d node%s tag(%s) location(%s) image(%s) size(%s) options(%s)",
count, count > 1 ? "s" : "", tag, template.getLocation().getId(), template count, count > 1 ? "s" : "", tag, template.getLocation().getId(), template
.getImage().getId(), template.getSize().getId(), template.getOptions()); .getImage().getId(), template.getSize().getId(), template.getOptions());
final Set<NodeMetadata> nodes = Sets.newHashSet(); final Set<NodeMetadata> nodes = Sets.newHashSet();
Map<?, ListenableFuture<Void>> responses = runNodesAndAddToSetStrategy.execute(tag, count, Map<?, ListenableFuture<Void>> responses = runNodesAndAddToSetStrategy.execute(tag, count,
template, nodes); template, nodes);
Map<?, Exception> exceptions = awaitCompletion(responses, executor, null, logger, Map<?, Exception> exceptions = awaitCompletion(responses, executor, null, logger,
"starting nodes"); "starting nodes");
if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) { if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) {
ImmutableMap<?, ? extends ComputeMetadata> currentNodes = Maps.uniqueIndex( ImmutableMap<?, ? extends ComputeMetadata> currentNodes = Maps.uniqueIndex(
listNodesStrategy.execute(), METADATA_TO_ID); listNodesStrategy.execute(), METADATA_TO_ID);
for (Entry<?, Exception> entry : exceptions.entrySet()) { for (Entry<?, Exception> entry : exceptions.entrySet()) {
logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry
.getKey(), entry.getValue().getMessage()); .getKey(), entry.getValue().getMessage());
destroyNode(currentNodes.get(entry.getKey())); destroyNode(currentNodes.get(entry.getKey()));
} }
} }
return Maps.uniqueIndex(nodes, METADATA_TO_ID); return Maps.uniqueIndex(nodes, METADATA_TO_ID);
} }
@Override @Override
public void destroyNode(ComputeMetadata node) { public void destroyNode(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType()); + node.getType());
checkNotNull(node.getId(), "node.id"); checkNotNull(node.getId(), "node.id");
logger.debug(">> destroying node(%s)", node.getId()); logger.debug(">> destroying node(%s)", node.getId());
boolean successful = destroyNodeStrategy.execute(node); boolean successful = destroyNodeStrategy.execute(node);
logger.debug("<< destroyed node(%s) success(%s)", node.getId(), successful); logger.debug("<< destroyed node(%s) success(%s)", node.getId(), successful);
} }
@Override @Override
public void destroyNodesWithTag(String tag) { // TODO parallel public void destroyNodesWithTag(String tag) { // TODO parallel
logger.debug(">> destroying nodes by tag(%s)", tag); logger.debug(">> destroying nodes by tag(%s)", tag);
Iterable<? extends NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodesWithTag(tag) Iterable<? extends NodeMetadata> nodesToDestroy = Iterables.filter(doGetNodesWithTag(tag)
.values(), new Predicate<NodeMetadata>() { .values(), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getState() != NodeState.TERMINATED;
}
});
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
for (final NodeMetadata node : nodesToDestroy) {
responses.put(node, makeListenable(executor.submit(new Callable<Void>() {
@Override @Override
public boolean apply(NodeMetadata input) { public Void call() throws Exception {
return input.getState() != NodeState.TERMINATED; destroyNode(node);
return null;
} }
}); }), executor));
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap(); }
for (final NodeMetadata node : nodesToDestroy) { awaitCompletion(responses, executor, null, logger, "destroying nodes");
responses.put(node, makeListenable(executor.submit(new Callable<Void>() { logger.debug("<< destroyed");
@Override }
public Void call() throws Exception {
destroyNode(node);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "destroying nodes");
logger.debug("<< destroyed");
}
@Override @Override
public Map<String, ? extends ComputeMetadata> getNodes() { public Map<String, ? extends ComputeMetadata> getNodes() {
logger.debug(">> listing servers"); logger.debug(">> listing servers");
ImmutableMap<String, ? extends ComputeMetadata> map = Maps.uniqueIndex(listNodesStrategy ImmutableMap<String, ? extends ComputeMetadata> map = Maps.uniqueIndex(listNodesStrategy
.execute(), METADATA_TO_ID); .execute(), METADATA_TO_ID);
logger.debug("<< list(%d)", map.size()); logger.debug("<< list(%d)", map.size());
return map; return map;
} }
/** /**
* If the result of {@link ListNodesStrategy#execute} is a set of nodes, then return them. * If the result of {@link ListNodesStrategy#execute} is a set of nodes, then return them.
* Otherwise iteratively call {@link #getNodeMetadata} * Otherwise iteratively call {@link #getNodeMetadata}
*/ */
protected Map<String, ? extends NodeMetadata> doGetNodesWithTag(final String tag) { protected Map<String, ? extends NodeMetadata> doGetNodesWithTag(final String tag) {
Iterable<? extends NodeMetadata> nodes = Iterables.filter(Iterables.transform( Iterable<? extends NodeMetadata> nodes = Iterables.filter(Iterables.transform(
listNodesStrategy.execute(), new Function<ComputeMetadata, NodeMetadata>() { listNodesStrategy.execute(), new Function<ComputeMetadata, NodeMetadata>() {
@Override @Override
public NodeMetadata apply(ComputeMetadata from) { public NodeMetadata apply(ComputeMetadata from) {
return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) return from instanceof NodeMetadata ? NodeMetadata.class.cast(from)
: getNodeMetadata(from); : getNodeMetadata(from);
} }
}), new Predicate<NodeMetadata>() { }), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return tag.equals(input.getTag());
}
});
return Maps.uniqueIndex(Iterables.filter(nodes, new NodeMatchesTag(tag)), METADATA_TO_ID);
}
@Override
public Map<String, ? extends NodeMetadata> getNodesWithTag(String tag) {
logger.debug(">> listing nodes by tag(%s)", tag);
Map<String, ? extends NodeMetadata> nodes = doGetNodesWithTag(tag);
logger.debug("<< list(%d)", nodes.size());
return nodes;
}
@Override
public Map<String, ? extends Size> getSizes() {
return sizes.get();
}
@Override
public Map<String, ? extends Image> getImages() {
return images.get();
}
@Override
public Map<String, ? extends Location> getLocations() {
return locations.get();
}
@Override
public TemplateBuilder templateBuilder() {
return templateBuilderProvider.get();
}
@Override
public NodeMetadata getNodeMetadata(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
return getNodeMetadataStrategy.execute(node);
}
@Override
public void rebootNode(ComputeMetadata node) {
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
checkNotNull(node.getId(), "node.id");
logger.debug(">> rebooting node(%s)", node.getId());
boolean successful = rebootNodeStrategy.execute(node);
logger.debug("<< rebooted node(%s) success(%s)", node.getId(), successful);
}
@Override
public void rebootNodesWithTag(String tag) { // TODO parallel
logger.debug(">> rebooting nodes by tag(%s)", tag);
Iterable<? extends NodeMetadata> nodesToReboot = Iterables.filter(doGetNodesWithTag(tag)
.values(), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getState() != NodeState.TERMINATED;
}
});
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
for (final NodeMetadata node : nodesToReboot) {
responses.put(node, makeListenable(executor.submit(new Callable<Void>() {
@Override @Override
public boolean apply(NodeMetadata input) { public Void call() throws Exception {
return tag.equals(input.getTag()); rebootNode(node);
return null;
} }
}), executor));
}
awaitCompletion(responses, executor, null, logger, "rebooting nodes");
logger.debug("<< rebooted");
}
}); /**
return Maps.uniqueIndex(Iterables.filter(nodes, new NodeMatchesTag(tag)), METADATA_TO_ID); * @see #runScriptOnNodesWithTag(String, org.jclouds.domain.Credentials, byte[],
} * org.jclouds.compute.options.RunScriptOptions)
*/
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, Credentials credentials,
byte[] runScript) {
return runScriptOnNodesWithTag(tag, credentials, runScript, RunScriptOptions.NONE);
}
@Override /**
public Map<String, ? extends NodeMetadata> getNodesWithTag(String tag) { * Run the script on all nodes with the specific tag.
logger.debug(">> listing nodes by tag(%s)", tag); *
Map<String, ? extends NodeMetadata> nodes = doGetNodesWithTag(tag); * @param tag
logger.debug("<< list(%d)", nodes.size()); * tag to look up the nodes
return nodes; * @param credentials
} * nullable credentials to use (same for all nodes).
* @param runScript
* script to run in byte format. If the script is a string, use
* {@link String#getBytes()} to retrieve the bytes
* @param options
* nullable options to how to run the script
* @return map with node identifiers and corresponding responses
*/
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag,
@Nullable Credentials credentials, byte[] runScript, @Nullable RunScriptOptions options) {
checkNotEmpty(tag, "Tag must be provided");
checkNotNull(runScript,
"The script (represented by bytes array - use \"script\".getBytes() must be provided");
if (options == null)
options = RunScriptOptions.NONE;
@Override Map<String, ? extends NodeMetadata> nodes = getNodesWithTag(tag);
public Map<String, ? extends Size> getSizes() { Map<String, ExecResponse> responses = Maps.newHashMap();
return sizes.get();
}
@Override for (NodeMetadata node : nodes.values()) {
public Map<String, ? extends Image> getImages() { if (NodeState.RUNNING != node.getState())
return images.get(); continue; // make sure the node is active
}
@Override if (options.isOverrideCredentials()) {
public Map<String, ? extends Location> getLocations() { // override the credentials with provided to this method
return locations.get(); checkNotNull(credentials,
} "If the credentials need to be overridden, they can't be null");
node = ComputeUtils.installNewCredentials(node, credentials);
} else {
// don't override
checkNotNull(node.getCredentials(),
"If the default credentials need to be used, they can't be null");
}
@Override // todo: execute script as root if required
public TemplateBuilder templateBuilder() {
return templateBuilderProvider.get();
}
@Override ComputeUtils.SshCallable<?> callable = utils.runScriptOnNode(node, "computeserv.sh",
public NodeMetadata getNodeMetadata(ComputeMetadata node) { runScript);
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not "
+ node.getType());
return getNodeMetadataStrategy.execute(node);
}
@Override Map<ComputeUtils.SshCallable<?>, ?> scriptRunResults = utils.runCallablesOnNode(node, Sets
public void rebootNode(ComputeMetadata node) { .<SshCallable<?>> newHashSet(callable), null);
checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " responses.put(node.getId(), (ExecResponse) scriptRunResults.get(callable));
+ node.getType()); }
checkNotNull(node.getId(), "node.id"); return responses;
logger.debug(">> rebooting node(%s)", node.getId()); }
boolean successful = rebootNodeStrategy.execute(node);
logger.debug("<< rebooted node(%s) success(%s)", node.getId(), successful);
}
@Override
public void rebootNodesWithTag(String tag) { // TODO parallel
logger.debug(">> rebooting nodes by tag(%s)", tag);
Iterable<? extends NodeMetadata> nodesToReboot = Iterables.filter(doGetNodesWithTag(tag)
.values(), new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getState() != NodeState.TERMINATED;
}
});
Map<NodeMetadata, ListenableFuture<Void>> responses = Maps.newHashMap();
for (final NodeMetadata node : nodesToReboot) {
responses.put(node, makeListenable(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
rebootNode(node);
return null;
}
}), executor));
}
awaitCompletion(responses, executor, null, logger, "rebooting nodes");
logger.debug("<< rebooted");
}
/**
* @see #runScriptOnNodesWithTag(String, org.jclouds.domain.Credentials, byte[],
* org.jclouds.compute.options.RunScriptOptions)
*/
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, Credentials credentials,
byte[] runScript) {
return runScriptOnNodesWithTag(tag, credentials, runScript, RunScriptOptions.NONE);
}
/**
* Run the script on all nodes with the specific tag.
*
* @param tag tag to look up the nodes
* @param credentials nullable credentials to use (same for all nodes).
* @param runScript script to run in byte format. If the script is a string, use
* {@link String#getBytes()} to retrieve the bytes
* @param options nullable options to how to run the script
* @return map with node identifiers and corresponding responses
*/
public Map<String, ExecResponse> runScriptOnNodesWithTag(String tag, @Nullable Credentials credentials,
byte[] runScript, @Nullable RunScriptOptions options) {
checkNotEmpty(tag, "Tag must be provided");
checkNotNull(runScript,
"The script (represented by bytes array - use \"script\".getBytes() must be provided");
if(options == null) options = RunScriptOptions.NONE;
Map<String, ? extends NodeMetadata> nodes = getNodesWithTag(tag);
Map<String, ExecResponse> responses = Maps.newHashMap();
for(NodeMetadata node : nodes.values()) {
if(NodeState.RUNNING != node.getState()) continue; //make sure the node is active
if(options.isOverrideCredentials()) {
//override the credentials with provided to this method
checkNotNull(credentials, "If the credentials need to be overridden, they can't be null");
node = ComputeUtils.installNewCredentials(node, credentials);
} else {
//don't override
checkNotNull(node.getCredentials(), "If the default credentials need to be used, they can't be null");
}
//todo: execute script as root if required
ComputeUtils.SshCallable<?> callable = utils.runScriptOnNode(node, "computeserv.sh", runScript);
Map<ComputeUtils.SshCallable<?>, ?> scriptRunResults = utils.runCallablesOnNode(node,
Sets.newHashSet(callable),
null);
responses.put(node.getId(),
(ExecResponse) scriptRunResults.get(callable));
}
return responses;
}
} }

View File

@ -97,7 +97,7 @@ public class TemplateBuilderImpl implements TemplateBuilder {
private TemplateOptions options = TemplateOptions.NONE; private TemplateOptions options = TemplateOptions.NONE;
@Inject @Inject
public TemplateBuilderImpl(Map<String, ? extends Location> locations, protected TemplateBuilderImpl(Map<String, ? extends Location> locations,
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, Map<String, ? extends Image> images, Map<String, ? extends Size> sizes,
Location defaultLocation) { Location defaultLocation) {
this.locations = locations; this.locations = locations;

View File

@ -62,273 +62,275 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ComputeUtils { public class ComputeUtils {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
@Inject(optional = true) @Inject(optional = true)
private SshClient.Factory sshFactory; private SshClient.Factory sshFactory;
protected final Predicate<SshClient> runScriptNotRunning; protected final Predicate<SshClient> runScriptNotRunning;
private final Predicate<InetSocketAddress> socketTester; private final Predicate<InetSocketAddress> socketTester;
private final ExecutorService executor; private final ExecutorService executor;
@Inject @Inject
public ComputeUtils(Predicate<InetSocketAddress> socketTester, public ComputeUtils(Predicate<InetSocketAddress> socketTester,
@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning, @Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
this.socketTester = socketTester; this.socketTester = socketTester;
this.runScriptNotRunning = runScriptNotRunning; this.runScriptNotRunning = runScriptNotRunning;
this.executor = executor; this.executor = executor;
} }
public static Iterable<? extends ComputeMetadata> filterByName( public static Iterable<? extends ComputeMetadata> filterByName(
Iterable<? extends ComputeMetadata> nodes, final String name) { Iterable<? extends ComputeMetadata> nodes, final String name) {
return Iterables.filter(nodes, new Predicate<ComputeMetadata>() { return Iterables.filter(nodes, new Predicate<ComputeMetadata>() {
@Override @Override
public boolean apply(ComputeMetadata input) { public boolean apply(ComputeMetadata input) {
return input.getName().equalsIgnoreCase(name); return input.getName().equalsIgnoreCase(name);
}
});
}
public static final Comparator<InetAddress> ADDRESS_COMPARATOR = new Comparator<InetAddress>() {
@Override
public int compare(InetAddress o1, InetAddress o2) {
return (o1 == o2) ? 0 : o1.getHostAddress().compareTo(o2.getHostAddress());
}
};
public void runOptionsOnNode(NodeMetadata node, TemplateOptions options) {
List<SshCallable<?>> callables = Lists.newArrayList();
if (options.getRunScript() != null) {
callables.add(runScriptOnNode(node, "runscript.sh", options.getRunScript()));
}
if (options.getPublicKey() != null) {
callables.add(authorizeKeyOnNode(node, options.getPublicKey()));
}
// changing the key "MUST" come last or else the other commands may fail.
if (callables.size() > 0 || options.getPrivateKey() != null) {
runCallablesOnNode(node, callables, options.getPrivateKey() != null ? installKeyOnNode(
node, options.getPrivateKey()) : null);
}
}
public InstallRSAPrivateKey installKeyOnNode(NodeMetadata node, String privateKey) {
return new InstallRSAPrivateKey(node, privateKey);
}
public AuthorizeRSAPublicKey authorizeKeyOnNode(NodeMetadata node, String publicKey) {
return new AuthorizeRSAPublicKey(node, publicKey);
}
public RunScriptOnNode runScriptOnNode(NodeMetadata node, String scriptName, byte[] script) {
return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script);
}
public Map<SshCallable<?>, ?> runCallablesOnNode(NodeMetadata node,
Iterable<? extends SshCallable<?>> parallel, @Nullable SshCallable<?> last) {
checkState(this.sshFactory != null, "runScript requested, but no SshModule configured");
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
22);
socketTester.apply(socket);
SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account,
node.getCredentials().key.getBytes()) : sshFactory.create(socket, node
.getCredentials().account, node.getCredentials().key);
for (int i = 0; i < 3; i++) {
try {
ssh.connect();
Map<SshCallable<?>, ListenableFuture<?>> responses = Maps.newHashMap();
for (SshCallable<?> callable : parallel) {
callable.setConnection(ssh, logger);
responses.put(callable, ConcurrentUtils.makeListenable(executor.submit(callable),
executor));
} }
});
}
public static final Comparator<InetAddress> ADDRESS_COMPARATOR = new Comparator<InetAddress>() { Map<SshCallable<?>, Exception> exceptions = awaitCompletion(responses, executor, null,
logger, "ssh");
@Override if (exceptions.size() > 0)
public int compare(InetAddress o1, InetAddress o2) { throw new RuntimeException(String.format("error invoking callables on host %s: %s",
return (o1 == o2) ? 0 : o1.getHostAddress().compareTo(o2.getHostAddress()); socket, exceptions));
} if (last != null) {
last.setConnection(ssh, logger);
}; try {
last.call();
public void runOptionsOnNode(NodeMetadata node, TemplateOptions options) { } catch (Exception e) {
List<SshCallable<?>> callables = Lists.newArrayList(); Throwables.propagate(e);
if (options.getRunScript() != null) { }
callables.add(runScriptOnNode(node, "runscript.sh", options.getRunScript()));
}
if (options.getPublicKey() != null) {
callables.add(authorizeKeyOnNode(node, options.getPublicKey()));
}
// changing the key "MUST" come last or else the other commands may fail.
if (callables.size() > 0 || options.getPrivateKey() != null) {
runCallablesOnNode(node, callables, options.getPrivateKey() != null ? installKeyOnNode(
node, options.getPrivateKey()) : null);
}
}
public InstallRSAPrivateKey installKeyOnNode(NodeMetadata node, String privateKey) {
return new InstallRSAPrivateKey(node, privateKey);
}
public AuthorizeRSAPublicKey authorizeKeyOnNode(NodeMetadata node, String publicKey) {
return new AuthorizeRSAPublicKey(node, publicKey);
}
public RunScriptOnNode runScriptOnNode(NodeMetadata node, String scriptName, byte[] script) {
return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script);
}
public Map<SshCallable<?>, ?> runCallablesOnNode(NodeMetadata node, Iterable<? extends SshCallable<?>> parallel,
@Nullable SshCallable<?> last) {
checkState(this.sshFactory != null, "runScript requested, but no SshModule configured");
InetSocketAddress socket = new InetSocketAddress(Iterables.get(node.getPublicAddresses(), 0),
22);
socketTester.apply(socket);
SshClient ssh = isKeyAuth(node) ? sshFactory.create(socket, node.getCredentials().account,
node.getCredentials().key.getBytes()) : sshFactory.create(socket, node
.getCredentials().account, node.getCredentials().key);
for (int i = 0; i < 3; i++) {
try {
ssh.connect();
Map<SshCallable<?>, ListenableFuture<?>> responses = Maps.newHashMap();
for (SshCallable<?> callable : parallel) {
callable.setConnection(ssh, logger);
responses.put(callable, ConcurrentUtils.makeListenable(executor.submit(callable),
executor));
}
Map<SshCallable<?>, Exception> exceptions = awaitCompletion(responses, executor, null,
logger, "ssh");
if (exceptions.size() > 0)
throw new RuntimeException(String.format("error invoking callables on host %s: %s",
socket, exceptions));
if (last != null) {
last.setConnection(ssh, logger);
try {
last.call();
} catch (Exception e) {
Throwables.propagate(e);
}
}
return transform(responses);
} catch (RuntimeException from) {
if (Iterables.size(Iterables.filter(Throwables.getCausalChain(from),
ConnectException.class)) >= 1// auth fail sometimes happens in EC2
|| Throwables.getRootCause(from).getMessage().indexOf("Auth fail") != -1
|| Throwables.getRootCause(from).getMessage().indexOf("invalid privatekey") != -1) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw Throwables.propagate(e);
}
continue;
}
throw Throwables.propagate(from);
} finally {
if (ssh != null)
ssh.disconnect();
} }
} return transform(responses);
throw new RuntimeException(String.format("Couldn't connect to node %s and run the script", node.getId())); } catch (RuntimeException from) {
} if (Iterables.size(Iterables.filter(Throwables.getCausalChain(from),
ConnectException.class)) >= 1// auth fail sometimes happens in EC2
|| Throwables.getRootCause(from).getMessage().indexOf("Auth fail") != -1
|| Throwables.getRootCause(from).getMessage().indexOf("invalid privatekey") != -1) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw Throwables.propagate(e);
}
continue;
}
throw Throwables.propagate(from);
} finally {
if (ssh != null)
ssh.disconnect();
}
}
throw new RuntimeException(String.format("Couldn't connect to node %s and run the script",
node.getId()));
}
public <T> Map<SshCallable<?>, T> transform(Map<SshCallable<?>, ListenableFuture<?>> responses) { @SuppressWarnings("unchecked")
Map<SshCallable<?>, T> actualResponses = Maps.newHashMap(); public <T> Map<SshCallable<?>, T> transform(Map<SshCallable<?>, ListenableFuture<?>> responses) {
for(Map.Entry<SshCallable<?>, ListenableFuture<?>> entry : responses.entrySet()) { Map<SshCallable<?>, T> actualResponses = Maps.newHashMap();
try { for (Map.Entry<SshCallable<?>, ListenableFuture<?>> entry : responses.entrySet()) {
try {
actualResponses.put(entry.getKey(), (T) entry.getValue().get()); actualResponses.put(entry.getKey(), (T) entry.getValue().get());
} catch(InterruptedException e) { } catch (InterruptedException e) {
throw Throwables.propagate(e); throw Throwables.propagate(e);
} catch(ExecutionException e) { } catch (ExecutionException e) {
throw Throwables.propagate(e); throw Throwables.propagate(e);
} }
} }
return actualResponses; return actualResponses;
} }
public static interface SshCallable<T> extends Callable<T> { public static interface SshCallable<T> extends Callable<T> {
void setConnection(SshClient ssh, Logger logger); void setConnection(SshClient ssh, Logger logger);
} }
public static class RunScriptOnNode implements SshCallable<ExecResponse> { public static class RunScriptOnNode implements SshCallable<ExecResponse> {
private SshClient ssh; private SshClient ssh;
protected final Predicate<SshClient> runScriptNotRunning; protected final Predicate<SshClient> runScriptNotRunning;
private final NodeMetadata node; private final NodeMetadata node;
private final String scriptName; private final String scriptName;
private final byte[] script; private final byte[] script;
private Logger logger = Logger.NULL; private Logger logger = Logger.NULL;
RunScriptOnNode(@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning, RunScriptOnNode(@Named("NOT_RUNNING") Predicate<SshClient> runScriptNotRunning,
NodeMetadata node, String scriptName, byte[] script) { NodeMetadata node, String scriptName, byte[] script) {
this.runScriptNotRunning = runScriptNotRunning; this.runScriptNotRunning = runScriptNotRunning;
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.scriptName = checkNotNull(scriptName, "scriptName"); this.scriptName = checkNotNull(scriptName, "scriptName");
this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap
.<String, String> of(), Iterables.toArray(Splitter.on("\n").split( .<String, String> of(), Iterables.toArray(Splitter.on("\n").split(
new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX)
.getBytes(); .getBytes();
} }
@Override @Override
public ExecResponse call() throws Exception { public ExecResponse call() throws Exception {
ssh.put(scriptName, new ByteArrayInputStream(script)); ssh.put(scriptName, new ByteArrayInputStream(script));
ExecResponse returnVal = ssh.exec("chmod 755 " + scriptName); ExecResponse returnVal = ssh.exec("chmod 755 " + scriptName);
returnVal = ssh.exec("./" + scriptName + " init"); returnVal = ssh.exec("./" + scriptName + " init");
if (node.getCredentials().account.equals("root")) { if (node.getCredentials().account.equals("root")) {
logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account, logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account,
Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
returnVal = ssh.exec("./" + scriptName + " start"); returnVal = ssh.exec("./" + scriptName + " start");
} else if (isKeyAuth(node)) { } else if (isKeyAuth(node)) {
logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account, logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account,
Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
returnVal = ssh.exec("sudo ./" + scriptName + " start"); returnVal = ssh.exec("sudo ./" + scriptName + " start");
} else { } else {
logger.debug(">> running sudo -S %s as %s@%s", scriptName, logger.debug(">> running sudo -S %s as %s@%s", scriptName,
node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0) node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0)
.getHostAddress()); .getHostAddress());
returnVal = ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key, returnVal = ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key,
scriptName + " start")); scriptName + " start"));
} }
runScriptNotRunning.apply(ssh); runScriptNotRunning.apply(ssh);
logger.debug("<< complete(%d)", returnVal.getExitCode()); logger.debug("<< complete(%d)", returnVal.getExitCode());
return returnVal; return returnVal;
} }
@Override @Override
public void setConnection(SshClient ssh, Logger logger) { public void setConnection(SshClient ssh, Logger logger) {
this.logger = checkNotNull(logger, "logger"); this.logger = checkNotNull(logger, "logger");
this.ssh = checkNotNull(ssh, "ssh"); this.ssh = checkNotNull(ssh, "ssh");
} }
} }
public static class InstallRSAPrivateKey implements SshCallable<ExecResponse> { public static class InstallRSAPrivateKey implements SshCallable<ExecResponse> {
private SshClient ssh; private SshClient ssh;
private final NodeMetadata node; private final NodeMetadata node;
private final String privateKey; private final String privateKey;
private Logger logger = Logger.NULL; private Logger logger = Logger.NULL;
InstallRSAPrivateKey(NodeMetadata node, String privateKey) { InstallRSAPrivateKey(NodeMetadata node, String privateKey) {
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.privateKey = checkNotNull(privateKey, "privateKey"); this.privateKey = checkNotNull(privateKey, "privateKey");
} }
@Override @Override
public ExecResponse call() throws Exception { public ExecResponse call() throws Exception {
ssh.exec("mkdir .ssh"); ssh.exec("mkdir .ssh");
ssh.put(".ssh/id_rsa", new ByteArrayInputStream(privateKey.getBytes())); ssh.put(".ssh/id_rsa", new ByteArrayInputStream(privateKey.getBytes()));
logger.debug(">> installing rsa key for %s@%s", node.getCredentials().account, Iterables logger.debug(">> installing rsa key for %s@%s", node.getCredentials().account, Iterables
.get(node.getPublicAddresses(), 0).getHostAddress()); .get(node.getPublicAddresses(), 0).getHostAddress());
return ssh.exec("chmod 600 .ssh/id_rsa"); return ssh.exec("chmod 600 .ssh/id_rsa");
} }
@Override @Override
public void setConnection(SshClient ssh, Logger logger) { public void setConnection(SshClient ssh, Logger logger) {
this.logger = checkNotNull(logger, "logger"); this.logger = checkNotNull(logger, "logger");
this.ssh = checkNotNull(ssh, "ssh"); this.ssh = checkNotNull(ssh, "ssh");
} }
} }
public static class AuthorizeRSAPublicKey implements SshCallable<ExecResponse> { public static class AuthorizeRSAPublicKey implements SshCallable<ExecResponse> {
private SshClient ssh; private SshClient ssh;
private final NodeMetadata node; private final NodeMetadata node;
private final String publicKey; private final String publicKey;
private Logger logger = Logger.NULL; private Logger logger = Logger.NULL;
AuthorizeRSAPublicKey(NodeMetadata node, String publicKey) { AuthorizeRSAPublicKey(NodeMetadata node, String publicKey) {
this.node = checkNotNull(node, "node"); this.node = checkNotNull(node, "node");
this.publicKey = checkNotNull(publicKey, "publicKey"); this.publicKey = checkNotNull(publicKey, "publicKey");
} }
@Override @Override
public ExecResponse call() throws Exception { public ExecResponse call() throws Exception {
ssh.exec("mkdir .ssh"); ssh.exec("mkdir .ssh");
ssh.put(".ssh/id_rsa.pub", new ByteArrayInputStream(publicKey.getBytes())); ssh.put(".ssh/id_rsa.pub", new ByteArrayInputStream(publicKey.getBytes()));
logger.debug(">> authorizing rsa public key for %s@%s", node.getCredentials().account, logger.debug(">> authorizing rsa public key for %s@%s", node.getCredentials().account,
Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); Iterables.get(node.getPublicAddresses(), 0).getHostAddress());
ExecResponse returnVal = ssh.exec("cat .ssh/id_rsa.pub >> .ssh/authorized_keys"); ExecResponse returnVal = ssh.exec("cat .ssh/id_rsa.pub >> .ssh/authorized_keys");
returnVal = ssh.exec("chmod 600 .ssh/authorized_keys"); returnVal = ssh.exec("chmod 600 .ssh/authorized_keys");
logger.debug("<< complete(%d)", returnVal.getExitCode()); logger.debug("<< complete(%d)", returnVal.getExitCode());
return returnVal; return returnVal;
} }
@Override @Override
public void setConnection(SshClient ssh, Logger logger) { public void setConnection(SshClient ssh, Logger logger) {
this.logger = checkNotNull(logger, "logger"); this.logger = checkNotNull(logger, "logger");
this.ssh = checkNotNull(ssh, "ssh"); this.ssh = checkNotNull(ssh, "ssh");
} }
} }
public static boolean isKeyAuth(NodeMetadata createdNode) { public static boolean isKeyAuth(NodeMetadata createdNode) {
return createdNode.getCredentials().key != null return createdNode.getCredentials().key != null
&& createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----"); && createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----");
} }
/** /**
* Given the instances of {@link NodeMetadata} (immutable) * Given the instances of {@link NodeMetadata} (immutable) and {@link Credentials} (immutable),
* and {@link Credentials} (immutable), returns a new instance of {@link NodeMetadata} * returns a new instance of {@link NodeMetadata} that has new credentials
* that has new credentials */
*/ public static NodeMetadata installNewCredentials(NodeMetadata node, Credentials newCredentials) {
public static NodeMetadata installNewCredentials(NodeMetadata node, Credentials newCredentials) { return new NodeMetadataImpl(node.getId(), node.getName(), node.getLocationId(),
return new NodeMetadataImpl(node.getId(), node.getName(), node.getLocationId(), node.getUri(), node.getUri(), node.getUserMetadata(), node.getTag(), node.getState(), node
node.getUserMetadata(), node.getTag(), node.getState(), node. getPublicAddresses(), .getPublicAddresses(), node.getPrivateAddresses(), node.getExtra(),
node.getPrivateAddresses(), node.getExtra(), newCredentials); newCredentials);
} }
} }

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.compute-test (ns org.jclouds.compute-test
(:use [org.jclouds.compute] :reload-all) (:use [org.jclouds.compute] :reload-all)
(:use clojure.test)) (:use clojure.test))

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.core (ns org.jclouds.core
"Core functionality used across blobstore and compute." "Core functionality used across blobstore and compute."
(:use clojure.contrib.logging (:use clojure.contrib.logging
@ -8,6 +26,7 @@
(def module-lookup (def module-lookup
{:log4j 'org.jclouds.logging.log4j.config.Log4JLoggingModule {:log4j 'org.jclouds.logging.log4j.config.Log4JLoggingModule
:lognull 'org.jclouds.logging.config.NullLoggingModule
:ssh 'org.jclouds.ssh.jsch.config.JschSshClientModule :ssh 'org.jclouds.ssh.jsch.config.JschSshClientModule
:enterprise 'org.jclouds.enterprise.config.EnterpriseConfigurationModule :enterprise 'org.jclouds.enterprise.config.EnterpriseConfigurationModule
:httpnio 'org.jclouds.http.httpnio.config.NioTransformingHttpCommandExecutorServiceModule :httpnio 'org.jclouds.http.httpnio.config.NioTransformingHttpCommandExecutorServiceModule

View File

@ -1,3 +1,21 @@
;;
;; 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.
;; ====================================================================
;;
(ns org.jclouds.core-test (ns org.jclouds.core-test
(:use [org.jclouds.core] :reload-all) (:use [org.jclouds.core] :reload-all)
(:use clojure.test)) (:use clojure.test))

View File

@ -93,372 +93,369 @@ import com.google.inject.TypeLiteral;
*/ */
public class GoGridComputeServiceContextModule extends GoGridContextModule { public class GoGridComputeServiceContextModule extends GoGridContextModule {
@Override @Override
protected void configure() { protected void configure() {
super.configure(); super.configure();
bind(new TypeLiteral<Function<Server, NodeMetadata>>() { bind(new TypeLiteral<Function<Server, NodeMetadata>>() {
}).to(ServerToNodeMetadata.class); }).to(ServerToNodeMetadata.class);
bind(AddNodeWithTagStrategy.class).to(GoGridAddNodeWithTagStrategy.class); bind(AddNodeWithTagStrategy.class).to(GoGridAddNodeWithTagStrategy.class);
bind(ListNodesStrategy.class).to(GoGridListNodesStrategy.class); bind(ListNodesStrategy.class).to(GoGridListNodesStrategy.class);
bind(GetNodeMetadataStrategy.class).to(GoGridGetNodeMetadataStrategy.class); bind(GetNodeMetadataStrategy.class).to(GoGridGetNodeMetadataStrategy.class);
bind(RebootNodeStrategy.class).to(GoGridRebootNodeStrategy.class); bind(RebootNodeStrategy.class).to(GoGridRebootNodeStrategy.class);
bind(DestroyNodeStrategy.class).to(GoGridDestroyNodeStrategy.class); bind(DestroyNodeStrategy.class).to(GoGridDestroyNodeStrategy.class);
} }
@Provides @Provides
TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.osFamily(CENTOS).imageNameMatches(".*w/ None.*");
Location defaultLocation) { }
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).osFamily(CENTOS)
.imageNameMatches(".*w/ None.*");
}
@Provides @Provides
@Named("NAMING_CONVENTION") @Named("NAMING_CONVENTION")
@Singleton @Singleton
String provideNamingConvention() { String provideNamingConvention() {
return "%s-%d"; return "%s-%d";
} }
@Singleton @Singleton
public static class GoGridAddNodeWithTagStrategy implements AddNodeWithTagStrategy { public static class GoGridAddNodeWithTagStrategy implements AddNodeWithTagStrategy {
private final GoGridClient client; private final GoGridClient client;
private final Function<Size, String> sizeToRam; private final Function<Size, String> sizeToRam;
private final Function<Server, NodeMetadata> serverToNodeMetadata; private final Function<Server, NodeMetadata> serverToNodeMetadata;
private RetryablePredicate<Server> serverLatestJobCompleted; private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort; private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject @Inject
protected GoGridAddNodeWithTagStrategy(GoGridClient client, protected GoGridAddNodeWithTagStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata, Function<Size, String> sizeToRam) { Function<Server, NodeMetadata> serverToNodeMetadata, Function<Size, String> sizeToRam) {
this.client = client; this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata; this.serverToNodeMetadata = serverToNodeMetadata;
this.sizeToRam = sizeToRam; this.sizeToRam = sizeToRam;
this.serverLatestJobCompleted = new RetryablePredicate<Server>( this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS); new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>( this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS); new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS);
} }
@Override @Override
public NodeMetadata execute(String tag, String name, Template template) { public NodeMetadata execute(String tag, String name, Template template) {
Server addedServer = null; Server addedServer = null;
boolean notStarted = true; boolean notStarted = true;
int numOfRetries = 20; int numOfRetries = 20;
// lock-free consumption of a shared resource: IP address pool // lock-free consumption of a shared resource: IP address pool
while (notStarted) { // TODO: replace with Predicate-based thread collision avoidance for while (notStarted) { // TODO: replace with Predicate-based thread collision avoidance for
// simplicity // simplicity
Set<Ip> availableIps = client.getIpServices().getIpList( Set<Ip> availableIps = client.getIpServices().getIpList(
new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC)); new GetIpListOptions().onlyUnassigned().onlyWithType(IpType.PUBLIC));
if (availableIps.size() == 0) if (availableIps.size() == 0)
throw new RuntimeException("No public IPs available on this account."); throw new RuntimeException("No public IPs available on this account.");
int ipIndex = new SecureRandom().nextInt(availableIps.size()); int ipIndex = new SecureRandom().nextInt(availableIps.size());
Ip availableIp = Iterables.get(availableIps, ipIndex); Ip availableIp = Iterables.get(availableIps, ipIndex);
try {
addedServer = client.getServerServices().addServer(name,
checkNotNull(template.getImage().getId()),
sizeToRam.apply(template.getSize()), availableIp.getIp());
notStarted = false;
} catch (Exception e) {
if (--numOfRetries == 0)
Throwables.propagate(e);
notStarted = true;
}
}
serverLatestJobCompleted.apply(addedServer);
client.getServerServices().power(addedServer.getName(), PowerCommand.START);
serverLatestJobCompletedShort.apply(addedServer);
addedServer = Iterables.getOnlyElement(client.getServerServices().getServersByName(
addedServer.getName()));
return serverToNodeMetadata.apply(addedServer);
}
}
@Singleton
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject
protected GoGridRebootNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
serverLatestJobCompleted.apply(server);
client.getServerServices().power(server.getName(), PowerCommand.START);
return serverLatestJobCompletedShort.apply(server);
}
}
@Singleton
public static class GoGridListNodesStrategy implements ListNodesStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridListNodesStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public Iterable<? extends ComputeMetadata> execute() {
return Iterables.transform(client.getServerServices().getServerList(),
serverToNodeMetadata);
}
}
@Singleton
public static class GoGridGetNodeMetadataStrategy implements GetNodeMetadataStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridGetNodeMetadataStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public NodeMetadata execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
return server == null ? null : serverToNodeMetadata.apply(server);
}
}
@Singleton
public static class GoGridDestroyNodeStrategy implements DestroyNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
@Inject
protected GoGridDestroyNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().deleteByName(server.getName());
return serverLatestJobCompleted.apply(server);
}
}
@Singleton
@Provides
Map<String, NodeState> provideServerToNodeState() {
return ImmutableMap.<String, NodeState> builder().put("On", NodeState.RUNNING).put(
"Starting", NodeState.PENDING).put("Off", NodeState.SUSPENDED).put("Saving",
NodeState.PENDING).put("Restarting", NodeState.PENDING).put("Stopping",
NodeState.PENDING).build();
}
@Singleton
@Provides
Function<String, InetAddress> provideStringIpToInetAddress() {
return new Function<String, InetAddress>() {
@Override
public InetAddress apply(String from) {
try {
return InetAddress.getByName(from);
} catch (UnknownHostException e) {
// TODO: log the failure.
return null;
}
}
};
}
/**
* Finds matches to required configurations. GoGrid's documentation only specifies how much RAM
* one can get with different instance types. The # of cores and disk sizes are purely empyrical
* and aren't guaranteed. However, these are the matches found: Ram: 512MB, CPU: 1 core, HDD: 28
* GB Ram: 1GB, CPU: 1 core, HDD: 57 GB Ram: 2GB, CPU: 1 core, HDD: 113 GB Ram: 4GB, CPU: 3
* cores, HDD: 233 GB Ram: 8GB, CPU: 6 cores, HDD: 462 GB (as of March 2010)
*
* @return matched size
*/
@Singleton
@Provides
Function<Size, String> provideSizeToRam() {
return new Function<Size, String>() {
@Override
public String apply(Size size) {
if (size.getRam() >= 8 * 1024 || size.getCores() >= 6 || size.getDisk() >= 450)
return "8GB";
if (size.getRam() >= 4 * 1024 || size.getCores() >= 3 || size.getDisk() >= 230)
return "4GB";
if (size.getRam() >= 2 * 1024 || size.getDisk() >= 110)
return "2GB";
if (size.getRam() >= 1024 || size.getDisk() >= 55)
return "1GB";
return "512MB"; /* smallest */
}
};
}
@Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
private final Map<String, NodeState> serverStateToNodeState;
private final Function<String, InetAddress> stringIpToInetAddress;
private final GoGridClient client;
@SuppressWarnings("unused")
@Inject
ServerToNodeMetadata(Map<String, NodeState> serverStateToNodeState,
Function<String, InetAddress> stringIpToInetAddress, GoGridClient client) {
this.serverStateToNodeState = serverStateToNodeState;
this.stringIpToInetAddress = stringIpToInetAddress;
this.client = client;
}
@Override
public NodeMetadata apply(Server from) {
String locationId = "Unavailable";
String tag = CharMatcher.JAVA_LETTER.retainFrom(from.getName());
Set<InetAddress> ipSet = ImmutableSet
.of(stringIpToInetAddress.apply(from.getIp().getIp()));
NodeState state = serverStateToNodeState.get(from.getState().getName());
Credentials creds = client.getServerServices().getServerCredentialsList().get(
from.getName());
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
ImmutableMap.<String, String> of(), tag, state, ipSet, ImmutableList
.<InetAddress> of(), ImmutableMap.<String, String> of(), creds);
}
}
@Provides
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
RestContext<GoGridAsyncClient, GoGridClient> context) {
return new ComputeServiceContextImpl<GoGridAsyncClient, GoGridClient>(computeService, context);
}
@Provides
@Singleton
@Named("NOT_RUNNING")
protected Predicate<SshClient> runScriptRunning(RunScriptRunning stateRunning) {
return new RetryablePredicate<SshClient>(Predicates.not(stateRunning), 600, 3,
TimeUnit.SECONDS);
}
@Provides
@Singleton
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("SANFRANCISCO");
}
@Provides
@Singleton
Map<String, ? extends Location> getDefaultLocations(GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing locations");
locations.add(new LocationImpl(LocationScope.ZONE, "SANFRANCISCO", "San Francisco, CA", null,
true));
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(GoGridClient sync,
Map<String, ? extends Image> images, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
sizes.add(new SizeImpl("1", "1", null, null, ImmutableMap.<String, String> of(), 1, 512, 28,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("2", "2", null, null, ImmutableMap.<String, String> of(), 1, 1024, 57,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("3", "3", null, null, ImmutableMap.<String, String> of(), 1, 2048,
113, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("4", "4", null, null, ImmutableMap.<String, String> of(), 3, 4096,
233, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("5", "5", null, null, ImmutableMap.<String, String> of(), 6, 8192,
462, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
holder.logger.debug("<< sizes(%d)", sizes.size());
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
public static final Pattern GOGRID_OS_NAME_PATTERN = Pattern.compile("([a-zA-Z]*)(.*)");
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer, Location location,
PopulateDefaultLoginCredentialsForImageStrategy authenticator)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
Set<ServerImage> allImages = sync.getImageServices().getImageList();
for (ServerImage from : allImages) {
OsFamily os = null;
Architecture arch = (from.getOs().getName().indexOf("64") == -1 && from.getDescription()
.indexOf("64") == -1) ? Architecture.X86_32 : Architecture.X86_64;
String osDescription;
String version = "";
osDescription = from.getOs().getName();
String matchedOs = GoGridUtils.parseStringByPatternAndGetNthMatchGroup(from.getOs()
.getName(), GOGRID_OS_NAME_PATTERN, 1);
try { try {
os = OsFamily.fromValue(matchedOs.toLowerCase()); addedServer = client.getServerServices().addServer(name,
} catch (IllegalArgumentException e) { checkNotNull(template.getImage().getId()),
holder.logger.debug("<< didn't match os(%s)", matchedOs); sizeToRam.apply(template.getSize()), availableIp.getIp());
notStarted = false;
} catch (Exception e) {
if (--numOfRetries == 0)
Throwables.propagate(e);
notStarted = true;
} }
Credentials defaultCredentials = authenticator.execute(from); }
images.add(new ImageImpl(from.getId() + "", from.getFriendlyName(), location.getId(), serverLatestJobCompleted.apply(addedServer);
null, ImmutableMap.<String, String> of(), from.getDescription(), version, os,
osDescription, arch, defaultCredentials)); client.getServerServices().power(addedServer.getName(), PowerCommand.START);
} serverLatestJobCompletedShort.apply(addedServer);
holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer); addedServer = Iterables.getOnlyElement(client.getServerServices().getServersByName(
} addedServer.getName()));
return serverToNodeMetadata.apply(addedServer);
}
}
@Singleton
public static class GoGridRebootNodeStrategy implements RebootNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
private RetryablePredicate<Server> serverLatestJobCompletedShort;
@Inject
protected GoGridRebootNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
this.serverLatestJobCompletedShort = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 60, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().power(server.getName(), PowerCommand.RESTART);
serverLatestJobCompleted.apply(server);
client.getServerServices().power(server.getName(), PowerCommand.START);
return serverLatestJobCompletedShort.apply(server);
}
}
@Singleton
public static class GoGridListNodesStrategy implements ListNodesStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridListNodesStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public Iterable<? extends ComputeMetadata> execute() {
return Iterables.transform(client.getServerServices().getServerList(),
serverToNodeMetadata);
}
}
@Singleton
public static class GoGridGetNodeMetadataStrategy implements GetNodeMetadataStrategy {
private final GoGridClient client;
private final Function<Server, NodeMetadata> serverToNodeMetadata;
@Inject
protected GoGridGetNodeMetadataStrategy(GoGridClient client,
Function<Server, NodeMetadata> serverToNodeMetadata) {
this.client = client;
this.serverToNodeMetadata = serverToNodeMetadata;
}
@Override
public NodeMetadata execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
return server == null ? null : serverToNodeMetadata.apply(server);
}
}
@Singleton
public static class GoGridDestroyNodeStrategy implements DestroyNodeStrategy {
private final GoGridClient client;
private RetryablePredicate<Server> serverLatestJobCompleted;
@Inject
protected GoGridDestroyNodeStrategy(GoGridClient client) {
this.client = client;
this.serverLatestJobCompleted = new RetryablePredicate<Server>(
new ServerLatestJobCompleted(client.getJobServices()), 800, 20, TimeUnit.SECONDS);
}
@Override
public boolean execute(ComputeMetadata node) {
Server server = Iterables.getOnlyElement(client.getServerServices().getServersByName(
node.getName()));
client.getServerServices().deleteByName(server.getName());
return serverLatestJobCompleted.apply(server);
}
}
@Singleton
@Provides
Map<String, NodeState> provideServerToNodeState() {
return ImmutableMap.<String, NodeState> builder().put("On", NodeState.RUNNING).put(
"Starting", NodeState.PENDING).put("Off", NodeState.SUSPENDED).put("Saving",
NodeState.PENDING).put("Restarting", NodeState.PENDING).put("Stopping",
NodeState.PENDING).build();
}
@Singleton
@Provides
Function<String, InetAddress> provideStringIpToInetAddress() {
return new Function<String, InetAddress>() {
@Override
public InetAddress apply(String from) {
try {
return InetAddress.getByName(from);
} catch (UnknownHostException e) {
// TODO: log the failure.
return null;
}
}
};
}
/**
* Finds matches to required configurations. GoGrid's documentation only specifies how much RAM
* one can get with different instance types. The # of cores and disk sizes are purely empyrical
* and aren't guaranteed. However, these are the matches found: Ram: 512MB, CPU: 1 core, HDD: 28
* GB Ram: 1GB, CPU: 1 core, HDD: 57 GB Ram: 2GB, CPU: 1 core, HDD: 113 GB Ram: 4GB, CPU: 3
* cores, HDD: 233 GB Ram: 8GB, CPU: 6 cores, HDD: 462 GB (as of March 2010)
*
* @return matched size
*/
@Singleton
@Provides
Function<Size, String> provideSizeToRam() {
return new Function<Size, String>() {
@Override
public String apply(Size size) {
if (size.getRam() >= 8 * 1024 || size.getCores() >= 6 || size.getDisk() >= 450)
return "8GB";
if (size.getRam() >= 4 * 1024 || size.getCores() >= 3 || size.getDisk() >= 230)
return "4GB";
if (size.getRam() >= 2 * 1024 || size.getDisk() >= 110)
return "2GB";
if (size.getRam() >= 1024 || size.getDisk() >= 55)
return "1GB";
return "512MB"; /* smallest */
}
};
}
@Singleton
private static class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
private final Map<String, NodeState> serverStateToNodeState;
private final Function<String, InetAddress> stringIpToInetAddress;
private final GoGridClient client;
@SuppressWarnings("unused")
@Inject
ServerToNodeMetadata(Map<String, NodeState> serverStateToNodeState,
Function<String, InetAddress> stringIpToInetAddress, GoGridClient client) {
this.serverStateToNodeState = serverStateToNodeState;
this.stringIpToInetAddress = stringIpToInetAddress;
this.client = client;
}
@Override
public NodeMetadata apply(Server from) {
String locationId = "Unavailable";
String tag = CharMatcher.JAVA_LETTER.retainFrom(from.getName());
Set<InetAddress> ipSet = ImmutableSet
.of(stringIpToInetAddress.apply(from.getIp().getIp()));
NodeState state = serverStateToNodeState.get(from.getState().getName());
Credentials creds = client.getServerServices().getServerCredentialsList().get(
from.getName());
return new NodeMetadataImpl(from.getId() + "", from.getName(), locationId, null,
ImmutableMap.<String, String> of(), tag, state, ipSet, ImmutableList
.<InetAddress> of(), ImmutableMap.<String, String> of(), creds);
}
}
@Provides
@Singleton
ComputeServiceContext provideContext(ComputeService computeService,
RestContext<GoGridAsyncClient, GoGridClient> context) {
return new ComputeServiceContextImpl<GoGridAsyncClient, GoGridClient>(computeService, context);
}
@Provides
@Singleton
@Named("NOT_RUNNING")
protected Predicate<SshClient> runScriptRunning(RunScriptRunning stateRunning) {
return new RetryablePredicate<SshClient>(Predicates.not(stateRunning), 600, 3,
TimeUnit.SECONDS);
}
@Provides
@Singleton
Location getDefaultLocation(Map<String, ? extends Location> locations) {
return locations.get("SANFRANCISCO");
}
@Provides
@Singleton
Map<String, ? extends Location> getDefaultLocations(GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer) {
final Set<Location> locations = Sets.newHashSet();
holder.logger.debug(">> providing locations");
locations.add(new LocationImpl(LocationScope.ZONE, "SANFRANCISCO", "San Francisco, CA", null,
true));
holder.logger.debug("<< locations(%d)", locations.size());
return Maps.uniqueIndex(locations, new Function<Location, String>() {
@Override
public String apply(Location from) {
return from.getId();
}
});
}
@Provides
@Singleton
protected Function<ComputeMetadata, String> indexer() {
return new Function<ComputeMetadata, String>() {
@Override
public String apply(ComputeMetadata from) {
return from.getId();
}
};
}
@Provides
@Singleton
protected Map<String, ? extends Size> provideSizes(GoGridClient sync,
Map<String, ? extends Image> images, LogHolder holder,
Function<ComputeMetadata, String> indexer) throws InterruptedException,
TimeoutException, ExecutionException {
final Set<Size> sizes = Sets.newHashSet();
holder.logger.debug(">> providing sizes");
sizes.add(new SizeImpl("1", "1", null, null, ImmutableMap.<String, String> of(), 1, 512, 28,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("2", "2", null, null, ImmutableMap.<String, String> of(), 1, 1024, 57,
ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("3", "3", null, null, ImmutableMap.<String, String> of(), 1, 2048,
113, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("4", "4", null, null, ImmutableMap.<String, String> of(), 3, 4096,
233, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
sizes.add(new SizeImpl("5", "5", null, null, ImmutableMap.<String, String> of(), 6, 8192,
462, ImmutableSet.<Architecture> of(Architecture.X86_32, Architecture.X86_64)));
holder.logger.debug("<< sizes(%d)", sizes.size());
return Maps.uniqueIndex(sizes, indexer);
}
private static class LogHolder {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
}
public static final Pattern GOGRID_OS_NAME_PATTERN = Pattern.compile("([a-zA-Z]*)(.*)");
@Provides
@Singleton
protected Map<String, ? extends Image> provideImages(final GoGridClient sync, LogHolder holder,
Function<ComputeMetadata, String> indexer, Location location,
PopulateDefaultLoginCredentialsForImageStrategy authenticator)
throws InterruptedException, ExecutionException, TimeoutException {
final Set<Image> images = Sets.newHashSet();
holder.logger.debug(">> providing images");
Set<ServerImage> allImages = sync.getImageServices().getImageList();
for (ServerImage from : allImages) {
OsFamily os = null;
Architecture arch = (from.getOs().getName().indexOf("64") == -1 && from.getDescription()
.indexOf("64") == -1) ? Architecture.X86_32 : Architecture.X86_64;
String osDescription;
String version = "";
osDescription = from.getOs().getName();
String matchedOs = GoGridUtils.parseStringByPatternAndGetNthMatchGroup(from.getOs()
.getName(), GOGRID_OS_NAME_PATTERN, 1);
try {
os = OsFamily.fromValue(matchedOs.toLowerCase());
} catch (IllegalArgumentException e) {
holder.logger.debug("<< didn't match os(%s)", matchedOs);
}
Credentials defaultCredentials = authenticator.execute(from);
images.add(new ImageImpl(from.getId() + "", from.getFriendlyName(), location.getId(),
null, ImmutableMap.<String, String> of(), from.getDescription(), version, os,
osDescription, arch, defaultCredentials));
}
holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer);
}
} }

View File

@ -109,10 +109,8 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext
} }
@Provides @Provides
TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.osFamily(UBUNTU);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).osFamily(UBUNTU);
} }
@Provides @Provides

View File

@ -112,11 +112,8 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
} }
@Provides @Provides
TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.sizeId("MIRO1B").osFamily(UBUNTU);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).sizeId("MIRO1B")
.osFamily(UBUNTU);
} }
@Provides @Provides
@ -417,7 +414,7 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo
images.add(new ImageImpl(from.getId(), from.getDescription(), null, null, ImmutableMap images.add(new ImageImpl(from.getId(), from.getDescription(), null, null, ImmutableMap
.<String, String> of(), from.getDescription(), version, os, osDescription, arch, .<String, String> of(), from.getDescription(), version, os, osDescription, arch,
new Credentials("root", null))); new Credentials("root", null)));
} }
holder.logger.debug("<< images(%d)", images.size()); holder.logger.debug("<< images(%d)", images.size());
return Maps.uniqueIndex(images, indexer); return Maps.uniqueIndex(images, indexer);

View File

@ -50,16 +50,19 @@ public class ParseDestroyResponseFromJsonResponse extends ParseJson<List<String>
return cancel_messages; return cancel_messages;
} }
@SuppressWarnings("unused")
public void setCancelMessages(List<String> cancel_messages) { public void setCancelMessages(List<String> cancel_messages) {
this.cancel_messages = cancel_messages; this.cancel_messages = cancel_messages;
} }
} }
@Override @Override
protected List<String> apply(InputStream stream) { protected List<String> apply(InputStream stream) {
Type setType = new TypeToken<Map<String, DestroyResponse>>() { Type setType = new TypeToken<Map<String, DestroyResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, DestroyResponse> responseMap = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, DestroyResponse> responseMap = gson.fromJson(new InputStreamReader(stream,
"UTF-8"), setType);
return responseMap.values().iterator().next().getCancelMessages(); return responseMap.values().iterator().next().getCancelMessages();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -18,14 +18,6 @@
*/ */
package org.jclouds.rimuhosting.miro.functions; package org.jclouds.rimuhosting.miro.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Image;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -33,10 +25,19 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Image;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@Singleton @Singleton
public class ParseImagesFromJsonResponse extends ParseJson<SortedSet<Image>> { public class ParseImagesFromJsonResponse extends ParseJson<SortedSet<Image>> {
@ -52,6 +53,7 @@ public class ParseImagesFromJsonResponse extends ParseJson<SortedSet<Image>> {
return distro_infos; return distro_infos;
} }
@SuppressWarnings("unused")
public void setDistroInfos(SortedSet<Image> distro_infos) { public void setDistroInfos(SortedSet<Image> distro_infos) {
this.distro_infos = distro_infos; this.distro_infos = distro_infos;
} }
@ -61,7 +63,8 @@ public class ParseImagesFromJsonResponse extends ParseJson<SortedSet<Image>> {
Type setType = new TypeToken<Map<String, DistroResponse>>() { Type setType = new TypeToken<Map<String, DistroResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, DistroResponse> t = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, DistroResponse> t = gson.fromJson(new InputStreamReader(stream, "UTF-8"),
setType);
return t.values().iterator().next().getDistroInfos(); return t.values().iterator().next().getDistroInfos();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -18,24 +18,25 @@
*/ */
package org.jclouds.rimuhosting.miro.functions; package org.jclouds.rimuhosting.miro.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@Singleton @Singleton
public class ParseInstanceFromJsonResponse extends ParseJson<Server> { public class ParseInstanceFromJsonResponse extends ParseJson<Server> {
@Inject @Inject
@ -45,20 +46,24 @@ public class ParseInstanceFromJsonResponse extends ParseJson<Server> {
private static class OrderResponse extends RimuHostingResponse { private static class OrderResponse extends RimuHostingResponse {
private Server about_order; private Server about_order;
public Server getAboutOrder() { public Server getAboutOrder() {
return about_order; return about_order;
} }
@SuppressWarnings("unused")
public void setAboutOrder(Server about_orders) { public void setAboutOrder(Server about_orders) {
this.about_order = about_orders; this.about_order = about_orders;
} }
} }
@Override @Override
protected Server apply(InputStream stream) { protected Server apply(InputStream stream) {
Type setType = new TypeToken<Map<String, OrderResponse>>() { Type setType = new TypeToken<Map<String, OrderResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream,
"UTF-8"), setType);
return responseMap.values().iterator().next().getAboutOrder(); return responseMap.values().iterator().next().getAboutOrder();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -18,20 +18,22 @@
*/ */
package org.jclouds.rimuhosting.miro.functions; package org.jclouds.rimuhosting.miro.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.ServerInfo;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.ServerInfo;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@ -49,16 +51,19 @@ public class ParseInstanceInfoFromJsonResponse extends ParseJson<ServerInfo> {
return running_vps_info; return running_vps_info;
} }
@SuppressWarnings("unused")
public void setInstanceInfo(ServerInfo running_vps_info) { public void setInstanceInfo(ServerInfo running_vps_info) {
this.running_vps_info = running_vps_info; this.running_vps_info = running_vps_info;
} }
} }
@Override @Override
protected ServerInfo apply(InputStream stream) { protected ServerInfo apply(InputStream stream) {
Type setType = new TypeToken<Map<String, OrderResponse>>() { Type setType = new TypeToken<Map<String, OrderResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream,
"UTF-8"), setType);
return responseMap.values().iterator().next().getInstanceInfo(); return responseMap.values().iterator().next().getInstanceInfo();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -18,14 +18,6 @@
*/ */
package org.jclouds.rimuhosting.miro.functions; package org.jclouds.rimuhosting.miro.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -33,6 +25,16 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@ -45,20 +47,24 @@ public class ParseInstancesFromJsonResponse extends ParseJson<SortedSet<Server>>
private static class OrderResponse extends RimuHostingResponse { private static class OrderResponse extends RimuHostingResponse {
private SortedSet<Server> about_orders; private SortedSet<Server> about_orders;
public SortedSet<Server> getAboutOrders() { public SortedSet<Server> getAboutOrders() {
return about_orders; return about_orders;
} }
@SuppressWarnings("unused")
public void setAboutOrders(SortedSet<Server> about_orders) { public void setAboutOrders(SortedSet<Server> about_orders) {
this.about_orders = about_orders; this.about_orders = about_orders;
} }
} }
@Override @Override
protected SortedSet<Server> apply(InputStream stream) { protected SortedSet<Server> apply(InputStream stream) {
Type setType = new TypeToken<Map<String, OrderResponse>>() { Type setType = new TypeToken<Map<String, OrderResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, OrderResponse> responseMap = gson.fromJson(new InputStreamReader(stream,
"UTF-8"), setType);
return responseMap.values().iterator().next().getAboutOrders(); return responseMap.values().iterator().next().getAboutOrders();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -18,14 +18,6 @@
*/ */
package org.jclouds.rimuhosting.miro.functions; package org.jclouds.rimuhosting.miro.functions;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.PricingPlan;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -33,6 +25,16 @@ import java.lang.reflect.Type;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.rimuhosting.miro.domain.PricingPlan;
import org.jclouds.rimuhosting.miro.domain.internal.RimuHostingResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/** /**
* @author Ivan Meredith * @author Ivan Meredith
*/ */
@ -50,16 +52,19 @@ public class ParsePricingPlansFromJsonResponse extends ParseJson<SortedSet<Prici
return pricing_plan_infos; return pricing_plan_infos;
} }
@SuppressWarnings("unused")
public void setPricingPlanInfos(SortedSet<PricingPlan> pricing_plan_infos) { public void setPricingPlanInfos(SortedSet<PricingPlan> pricing_plan_infos) {
this.pricing_plan_infos = pricing_plan_infos; this.pricing_plan_infos = pricing_plan_infos;
} }
} }
@Override @Override
protected SortedSet<PricingPlan> apply(InputStream stream) { protected SortedSet<PricingPlan> apply(InputStream stream) {
Type setType = new TypeToken<Map<String, PlansResponse>>() { Type setType = new TypeToken<Map<String, PlansResponse>>() {
}.getType(); }.getType();
try { try {
Map<String, PlansResponse> responseMap = gson.fromJson(new InputStreamReader(stream, "UTF-8"), setType); Map<String, PlansResponse> responseMap = gson.fromJson(new InputStreamReader(stream,
"UTF-8"), setType);
return responseMap.values().iterator().next().getPricingPlanInfos(); return responseMap.values().iterator().next().getPricingPlanInfos();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new RuntimeException("jclouds requires UTF-8 encoding", e); throw new RuntimeException("jclouds requires UTF-8 encoding", e);

View File

@ -1,74 +0,0 @@
/**
*
* Copyright (C) 2009 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.rimuhosting.miro;
import com.google.common.base.Predicate;
import org.jclouds.logging.Logger;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.rimuhosting.miro.domain.NewServerResponse;
import org.jclouds.ssh.SshClient.Factory;
import javax.annotation.Resource;
import javax.inject.Inject;
import java.net.InetSocketAddress;
/**
* @author Ivan Meredith
*/
public class RimuHostingComputeClient {
@Resource
protected Logger logger = Logger.NULL;
private final Predicate<InetSocketAddress> socketTester;
private final RimuHostingClient rhClient;
@Inject
public RimuHostingComputeClient(RimuHostingClient rhClient, Factory sshFactory,
Predicate<InetSocketAddress> socketTester) {
this.rhClient = rhClient;
this.sshFactory = sshFactory;
this.socketTester = socketTester;
}
private final Factory sshFactory;
public Long start(String name, String planId, String imageId) {
logger.debug(">> instantiating RimuHosting VPS name(%s) plan(%s) image(%s)", name, planId, imageId);
NewServerResponse serverRespone = rhClient.createServer(name, imageId, planId);
logger.debug(">> VPS id(%d) started and running.", serverRespone.getServer().getId());
return serverRespone.getServer().getId();
}
public void reboot(Long id) {
Server server = rhClient.getServer(id);
logger.debug(">> rebooting VPS(%d)", server.getId());
rhClient.restartServer(id);
logger.debug("<< on VPS(%d)", server.getId());
}
public void destroy(Long id) {
Server server = rhClient.getServer(id);
logger.debug(">> destroy VPS(%d)", server.getId());
rhClient.destroyServer(id);
logger.debug(">> destroyed VPS");
}
}

View File

@ -1,105 +0,0 @@
/**
*
* Copyright (C) 2009 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.rimuhosting.miro;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.InetAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.predicates.AddressReachable;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.rimuhosting.miro.domain.Server;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code TerremarkVCloudClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "rimuhosting.RimuHostingComputeClientLiveTest")
public class RimuHostingComputeClientLiveTest {
RimuHostingComputeClient client;
RimuHostingClient rhClient;
private Long id;
private InetAddress publicIp;
private Predicate<InetAddress> addressTester;
@Test
public void testPowerOn() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
String imageId = "lenny";
String serverName = "test.compute.jclouds.org";
String planId = "MIRO1B";
id = client.start(serverName, planId, imageId);
Server server = rhClient.getServer(id);
assertEquals(imageId, server.getImageId());
assertEquals(serverName, server.getName());
assertEquals(new Integer(160), server.getInstanceParameters().getRam());
}
@AfterTest
void cleanup() throws InterruptedException, ExecutionException, TimeoutException {
if (id != null)
client.destroy(id);
}
@BeforeGroups(groups = { "live" })
public void setupClient() {
String key = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
Injector injector = new RimuHostingContextBuilder(new RimuHostingPropertiesBuilder(key)
.relaxSSLHostname(true).build()).withModules(new Log4JLoggingModule(),
new JschSshClientModule(), new AbstractModule() {
@Override
protected void configure() {
}
@SuppressWarnings("unused")
@Provides
private Predicate<InetAddress> addressTester(AddressReachable reachable) {
return new RetryablePredicate<InetAddress>(reachable, 60, 5, TimeUnit.SECONDS);
}
}).buildInjector();
client = injector.getInstance(RimuHostingComputeClient.class);
rhClient = injector.getInstance(RimuHostingClient.class);
addressTester = injector.getInstance(Key.get(new TypeLiteral<Predicate<InetAddress>>() {
}));
}
}

View File

@ -114,10 +114,8 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule {
} }
@Provides @Provides
protected TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, protected TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.osFamily(UBUNTU);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).osFamily(UBUNTU);
} }
@Override @Override

View File

@ -20,13 +20,8 @@ package org.jclouds.vcloud.hostingdotcom.compute.config;
import static org.jclouds.compute.domain.OsFamily.CENTOS; import static org.jclouds.compute.domain.OsFamily.CENTOS;
import java.util.Map;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Size;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.TemplateBuilderImpl; import org.jclouds.compute.internal.TemplateBuilderImpl;
import org.jclouds.domain.Location;
import org.jclouds.vcloud.compute.VCloudComputeClient; import org.jclouds.vcloud.compute.VCloudComputeClient;
import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule; import org.jclouds.vcloud.compute.config.VCloudComputeServiceContextModule;
import org.jclouds.vcloud.hostingdotcom.compute.HostingDotComVCloudComputeClient; import org.jclouds.vcloud.hostingdotcom.compute.HostingDotComVCloudComputeClient;
@ -47,10 +42,8 @@ public class HostingDotComVCloudComputeServiceContextModule extends
} }
@Override @Override
protected TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, protected TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.osFamily(CENTOS);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).osFamily(CENTOS);
} }
} }

View File

@ -42,7 +42,6 @@ import org.jclouds.compute.domain.internal.SizeImpl;
import org.jclouds.compute.internal.TemplateBuilderImpl; import org.jclouds.compute.internal.TemplateBuilderImpl;
import org.jclouds.concurrent.ConcurrentUtils; import org.jclouds.concurrent.ConcurrentUtils;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.VCloudClient;
import org.jclouds.vcloud.VCloudMediaType; import org.jclouds.vcloud.VCloudMediaType;
import org.jclouds.vcloud.compute.VCloudComputeClient; import org.jclouds.vcloud.compute.VCloudComputeClient;
@ -79,10 +78,8 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer
} }
@Override @Override
protected TemplateBuilder provideTemplate(Map<String, ? extends Location> locations, protected TemplateBuilder provideTemplate(TemplateBuilderImpl template) {
Map<String, ? extends Image> images, Map<String, ? extends Size> sizes, return template.osFamily(JEOS);
Location defaultLocation) {
return new TemplateBuilderImpl(locations, images, sizes, defaultLocation).osFamily(JEOS);
} }
private static final ComputeOptionsToSize sizeConverter = new ComputeOptionsToSize(); private static final ComputeOptionsToSize sizeConverter = new ComputeOptionsToSize();