From dd4087982bbe74863916095019b899a3957785b0 Mon Sep 17 00:00:00 2001 From: Alex Yarmula Date: Thu, 6 May 2010 15:53:59 -0700 Subject: [PATCH] added runScriptOnNodesMatching; removed runScriptOnNodesWithTag as it proved unflexible and the new method is a broader case; use runScriptOnNodesMatching instead --- .../org/jclouds/compute/ComputeService.java | 20 +-- .../compute/RunScriptOnNodesException.java | 12 +- .../compute/internal/BaseComputeService.java | 154 +++++++++--------- .../jclouds/compute/util/ComputeUtils.java | 2 +- .../compute/BaseComputeServiceLiveTest.java | 11 +- 5 files changed, 102 insertions(+), 97 deletions(-) diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java index 7dcdc71f6e..bd71904f20 100755 --- a/compute/src/main/java/org/jclouds/compute/ComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java @@ -21,6 +21,7 @@ package org.jclouds.compute; import java.util.Map; import java.util.Set; +import com.google.common.base.Predicate; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; @@ -170,27 +171,26 @@ public interface ComputeService { /** * Runs the script without any additional options * - * @see #runScriptOnNodesWithTag(String, byte[], org.jclouds.compute.options.RunScriptOptions) + * @see #runScriptOnNodesMatching(Predicate, byte[], org.jclouds.compute.options.RunScriptOptions) */ - Map runScriptOnNodesWithTag(String tag, byte[] runScript) + Map runScriptOnNodesMatching(Predicate filter, byte[] runScript) throws RunScriptOnNodesException; /** * Run the script on all nodes with the specific tag. - * - * @param tag - * tag to look up the nodes + * + * @param filter + * Predicate-based filter to define on which nodes the script is to be + * executed * @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 + * nullable options to how to run the script, whether to override credentials * @return map with node identifiers and corresponding responses - * @throws RunScriptOnNodesException - * when there's a problem running the script on the nodes. Note that successful and - * failed nodes are a part of this exception, so be sure to inspect this carefully. + * @throws RunScriptOnNodesException if anything goes wrong during script execution */ - Map runScriptOnNodesWithTag(String tag, byte[] runScript, + Map runScriptOnNodesMatching(Predicate filter, byte[] runScript, RunScriptOptions options) throws RunScriptOnNodesException; } diff --git a/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java b/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java index 318bd3c32e..7ad76c6118 100644 --- a/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java +++ b/compute/src/main/java/org/jclouds/compute/RunScriptOnNodesException.java @@ -22,6 +22,7 @@ import java.util.Map; import javax.annotation.Nullable; +import com.google.common.base.Predicate; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.util.ComputeUtils; @@ -35,21 +36,19 @@ public class RunScriptOnNodesException extends Exception { /** The serialVersionUID */ private static final long serialVersionUID = -2272965726680821281L; - private final String tag; private final byte[] runScript; private final RunScriptOptions options; private final Map successfulNodes; private final Map failedNodes; private final Map executionExceptions; - public RunScriptOnNodesException(String tag, final byte[] runScript, + public RunScriptOnNodesException(final byte[] runScript, @Nullable final RunScriptOptions options, Map successfulNodes, Map executionExceptions, Map failedNodes) { - super(String.format("error runScript on node tag(%s) options(%s)%n%s%n%s", tag, + super(String.format("error runScript on filtered nodes options(%s)%n%s%n%s", options, ComputeUtils.createExecutionErrorMessage(executionExceptions), ComputeUtils .createNodeErrorMessage(failedNodes))); - this.tag = tag; this.runScript = runScript; this.options = options; this.successfulNodes = successfulNodes; @@ -58,7 +57,6 @@ public class RunScriptOnNodesException extends Exception { } /** - * * @return Nodes that performed ssh without error */ public Map getSuccessfulNodes() { @@ -81,10 +79,6 @@ public class RunScriptOnNodesException extends Exception { return failedNodes; } - public String getTag() { - return tag; - } - public byte[] getRunScript() { return runScript; } 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 a1cf8fb4a2..be7e02cfeb 100755 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -27,7 +27,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion; import static org.jclouds.concurrent.ConcurrentUtils.makeListenable; -import static org.jclouds.util.Utils.checkNotEmpty; import java.util.Map; import java.util.Set; @@ -77,7 +76,7 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; /** - * + * * @author Adrian Cole */ @Singleton @@ -99,6 +98,7 @@ public class BaseComputeService implements ComputeService { protected final Provider templateBuilderProvider; protected final ComputeUtils utils; protected final ExecutorService executor; + protected final ComputeMetadataToNodeMetadata computeMetadataToNodeMetadata; private static class NodeMatchesTag implements Predicate { private final String tag; @@ -116,28 +116,29 @@ public class BaseComputeService implements ComputeService { @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) { + 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"); + "getNodeMetadataStrategy"); this.runNodesAndAddToSetStrategy = checkNotNull(runNodesAndAddToSetStrategy, - "runNodesAndAddToSetStrategy"); + "runNodesAndAddToSetStrategy"); this.rebootNodeStrategy = checkNotNull(rebootNodeStrategy, "rebootNodeStrategy"); this.destroyNodeStrategy = checkNotNull(destroyNodeStrategy, "destroyNodeStrategy"); this.templateBuilderProvider = checkNotNull(templateBuilderProvider, - "templateBuilderProvider"); + "templateBuilderProvider"); this.utils = checkNotNull(utils, "utils"); this.executor = checkNotNull(executor, "executor"); + this.computeMetadataToNodeMetadata = new ComputeMetadataToNodeMetadata(); } @Override @@ -147,18 +148,18 @@ public class BaseComputeService implements ComputeService { @Override public Set runNodesWithTag(final String tag, int count, - final Template template) throws RunNodesException { + final Template template) throws RunNodesException { 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()); + count, count > 1 ? "s" : "", tag, template.getLocation().getId(), template + .getImage().getId(), template.getSize().getId(), template.getOptions()); final Set nodes = Sets.newHashSet(); final Map badNodes = Maps.newLinkedHashMap(); Map> responses = runNodesAndAddToSetStrategy.execute(tag, count, - template, nodes, badNodes); + template, nodes, badNodes); Map executionExceptions = awaitCompletion(responses, executor, null, logger, - "starting nodes"); + "starting nodes"); if (executionExceptions.size() > 0 || badNodes.size() > 0) { throw new RunNodesException(tag, count, template, nodes, executionExceptions, badNodes); } @@ -168,7 +169,7 @@ public class BaseComputeService implements ComputeService { @Override public void destroyNode(ComputeMetadata node) { checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " - + node.getType()); + + node.getType()); checkNotNull(node.getId(), "node.id"); logger.debug(">> destroying node(%s)", node.getId()); boolean successful = destroyNodeStrategy.execute(node); @@ -179,13 +180,13 @@ public class BaseComputeService implements ComputeService { public void destroyNodesWithTag(String tag) { // TODO parallel logger.debug(">> destroying nodes by tag(%s)", tag); Iterable nodesToDestroy = Iterables.filter(doListNodesWithTag(tag), - new Predicate() { - @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; + 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() { @@ -212,7 +213,7 @@ public class BaseComputeService implements ComputeService { options = GetNodesOptions.NONE; } Set set = Sets - .newLinkedHashSet(listNodesStrategy.execute(options)); + .newLinkedHashSet(listNodesStrategy.execute(options)); logger.debug("<< list(%d)", set.size()); return set; } @@ -223,17 +224,20 @@ public class BaseComputeService implements ComputeService { */ protected Set doListNodesWithTag(final String tag) { return Sets.newHashSet(Iterables.filter(Iterables.transform(listNodesStrategy - .execute(GetNodesOptions.NONE), new Function() { - - @Override - public NodeMetadata apply(ComputeMetadata from) { - return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) - : getNodeMetadata(from); - } - - }), new NodeMatchesTag(tag))); + .execute(GetNodesOptions.NONE), computeMetadataToNodeMetadata), new NodeMatchesTag(tag))); } + class ComputeMetadataToNodeMetadata + implements Function { + + @Override + public NodeMetadata apply(ComputeMetadata from) { + return from instanceof NodeMetadata ? NodeMetadata.class.cast(from) + : getNodeMetadata(from); + } + } + + @Override public Set listNodesWithTag(String tag) { logger.debug(">> listing nodes by tag(%s)", tag); @@ -265,14 +269,14 @@ public class BaseComputeService implements ComputeService { @Override public NodeMetadata getNodeMetadata(ComputeMetadata node) { checkArgument(node.getType() == ComputeType.NODE, "this is only valid for nodes, not " - + node.getType()); + + 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()); + + node.getType()); checkNotNull(node.getId(), "node.id"); logger.debug(">> rebooting node(%s)", node.getId()); boolean successful = rebootNodeStrategy.execute(node); @@ -283,13 +287,13 @@ public class BaseComputeService implements ComputeService { public void rebootNodesWithTag(String tag) { // TODO parallel logger.debug(">> rebooting nodes by tag(%s)", tag); Iterable nodesToReboot = Iterables.filter(doListNodesWithTag(tag), - new Predicate() { - @Override - public boolean apply(NodeMetadata input) { - return input.getState() != NodeState.TERMINATED; + 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() { @@ -306,31 +310,33 @@ public class BaseComputeService implements ComputeService { /** * @throws RunScriptOnNodesException - * @see #runScriptOnNodesWithTag(String, byte[], org.jclouds.compute.options.RunScriptOptions) + * @see #runScriptOnNodesMatching(Predicate, byte[], org.jclouds.compute.options.RunScriptOptions) */ - public Map runScriptOnNodesWithTag(String tag, byte[] runScript) - throws RunScriptOnNodesException { - return runScriptOnNodesWithTag(tag, runScript, RunScriptOptions.NONE); + public Map runScriptOnNodesMatching(Predicate filter, byte[] runScript) + throws RunScriptOnNodesException { + return runScriptOnNodesMatching(filter, runScript, RunScriptOptions.NONE); } /** * Run the script on all nodes with the specific tag. - * - * @param tag - * tag to look up the nodes + * + * @param filter + * Predicate-based filter to define on which nodes the script is to be + * executed * @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 - * @throws RunScriptOnNodesException + * @throws RunScriptOnNodesException if anything goes wrong during script execution */ - public Map runScriptOnNodesWithTag(String tag, - final byte[] runScript, @Nullable final RunScriptOptions options) - throws RunScriptOnNodesException { - Iterable nodes = verifyParametersAndGetNodes(tag, runScript, - (options != null) ? options : RunScriptOptions.NONE); + public Map runScriptOnNodesMatching(Predicate filter, + final byte[] runScript, @Nullable final RunScriptOptions options) + throws RunScriptOnNodesException { + Iterable nodes = verifyParametersAndGetNodes(filter, runScript, + (options != null) ? options : RunScriptOptions.NONE); + final Map execs = Maps.newHashMap(); final Map badNodes = Maps.newLinkedHashMap(); @@ -367,48 +373,44 @@ public class BaseComputeService implements ComputeService { } Map exceptions = awaitCompletion(responses, executor, null, logger, - "starting nodes"); + "starting nodes"); if (exceptions.size() > 0 || badNodes.size() > 0) { - throw new RunScriptOnNodesException(tag, runScript, options, execs, exceptions, badNodes); + throw new RunScriptOnNodesException(runScript, options, execs, exceptions, badNodes); } return execs; + } - private Iterable verifyParametersAndGetNodes(String tag, - byte[] runScript, final RunScriptOptions options) { - checkNotEmpty(tag, "Tag must be provided"); + private Iterable verifyParametersAndGetNodes(Predicate filter, + byte[] runScript, final RunScriptOptions options) { + checkNotNull(filter, "Filter must be provided"); checkNotNull(runScript, - "The script (represented by bytes array - use \"script\".getBytes() must be provided"); + "The script (represented by bytes array - use \"script\".getBytes() must be provided"); checkNotNull(options, "options"); - Iterable nodes = Iterables.filter(listNodesWithTag(tag), - new Predicate() { - - @Override - public boolean apply(NodeMetadata input) { - return input.getState() == NodeState.RUNNING; - } - - }); + Iterable nodes = Iterables.filter( + Iterables.transform(listNodes(), computeMetadataToNodeMetadata), + filter); + return Iterables.transform(nodes, new Function() { @Override public NodeMetadata apply(NodeMetadata node) { checkArgument(node.getPublicAddresses().size() > 0, "no public ip addresses on node: " - + node); + + node); 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"); + "If the default credentials need to be used, they can't be null"); checkNotNull(node.getCredentials().account, - "Account name for ssh authentication must be " - + "specified. Try passing RunScriptOptions with new credentials"); + "Account name for ssh authentication must be " + + "specified. Try passing RunScriptOptions with new credentials"); checkNotNull(node.getCredentials().key, - "Key or password for ssh authentication must be " - + "specified. Try passing RunScriptOptions with new credentials"); + "Key or password for ssh authentication must be " + + "specified. Try passing RunScriptOptions with new credentials"); } return node; } 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 637fb4e5ef..980205f141 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeUtils.java @@ -43,6 +43,7 @@ import javax.annotation.Nullable; import javax.annotation.Resource; import javax.inject.Named; +import com.google.common.base.Function; import org.jclouds.Constants; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.NodeMetadata; @@ -464,5 +465,4 @@ public class ComputeUtils { } return providers; } - } diff --git a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java index fb0061e163..c244f166e3 100755 --- a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java @@ -77,6 +77,8 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; +import javax.annotation.Nullable; + /** * * @author Adrian Cole @@ -247,8 +249,15 @@ public abstract class BaseComputeServiceLiveTest { private Map runScriptWithCreds(String tag, OsFamily osFamily, Credentials creds) throws RunScriptOnNodesException { + Predicate filter = new Predicate() { + @Override + public boolean apply(@Nullable NodeMetadata nodeMetadata) { + return true; /*accept all*/ + } + }; + try { - return client.runScriptOnNodesWithTag(tag, buildScript(osFamily).getBytes(), + return client.runScriptOnNodesMatching(filter, buildScript(osFamily).getBytes(), RunScriptOptions.Builder.overrideCredentialsWith(creds)); } catch (SshException e) { if (Throwables.getRootCause(e).getMessage().contains("Auth fail")) {