diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java index 9bc8fbc91c..3481944a91 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/EC2ComputeService.java @@ -45,11 +45,11 @@ import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; -import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; @@ -90,7 +90,7 @@ public class EC2ComputeService extends BaseComputeService { @Named("NODE_RUNNING") Predicate nodeRunning, @Named("NODE_TERMINATED") Predicate nodeTerminated, @Named("NODE_SUSPENDED") Predicate nodeSuspended, - RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client, Map credentialsMap, @Named("SECURITY") Map securityGroupMap, @Named("PLACEMENT") Map placementGroupMap, @@ -98,7 +98,7 @@ public class EC2ComputeService extends BaseComputeService { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, - nodeSuspended, statementRunner, timeouts, executor); + nodeSuspended, initScriptRunnerFactory, timeouts, executor); this.ec2Client = ec2Client; this.credentialsMap = credentialsMap; this.securityGroupMap = securityGroupMap; diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceTest.java index 15e732391f..5e61476aea 100644 --- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceTest.java +++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceTest.java @@ -33,11 +33,11 @@ import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; -import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.ec2.EC2Client; import org.jclouds.ec2.services.PlacementGroupClient; @@ -62,7 +62,7 @@ public class EC2ComputeServiceTest { createMock(DestroyNodeStrategy.class), createMock(ResumeNodeStrategy.class), createMock(SuspendNodeStrategy.class), createMock(Provider.class), createMock(Provider.class), createMock(Predicate.class), createMock(Predicate.class), createMock(Predicate.class), - createMock(RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class), + createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class), createMock(Timeouts.class), createMock(ExecutorService.class), client, createMock(Map.class), createMock(Map.class), createMock(Map.class), createMock(Predicate.class)); diff --git a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java index 7d92b372f4..6f2f8e9f77 100644 --- a/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java +++ b/apis/vcloud/src/main/java/org/jclouds/vcloud/compute/functions/VAppToNodeMetadata.java @@ -28,6 +28,7 @@ import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.toComputeOs; import java.util.Map; +import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Singleton; @@ -36,6 +37,7 @@ import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadataBuilder; import org.jclouds.compute.domain.NodeState; import org.jclouds.domain.Credentials; +import org.jclouds.logging.Logger; import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.VApp; @@ -46,6 +48,9 @@ import com.google.common.base.Function; */ @Singleton public class VAppToNodeMetadata implements Function { + @Resource + protected static Logger logger = Logger.NULL; + protected final FindLocationForResource findLocationForResourceInVDC; protected final Function hardwareForVApp; protected final Map vAppStatusToNodeState; @@ -66,7 +71,12 @@ public class VAppToNodeMetadata implements Function { builder.uri(from.getHref()); builder.name(from.getName()); builder.location(findLocationForResourceInVDC.apply(from.getVDC())); - builder.tag(parseTagFromName(from.getName())); + String tag = parseTagFromName(from.getName()); + builder.tag(tag); + if (logger.isTraceEnabled()) { + if (tag.startsWith("NOTAG#")) + logger.warn("failed to parse tag from name %s", from); + } builder.operatingSystem(toComputeOs(from, null)); builder.hardware(hardwareForVApp.apply(from)); builder.state(vAppStatusToNodeState.get(from.getStatus())); diff --git a/common/trmk/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeService.java b/common/trmk/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeService.java index 4d2ea5735c..54264ca16b 100644 --- a/common/trmk/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeService.java +++ b/common/trmk/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeService.java @@ -41,11 +41,11 @@ import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.ResumeNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; -import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; @@ -76,13 +76,13 @@ public class TerremarkVCloudComputeService extends BaseComputeService { @Named("NODE_RUNNING") Predicate nodeRunning, @Named("NODE_TERMINATED") Predicate nodeTerminated, @Named("NODE_SUSPENDED") Predicate nodeSuspended, - RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys, ConcurrentMap credentialsMap, NodeMetadataToOrgAndName nodeToOrgAndName) { super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, - nodeSuspended, statementRunner, timeouts, executor); + nodeSuspended, initScriptRunnerFactory, timeouts, executor); this.cleanupOrphanKeys = cleanupOrphanKeys; } diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java index d4096825ff..e94b060f6c 100755 --- a/compute/src/main/java/org/jclouds/compute/ComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java @@ -166,6 +166,8 @@ public interface ComputeService { * * @throws UnsupportedOperationException * if the underlying provider doesn't support suspend/resume + * @throws NoSuchElementException + * if no nodes matched the predicate specified */ void resumeNodesMatching(Predicate filter); @@ -189,6 +191,11 @@ public interface ComputeService { *

note

* * affected nodes may not resume with the same IP address(es) + * + * @throws UnsupportedOperationException + * if the underlying provider doesn't support suspend/resume + * @throws NoSuchElementException + * if no nodes matched the predicate specified */ void suspendNodesMatching(Predicate filter); @@ -215,6 +222,9 @@ public interface ComputeService { /** * nodes matching the filter are treated as a logical set. Using this command, you can save time * by rebooting the nodes in parallel. + * + * @throws NoSuchElementException + * if no nodes matched the predicate specified */ void rebootNodesMatching(Predicate filter); @@ -233,54 +243,34 @@ public interface ComputeService { Set listNodesDetailsMatching(Predicate filter); /** - * Runs the script without any additional options - * - * @see #runScriptOnNodesMatching(Predicate, Payload, - * org.jclouds.compute.options.RunScriptOptions) - * @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String) + * @see org.jclouds.io.Payloads + * @see ComputeService#runScriptOnNodesMatching(Predicate, Statement, RunScriptOptions) */ @Deprecated Map runScriptOnNodesMatching(Predicate filter, Payload runScript) throws RunScriptOnNodesException; /** - * Run the script on all nodes with the specific predicate. - * - * @param filter - * Predicate-based filter to define on which nodes the script is to be executed - * @param runScript - * payload containing the script to run - * @param options - * nullable options to how to run the script, whether to override credentials - * @return map with node identifiers and corresponding responses - * @throws RunScriptOnNodesException - * if anything goes wrong during script execution - * - * @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String) * @see org.jclouds.io.Payloads + * @see ComputeService#runScriptOnNodesMatching(Predicate, Statement, RunScriptOptions) */ @Deprecated Map runScriptOnNodesMatching(Predicate filter, Payload runScript, RunScriptOptions options) throws RunScriptOnNodesException; /** - * Run the script on all nodes with the specific predicate. * - * @param filter - * Predicate-based filter to define on which nodes the script is to be executed - * @param runScript - * string containing the script to run - * @param options - * nullable options to how to run the script, whether to override credentials - * @return map with node identifiers and corresponding responses - * @throws RunScriptOnNodesException - * if anything goes wrong during script execution - * - * @see org.jclouds.compute.predicates.NodePredicates#runningWithTag(String) - * @see org.jclouds.scriptbuilder.domain.Statements + * @see ComputeService#runScriptOnNodesMatching(Predicate, Statement, RunScriptOptions) */ - Map runScriptOnNodesMatching(Predicate filter, String runScript, - RunScriptOptions options) throws RunScriptOnNodesException; + Map runScriptOnNodesMatching(Predicate filter, String runScript) + throws RunScriptOnNodesException; + + /** + * + * @see ComputeService#runScriptOnNodesMatching(Predicate, Statement, RunScriptOptions) + */ + Map runScriptOnNodesMatching(Predicate filter, + Statement runScript) throws RunScriptOnNodesException; /** * Run the script on all nodes with the specific predicate. @@ -292,6 +282,8 @@ public interface ComputeService { * @param options * nullable options to how to run the script, whether to override credentials * @return map with node identifiers and corresponding responses + * @throws NoSuchElementException + * if no nodes matched the predicate specified * @throws RunScriptOnNodesException * if anything goes wrong during script execution * diff --git a/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNode.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNode.java new file mode 100644 index 0000000000..c3841a6b65 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNode.java @@ -0,0 +1,65 @@ +/** + * + * Copyright (C) 2010 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.callables; + +import java.util.concurrent.Callable; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.ssh.ExecResponse; + +import com.google.common.annotations.Beta; + +/** + * Separates out how one implements the ability to run a script on a node. + * + * @author Adrian Cole + */ +@Beta +public interface RunScriptOnNode extends Callable { + + public interface Factory { + RunScriptOnNode create(NodeMetadata node, String script); + + RunScriptOnNode create(NodeMetadata node, Statement script); + + RunScriptOnNode create(NodeMetadata node, Statement script, RunScriptOptions options); + } + + /** + * Note that {@link #init} must be called first. + */ + @Override + ExecResponse call(); + + /** + * verifies that the command can execute on the node. For example, if this is ssh, it may attempt + * to find a reachable socket. If this is using an API, it may attempt to validate that + * connection. + */ + RunScriptOnNode init(); + + /** + * the node this command is being executed on. + */ + NodeMetadata getNode(); + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNode.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java similarity index 80% rename from compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNode.java rename to compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java index 1eddf75e50..0d84880954 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNode.java +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSsh.java @@ -20,16 +20,15 @@ package org.jclouds.compute.callables; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import java.util.Collections; -import java.util.concurrent.Callable; -import javax.annotation.Nullable; import javax.annotation.Resource; -import javax.inject.Inject; import javax.inject.Named; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; import org.jclouds.scriptbuilder.InitBuilder; @@ -40,28 +39,19 @@ import org.jclouds.ssh.SshClient; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; -import com.google.common.collect.Iterables; +import com.google.common.base.Objects; import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; /** * * @author Adrian Cole */ -public class StartInitScriptOnNode implements Callable { +public class RunScriptOnNodeAsInitScriptUsingSsh implements RunScriptOnNode { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - public interface Factory { - @Named("blocking") - StartInitScriptOnNode blockOnComplete(NodeMetadata node, @Nullable String name, Statement script, - boolean runAsRoot); - - @Named("nonblocking") - StartInitScriptOnNode dontBlockOnComplete(NodeMetadata node, @Nullable String name, Statement script, - boolean runAsRoot); - } - protected final Function sshFactory; protected final NodeMetadata node; protected final Statement init; @@ -70,21 +60,22 @@ public class StartInitScriptOnNode implements Callable { protected SshClient ssh; - @Inject - public StartInitScriptOnNode(Function sshFactory, @Assisted NodeMetadata node, - @Assisted @Nullable String name, @Assisted Statement script, @Assisted boolean runAsRoot) { + @AssistedInject + public RunScriptOnNodeAsInitScriptUsingSsh(Function sshFactory, + @Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options) { this.sshFactory = checkNotNull(sshFactory, "sshFactory"); this.node = checkNotNull(node, "node"); + String name = options.getTaskName(); if (name == null) { if (checkNotNull(script, "script") instanceof InitBuilder) name = InitBuilder.class.cast(script).getInstanceName(); else name = "jclouds-script-" + System.currentTimeMillis(); } - this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) - : createInitScript(checkNotNull(name, "name"), script); this.name = checkNotNull(name, "name"); - this.runAsRoot = runAsRoot; + this.init = checkNotNull(script, "script") instanceof InitBuilder ? InitBuilder.class.cast(script) + : createInitScript(name, script); + this.runAsRoot = options.shouldRunAsRoot(); } public static InitBuilder createInitScript(String name, Statement script) { @@ -94,7 +85,7 @@ public class StartInitScriptOnNode implements Callable { @Override public ExecResponse call() { - ssh = sshFactory.apply(node); + checkState(ssh != null, "please call init() before invoking call"); try { ssh.connect(); return doCall(); @@ -102,7 +93,12 @@ public class StartInitScriptOnNode implements Callable { if (ssh != null) ssh.disconnect(); } + } + @Override + public RunScriptOnNode init() { + ssh = sshFactory.apply(node); + return this; } /** @@ -127,8 +123,7 @@ public class StartInitScriptOnNode implements Callable { protected ExecResponse runCommand(String command) { ExecResponse returnVal; logger.debug(">> running [%s] as %s@%s", command.replace(node.getAdminPassword() != null ? node - .getAdminPassword() : "XXXXX", "XXXXX"), node.getCredentials().identity, Iterables.get(node - .getPublicAddresses(), 0)); + .getAdminPassword() : "XXXXX", "XXXXX"), ssh.getUsername(), ssh.getHostAddress()); returnVal = ssh.exec(command); return returnVal; } @@ -153,4 +148,10 @@ public class StartInitScriptOnNode implements Callable { public NodeMetadata getNode() { return node; } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("node", node).add("name", name).add("runAsRoot", runAsRoot).toString(); + } + } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNodeAndBlockUntilComplete.java b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java similarity index 86% rename from compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNodeAndBlockUntilComplete.java rename to compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java index 3119fa984d..753e10fb51 100644 --- a/compute/src/main/java/org/jclouds/compute/callables/StartInitScriptOnNodeAndBlockUntilComplete.java +++ b/compute/src/main/java/org/jclouds/compute/callables/RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import javax.inject.Named; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.ssh.ExecResponse; @@ -39,15 +40,15 @@ import com.google.inject.assistedinject.Assisted; * * @author Adrian Cole */ -public class StartInitScriptOnNodeAndBlockUntilComplete extends StartInitScriptOnNode { +public class RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete extends RunScriptOnNodeAsInitScriptUsingSsh { protected final Predicate runScriptNotRunning; @Inject - public StartInitScriptOnNodeAndBlockUntilComplete( + public RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete( @Named("SCRIPT_COMPLETE") Predicate runScriptNotRunning, - Function sshFactory, @Assisted NodeMetadata node, @Assisted String scriptName, - @Assisted Statement script, @Assisted boolean runAsRoot) { - super(sshFactory, node, scriptName, script, runAsRoot); + Function sshFactory, @Assisted NodeMetadata node, @Assisted Statement script, + @Assisted RunScriptOptions options) { + super(sshFactory, node, script, options); this.runScriptNotRunning = checkNotNull(runScriptNotRunning, "runScriptNotRunning"); } diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java index 6134d35717..3c9bd2d0ca 100644 --- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java @@ -19,6 +19,7 @@ package org.jclouds.compute.config; +import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.compute.domain.OsFamily.UBUNTU; @@ -31,8 +32,9 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.collect.Memoized; -import org.jclouds.compute.callables.StartInitScriptOnNode; -import org.jclouds.compute.callables.StartInitScriptOnNodeAndBlockUntilComplete; +import org.jclouds.compute.callables.RunScriptOnNode; +import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh; +import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Image; @@ -41,16 +43,17 @@ import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode; import org.jclouds.compute.functions.TemplateOptionsToStatement; +import org.jclouds.compute.options.RunScriptOptions; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; -import org.jclouds.compute.strategy.RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap; -import org.jclouds.compute.util.ComputeServiceUtils; +import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap; import org.jclouds.domain.Location; import org.jclouds.json.Json; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.suppliers.RetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.Statements; import org.jclouds.ssh.SshClient; import com.google.common.base.Function; @@ -58,6 +61,7 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.Maps; import com.google.inject.AbstractModule; +import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -77,9 +81,12 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { bind(new TypeLiteral>() { }).to(TemplateOptionsToStatement.class); - install(new FactoryModuleBuilder().implement(StartInitScriptOnNode.class, Names.named("blocking"), - StartInitScriptOnNodeAndBlockUntilComplete.class).implement(StartInitScriptOnNode.class, - Names.named("nonblocking"), StartInitScriptOnNode.class).build(StartInitScriptOnNode.Factory.class)); + install(new FactoryModuleBuilder().implement(RunScriptOnNode.class, Names.named("blocking"), + RunScriptOnNodeAsInitScriptUsingSshAndBlockUntilComplete.class).implement(RunScriptOnNode.class, + Names.named("nonblocking"), RunScriptOnNodeAsInitScriptUsingSsh.class).build( + RunScriptOnNodeFactoryImpl.Factory.class)); + + bind(RunScriptOnNode.Factory.class).to(RunScriptOnNodeFactoryImpl.class); install(new FactoryModuleBuilder().implement(new TypeLiteral>() { }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).implement( @@ -87,10 +94,47 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { }, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).build( CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); - install(new FactoryModuleBuilder().implement(new TypeLiteral>() { - }, RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.class).build( - RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory.class)); - requestStaticInjection(ComputeServiceUtils.class); + install(new FactoryModuleBuilder().implement(new TypeLiteral>() { + }, InitializeRunScriptOnNodeOrPlaceInBadMap.class).build(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class)); + } + + @Singleton + static class RunScriptOnNodeFactoryImpl implements RunScriptOnNode.Factory { + + static interface Factory { + + @Named("blocking") + RunScriptOnNode blockOnComplete(NodeMetadata node, Statement script, RunScriptOptions options); + + @Named("nonblocking") + RunScriptOnNode dontBlockOnComplete(NodeMetadata node, Statement script, RunScriptOptions options); + } + + private final Factory factory; + + @Inject + RunScriptOnNodeFactoryImpl(Factory factory) { + this.factory = checkNotNull(factory, "factory"); + } + + @Override + public RunScriptOnNode create(NodeMetadata node, Statement runScript, RunScriptOptions options) { + checkNotNull(node, "node"); + checkNotNull(runScript, "runScript"); + checkNotNull(options, "options"); + return options.shouldBlockOnComplete() ? factory.blockOnComplete(node, runScript, options) : factory + .dontBlockOnComplete(node, runScript, options); + } + + @Override + public RunScriptOnNode create(NodeMetadata node, String script) { + return create(node, Statements.exec(checkNotNull(script, "script"))); + } + + @Override + public RunScriptOnNode create(NodeMetadata node, Statement script) { + return create(node, script, RunScriptOptions.NONE); + } } @Provides diff --git a/compute/src/main/java/org/jclouds/compute/functions/CreateSshClientOncePortIsListeningOnNode.java b/compute/src/main/java/org/jclouds/compute/functions/CreateSshClientOncePortIsListeningOnNode.java index 869bb22d1e..9f686c12d0 100644 --- a/compute/src/main/java/org/jclouds/compute/functions/CreateSshClientOncePortIsListeningOnNode.java +++ b/compute/src/main/java/org/jclouds/compute/functions/CreateSshClientOncePortIsListeningOnNode.java @@ -52,8 +52,10 @@ public class CreateSshClientOncePortIsListeningOnNode implements Function credentialStore; - + private final Supplier> images; private final Supplier> hardwareProfiles; private final Supplier> locations; @@ -124,7 +126,7 @@ public class BaseComputeService implements ComputeService { private final Predicate nodeRunning; private final Predicate nodeTerminated; private final Predicate nodeSuspended; - private final RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner; + private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final Timeouts timeouts; private final ExecutorService executor; @@ -140,7 +142,7 @@ public class BaseComputeService implements ComputeService { @Named("NODE_RUNNING") Predicate nodeRunning, @Named("NODE_TERMINATED") Predicate nodeTerminated, @Named("NODE_SUSPENDED") Predicate nodeSuspended, - RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory statementRunner, Timeouts timeouts, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) { this.context = checkNotNull(context, "context"); this.credentialStore = checkNotNull(credentialStore, "credentialStore"); @@ -159,7 +161,7 @@ public class BaseComputeService implements ComputeService { this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); this.nodeTerminated = checkNotNull(nodeTerminated, "nodeTerminated"); this.nodeSuspended = checkNotNull(nodeSuspended, "nodeSuspended"); - this.statementRunner = checkNotNull(statementRunner, "statementRunner"); + this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory"); this.timeouts = checkNotNull(timeouts, "timeouts"); this.executor = checkNotNull(executor, "executor"); } @@ -189,7 +191,8 @@ public class BaseComputeService implements ComputeService { Map> responses = runNodesAndAddToSetStrategy.execute(tag, count, template, goodNodes, badNodes, customizationResponses); - Map executionExceptions = awaitCompletion(responses, executor, null, logger, "resuming nodes"); + Map executionExceptions = awaitCompletion(responses, executor, null, logger, "runNodesWithTag(" + + tag + ")"); for (NodeMetadata node : concat(goodNodes, badNodes.keySet())) if (node.getCredentials() != null) credentialStore.put("node#" + node.getId(), node.getCredentials()); @@ -269,13 +272,25 @@ public class BaseComputeService implements ComputeService { }); } - }, executor, null, logger, "destroying nodes")); + }, executor, null, logger, "destroyNodesMatching(" + filter + ")")); logger.debug("<< destroyed(%d)", set.size()); return set; } - private Iterable nodesMatchingFilterAndNotTerminated(Predicate filter) { - return filter(detailsOnAllNodes(), and(filter, not(TERMINATED))); + Iterable nodesMatchingFilterAndNotTerminated(Predicate filter) { + return filter(detailsOnAllNodes(), and(checkNotNull(filter, "filter"), not(TERMINATED))); + } + + /** + * @throws NoSuchElementException + * if none found + */ + Iterable nodesMatchingFilterAndNotTerminatedExceptionIfNotFound( + Predicate filter) { + Iterable nodes = nodesMatchingFilterAndNotTerminated(filter); + if (Iterables.size(nodes) == 0) + throw new NoSuchElementException("no nodes matched filter: " + filter); + return nodes; } /** @@ -360,15 +375,16 @@ public class BaseComputeService implements ComputeService { @Override public void rebootNodesMatching(Predicate filter) { logger.debug(">> rebooting nodes matching(%s)", filter); - transformParallel(nodesMatchingFilterAndNotTerminated(filter), new Function>() { - // TODO use native async - @Override - public Future apply(NodeMetadata from) { - rebootNode(from.getId()); - return immediateFuture(null); - } + transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), + new Function>() { + // TODO use native async + @Override + public Future apply(NodeMetadata from) { + rebootNode(from.getId()); + return immediateFuture(null); + } - }, executor, null, logger, "rebooting nodes"); + }, executor, null, logger, "rebootNodesMatching(" + filter + ")"); logger.debug("<< rebooted"); } @@ -378,10 +394,10 @@ public class BaseComputeService implements ComputeService { @Override public void resumeNode(String id) { checkNotNull(id, "id"); - logger.debug(">> resumeing node(%s)", id); + logger.debug(">> resuming node(%s)", id); NodeMetadata node = resumeNodeStrategy.resumeNode(id); boolean successful = nodeRunning.apply(node); - logger.debug("<< resumeed node(%s) success(%s)", id, successful); + logger.debug("<< resumed node(%s) success(%s)", id, successful); } /** @@ -389,17 +405,18 @@ public class BaseComputeService implements ComputeService { */ @Override public void resumeNodesMatching(Predicate filter) { - logger.debug(">> resumeing nodes matching(%s)", filter); - transformParallel(nodesMatchingFilterAndNotTerminated(filter), new Function>() { - // TODO use native async - @Override - public Future apply(NodeMetadata from) { - resumeNode(from.getId()); - return immediateFuture(null); - } + logger.debug(">> resuming nodes matching(%s)", filter); + transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), + new Function>() { + // TODO use native async + @Override + public Future apply(NodeMetadata from) { + resumeNode(from.getId()); + return immediateFuture(null); + } - }, executor, null, logger, "resumeing nodes"); - logger.debug("<< resumeed"); + }, executor, null, logger, "resumeNodesMatching(" + filter + ")"); + logger.debug("<< resumed"); } /** @@ -420,15 +437,16 @@ public class BaseComputeService implements ComputeService { @Override public void suspendNodesMatching(Predicate filter) { logger.debug(">> suspending nodes matching(%s)", filter); - transformParallel(nodesMatchingFilterAndNotTerminated(filter), new Function>() { - // TODO use native async - @Override - public Future apply(NodeMetadata from) { - suspendNode(from.getId()); - return immediateFuture(null); - } + transformParallel(nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), + new Function>() { + // TODO use native async + @Override + public Future apply(NodeMetadata from) { + suspendNode(from.getId()); + return immediateFuture(null); + } - }, executor, null, logger, "suspending nodes"); + }, executor, null, logger, "suspendNodesMatching(" + filter + ")"); logger.debug("<< suspended"); } @@ -446,7 +464,7 @@ public class BaseComputeService implements ComputeService { */ @Override public Map runScriptOnNodesMatching(Predicate filter, Payload runScript, - @Nullable RunScriptOptions options) throws RunScriptOnNodesException { + RunScriptOptions options) throws RunScriptOnNodesException { try { return runScriptOnNodesMatching(filter, Statements.exec(Strings2.toStringAndClose(checkNotNull(runScript, "runScript").getInput())), options); @@ -460,9 +478,18 @@ public class BaseComputeService implements ComputeService { * {@inheritDoc} */ @Override - public Map runScriptOnNodesMatching(Predicate filter, String runScript, - @Nullable RunScriptOptions options) throws RunScriptOnNodesException { - return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript")), options); + public Map runScriptOnNodesMatching(Predicate filter, String runScript) + throws RunScriptOnNodesException { + return runScriptOnNodesMatching(filter, Statements.exec(checkNotNull(runScript, "runScript"))); + } + + /** + * {@inheritDoc} + */ + @Override + public Map runScriptOnNodesMatching(Predicate filter, Statement runScript) + throws RunScriptOnNodesException { + return runScriptOnNodesMatching(filter, runScript, RunScriptOptions.NONE); } /** @@ -470,57 +497,38 @@ public class BaseComputeService implements ComputeService { */ @Override public Map runScriptOnNodesMatching(Predicate filter, Statement runScript, - @Nullable RunScriptOptions options) throws RunScriptOnNodesException { + RunScriptOptions options) throws RunScriptOnNodesException { - checkNotNull(filter, "Filter must be provided"); + checkNotNull(filter, "filter"); checkNotNull(runScript, "runScript"); checkNotNull(options, "options"); - Iterable nodes = filter(detailsOnAllNodes(), filter); - Map goodNodes = newLinkedHashMap(); Map badNodes = newLinkedHashMap(); + Map> responses = newLinkedHashMap(); + Map exceptions = ImmutableMap. of(); - Map> responses = newLinkedHashMap(); - nodes = filterNodesWhoCanRunScripts(nodes, badNodes, options.getOverrideCredentials()); - - for (NodeMetadata node : nodes) { - responses.put(node, executor.submit(statementRunner.create(node, runScript, options, goodNodes, badNodes))); + Iterable scriptRunners = transformNodesIntoInitializedScriptRunners( + nodesMatchingFilterAndNotTerminatedExceptionIfNotFound(filter), runScript, options, badNodes); + if (Iterables.size(scriptRunners) > 0) { + for (RunScriptOnNode runner : scriptRunners) { + responses.put(runner.getNode(), executor.submit(new RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap( + runner, goodNodes, badNodes))); + } + exceptions = awaitCompletion(responses, executor, null, logger, "runScriptOnNodesMatching(" + filter + ")"); } - Map exceptions = awaitCompletion(responses, executor, null, logger, "running script on nodes"); if (exceptions.size() > 0 || badNodes.size() > 0) { throw new RunScriptOnNodesException(runScript, options, goodNodes, exceptions, badNodes); } return goodNodes; - } - private Iterable filterNodesWhoCanRunScripts(Iterable nodes, - final Map badNodes, final @Nullable Credentials overridingCredentials) { - nodes = filter(transform(nodes, new Function() { - - @Override - public NodeMetadata apply(NodeMetadata node) { - try { - checkArgument(node.getPublicAddresses().size() > 0, "no public ip addresses on node: " + node); - if (overridingCredentials != null) { - node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(overridingCredentials).build(); - } else { - checkNotNull(node.getCredentials(), "If the default credentials need to be used, they can't be null"); - checkNotNull(node.getCredentials().identity, "Account name for ssh authentication must be " - + "specified. Try passing RunScriptOptions with new credentials"); - checkNotNull(node.getCredentials().credential, "Key or password for ssh authentication must be " - + "specified. Try passing RunScriptOptions with new credentials"); - } - return node; - } catch (Exception e) { - badNodes.put(node, e); - return null; - } - } - }), notNull()); - return nodes; + private Iterable transformNodesIntoInitializedScriptRunners( + Iterable nodes, Statement script, RunScriptOptions options, + Map badNodes) { + return filter(transformParallel(nodes, new TransformNodesIntoInitializedScriptRunners(script, options, badNodes), + executor, null, logger, "transformNodesIntoInitializedScriptRunners(" + nodes + ")"), notNull()); } private Set detailsOnAllNodes() { @@ -531,4 +539,27 @@ public class BaseComputeService implements ComputeService { public TemplateOptions templateOptions() { return templateOptionsProvider.get(); } + + private final class TransformNodesIntoInitializedScriptRunners implements + Function> { + private final Map badNodes; + private final Statement script; + private final RunScriptOptions options; + + private TransformNodesIntoInitializedScriptRunners(Statement script, RunScriptOptions options, + Map badNodes) { + this.badNodes = checkNotNull(badNodes, "badNodes"); + this.script = checkNotNull(script, "script"); + this.options = checkNotNull(options, "options"); + } + + @Override + public Future apply(NodeMetadata node) { + checkNotNull(node, "node"); + if (options.getOverrideCredentials() != null) { + node = NodeMetadataBuilder.fromNodeMetadata(node).credentials(options.getOverrideCredentials()).build(); + } + return executor.submit(initScriptRunnerFactory.create(node, script, options, badNodes)); + } + } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java index f52f2892d1..ae31acdff3 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java @@ -32,7 +32,7 @@ import javax.annotation.Nullable; import javax.annotation.Resource; import javax.inject.Named; -import org.jclouds.compute.callables.StartInitScriptOnNode; +import org.jclouds.compute.callables.RunScriptOnNode; import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.options.TemplateOptions; @@ -70,7 +70,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal protected Logger logger = Logger.NULL; private final Predicate nodeRunning; - private final ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement; + private final InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory; private final GetNodeMetadataStrategy getNode; private final RetryIfSocketNotYetOpen socketTester; private final Timeouts timeouts; @@ -90,15 +90,14 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal @Named("NODE_RUNNING") Predicate nodeRunning, GetNodeMetadataStrategy getNode, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, Function templateOptionsToStatement, - ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted TemplateOptions options, - @Assisted @Nullable NodeMetadata node, @Assisted Set goodNodes, - @Assisted Map badNodes, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + @Assisted TemplateOptions options, @Assisted @Nullable NodeMetadata node, + @Assisted Set goodNodes, @Assisted Map badNodes, @Assisted Multimap customizationResponses) { this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply( checkNotNull(options, "options")); this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning"); - this.scriptInvokerForNodeAndStatement = checkNotNull(scriptInvokerForNodeAndStatement, - "scriptInvokerForNodeAndStatement"); + this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory"); this.getNode = checkNotNull(getNode, "getNode"); this.socketTester = checkNotNull(socketTester, "socketTester"); this.timeouts = checkNotNull(timeouts, "timeouts"); @@ -114,11 +113,12 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal @Named("NODE_RUNNING") Predicate nodeRunning, GetNodeMetadataStrategy getNode, RetryIfSocketNotYetOpen socketTester, Timeouts timeouts, Function templateOptionsToStatement, - ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted TemplateOptions options, - @Assisted Set goodNodes, @Assisted Map badNodes, + InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, + @Assisted TemplateOptions options, @Assisted Set goodNodes, + @Assisted Map badNodes, @Assisted Multimap customizationResponses) { - this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, scriptInvokerForNodeAndStatement, - options, null, goodNodes, badNodes, customizationResponses); + this(nodeRunning, getNode, socketTester, timeouts, templateOptionsToStatement, initScriptRunnerFactory, options, + null, goodNodes, badNodes, customizationResponses); } @Override @@ -135,10 +135,11 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal .getId(), timeouts.nodeRunning / 1000, node.getState())); } if (statement != null) { - StartInitScriptOnNode scriptInstructions = scriptInvokerForNodeAndStatement.create(node, statement, - options); - ExecResponse exec = scriptInstructions.call(); - customizationResponses.put(node, exec); + RunScriptOnNode runner = initScriptRunnerFactory.create(node, statement, options, badNodes).call(); + if (runner != null) { + ExecResponse exec = runner.call(); + customizationResponses.put(node, exec); + } } if (options.getPort() > 0) { findReachableSocketOnNode(socketTester.seconds(options.getSeconds()), node, options.getPort()); diff --git a/compute/src/main/java/org/jclouds/compute/strategy/InitializeRunScriptOnNodeOrPlaceInBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/InitializeRunScriptOnNodeOrPlaceInBadMap.java new file mode 100644 index 0000000000..69fbeeb6ad --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/strategy/InitializeRunScriptOnNodeOrPlaceInBadMap.java @@ -0,0 +1,79 @@ +/** + * + * Copyright (C) 2010 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.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.concurrent.Callable; + +import javax.inject.Inject; + +import org.jclouds.compute.callables.RunScriptOnNode; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.options.RunScriptOptions; +import org.jclouds.scriptbuilder.domain.Statement; + +import com.google.common.base.Objects; +import com.google.inject.assistedinject.Assisted; + +/** + * + * @author Adrian Cole + */ +public class InitializeRunScriptOnNodeOrPlaceInBadMap implements Callable { + + public interface Factory { + Callable create(NodeMetadata node, Statement script, RunScriptOptions options, + Map badNodes); + } + + private final RunScriptOnNode.Factory runScriptOnNodeFactory; + private final Statement script; + private final Map badNodes; + private final NodeMetadata node; + private final RunScriptOptions options; + + @Inject + InitializeRunScriptOnNodeOrPlaceInBadMap(RunScriptOnNode.Factory runScriptOnNodeFactory, + @Assisted NodeMetadata node, @Assisted Statement script, @Assisted RunScriptOptions options, + @Assisted Map badNodes) { + this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory"); + this.script = checkNotNull(script, "script"); + this.badNodes = checkNotNull(badNodes, "badNodes"); + this.node = checkNotNull(node, "node"); + this.options = checkNotNull(options, "options"); + } + + @Override + public RunScriptOnNode call() throws Exception { + try { + return runScriptOnNodeFactory.create(node, script, options).init(); + } catch (Exception e) { + badNodes.put(node, e); + return null; + } + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("node", node).add("options", options).toString(); + } +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java new file mode 100644 index 0000000000..bf9e6d4d25 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/strategy/RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java @@ -0,0 +1,89 @@ +/** + * + * Copyright (C) 2010 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.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Throwables.getRootCause; + +import java.util.Map; +import java.util.concurrent.Callable; + +import javax.annotation.Resource; +import javax.inject.Named; + +import org.jclouds.compute.callables.RunScriptOnNode; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +import org.jclouds.ssh.ExecResponse; + +import com.google.common.base.Objects; +import com.google.inject.assistedinject.AssistedInject; + +/** + * + * @author Adrian Cole + */ +public class RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + private final RunScriptOnNode runScriptOnNode; + private final Map badNodes; + private final Map goodNodes; + + private transient boolean tainted; + + @AssistedInject + public RunScriptOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap(RunScriptOnNode runScriptOnNode, + Map goodNodes, Map badNodes) { + this.runScriptOnNode = checkNotNull(runScriptOnNode, "runScriptOnNode"); + this.badNodes = checkNotNull(badNodes, "badNodes"); + this.goodNodes = checkNotNull(goodNodes, "goodNodes"); + } + + @Override + public ExecResponse call() { + checkState(runScriptOnNode != null, "runScriptOnNode must be set"); + checkState(!tainted, "this object is not designed to be reused: %s", toString()); + tainted = true; + try { + ExecResponse exec = runScriptOnNode.call(); + logger.trace("<< script output for node(%s): %s", runScriptOnNode.getNode().getId(), exec); + logger.debug("<< options applied node(%s)", runScriptOnNode.getNode().getId()); + goodNodes.put(runScriptOnNode.getNode(), exec); + return exec; + } catch (Exception e) { + logger.error(e, "<< problem applying options to node(%s): ", runScriptOnNode.getNode().getId(), + getRootCause(e).getMessage()); + badNodes.put(runScriptOnNode.getNode(), e); + } + return null; + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("runScriptOnNode", runScriptOnNode).add("goodNodes", goodNodes).add( + "badNodes", badNodes).toString(); + } + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java b/compute/src/main/java/org/jclouds/compute/strategy/RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java deleted file mode 100644 index 5bcffbbdfe..0000000000 --- a/compute/src/main/java/org/jclouds/compute/strategy/RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * - * Copyright (C) 2010 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.strategy; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.base.Throwables.getRootCause; - -import java.util.Map; -import java.util.concurrent.Callable; - -import javax.annotation.Nullable; -import javax.annotation.Resource; -import javax.inject.Named; - -import org.jclouds.compute.callables.StartInitScriptOnNode; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.options.RunScriptOptions; -import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.logging.Logger; -import org.jclouds.scriptbuilder.domain.Statement; -import org.jclouds.ssh.ExecResponse; - -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; - -/** - * - * @author Adrian Cole - */ -public class RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Callable { - public static interface Factory { - Callable create(NodeMetadata node, Statement statement, RunScriptOptions options, - Map goodNodes, Map badNodes); - - } - - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected Logger logger = Logger.NULL; - // NOTE this is mutable - protected NodeMetadata node; - private final Map badNodes; - private final Map goodNodes; - private final RunScriptOptions options; - - protected final Statement statement; - private final ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement; - private transient boolean tainted; - - @AssistedInject - public RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap( - ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted NodeMetadata node, - @Assisted @Nullable Statement statement, @Assisted RunScriptOptions options, - @Assisted Map goodNodes, @Assisted Map badNodes) { - this.statement = checkNotNull(statement, "statement"); - this.scriptInvokerForNodeAndStatement = checkNotNull(scriptInvokerForNodeAndStatement, - "scriptInvokerForNodeAndStatement"); - this.node = node; - this.badNodes = checkNotNull(badNodes, "badNodes"); - this.goodNodes = checkNotNull(goodNodes, "goodNodes"); - this.options = checkNotNull(options, "options"); - } - - @AssistedInject - public RunStatementOnNodeAndAddToGoodMapOrPutExceptionIntoBadMap( - ScriptInvokerForNodeAndStatement scriptInvokerForNodeAndStatement, @Assisted @Nullable Statement statement, - @Assisted RunScriptOptions options, @Assisted Map goodNodes, - @Assisted Map badNodes) { - this(scriptInvokerForNodeAndStatement, null, statement, options, goodNodes, badNodes); - } - - @Override - public Void call() { - checkState(node != null, "node must be set"); - checkState(!tainted, "this object is not designed to be reused: %s", toString()); - tainted = true; - try { - StartInitScriptOnNode scriptInstructions = scriptInvokerForNodeAndStatement.create(node, statement, options); - ExecResponse exec = scriptInstructions.call(); - logger.trace("<< script output for node(%s): %s", node.getId(), exec); - logger.debug("<< options applied node(%s)", node.getId()); - goodNodes.put(node, exec); - } catch (Exception e) { - logger.error(e, "<< problem applying options to node(%s): ", node.getId(), getRootCause(e).getMessage()); - badNodes.put(node, e); - } - return null; - } - -} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/ScriptInvokerForNodeAndStatement.java b/compute/src/main/java/org/jclouds/compute/strategy/ScriptInvokerForNodeAndStatement.java deleted file mode 100644 index 78f7a77f04..0000000000 --- a/compute/src/main/java/org/jclouds/compute/strategy/ScriptInvokerForNodeAndStatement.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * - * Copyright (C) 2010 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.strategy; - -import static com.google.common.base.Preconditions.checkNotNull; - -import javax.inject.Singleton; - -import org.jclouds.compute.callables.StartInitScriptOnNode; -import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.options.RunScriptOptions; -import org.jclouds.scriptbuilder.domain.Statement; - -import com.google.inject.Inject; - -/** - * - * @author Adrian Cole - */ -@Singleton -public class ScriptInvokerForNodeAndStatement { - - private final StartInitScriptOnNode.Factory initAndStartScriptOnNodeFactory; - - @Inject - public ScriptInvokerForNodeAndStatement(StartInitScriptOnNode.Factory initAndStartScriptOnNodeFactory) { - this.initAndStartScriptOnNodeFactory = checkNotNull(initAndStartScriptOnNodeFactory, - "initAndStartScriptOnNodeFactory"); - } - - public StartInitScriptOnNode create(NodeMetadata node, Statement runScript, RunScriptOptions options) { - checkNotNull(node, "node"); - checkNotNull(runScript, "runScript"); - checkNotNull(options, "options"); - return options.shouldBlockOnComplete() ? initAndStartScriptOnNodeFactory.blockOnComplete(node, options - .getTaskName(), runScript, options.shouldRunAsRoot()) : initAndStartScriptOnNodeFactory - .dontBlockOnComplete(node, options.getTaskName(), runScript, options.shouldRunAsRoot()); - } -} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java index 5018710a84..76a27da995 100644 --- a/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java +++ b/compute/src/main/java/org/jclouds/compute/util/ComputeServiceUtils.java @@ -36,9 +36,6 @@ import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Resource; -import javax.inject.Named; - import org.jclouds.compute.ComputeServiceContextBuilder; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Hardware; @@ -47,9 +44,7 @@ import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Processor; import org.jclouds.compute.domain.Volume; import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; -import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.http.HttpRequest; -import org.jclouds.logging.Logger; import org.jclouds.net.IPSocket; import org.jclouds.rest.Providers; import org.jclouds.scriptbuilder.domain.Statement; @@ -106,10 +101,6 @@ public class ComputeServiceUtils { return extractZipIntoDirectory(new HttpRequest("GET", zip), directory); } - @Resource - @Named(ComputeServiceConstants.COMPUTE_LOGGER) - protected static Logger logger = Logger.NULL; - /** * * @@ -117,12 +108,7 @@ public class ComputeServiceUtils { */ public static String parseTagFromName(String from) { Matcher matcher = DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from); - String returnVal = matcher.find() ? matcher.group(1) : "NOTAG#" + from; - if (logger.isTraceEnabled()) { - if (returnVal.startsWith("NOTAG#")) - logger.trace("failed to parse tag from name %s", from); - } - return returnVal; + return matcher.find() ? matcher.group(1) : "NOTAG#" + from; } public static double getCores(Hardware input) { @@ -207,7 +193,8 @@ public class ComputeServiceUtils { } }), socketTester); } catch (NoSuchElementException e) { - throw new RuntimeException(String.format("could not connect to any ip address port %d on node %s", port, node)); + throw new NoSuchElementException(String.format("could not connect to any ip address port %d on node %s", port, + node)); } return socket; } diff --git a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java index adb308499d..98bb147d07 100755 --- a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java @@ -62,6 +62,8 @@ import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OperatingSystemBuilder; +import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.options.TemplateOptions; @@ -201,6 +203,12 @@ public abstract class BaseComputeServiceLiveTest { assert duration < 1000 : String.format("%dms to get images", duration); } + @Test(enabled = true, expectedExceptions = NoSuchElementException.class) + public void testCorrectExceptionRunningNodesNotFound() throws Exception { + client.runScriptOnNodesMatching(runningWithTag("zebras-are-awesome"), buildScript(new OperatingSystemBuilder() + .family(OsFamily.UBUNTU).description("ffoo").build())); + } + // since surefire and eclipse don't otherwise guarantee the order, we are // starting this one alphabetically before create2nodes.. @Test(enabled = true, dependsOnMethods = { "testCompareSizes" }) diff --git a/providers/trmk-ecloud/pom.xml b/providers/trmk-ecloud/pom.xml index 55e537def2..eef065ac0d 100644 --- a/providers/trmk-ecloud/pom.xml +++ b/providers/trmk-ecloud/pom.xml @@ -118,6 +118,7 @@ test + 1 test.trmk-ecloud.endpoint