diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java index 776fd6f16a..90a609d5dd 100644 --- a/compute/src/main/java/org/jclouds/compute/ComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java @@ -28,11 +28,10 @@ import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.options.RunScriptOptions; -import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; +import org.jclouds.ssh.ExecResponse; import com.google.inject.ImplementedBy; -import org.jclouds.ssh.ExecResponse; /** * Provides portable access to launching compute instances. diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java index 698f6f7bb8..c649aa30cd 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -61,9 +61,9 @@ import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.util.ComputeUtils; -import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; +import org.jclouds.ssh.ExecResponse; import com.google.common.base.Function; import com.google.common.base.Predicate; @@ -72,306 +72,309 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; -import org.jclouds.ssh.ExecResponse; /** - * + * * @author Adrian Cole */ @Singleton public class BaseComputeService implements ComputeService { - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; - protected final ComputeServiceContext context; - protected final Provider> images; - protected final Provider> sizes; - protected final Provider> locations; - protected final ListNodesStrategy listNodesStrategy; - protected final GetNodeMetadataStrategy getNodeMetadataStrategy; - protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy; - protected final RebootNodeStrategy rebootNodeStrategy; - protected final DestroyNodeStrategy destroyNodeStrategy; - protected final Provider templateBuilderProvider; - protected final ComputeUtils utils; - protected final ExecutorService executor; + protected final ComputeServiceContext context; + protected final Provider> images; + protected final Provider> sizes; + protected final Provider> locations; + protected final ListNodesStrategy listNodesStrategy; + protected final GetNodeMetadataStrategy getNodeMetadataStrategy; + protected final RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy; + protected final RebootNodeStrategy rebootNodeStrategy; + protected final DestroyNodeStrategy destroyNodeStrategy; + protected final Provider templateBuilderProvider; + protected final ComputeUtils utils; + protected final ExecutorService executor; - private static class NodeMatchesTag implements Predicate { - private final String tag; + private static class NodeMatchesTag implements Predicate { + private final String tag; - public NodeMatchesTag(String tag) { - this.tag = tag; - } + public NodeMatchesTag(String tag) { + this.tag = tag; + } - @Override - public boolean apply(NodeMetadata from) { - return from.getTag().equals(tag); - } + @Override + public boolean apply(NodeMetadata from) { + return from.getTag().equals(tag); + } - }; + }; - public static Function METADATA_TO_ID = new Function() { - @Override - public String apply(ComputeMetadata from) { - return from.getId(); - } - }; + public static Function METADATA_TO_ID = new Function() { + @Override + public String apply(ComputeMetadata from) { + return from.getId(); + } + }; - public static Function METADATA_TO_NAME = new Function() { - @Override - public String apply(ComputeMetadata from) { - return from.getName(); - } - }; + public static Function METADATA_TO_NAME = new Function() { + @Override + public String apply(ComputeMetadata from) { + return from.getName(); + } + }; - @Inject - protected BaseComputeService(ComputeServiceContext context, - Provider> images, - Provider> sizes, - Provider> locations, - ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, - RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy, - RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, - Provider templateBuilderProvider, ComputeUtils utils, - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { - this.context = checkNotNull(context, "context"); - this.images = checkNotNull(images, "images"); - this.sizes = checkNotNull(sizes, "sizes"); - this.locations = checkNotNull(locations, "locations"); - this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy"); - this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy, - "getNodeMetadataStrategy"); - this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, - "runNodesAndAddToSetStrategy"); - this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy"); - this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy"); - this.templateBuilderProvider = checkNotNull(templateBuilderProvider, - "templateBuilderProvider"); - this.utils = checkNotNull(utils, "utils"); - this.executor = checkNotNull(executor, "executor"); - } + @Inject + protected BaseComputeService(ComputeServiceContext context, + Provider> images, + Provider> sizes, + Provider> locations, + ListNodesStrategy listNodesStrategy, GetNodeMetadataStrategy getNodeMetadataStrategy, + RunNodesAndAddToSetStrategy runNodesAndAddToSetStrategy, + RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, + Provider templateBuilderProvider, ComputeUtils utils, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { + this.context = checkNotNull(context, "context"); + this.images = checkNotNull(images, "images"); + this.sizes = checkNotNull(sizes, "sizes"); + this.locations = checkNotNull(locations, "locations"); + this.listNodesStrategy = checkNotNull(listNodesStrategy, "listNodesStrategy"); + this.getNodeMetadataStrategy = checkNotNull(getNodeMetadataStrategy, + "getNodeMetadataStrategy"); + this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, + "runNodesAndAddToSetStrategy"); + this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy"); + this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy"); + this.templateBuilderProvider = checkNotNull(templateBuilderProvider, + "templateBuilderProvider"); + this.utils = checkNotNull(utils, "utils"); + this.executor = checkNotNull(executor, "executor"); + } - @Override - public ComputeServiceContext getContext() { - return context; - } + @Override + public ComputeServiceContext getContext() { + return context; + } - @Override - public Map runNodesWithTag(final String tag, int count, - final Template template) { - checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens"); - checkNotNull(template.getLocation(), "location"); - 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 + @Override + public Map runNodesWithTag(final String tag, int count, + final Template template) { + checkArgument(tag.indexOf('-') == -1, "tag cannot contain hyphens"); + checkNotNull(template.getLocation(), "location"); + 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 .getImage().getId(), template.getSize().getId(), template.getOptions()); - final Set nodes = Sets.newHashSet(); - Map> responses = runNodesAndAddToSetStrategy.execute(tag, count, - template, nodes); - Map exceptions = awaitCompletion(responses, executor, null, logger, - "starting nodes"); - if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) { - ImmutableMap currentNodes = Maps.uniqueIndex( - listNodesStrategy.execute(), METADATA_TO_ID); - for (Entry entry : exceptions.entrySet()) { - logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry - .getKey(), entry.getValue().getMessage()); - destroyNode(currentNodes.get(entry.getKey())); - } - } - return Maps.uniqueIndex(nodes, METADATA_TO_ID); - } + final Set nodes = Sets.newHashSet(); + Map> responses = runNodesAndAddToSetStrategy.execute(tag, count, + template, nodes); + Map exceptions = awaitCompletion(responses, executor, null, logger, + "starting nodes"); + if (exceptions.size() > 0 && template.getOptions().shouldDestroyOnError()) { + ImmutableMap currentNodes = Maps.uniqueIndex( + listNodesStrategy.execute(), METADATA_TO_ID); + for (Entry entry : exceptions.entrySet()) { + logger.error(entry.getValue(), "<< error applying nodes(%s) [%s] destroying ", entry + .getKey(), entry.getValue().getMessage()); + destroyNode(currentNodes.get(entry.getKey())); + } + } + return Maps.uniqueIndex(nodes, METADATA_TO_ID); + } - @Override - public void destroyNode(ComputeMetadata node) { - checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " - + node.getType()); - checkNotNull(node.getId(), "node.id"); - logger.debug(">> destroying node(%s)", node.getId()); - boolean successful = destroyNodeStrategy.execute(node); - logger.debug("<< destroyed node(%s) success(%s)", node.getId(), successful); - } + @Override + public void destroyNode(ComputeMetadata node) { + checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " + + node.getType()); + checkNotNull(node.getId(), "node.id"); + logger.debug(">> destroying node(%s)", node.getId()); + boolean successful = destroyNodeStrategy.execute(node); + logger.debug("<< destroyed node(%s) success(%s)", node.getId(), successful); + } - @Override - public void destroyNodesWithTag(String tag) { // TODO parallel - logger.debug(">> destroying nodes by tag(%s)", tag); - Iterable nodesToDestroy = Iterables.filter(doGetNodesWithTag(tag) - .values(), new Predicate() { + @Override + public void destroyNodesWithTag(String tag) { // TODO parallel + logger.debug(">> destroying nodes by tag(%s)", tag); + Iterable nodesToDestroy = Iterables.filter(doGetNodesWithTag(tag) + .values(), new Predicate() { + @Override + public boolean apply(NodeMetadata input) { + return input.getState() != NodeState.TERMINATED; + + } + }); + Map> responses = Maps.newHashMap(); + for (final NodeMetadata node : nodesToDestroy) { + responses.put(node, makeListenable(executor.submit(new Callable() { @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; - + public Void call() throws Exception { + destroyNode(node); + return null; } - }); - Map> responses = Maps.newHashMap(); - for (final NodeMetadata node : nodesToDestroy) { - responses.put(node, makeListenable(executor.submit(new Callable() { - @Override - public Void call() throws Exception { - destroyNode(node); - return null; - } - }), executor)); - } - awaitCompletion(responses, executor, null, logger, "destroying nodes"); - logger.debug("<< destroyed"); - } + }), executor)); + } + awaitCompletion(responses, executor, null, logger, "destroying nodes"); + logger.debug("<< destroyed"); + } - @Override - public Map getNodes() { - logger.debug(">> listing servers"); - ImmutableMap map = Maps.uniqueIndex(listNodesStrategy - .execute(), METADATA_TO_ID); - logger.debug("<< list(%d)", map.size()); - return map; - } + @Override + public Map getNodes() { + logger.debug(">> listing servers"); + ImmutableMap map = Maps.uniqueIndex(listNodesStrategy + .execute(), METADATA_TO_ID); + logger.debug("<< list(%d)", map.size()); + return map; + } - /** - * If the result of {@link ListNodesStrategy#execute} is a set of nodes, then return them. - * Otherwise iteratively call {@link #getNodeMetadata} - */ - protected Map doGetNodesWithTag(final String tag) { - Iterable nodes = Iterables.filter(Iterables.transform( - listNodesStrategy.execute(), new Function() { + /** + * If the result of {@link ListNodesStrategy#execute} is a set of nodes, then return them. + * Otherwise iteratively call {@link #getNodeMetadata} + */ + protected Map doGetNodesWithTag(final String tag) { + Iterable nodes = Iterables.filter(Iterables.transform( + listNodesStrategy.execute(), new Function() { - @Override - public NodeMetadata apply(ComputeMetadata from) { - return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) - : getNodeMetadata(from); - } + @Override + public NodeMetadata apply(ComputeMetadata from) { + return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) + : getNodeMetadata(from); + } - }), new Predicate() { + }), new Predicate() { + @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 getNodesWithTag(String tag) { + logger.debug(">> listing nodes by tag(%s)", tag); + Map nodes = doGetNodesWithTag(tag); + logger.debug("<< list(%d)", nodes.size()); + return nodes; + } + + @Override + public Map getSizes() { + return sizes.get(); + } + + @Override + public Map getImages() { + return images.get(); + } + + @Override + public Map 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 nodesToReboot = Iterables.filter(doGetNodesWithTag(tag) + .values(), new Predicate() { + @Override + public boolean apply(NodeMetadata input) { + return input.getState() != NodeState.TERMINATED; + + } + }); + Map> responses = Maps.newHashMap(); + for (final NodeMetadata node : nodesToReboot) { + responses.put(node, makeListenable(executor.submit(new Callable() { @Override - public boolean apply(NodeMetadata input) { - return tag.equals(input.getTag()); + public Void call() throws Exception { + 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, byte[], org.jclouds.compute.options.RunScriptOptions) + */ + public Map runScriptOnNodesWithTag(String tag, byte[] runScript) { + return runScriptOnNodesWithTag(tag, runScript, RunScriptOptions.NONE); + } - @Override - public Map getNodesWithTag(String tag) { - logger.debug(">> listing nodes by tag(%s)", tag); - Map nodes = doGetNodesWithTag(tag); - logger.debug("<< list(%d)", nodes.size()); - return nodes; - } + /** + * Run the script on all nodes with the specific tag. + * + * @param tag + * tag to look up the 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, whether to override credentials + * @return map with node identifiers and corresponding responses + */ + @SuppressWarnings("unchecked") + public Map runScriptOnNodesWithTag(String tag, 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 - public Map getSizes() { - return sizes.get(); - } + Map nodes = getNodesWithTag(tag); + Map responses = Maps.newHashMap(); - @Override - public Map getImages() { - return images.get(); - } + for (NodeMetadata node : nodes.values()) { + if (NodeState.RUNNING != node.getState()) + continue; // make sure the node is active - @Override - public Map getLocations() { - return locations.get(); - } + if (options.getOverrideCredentials() != null) { + // override the credentials with provided to this method + node = ComputeUtils.installNewCredentials(node, options.getOverrideCredentials()); + } else { + // don't override + checkNotNull(node.getCredentials(), + "If the default credentials need to be used, they can't be null"); + } - @Override - public TemplateBuilder templateBuilder() { - return templateBuilderProvider.get(); - } + ComputeUtils.SshCallable callable; + if (options.isRunAsRoot()) + callable = utils.runScriptOnNode(node, "computeserv.sh", runScript); + else + callable = utils.runScriptOnNodeAsDefaultUser(node, "computeserv.sh", runScript); - @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 nodesToReboot = Iterables.filter(doGetNodesWithTag(tag) - .values(), new Predicate() { - @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; - - } - }); - Map> responses = Maps.newHashMap(); - for (final NodeMetadata node : nodesToReboot) { - responses.put(node, makeListenable(executor.submit(new Callable() { - @Override - public Void call() throws Exception { - rebootNode(node); - return null; - } - }), executor)); - } - awaitCompletion(responses, executor, null, logger, "rebooting nodes"); - logger.debug("<< rebooted"); - } - - /** - * @see #runScriptOnNodesWithTag(String, byte[], - * org.jclouds.compute.options.RunScriptOptions) - */ - public Map runScriptOnNodesWithTag(String tag, - byte[] runScript) { - return runScriptOnNodesWithTag(tag, runScript, RunScriptOptions.NONE); - } - - /** - * Run the script on all nodes with the specific tag. - * - * @param tag tag to look up the 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, whether to override credentials - * @return map with node identifiers and corresponding responses - */ - public Map runScriptOnNodesWithTag(String tag, 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 nodes = getNodesWithTag(tag); - Map responses = Maps.newHashMap(); - - for(NodeMetadata node : nodes.values()) { - if(NodeState.RUNNING != node.getState()) continue; //make sure the node is active - - if(options.getOverrideCredentials() != null) { - //override the credentials with provided to this method - node = ComputeUtils.installNewCredentials(node, options.getOverrideCredentials()); - } else { - //don't override - checkNotNull(node.getCredentials(), "If the default credentials need to be used, they can't be null"); - } - - ComputeUtils.SshCallable callable; - if(options.isRunAsRoot()) - callable = utils.runScriptOnNode(node, "computeserv.sh", runScript); - else - callable = utils.runScriptOnNodeAsDefaultUser(node, "computeserv.sh", runScript); - - Map, ?> scriptRunResults = utils.runCallablesOnNode(node, - Sets.newHashSet(callable), - null); - responses.put(node.getId(), - (ExecResponse) scriptRunResults.get(callable)); - } - return responses; - } + Map, ?> scriptRunResults = utils.runCallablesOnNode(node, Sets + .newHashSet(callable), null); + responses.put(node.getId(), (ExecResponse) scriptRunResults.get(callable)); + } + return responses; + } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java b/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java index e3eb60f792..96d8882779 100644 --- a/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/RunScriptOptions.java @@ -22,69 +22,65 @@ import org.jclouds.domain.Credentials; /** * Enables additional options for running a script. - * + * * @author Oleksiy Yarmula */ public class RunScriptOptions { - /** - * Default options. The default settings are: - *
    - *
  • override the credentials with ones supplied in - * call to {@link org.jclouds.compute.ComputeService#runScriptOnNodesWithTag}
  • - *
  • run the script as root (versus running with current privileges)
  • - *
- */ - public static final RunScriptOptions NONE = new RunScriptOptions(); + /** + * Default options. The default settings are: + *
    + *
  • override the credentials with ones supplied in call to + * {@link org.jclouds.compute.ComputeService#runScriptOnNodesWithTag}
  • + *
  • run the script as root (versus running with current privileges)
  • + *
+ */ + public static final RunScriptOptions NONE = new RunScriptOptions(); - private Credentials overridingCredentials; - private boolean runAsRoot = true; + private Credentials overridingCredentials; + private boolean runAsRoot = true; - private void withOverridingCredentials(Credentials overridingCredentials) { - this.overridingCredentials = overridingCredentials; - } + public RunScriptOptions withOverridingCredentials(Credentials overridingCredentials) { + this.overridingCredentials = overridingCredentials; + return this; + } - private void runAsRoot(boolean runAsRoot) { - this.runAsRoot = runAsRoot; - } + public RunScriptOptions runAsRoot(boolean runAsRoot) { + this.runAsRoot = runAsRoot; + return this; + } - /** - * Whether to override the credentials with ones supplied in - * call to {@link org.jclouds.compute.ComputeService#runScriptOnNodesWithTag}. - * By default, true. - * @return value - */ - public Credentials getOverrideCredentials() { - return overridingCredentials; - } + /** + * Whether to override the credentials with ones supplied in call to + * {@link org.jclouds.compute.ComputeService#runScriptOnNodesWithTag}. By default, true. + * + * @return value + */ + public Credentials getOverrideCredentials() { + return overridingCredentials; + } - /** - * Whether to run the script as root (or run with current privileges). - * By default, true. - * @return value - */ - public boolean isRunAsRoot() { - return runAsRoot; - } + /** + * Whether to run the script as root (or run with current privileges). By default, true. + * + * @return value + */ + public boolean isRunAsRoot() { + return runAsRoot; + } - public static class Builder { - private RunScriptOptions options; + public static class Builder { - public Builder overrideCredentials(Credentials credentials) { - if(options == null) options = new RunScriptOptions(); - options.withOverridingCredentials(credentials); - return this; - } + public static RunScriptOptions overrideCredentialsWith(Credentials credentials) { + RunScriptOptions options = new RunScriptOptions(); + return options.withOverridingCredentials(credentials); + } - public Builder runAsRoot(boolean value) { - if(options == null) options = new RunScriptOptions(); - options.runAsRoot(value); - return this; - } + public static RunScriptOptions runAsRoot(boolean value) { + RunScriptOptions options = new RunScriptOptions(); + return options.runAsRoot(value); + } - public RunScriptOptions build() { - return options; - } - } + } } diff --git a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java index 725170fa36..defc3691f9 100644 --- a/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java +++ b/compute/src/main/java/org/jclouds/compute/options/TemplateOptions.java @@ -34,6 +34,18 @@ public class TemplateOptions { private boolean destroyOnError; + private int port = -1; + + private int seconds = -1; + + public int getPort() { + return port; + } + + public int getSeconds() { + return seconds; + } + public int[] getInboundPorts() { return inboundPorts; } @@ -54,6 +66,17 @@ public class TemplateOptions { return destroyOnError; } + /** + * When the node is started, wait until the following port is active + */ + public TemplateOptions blockOnPort(int port, int seconds) { + checkArgument(port > 0 && port < 65536, "port must be a positive integer < 65535"); + checkArgument(seconds > 0, "seconds must be a positive integer"); + this.port = port; + this.seconds = seconds; + return this; + } + /** * If there is an error applying options after creating the node, destroy it. */ @@ -98,6 +121,8 @@ public class TemplateOptions { * Opens the set of ports to public access. */ public TemplateOptions inboundPorts(int... ports) { + for (int port : ports) + checkArgument(port > 0 && port < 65536, "port must be a positive integer < 65535"); this.inboundPorts = ports; return this; } @@ -119,6 +144,14 @@ public class TemplateOptions { return options.inboundPorts(ports); } + /** + * @see TemplateOptions#port + */ + public static TemplateOptions blockOnPort(int port, int seconds) { + TemplateOptions options = new TemplateOptions(); + return options.blockOnPort(port, seconds); + } + /** * @see TemplateOptions#runScript */ @@ -149,6 +182,7 @@ public class TemplateOptions { public String toString() { return "TemplateOptions [inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) + ", publicKey=" + (publicKey != null) + ", runScript=" - + (script != null) + ", destroyOnError=" + destroyOnError + "]"; + + (script != null) + ", destroyOnError=" + destroyOnError + ", port:seconds=" + port + + ":" + seconds + "]"; } } diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java index ef6882223b..3f8741468d 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import javax.annotation.Resource; @@ -46,6 +47,8 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.concurrent.ConcurrentUtils; import org.jclouds.domain.Credentials; import org.jclouds.logging.Logger; +import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.predicates.SocketOpen; import org.jclouds.scriptbuilder.InitBuilder; import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.ssh.ExecResponse; @@ -62,304 +65,330 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; /** - * + * * @author Adrian Cole */ public class ComputeUtils { - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - @Inject(optional = true) - private SshClient.Factory sshFactory; - protected final Predicate runScriptNotRunning; - private final Predicate socketTester; - private final ExecutorService executor; + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + @Inject(optional = true) + private SshClient.Factory sshFactory; + protected final Predicate runScriptNotRunning; + private final Predicate socketTester; + private final ExecutorService executor; - @Inject - public ComputeUtils(Predicate socketTester, - @Named("NOT_RUNNING") Predicate runScriptNotRunning, - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { - this.socketTester = socketTester; - this.runScriptNotRunning = runScriptNotRunning; - this.executor = executor; - } + private int sshRetries = 3; - public static Iterable filterByName( + @Inject + public ComputeUtils(Predicate socketTester, + @Named("NOT_RUNNING") Predicate runScriptNotRunning, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { + this.socketTester = socketTester; + this.runScriptNotRunning = runScriptNotRunning; + this.executor = executor; + } + + public static Iterable filterByName( Iterable nodes, final String name) { - return Iterables.filter(nodes, new Predicate() { - @Override - public boolean apply(ComputeMetadata input) { - return input.getName().equalsIgnoreCase(name); + return Iterables.filter(nodes, new Predicate() { + @Override + public boolean apply(ComputeMetadata input) { + return input.getName().equalsIgnoreCase(name); + } + }); + } + + public static final Comparator ADDRESS_COMPARATOR = new Comparator() { + + @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> 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); + } + + if (options.getPort() > 0) { + blockUntilPortIsListeningOnPublicIp(options.getPort(), options.getSeconds(), Iterables + .get(node.getPublicAddresses(), 0)); + } + } + + private void blockUntilPortIsListeningOnPublicIp(int port, int seconds, InetAddress inetAddress) { + logger.debug(">> blocking on port %s:%d for %d seconds", inetAddress, port, seconds); + RetryablePredicate tester = new RetryablePredicate( + new SocketOpen(), seconds, 1, TimeUnit.SECONDS); + InetSocketAddress socket = new InetSocketAddress(inetAddress, port); + boolean passed = tester.apply(socket); + if (passed) + logger.debug("<< port %s:%d opened", inetAddress, port); + else + logger.warn("<< port %s:%d didn't open after %d seconds", seconds, inetAddress, port); + } + + 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 RunScriptOnNode runScriptOnNodeAsDefaultUser(NodeMetadata node, String scriptName, + byte[] script) { + return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script, false); + } + + public Map, ?> runCallablesOnNode(NodeMetadata node, + Iterable> parallel, @Nullable SshCallable last) { + checkState(this.sshFactory != null, "runScript requested, but no SshModule configured"); + checkNotNull(node.getCredentials().key, "credentials.key for node " + node.getId()); + + 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 < sshRetries; i++) { + try { + ssh.connect(); + Map, 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 ADDRESS_COMPARATOR = new Comparator() { - - @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> 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 RunScriptOnNode runScriptOnNodeAsDefaultUser(NodeMetadata node, String scriptName, byte[] script) { - return new RunScriptOnNode(runScriptNotRunning, node, scriptName, script, false); - } - - public Map, ?> runCallablesOnNode(NodeMetadata node, Iterable> 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, ListenableFuture> responses = Maps.newHashMap(); - - for (SshCallable callable : parallel) { - callable.setConnection(ssh, logger); - responses.put(callable, ConcurrentUtils.makeListenable(executor.submit(callable), - executor)); - } - - Map, 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(); + Map, 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); + } } - } - throw new RuntimeException(String.format("Couldn't connect to node %s and run the script", node.getId())); - } + return transform(responses); + } catch (RuntimeException from) { + if (i + 1 == sshRetries) + throw Throwables.propagate(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 Map, T> transform(Map, ListenableFuture> responses) { - Map, T> actualResponses = Maps.newHashMap(); - for(Map.Entry, ListenableFuture> entry : responses.entrySet()) { - try { + public Map, T> transform(Map, ListenableFuture> responses) { + Map, T> actualResponses = Maps.newHashMap(); + for (Map.Entry, ListenableFuture> entry : responses.entrySet()) { + try { actualResponses.put(entry.getKey(), (T) entry.getValue().get()); - } catch(InterruptedException e) { - throw Throwables.propagate(e); - } catch(ExecutionException e) { - throw Throwables.propagate(e); - } - } - return actualResponses; - } + } catch (InterruptedException e) { + throw Throwables.propagate(e); + } catch (ExecutionException e) { + throw Throwables.propagate(e); + } + } + return actualResponses; + } - public static interface SshCallable extends Callable { - void setConnection(SshClient ssh, Logger logger); - } + public static interface SshCallable extends Callable { + void setConnection(SshClient ssh, Logger logger); + } - public static class RunScriptOnNode implements SshCallable { - private SshClient ssh; - protected final Predicate runScriptNotRunning; - private final NodeMetadata node; - private final String scriptName; - private final byte[] script; - private final boolean runAsRoot; - private Logger logger = Logger.NULL; + public static class RunScriptOnNode implements SshCallable { + private SshClient ssh; + protected final Predicate runScriptNotRunning; + private final NodeMetadata node; + private final String scriptName; + private final byte[] script; + private final boolean runAsRoot; + private Logger logger = Logger.NULL; - RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, - NodeMetadata node, String scriptName, byte[] script) { - this.runScriptNotRunning = runScriptNotRunning; - this.node = checkNotNull(node, "node"); - this.scriptName = checkNotNull(scriptName, "scriptName"); - this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap - . of(), Iterables.toArray(Splitter.on("\n").split( - new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) - .getBytes(); - this.runAsRoot = true; - } + RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, + NodeMetadata node, String scriptName, byte[] script) { + this.runScriptNotRunning = runScriptNotRunning; + this.node = checkNotNull(node, "node"); + this.scriptName = checkNotNull(scriptName, "scriptName"); + this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap + . of(), Iterables.toArray(Splitter.on("\n").split( + new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) + .getBytes(); + this.runAsRoot = true; + } - RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, - NodeMetadata node, String scriptName, byte[] script, boolean runAsRoot) { - this.runScriptNotRunning = runScriptNotRunning; - this.node = checkNotNull(node, "node"); - this.scriptName = checkNotNull(scriptName, "scriptName"); - this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap - . of(), Iterables.toArray(Splitter.on("\n").split( - new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) - .getBytes(); - this.runAsRoot = runAsRoot; - } + RunScriptOnNode(@Named("NOT_RUNNING") Predicate runScriptNotRunning, + NodeMetadata node, String scriptName, byte[] script, boolean runAsRoot) { + this.runScriptNotRunning = runScriptNotRunning; + this.node = checkNotNull(node, "node"); + this.scriptName = checkNotNull(scriptName, "scriptName"); + this.script = new InitBuilder("runscript", "/tmp", "/tmp", ImmutableMap + . of(), Iterables.toArray(Splitter.on("\n").split( + new String(checkNotNull(script, "script"))), String.class)).build(OsFamily.UNIX) + .getBytes(); + this.runAsRoot = runAsRoot; + } - @Override - public ExecResponse call() throws Exception { - ssh.put(scriptName, new ByteArrayInputStream(script)); - ExecResponse returnVal = ssh.exec("chmod 755 " + scriptName); - returnVal = ssh.exec("./" + scriptName + " init"); + @Override + public ExecResponse call() throws Exception { + ssh.put(scriptName, new ByteArrayInputStream(script)); + ExecResponse returnVal = ssh.exec("chmod 755 " + scriptName); + returnVal = ssh.exec("./" + scriptName + " init"); - if(runAsRoot) returnVal = runScriptAsRoot(); - else returnVal = runScriptAsDefaultUser(); - runScriptNotRunning.apply(ssh); - logger.debug("<< complete(%d)", returnVal.getExitCode()); - return returnVal; - } + if (runAsRoot) + returnVal = runScriptAsRoot(); + else + returnVal = runScriptAsDefaultUser(); + runScriptNotRunning.apply(ssh); + logger.debug("<< complete(%d)", returnVal.getExitCode()); + return returnVal; + } - @Override - public void setConnection(SshClient ssh, Logger logger) { - this.logger = checkNotNull(logger, "logger"); - this.ssh = checkNotNull(ssh, "ssh"); - } + @Override + public void setConnection(SshClient ssh, Logger logger) { + this.logger = checkNotNull(logger, "logger"); + this.ssh = checkNotNull(ssh, "ssh"); + } - private ExecResponse runScriptAsRoot() { - if (node.getCredentials().account.equals("root")) { - logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account, - Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); - return ssh.exec("./" + scriptName + " start"); - } else if (isKeyAuth(node)) { - logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account, - Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); - return ssh.exec("sudo ./" + scriptName + " start"); - } else { - logger.debug(">> running sudo -S %s as %s@%s", scriptName, - node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0) - .getHostAddress()); - return ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key, - scriptName + " start")); - } - } + private ExecResponse runScriptAsRoot() { + if (node.getCredentials().account.equals("root")) { + logger.debug(">> running %s as %s@%s", scriptName, node.getCredentials().account, + Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); + return ssh.exec("./" + scriptName + " start"); + } else if (isKeyAuth(node)) { + logger.debug(">> running sudo %s as %s@%s", scriptName, node.getCredentials().account, + Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); + return ssh.exec("sudo ./" + scriptName + " start"); + } else { + logger.debug(">> running sudo -S %s as %s@%s", scriptName, + node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0) + .getHostAddress()); + return ssh.exec(String.format("echo %s|sudo -S ./%s", node.getCredentials().key, + scriptName + " start")); + } + } - private ExecResponse runScriptAsDefaultUser() { - logger.debug(">> running script %s as %s@%s", scriptName, - node.getCredentials().account, Iterables.get(node.getPublicAddresses(), 0) - .getHostAddress()); - return ssh.exec(String.format("./%s", scriptName + " start")); - } - } + private ExecResponse runScriptAsDefaultUser() { + logger.debug(">> running script %s as %s@%s", scriptName, node.getCredentials().account, + Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); + return ssh.exec(String.format("./%s", scriptName + " start")); + } + } - public static class InstallRSAPrivateKey implements SshCallable { - private SshClient ssh; - private final NodeMetadata node; - private final String privateKey; + public static class InstallRSAPrivateKey implements SshCallable { + private SshClient ssh; + private final NodeMetadata node; + private final String privateKey; - private Logger logger = Logger.NULL; + private Logger logger = Logger.NULL; - InstallRSAPrivateKey(NodeMetadata node, String privateKey) { - this.node = checkNotNull(node, "node"); - this.privateKey = checkNotNull(privateKey, "privateKey"); - } + InstallRSAPrivateKey(NodeMetadata node, String privateKey) { + this.node = checkNotNull(node, "node"); + this.privateKey = checkNotNull(privateKey, "privateKey"); + } - @Override - public ExecResponse call() throws Exception { - ssh.exec("mkdir .ssh"); - ssh.put(".ssh/id_rsa", new ByteArrayInputStream(privateKey.getBytes())); - logger.debug(">> installing rsa key for %s@%s", node.getCredentials().account, Iterables - .get(node.getPublicAddresses(), 0).getHostAddress()); - return ssh.exec("chmod 600 .ssh/id_rsa"); - } + @Override + public ExecResponse call() throws Exception { + ssh.exec("mkdir .ssh"); + ssh.put(".ssh/id_rsa", new ByteArrayInputStream(privateKey.getBytes())); + logger.debug(">> installing rsa key for %s@%s", node.getCredentials().account, Iterables + .get(node.getPublicAddresses(), 0).getHostAddress()); + return ssh.exec("chmod 600 .ssh/id_rsa"); + } - @Override - public void setConnection(SshClient ssh, Logger logger) { - this.logger = checkNotNull(logger, "logger"); - this.ssh = checkNotNull(ssh, "ssh"); - } + @Override + public void setConnection(SshClient ssh, Logger logger) { + this.logger = checkNotNull(logger, "logger"); + this.ssh = checkNotNull(ssh, "ssh"); + } - } + } - public static class AuthorizeRSAPublicKey implements SshCallable { - private SshClient ssh; - private final NodeMetadata node; - private final String publicKey; + public static class AuthorizeRSAPublicKey implements SshCallable { + private SshClient ssh; + private final NodeMetadata node; + private final String publicKey; - private Logger logger = Logger.NULL; + private Logger logger = Logger.NULL; - AuthorizeRSAPublicKey(NodeMetadata node, String publicKey) { - this.node = checkNotNull(node, "node"); - this.publicKey = checkNotNull(publicKey, "publicKey"); - } + AuthorizeRSAPublicKey(NodeMetadata node, String publicKey) { + this.node = checkNotNull(node, "node"); + this.publicKey = checkNotNull(publicKey, "publicKey"); + } - @Override - public ExecResponse call() throws Exception { - ssh.exec("mkdir .ssh"); - ssh.put(".ssh/id_rsa.pub", new ByteArrayInputStream(publicKey.getBytes())); - logger.debug(">> authorizing rsa public key for %s@%s", node.getCredentials().account, - Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); - ExecResponse returnVal = ssh.exec("cat .ssh/id_rsa.pub >> .ssh/authorized_keys"); - returnVal = ssh.exec("chmod 600 .ssh/authorized_keys"); - logger.debug("<< complete(%d)", returnVal.getExitCode()); - return returnVal; - } + @Override + public ExecResponse call() throws Exception { + ssh.exec("mkdir .ssh"); + ssh.put(".ssh/id_rsa.pub", new ByteArrayInputStream(publicKey.getBytes())); + logger.debug(">> authorizing rsa public key for %s@%s", node.getCredentials().account, + Iterables.get(node.getPublicAddresses(), 0).getHostAddress()); + ExecResponse returnVal = ssh.exec("cat .ssh/id_rsa.pub >> .ssh/authorized_keys"); + returnVal = ssh.exec("chmod 600 .ssh/authorized_keys"); + logger.debug("<< complete(%d)", returnVal.getExitCode()); + return returnVal; + } - @Override - public void setConnection(SshClient ssh, Logger logger) { - this.logger = checkNotNull(logger, "logger"); - this.ssh = checkNotNull(ssh, "ssh"); - } + @Override + public void setConnection(SshClient ssh, Logger logger) { + this.logger = checkNotNull(logger, "logger"); + this.ssh = checkNotNull(ssh, "ssh"); + } - } + } - public static boolean isKeyAuth(NodeMetadata createdNode) { - return createdNode.getCredentials().key != null - && createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----"); - } + public static boolean isKeyAuth(NodeMetadata createdNode) { + return createdNode.getCredentials().key != null + && createdNode.getCredentials().key.startsWith("-----BEGIN RSA PRIVATE KEY-----"); + } - /** - * Given the instances of {@link NodeMetadata} (immutable) - * and {@link Credentials} (immutable), returns a new instance of {@link NodeMetadata} - * that has new credentials - */ - public static NodeMetadata installNewCredentials(NodeMetadata node, Credentials newCredentials) { - return new NodeMetadataImpl(node.getId(), node.getName(), node.getLocationId(), node.getUri(), - node.getUserMetadata(), node.getTag(), node.getState(), node. getPublicAddresses(), - node.getPrivateAddresses(), node.getExtra(), newCredentials); - } + /** + * Given the instances of {@link NodeMetadata} (immutable) and {@link Credentials} (immutable), + * returns a new instance of {@link NodeMetadata} that has new credentials + */ + public static NodeMetadata installNewCredentials(NodeMetadata node, Credentials newCredentials) { + return new NodeMetadataImpl(node.getId(), node.getName(), node.getLocationId(), + node.getUri(), node.getUserMetadata(), node.getTag(), node.getState(), node + .getPublicAddresses(), node.getPrivateAddresses(), node.getExtra(), + newCredentials); + } } diff --git a/compute/src/test/java/org/jclouds/compute/options/TemplateOptionsTest.java b/compute/src/test/java/org/jclouds/compute/options/TemplateOptionsTest.java new file mode 100755 index 0000000000..d5f5a836df --- /dev/null +++ b/compute/src/test/java/org/jclouds/compute/options/TemplateOptionsTest.java @@ -0,0 +1,152 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.compute.options; + +import static org.jclouds.compute.options.TemplateOptions.Builder.authorizePublicKey; +import static org.jclouds.compute.options.TemplateOptions.Builder.blockOnPort; +import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts; +import static org.jclouds.compute.options.TemplateOptions.Builder.installPrivateKey; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +/** + * Tests possible uses of TemplateOptions and TemplateOptions.Builder.* + * + * @author Adrian Cole + */ +public class TemplateOptionsTest { + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testinstallPrivateKeyBadFormat() { + TemplateOptions options = new TemplateOptions(); + options.installPrivateKey("whompy"); + } + + @Test + public void testinstallPrivateKey() { + TemplateOptions options = new TemplateOptions(); + options.installPrivateKey("-----BEGIN RSA PRIVATE KEY-----"); + assertEquals(options.getPrivateKey(), "-----BEGIN RSA PRIVATE KEY-----"); + } + + @Test + public void testNullinstallPrivateKey() { + TemplateOptions options = new TemplateOptions(); + assertEquals(options.getPrivateKey(), null); + } + + @Test + public void testinstallPrivateKeyStatic() { + TemplateOptions options = installPrivateKey("-----BEGIN RSA PRIVATE KEY-----"); + assertEquals(options.getPrivateKey(), "-----BEGIN RSA PRIVATE KEY-----"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testinstallPrivateKeyNPE() { + installPrivateKey(null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testauthorizePublicKeyBadFormat() { + TemplateOptions options = new TemplateOptions(); + options.authorizePublicKey("whompy"); + } + + @Test + public void testauthorizePublicKey() { + TemplateOptions options = new TemplateOptions(); + options.authorizePublicKey("ssh-rsa"); + assertEquals(options.getPublicKey(), "ssh-rsa"); + } + + @Test + public void testNullauthorizePublicKey() { + TemplateOptions options = new TemplateOptions(); + assertEquals(options.getPublicKey(), null); + } + + @Test + public void testauthorizePublicKeyStatic() { + TemplateOptions options = authorizePublicKey("ssh-rsa"); + assertEquals(options.getPublicKey(), "ssh-rsa"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testauthorizePublicKeyNPE() { + authorizePublicKey(null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testblockOnPortBadFormat() { + TemplateOptions options = new TemplateOptions(); + options.blockOnPort(-1, -1); + } + + @Test + public void testblockOnPort() { + TemplateOptions options = new TemplateOptions(); + options.blockOnPort(22, 30); + assertEquals(options.getPort(), 22); + assertEquals(options.getSeconds(), 30); + + } + + @Test + public void testNullblockOnPort() { + TemplateOptions options = new TemplateOptions(); + assertEquals(options.getPort(), -1); + assertEquals(options.getSeconds(), -1); + } + + @Test + public void testblockOnPortStatic() { + TemplateOptions options = blockOnPort(22, 30); + assertEquals(options.getPort(), 22); + assertEquals(options.getSeconds(), 30); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testinboundPortsBadFormat() { + TemplateOptions options = new TemplateOptions(); + options.inboundPorts(-1, -1); + } + + @Test + public void testinboundPorts() { + TemplateOptions options = new TemplateOptions(); + options.inboundPorts(22, 30); + assertEquals(options.getInboundPorts()[0], 22); + assertEquals(options.getInboundPorts()[1], 30); + + } + + @Test + public void testDefaultOpen22() { + TemplateOptions options = new TemplateOptions(); + assertEquals(options.getInboundPorts()[0], 22); + } + + @Test + public void testinboundPortsStatic() { + TemplateOptions options = inboundPorts(22, 30); + assertEquals(options.getInboundPorts()[0], 22); + assertEquals(options.getInboundPorts()[1], 30); + } +}