You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whirr.apache.org by as...@apache.org on 2012/03/28 00:00:26 UTC

svn commit: r1306027 [1/3] - in /whirr/trunk: ./ cli/src/main/java/org/apache/whirr/cli/command/ cli/src/test/java/org/apache/whirr/cli/command/ core/src/main/java/org/apache/whirr/ core/src/main/java/org/apache/whirr/actions/ core/src/main/java/org/ap...

Author: asavu
Date: Tue Mar 27 22:00:24 2012
New Revision: 1306027

URL: http://svn.apache.org/viewvc?rev=1306027&view=rev
Log:
WHIRR-504. Upgrade to jclouds 1.4.0 (Adrian Cole, Andrei Savu)

Added:
    whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/VariablesToExport.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/BaseServiceDryRunTest.java
    whirr/trunk/services/cassandra/src/test/java/org/apache/whirr/service/cassandra/CassandraServiceDryRunTest.java
Modified:
    whirr/trunk/CHANGES.txt
    whirr/trunk/cli/src/main/java/org/apache/whirr/cli/command/RunScriptCommand.java
    whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/BaseCommandTest.java
    whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java
    whirr/trunk/core/src/main/java/org/apache/whirr/ByonClusterController.java
    whirr/trunk/core/src/main/java/org/apache/whirr/Cluster.java
    whirr/trunk/core/src/main/java/org/apache/whirr/ClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/ClusterController.java
    whirr/trunk/core/src/main/java/org/apache/whirr/ClusterControllerFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.java
    whirr/trunk/core/src/main/java/org/apache/whirr/DynamicClusterControllerFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/DynamicHandlerMapFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/HandlerMapFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/BootstrapClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/ByonClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/CleanupClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/ConfigureServicesAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/DestroyClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/ScriptBasedClusterAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/StartServicesAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/actions/StopServicesAction.java
    whirr/trunk/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java
    whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java
    whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarter.java
    whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarterFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/compute/StartupProcess.java
    whirr/trunk/core/src/main/java/org/apache/whirr/net/DnsException.java
    whirr/trunk/core/src/main/java/org/apache/whirr/net/FastDnsResolver.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/BlobStoreContextBuilder.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/ClusterActionHandlerSupport.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/ComputeCache.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/DryRunModule.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/FirewallManager.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/RunUrlStatement.java
    whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/StatementBuilder.java
    whirr/trunk/core/src/main/java/org/apache/whirr/state/BlobClusterStateStore.java
    whirr/trunk/core/src/main/java/org/apache/whirr/state/ClusterStateStore.java
    whirr/trunk/core/src/main/java/org/apache/whirr/state/ClusterStateStoreFactory.java
    whirr/trunk/core/src/main/java/org/apache/whirr/state/FileClusterStateStore.java
    whirr/trunk/core/src/main/java/org/apache/whirr/state/MemoryClusterStateStore.java
    whirr/trunk/core/src/main/java/org/apache/whirr/util/BlobCache.java
    whirr/trunk/core/src/main/java/org/apache/whirr/util/KeyPair.java
    whirr/trunk/core/src/main/java/org/apache/whirr/util/Utils.java
    whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/ClusterTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/CleanupClusterActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/ConfigureServicesActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/ScriptBasedClusterActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/StartServicesActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/StopServicesActionTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/actions/integration/PhaseExecutionBarrierTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/command/AbstractClusterCommandTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/DryRunModuleTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/jclouds/StatementBuilderTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/jclouds/integration/FirewallManagerTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/state/integration/BlobClusterStateStoreTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/util/KeyPairTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/util/UtilsTest.java
    whirr/trunk/platforms/karaf/feature/pom.xml
    whirr/trunk/platforms/karaf/itests/src/test/java/org/apache/whirr/karaf/itest/WhirrKarafTestSupport.java
    whirr/trunk/platforms/karaf/itests/src/test/resources/whirr-zookeeper-test.properties
    whirr/trunk/pom.xml
    whirr/trunk/services/cassandra/src/test/resources/whirr-cassandra-test.properties
    whirr/trunk/services/cdh-oldtests/src/test/resources/whirr-zookeeper-cdh3-test.properties
    whirr/trunk/services/cdh/src/test/resources/whirr-zookeeper-cdh-test.properties
    whirr/trunk/services/chef/src/test/java/org/apache/whirr/service/chef/ChefServiceDryRunTest.java
    whirr/trunk/services/chef/src/test/java/org/apache/whirr/service/chef/RecipeTest.java
    whirr/trunk/services/elasticsearch/src/test/resources/whirr-elasticsearch-test.properties
    whirr/trunk/services/ganglia/src/test/resources/whirr-ganglia-test.properties
    whirr/trunk/services/hadoop/src/test/java/org/apache/whirr/service/hadoop/HadoopConfigurationBuilderTest.java
    whirr/trunk/services/puppet/src/test/java/org/apache/whirr/service/puppet/PuppetClusterActionHandlerFactoryTest.java
    whirr/trunk/services/puppet/src/test/resources/nginx-with-attribs.txt
    whirr/trunk/services/zookeeper/src/test/resources/whirr-zookeeper-test.properties

Modified: whirr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/whirr/trunk/CHANGES.txt?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/CHANGES.txt (original)
+++ whirr/trunk/CHANGES.txt Tue Mar 27 22:00:24 2012
@@ -82,6 +82,8 @@ Trunk (unreleased changes)
 
     WHIRR-563. Disable password based authentication (Rodrigo Duarte Sousa via Andrei Savu)
 
+    WHIRR-504. Upgrade to jclouds 1.4.0 (Adrian Cole, Andrei Savu)
+
   BUG FIXES
 
     WHIRR-555. Fix java install script: $(...) -> `...` (kve)

Modified: whirr/trunk/cli/src/main/java/org/apache/whirr/cli/command/RunScriptCommand.java
URL: http://svn.apache.org/viewvc/whirr/trunk/cli/src/main/java/org/apache/whirr/cli/command/RunScriptCommand.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/cli/src/main/java/org/apache/whirr/cli/command/RunScriptCommand.java (original)
+++ whirr/trunk/cli/src/main/java/org/apache/whirr/cli/command/RunScriptCommand.java Tue Mar 27 22:00:24 2012
@@ -152,7 +152,7 @@ public class RunScriptCommand extends Ab
 
   private int handleScriptOutput(PrintStream out, PrintStream err,
                                  Map<? extends NodeMetadata, ExecResponse> responses) {
-    int rc = 0;
+    int exitStatus = 0;
     for (Map.Entry<? extends NodeMetadata, ExecResponse> entry : responses.entrySet()) {
       out.printf("** Node %s: %s%n", entry.getKey().getId(),
         Iterables.concat(entry.getKey().getPrivateAddresses(),
@@ -160,12 +160,12 @@ public class RunScriptCommand extends Ab
 
       ExecResponse response = entry.getValue();
       if (response.getExitCode() != 0) {
-        rc = response.getExitCode();
+        exitStatus = response.getExitCode();
       }
       out.printf("%s%n", response.getOutput());
       err.printf("%s%n", response.getError());
     }
-    return rc;
+    return exitStatus;
   }
 
   private Statement execFile(String filePath) throws IOException {

Modified: whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/BaseCommandTest.java
URL: http://svn.apache.org/viewvc/whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/BaseCommandTest.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/BaseCommandTest.java (original)
+++ whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/BaseCommandTest.java Tue Mar 27 22:00:24 2012
@@ -18,21 +18,19 @@
 
 package org.apache.whirr.cli.command;
 
-import com.google.common.collect.ListMultimap;
-import org.apache.whirr.service.DryRunModule;
-import org.jclouds.compute.callables.RunScriptOnNode;
-import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
-import org.jclouds.compute.callables.SudoAwareInitManager;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.scriptbuilder.InitBuilder;
-import org.junit.Before;
+import static junit.framework.Assert.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
-import java.lang.reflect.Field;
 import java.util.Map;
 
-import static junit.framework.Assert.fail;
+import org.apache.whirr.service.DryRunModule;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.scriptbuilder.InitScript;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.junit.Before;
+
+import com.google.common.collect.ListMultimap;
 
 public class BaseCommandTest {
 
@@ -71,10 +69,10 @@ public class BaseCommandTest {
     }
   }
 
-  private Map.Entry<NodeMetadata, RunScriptOnNode> getEntryForPhase(
-      ListMultimap<NodeMetadata, RunScriptOnNode> executions, String phaseName)
+  private Map.Entry<NodeMetadata, Statement> getEntryForPhase(
+      ListMultimap<NodeMetadata, Statement> executions, String phaseName)
       throws Exception {
-    for (Map.Entry<NodeMetadata, RunScriptOnNode> entry : executions.entries()) {
+    for (Map.Entry<NodeMetadata, Statement> entry : executions.entries()) {
       if (getScriptName(entry.getValue()).startsWith(phaseName)) {
         return entry;
       }
@@ -82,15 +80,7 @@ public class BaseCommandTest {
     throw new IllegalStateException("phase not found: " + phaseName);
   }
 
-  private String getScriptName(RunScriptOnNode script) throws Exception {
-    if (script instanceof RunScriptOnNodeAsInitScriptUsingSsh) {
-      Field initField = SudoAwareInitManager.class
-          .getDeclaredField("init");
-      initField.setAccessible(true);
-      return ((InitBuilder) initField
-          .get(script))
-          .getInstanceName();
-    }
-    throw new IllegalArgumentException();
+  private String getScriptName(Statement script) throws Exception {
+    return InitScript.class.cast(script).getInstanceName();
   }
 }

Modified: whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java
URL: http://svn.apache.org/viewvc/whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java (original)
+++ whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java Tue Mar 27 22:00:24 2012
@@ -20,13 +20,14 @@ package org.apache.whirr.cli.command;
 
 import com.google.common.collect.Lists;
 import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.whirr.Cluster;
 import org.apache.whirr.ClusterController;
 import org.apache.whirr.ClusterControllerFactory;
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.InstanceTemplate;
-import org.apache.whirr.service.DryRunModule;
+import org.apache.whirr.service.DryRunModule.DryRun;
 import org.apache.whirr.util.KeyPair;
 import org.hamcrest.MatcherAssert;
 import org.junit.Test;
@@ -34,6 +35,8 @@ import org.junit.Test;
 import java.io.File;
 import java.util.Map;
 
+import joptsimple.OptionSet;
+
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
@@ -154,12 +157,34 @@ public class LaunchClusterCommandTest ex
     assertThat(outBytes.toString(), containsString("Started cluster of 0 instances")); 
   }
 
+  static class TestLaunchClusterCommand extends LaunchClusterCommand {
+    private ClusterSpec clusterSpec;
+    private DryRun dryRun;
+
+    public TestLaunchClusterCommand(ClusterControllerFactory factory) {
+      super(factory);
+    }
+
+    @Override
+    protected ClusterSpec getClusterSpec(OptionSet optionSet) throws ConfigurationException {
+      return this.clusterSpec = super.getClusterSpec(optionSet);
+    }
+
+    @Override
+    protected ClusterController createClusterController(String serviceName) {
+      ClusterController controller = super.createClusterController(serviceName);
+      this.dryRun = controller.getCompute().apply(clusterSpec).utils().injector().getInstance(DryRun.class).reset();
+      return controller;
+    }
+
+  };
+
   @Test
   public void testLaunchClusterUsingDryRun() throws Exception {
-    DryRunModule.resetDryRun();
 
     ClusterControllerFactory factory = new ClusterControllerFactory();
-    LaunchClusterCommand launchCluster = new LaunchClusterCommand(factory);
+    TestLaunchClusterCommand launchCluster = new TestLaunchClusterCommand(factory);
+
     Map<String, File> keys = KeyPair.generateTemporaryFiles();
 
     int rc = launchCluster.run(null, out, err, Lists.<String>newArrayList(
@@ -172,6 +197,6 @@ public class LaunchClusterCommandTest ex
     ));
 
     MatcherAssert.assertThat(rc, is(0));
-    assertExecutedPhases(DryRunModule.DryRun.INSTANCE, "setup", "configure", "start");
+    assertExecutedPhases(launchCluster.dryRun, "bootstrap", "configure", "start");
   }
 }

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/ByonClusterController.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/ByonClusterController.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/ByonClusterController.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/ByonClusterController.java Tue Mar 27 22:00:24 2012
@@ -38,12 +38,11 @@ import org.jclouds.compute.domain.NodeMe
 import org.jclouds.compute.domain.NodeState;
 import org.jclouds.compute.options.RunScriptOptions;
 import org.jclouds.scriptbuilder.domain.Statement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.Collections2;
 
 /**
@@ -52,8 +51,6 @@ import com.google.common.collect.Collect
  */
 public class ByonClusterController extends ClusterController {
 
-  private static final Logger LOG = LoggerFactory.getLogger(ClusterController.class);
-
   @Override
   public String getName() {
     return "byon";
@@ -62,7 +59,7 @@ public class ByonClusterController exten
   public Cluster launchCluster(ClusterSpec clusterSpec) throws IOException,
       InterruptedException {
 
-    Map<String, ClusterActionHandler> handlerMap = handlerMapFactory
+    LoadingCache<String, ClusterActionHandler> handlerMap = handlerMapFactory
         .create();
 
     ClusterAction bootstrapper = new ByonClusterAction(BOOTSTRAP_ACTION, getCompute(), handlerMap);
@@ -78,7 +75,7 @@ public class ByonClusterController exten
 
   public void destroyCluster(ClusterSpec clusterSpec) throws IOException,
       InterruptedException {
-    Map<String, ClusterActionHandler> handlerMap = handlerMapFactory
+    LoadingCache<String, ClusterActionHandler> handlerMap = handlerMapFactory
         .create();
 
     ClusterAction destroyer = new ByonClusterAction(DESTROY_ACTION, getCompute(), handlerMap);

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/Cluster.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/Cluster.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/Cluster.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/Cluster.java Tue Mar 27 22:00:24 2012
@@ -18,24 +18,25 @@
 
 package org.apache.whirr;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.common.net.InetAddresses;
-import org.apache.whirr.net.DnsResolver;
-import org.apache.whirr.net.FastDnsResolver;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.domain.Credentials;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.io.IOException;
 import java.net.InetAddress;
 import java.util.Properties;
 import java.util.Set;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import org.apache.whirr.net.DnsResolver;
+import org.apache.whirr.net.FastDnsResolver;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.domain.Credentials;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.net.InetAddresses;
 
 /**
  * This class represents a real cluster of {@link Instance}s.

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/ClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/ClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/ClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/ClusterAction.java Tue Mar 27 22:00:24 2012
@@ -37,7 +37,7 @@ public abstract class ClusterAction {
     this.getCompute = getCompute;
   }
   
-  protected Function<ClusterSpec, ComputeServiceContext> getCompute() {
+  public Function<ClusterSpec, ComputeServiceContext> getCompute() {
     return getCompute;
   }
   

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/ClusterController.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/ClusterController.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/ClusterController.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/ClusterController.java Tue Mar 27 22:00:24 2012
@@ -18,6 +18,9 @@
 
 package org.apache.whirr;
 
+import static org.apache.whirr.RolePredicates.withIds;
+import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideLoginCredentials;
+
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -43,6 +46,7 @@ import org.jclouds.compute.domain.NodeMe
 import org.jclouds.compute.domain.NodeState;
 import org.jclouds.compute.options.RunScriptOptions;
 import org.jclouds.domain.Credentials;
+import org.jclouds.domain.LoginCredentials;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,8 +56,6 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-import static org.apache.whirr.RolePredicates.withIds;
-import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideCredentialsWith;
 
 /**
  * This class is used to start and stop clusters.
@@ -90,7 +92,7 @@ public class ClusterController {
   /**
    * @return compute service contexts for use in managing the service
    */
-  protected Function<ClusterSpec, ComputeServiceContext> getCompute() {
+  public Function<ClusterSpec, ComputeServiceContext> getCompute() {
     return getCompute;
   }
 
@@ -261,13 +263,13 @@ public class ClusterController {
     ClusterSpec spec, Predicate<NodeMetadata> condition, Statement statement,
     RunScriptOptions options) throws IOException, RunScriptOnNodesException {
 
-    Credentials credentials = new Credentials(spec.getClusterUser(),
-      spec.getPrivateKey());
+    LoginCredentials credentials = LoginCredentials.builder()
+      .user(spec.getClusterUser()).privateKey(spec.getPrivateKey()).build();
 
     if (options == null) {
       options = defaultRunScriptOptionsForSpec(spec);
-    } else if (options.getOverridingCredentials() == null) {
-      options = options.overrideCredentialsWith(credentials);
+    } else if (options.getLoginUser() == null) {
+      options = options.overrideLoginCredentials(credentials);
     }
     condition = Predicates
       .and(runningInGroup(spec.getClusterName()), condition);
@@ -278,9 +280,9 @@ public class ClusterController {
   }
 
   public RunScriptOptions defaultRunScriptOptionsForSpec(ClusterSpec spec) {
-    Credentials credentials = new Credentials(spec.getClusterUser(),
-      spec.getPrivateKey());
-    return overrideCredentialsWith(credentials).wrapInInitScript(false)
+    LoginCredentials credentials = LoginCredentials.builder()
+      .user(spec.getClusterUser()).privateKey(spec.getPrivateKey()).build();
+    return overrideLoginCredentials(credentials).wrapInInitScript(false)
       .runAsRoot(false);
   }
 

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/ClusterControllerFactory.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/ClusterControllerFactory.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/ClusterControllerFactory.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/ClusterControllerFactory.java Tue Mar 27 22:00:24 2012
@@ -18,11 +18,11 @@
 
 package org.apache.whirr;
 
-import com.google.common.collect.Sets;
-
 import java.util.ServiceLoader;
 import java.util.Set;
 
+import com.google.common.collect.Sets;
+
 /**
  * This class is used to create {@link ClusterController} instances.
  * <p>

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.java Tue Mar 27 22:00:24 2012
@@ -439,7 +439,7 @@ public class ClusterSpec {
     return composed;
   }
 
-  private void checkAndSetKeyPair() throws ConfigurationException {
+  protected void checkAndSetKeyPair() throws ConfigurationException {
     String pairRepresentation = "";
     try {
       String privateKeyPath = getString(Property.PRIVATE_KEY_FILE);

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/DynamicClusterControllerFactory.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/DynamicClusterControllerFactory.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/DynamicClusterControllerFactory.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/DynamicClusterControllerFactory.java Tue Mar 27 22:00:24 2012
@@ -21,6 +21,7 @@ package org.apache.whirr;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+
 import com.google.common.collect.Sets;
 
 /**

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/DynamicHandlerMapFactory.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/DynamicHandlerMapFactory.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/DynamicHandlerMapFactory.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/DynamicHandlerMapFactory.java Tue Mar 27 22:00:24 2012
@@ -7,7 +7,7 @@
  * "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
+ *    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,
@@ -18,27 +18,35 @@
 
 package org.apache.whirr;
 
+import static org.apache.whirr.util.Utils.convertMapToLoadingCache;
+
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.whirr.service.ClusterActionHandler;
 
+import com.google.common.cache.LoadingCache;
+
 public class DynamicHandlerMapFactory extends HandlerMapFactory {
 
   protected final Map<String, ClusterActionHandler> clusterActionHandlerMap = new ConcurrentHashMap<String, ClusterActionHandler>();
+  protected final LoadingCache<String, ClusterActionHandler> cache = convertMapToLoadingCache(clusterActionHandlerMap);
 
   @Override
-  public Map<String, ClusterActionHandler> create() {
-    return clusterActionHandlerMap;
+  public LoadingCache<String, ClusterActionHandler> create() {
+    return cache;
   }
 
   public void bind(ClusterActionHandler clusterActionHandler) {
-     if (clusterActionHandler != null && clusterActionHandler.getRole() != null) {
+    if (clusterActionHandler != null && clusterActionHandler.getRole() != null) {
       clusterActionHandlerMap.put(clusterActionHandler.getRole(), clusterActionHandler);
+      cache.invalidate(clusterActionHandler.getRole());
     }
   }
 
   public void unbind(ClusterActionHandler clusterActionHandler) {
     if (clusterActionHandler != null && clusterActionHandler.getRole() != null) {
+      cache.invalidate(clusterActionHandler.getRole());
       clusterActionHandlerMap.remove(clusterActionHandler.getRole());
     }
   }

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/HandlerMapFactory.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/HandlerMapFactory.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/HandlerMapFactory.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/HandlerMapFactory.java Tue Mar 27 22:00:24 2012
@@ -18,16 +18,25 @@
 
 package org.apache.whirr;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.ServiceLoader;
+import java.util.Set;
 
 import org.apache.whirr.service.ClusterActionHandler;
 import org.apache.whirr.service.ClusterActionHandlerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
-import com.google.common.collect.MapMaker;
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 
 /**
@@ -41,70 +50,87 @@ import com.google.common.collect.Maps;
  * JUnit testable.
  */
 public class HandlerMapFactory {
+  private static final Logger LOG =
+    LoggerFactory.getLogger(HandlerMapFactory.class);
 
-   protected static final class ReturnHandlerByRoleOrPrefix implements Function<String, ClusterActionHandler> {
-      private final Map<String, ClusterActionHandlerFactory> factoryMap;
-      private final Map<String, ClusterActionHandler> handlerMap;
-
-      protected ReturnHandlerByRoleOrPrefix(Map<String, ClusterActionHandlerFactory> factoryMap,
-               Map<String, ClusterActionHandler> handlerMap) {
-         this.factoryMap = checkNotNull(factoryMap, "factoryMap");
-         this.handlerMap = checkNotNull(handlerMap, "handlerMap");
+  protected static final class ReturnHandlerByRoleOrPrefix extends CacheLoader<String, ClusterActionHandler> {
+    private final Map<String, ClusterActionHandlerFactory> factoryMap;
+    private final Map<String, ClusterActionHandler> handlerMap;
+
+    protected ReturnHandlerByRoleOrPrefix(Map<String, ClusterActionHandlerFactory> factoryMap,
+        Map<String, ClusterActionHandler> handlerMap) {
+      this.factoryMap = checkNotNull(factoryMap, "factoryMap");
+      this.handlerMap = checkNotNull(handlerMap, "handlerMap");
+    }
+
+    @Override
+    public ClusterActionHandler load(final String role) {
+      checkNotNull(role, "role");
+      Set<String> prefixes = factoryMap.keySet();
+      try {
+        String prefix = Iterables.find(prefixes, new Predicate<String>() {
+
+          @Override
+          public boolean apply(String prefix) {
+            return role.startsWith(prefix);
+          }
+
+        });
+        LOG.debug("role {} starts with a configured prefix {}", role, prefix);
+        ClusterActionHandlerFactory factory = factoryMap.get(prefix);
+        checkArgument(factory != null, "could not create action handler factory %s", prefix);
+        String subrole = role.substring(prefix.length());
+        ClusterActionHandler returnVal = factory.create(subrole);
+        checkArgument(returnVal != null, "action handler factory %s could not create action handler for role %s",
+            prefix, subrole);
+        return returnVal;
+      } catch (NoSuchElementException e) {
+        LOG.debug("role {} didn't start with any of the configured prefixes {}", role, prefixes);
+        ClusterActionHandler returnVal = handlerMap.get(role);
+        checkArgument(returnVal != null, "Action handler not found for role: %s; configured roles %s", role,
+            handlerMap.keySet());
+        return returnVal;
       }
 
+    }
+  }
+
+  public LoadingCache<String, ClusterActionHandler> create() {
+    return create(ServiceLoader.load(ClusterActionHandlerFactory.class),
+      ServiceLoader.load(ClusterActionHandler.class));
+  }
+
+  public LoadingCache<String, ClusterActionHandler> create(
+    Iterable<ClusterActionHandlerFactory> factories,
+    Iterable<ClusterActionHandler> handlers
+  ) {
+    Map<String, ClusterActionHandlerFactory> factoryMap =
+       indexFactoriesByRolePrefix(checkNotNull(factories, "factories"));
+    Map<String, ClusterActionHandler> handlerMap =
+       indexHandlersByRole(checkNotNull(handlers, "handlers"));
+    return CacheBuilder.newBuilder().build(new ReturnHandlerByRoleOrPrefix(factoryMap, handlerMap));
+  }
+
+  static Map<String, ClusterActionHandlerFactory> indexFactoriesByRolePrefix(
+        Iterable<ClusterActionHandlerFactory> handlers) {
+    return Maps.uniqueIndex(handlers, new Function<ClusterActionHandlerFactory, String>() {
+
       @Override
-      public ClusterActionHandler apply(String arg0) {
-         checkNotNull(arg0, "role");
-         for (String prefix : factoryMap.keySet()) {
-            if (arg0.startsWith(prefix)) {
-               return checkNotNull(
-                 factoryMap.get(prefix).create(arg0.substring(prefix.length())),
-                 "Unable to create the action handler"
-               );
-            }
-         }
-         return checkNotNull(handlerMap.get(arg0), "Action handler not found");
+      public String apply(ClusterActionHandlerFactory arg0) {
+        return arg0.getRolePrefix();
       }
-   }
 
-   public Map<String, ClusterActionHandler> create() {
-      return create(ServiceLoader.load(ClusterActionHandlerFactory.class),
-        ServiceLoader.load(ClusterActionHandler.class));
-   }
-
-   public Map<String, ClusterActionHandler> create(
-      Iterable<ClusterActionHandlerFactory> factories,
-      Iterable<ClusterActionHandler> handlers
-   ) {
-      Map<String, ClusterActionHandlerFactory> factoryMap =
-          indexFactoriesByRolePrefix(checkNotNull(factories, "factories"));
-      Map<String, ClusterActionHandler> handlerMap =
-          indexHandlersByRole(checkNotNull(handlers, "handlers"));
-
-      return new MapMaker().makeComputingMap(
-        new ReturnHandlerByRoleOrPrefix(factoryMap, handlerMap));
-   }
-
-   static Map<String, ClusterActionHandlerFactory> indexFactoriesByRolePrefix(
-            Iterable<ClusterActionHandlerFactory> handlers) {
-      return Maps.uniqueIndex(handlers, new Function<ClusterActionHandlerFactory, String>() {
-
-         @Override
-         public String apply(ClusterActionHandlerFactory arg0) {
-            return arg0.getRolePrefix();
-         }
-
-      });
-   }
-
-   static Map<String, ClusterActionHandler> indexHandlersByRole(Iterable<ClusterActionHandler> handlers) {
-      return Maps.uniqueIndex(handlers, new Function<ClusterActionHandler, String>() {
-
-         @Override
-         public String apply(ClusterActionHandler arg0) {
-            return arg0.getRole();
-         }
+    });
+  }
+
+  static Map<String, ClusterActionHandler> indexHandlersByRole(Iterable<ClusterActionHandler> handlers) {
+    return Maps.uniqueIndex(handlers, new Function<ClusterActionHandler, String>() {
+
+      @Override
+      public String apply(ClusterActionHandler arg0) {
+        return arg0.getRole();
+      }
 
-      });
-   }
+    });
+  }
 }

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java Tue Mar 27 22:00:24 2012
@@ -21,12 +21,6 @@ import static com.google.common.base.Pre
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Sets.newLinkedHashSet;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -34,11 +28,17 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import com.google.common.collect.Sets;
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.lang.StringUtils;
 
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
 /**
  * This class describes the type of instances that should be in the cluster.
  * This is done by specifying the number of instances in each role.

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/BootstrapClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/BootstrapClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/BootstrapClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/BootstrapClusterAction.java Tue Mar 27 22:00:24 2012
@@ -18,12 +18,15 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
 import org.apache.whirr.Cluster;
 import org.apache.whirr.Cluster.Instance;
 import org.apache.whirr.ClusterSpec;
@@ -41,14 +44,12 @@ import org.jclouds.compute.domain.Templa
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 /**
  * A {@link org.apache.whirr.ClusterAction} that starts instances in a cluster in parallel and
@@ -62,12 +63,12 @@ public class BootstrapClusterAction exte
   private final NodeStarterFactory nodeStarterFactory;
   
   public BootstrapClusterAction(final Function<ClusterSpec, ComputeServiceContext> getCompute,
-      final Map<String, ClusterActionHandler> handlerMap) {
+      final LoadingCache<String, ClusterActionHandler> handlerMap) {
     this(getCompute, handlerMap, new NodeStarterFactory());
   }
   
   BootstrapClusterAction(final Function<ClusterSpec, ComputeServiceContext> getCompute,
-      final Map<String, ClusterActionHandler> handlerMap, final NodeStarterFactory nodeStarterFactory) {
+      final LoadingCache<String, ClusterActionHandler> handlerMap, final NodeStarterFactory nodeStarterFactory) {
     super(getCompute, handlerMap);
     this.nodeStarterFactory = nodeStarterFactory;
   }
@@ -100,11 +101,6 @@ public class BootstrapClusterAction exte
       final Template template = BootstrapTemplate.build(clusterSpec, computeService,
         statementBuilder, entry.getValue().getTemplateBuilderStrategy(), entry.getKey());
 
-      if (template.getOptions() != null) {
-        template.getOptions()
-          .nameTask("bootstrap-" + Joiner.on('_').join(entry.getKey().getRoles()));
-      }
-
       Future<Set<? extends NodeMetadata>> nodesFuture = executorService.submit(
           new StartupProcess(
               clusterSpec.getClusterName(),

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/ByonClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/ByonClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/ByonClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/ByonClusterAction.java Tue Mar 27 22:00:24 2012
@@ -18,27 +18,24 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.get;
+import static com.google.common.collect.Iterables.transform;
+import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideLoginCredentials;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+
 import org.apache.commons.lang.StringUtils;
 import org.apache.whirr.Cluster;
 import org.apache.whirr.Cluster.Instance;
@@ -50,13 +47,21 @@ import org.apache.whirr.service.jclouds.
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.domain.ComputeMetadata;
+import org.jclouds.compute.domain.ExecResponse;
 import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.RunScriptOptions;
 import org.jclouds.domain.Credentials;
-import org.jclouds.scriptbuilder.domain.OsFamily;
-import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.domain.LoginCredentials;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
 public class ByonClusterAction extends ScriptBasedClusterAction {
 
   private static final Logger LOG =
@@ -65,7 +70,7 @@ public class ByonClusterAction extends S
   private final String action;
   
   public ByonClusterAction(String action, Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap) {
+      LoadingCache<String, ClusterActionHandler> handlerMap) {
     super(getCompute, handlerMap);
     this.action = action;
   }
@@ -78,10 +83,8 @@ public class ByonClusterAction extends S
   @Override
   protected void doAction(Map<InstanceTemplate, ClusterActionEvent> eventMap)
       throws IOException, InterruptedException {
-    
-    ExecutorService executorService = Executors.newCachedThreadPool();
-    
-    Set<Future<Void>> futures = Sets.newHashSet();
+        
+    final Collection<Future<ExecResponse>> futures = Sets.newHashSet();
 
     List<NodeMetadata> nodes = Lists.newArrayList();
     List<NodeMetadata> usedNodes = Lists.newArrayList();
@@ -99,8 +102,11 @@ public class ByonClusterAction extends S
       final ComputeServiceContext computeServiceContext = getCompute().apply(clusterSpec);
       final ComputeService computeService = computeServiceContext.getComputeService();
 
-      Credentials credentials = new Credentials(clusterSpec.getIdentity(), clusterSpec.getCredential());
+      LoginCredentials credentials = LoginCredentials.builder().user(clusterSpec.getClusterUser())
+            .privateKey(clusterSpec.getPrivateKey()).build();
       
+      final RunScriptOptions options = overrideLoginCredentials(credentials);
+
       if (numberAllocated == 0) {
         for (ComputeMetadata compute : computeService.listNodes()) {
           if (!(compute instanceof NodeMetadata)) {
@@ -111,10 +117,10 @@ public class ByonClusterAction extends S
       }
 
       int num = entry.getKey().getNumberOfInstances();
-      Predicate<NodeMetadata> unused = Predicates.not(Predicates.in(usedNodes));
+      Predicate<NodeMetadata> unused = not(in(usedNodes));
       Predicate<NodeMetadata> instancePredicate = new TagsPredicate(StringUtils.split(entry.getKey().getHardwareId()));      
 
-      List<NodeMetadata> templateNodes = new ArrayList(Collections2.filter(nodes, Predicates.and(unused, instancePredicate)));
+      List<NodeMetadata> templateNodes = Lists.newArrayList(filter(nodes, and(unused, instancePredicate)));
       if (templateNodes.size() < num) {
         LOG.warn("Not enough nodes available for template " + StringUtils.join(entry.getKey().getRoles(), "+"));
       }
@@ -122,33 +128,15 @@ public class ByonClusterAction extends S
       usedNodes.addAll(templateNodes);
       numberAllocated = usedNodes.size() ;
       
-      final Set<Instance> templateInstances = getInstances(
-          credentials, entry.getKey().getRoles(), templateNodes
-      );
+      Set<Instance> templateInstances = getInstances(credentials, entry.getKey().getRoles(), templateNodes);
       allInstances.addAll(templateInstances);
       
       for (final Instance instance : templateInstances) {
-        final Statement statement = statementBuilder.build(clusterSpec, instance);
-
-        futures.add(executorService.submit(new Callable<Void>() {
-          @Override
-          public Void call() throws Exception {
-            LOG.info("Running script on: {}", instance.getId());
-
-            if (LOG.isDebugEnabled()) {
-              LOG.debug("Running script:\n{}", statement.render(OsFamily.UNIX));
-            }
-
-            computeService.runScriptOnNode(instance.getId(), statement);
-            LOG.info("Script run completed on: {}", instance.getId());
-
-            return null;
-          }
-        }));
+         futures.add(runStatementOnInstanceInCluster(statementBuilder, instance, clusterSpec, options));
       }
     }
     
-    for (Future<Void> future : futures) {
+    for (Future<ExecResponse> future : futures) {
       try {
         future.get();
       } catch (ExecutionException e) {
@@ -165,12 +153,12 @@ public class ByonClusterAction extends S
   }
   
   private Set<Instance> getInstances(final Credentials credentials, final Set<String> roles,
-      Collection<NodeMetadata> nodes) {
-    return Sets.newLinkedHashSet(Collections2.transform(Sets.newLinkedHashSet(nodes),
+      Iterable<NodeMetadata> nodes) {
+    return ImmutableSet.copyOf(transform(nodes,
         new Function<NodeMetadata, Instance>() {
           @Override
           public Instance apply(NodeMetadata node) {
-            String publicIp = Iterables.get(node.getPublicAddresses(), 0);
+            String publicIp = get(node.getPublicAddresses(), 0);
             return new Instance(
                 credentials, roles, publicIp, publicIp, node.getId(), node
             );

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/CleanupClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/CleanupClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/CleanupClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/CleanupClusterAction.java Tue Mar 27 22:00:24 2012
@@ -18,33 +18,30 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
+import java.util.Set;
+
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.service.ClusterActionHandler;
 import org.jclouds.compute.ComputeServiceContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.Map;
-import java.util.Set;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
 
 /**
  * A {@link ClusterAction} for cleaning-up the cluster services
  */
 public class CleanupClusterAction extends ScriptBasedClusterAction {
 
-  private static final Logger LOG = LoggerFactory.getLogger(CleanupClusterAction.class);
-
   public CleanupClusterAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap
+      LoadingCache<String, ClusterActionHandler> handlerMap
   ) {
     super(getCompute, handlerMap);
   }
 
   public CleanupClusterAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap,
+      LoadingCache<String, ClusterActionHandler> handlerMap,
       Set<String> targetRoles,
       Set<String> targetInstanceIds
   ) {

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/ConfigureServicesAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/ConfigureServicesAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/ConfigureServicesAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/ConfigureServicesAction.java Tue Mar 27 22:00:24 2012
@@ -18,9 +18,12 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import com.google.common.primitives.Ints;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.InstanceTemplate;
 import org.apache.whirr.RolePredicates;
@@ -29,11 +32,10 @@ import org.apache.whirr.service.ClusterA
 import org.apache.whirr.service.FirewallManager.Rule;
 import org.jclouds.compute.ComputeServiceContext;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Collections2;
+import com.google.common.primitives.Ints;
 
 
 /**
@@ -44,14 +46,14 @@ public class ConfigureServicesAction ext
 
   public ConfigureServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap
+      LoadingCache<String, ClusterActionHandler> handlerMap
   ) {
     super(getCompute, handlerMap);
   }
 
   public ConfigureServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap,
+      LoadingCache<String, ClusterActionHandler> handlerMap,
       Set<String> targetRoles,
       Set<String> targetInstanceIds
   ) {

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/DestroyClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/DestroyClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/DestroyClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/DestroyClusterAction.java Tue Mar 27 22:00:24 2012
@@ -33,6 +33,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
 
 /**
  * A {@link ClusterAction} for tearing down a running cluster and freeing up all
@@ -45,7 +46,7 @@ public class DestroyClusterAction extend
 
   public DestroyClusterAction(
       final Function<ClusterSpec, ComputeServiceContext> getCompute,
-      final Map<String, ClusterActionHandler> handlerMap) {
+      final LoadingCache<String, ClusterActionHandler> handlerMap) {
     super(getCompute, handlerMap);
   }
 

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/ScriptBasedClusterAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/ScriptBasedClusterAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/ScriptBasedClusterAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/ScriptBasedClusterAction.java Tue Mar 27 22:00:24 2012
@@ -18,14 +18,21 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ComputationException;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.not;
+import static org.apache.whirr.RolePredicates.onlyRolesIn;
+import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideLoginCredentials;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import javax.annotation.Nullable;
+
 import org.apache.whirr.Cluster;
 import org.apache.whirr.Cluster.Instance;
 import org.apache.whirr.ClusterAction;
@@ -38,27 +45,24 @@ import org.apache.whirr.service.jclouds.
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.domain.ExecResponse;
-import org.jclouds.domain.Credentials;
-import org.jclouds.scriptbuilder.domain.OsFamily;
+import org.jclouds.compute.options.RunScriptOptions;
+import org.jclouds.domain.LoginCredentials;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nullable;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.whirr.RolePredicates.onlyRolesIn;
-import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideCredentialsWith;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+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 com.google.common.util.concurrent.UncheckedExecutionException;
 
 /**
  * A {@link ClusterAction} that provides the base functionality for running
@@ -69,20 +73,20 @@ public abstract class ScriptBasedCluster
   private static final Logger LOG = LoggerFactory
       .getLogger(ScriptBasedClusterAction.class);
 
-  private final Map<String, ClusterActionHandler> handlerMap;
+  private final LoadingCache<String, ClusterActionHandler> handlerMap;
   private final ImmutableSet<String> targetRoles;
   private final ImmutableSet<String> targetInstanceIds;
 
   protected ScriptBasedClusterAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap
+      LoadingCache<String, ClusterActionHandler> handlerMap
   ) {
     this(getCompute, handlerMap, ImmutableSet.<String>of(), ImmutableSet.<String>of());
   }
 
   protected ScriptBasedClusterAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap,
+      LoadingCache<String, ClusterActionHandler> handlerMap,
       Set<String> targetRoles,
       Set<String> targetInstanceIds
   ) {
@@ -155,16 +159,12 @@ public abstract class ScriptBasedCluster
       throws InterruptedException, IOException {
 
     final String phaseName = getAction();
-    final ExecutorService executorService = Executors.newCachedThreadPool();
     final Collection<Future<ExecResponse>> futures = Sets.newHashSet();
 
     final ClusterSpec clusterSpec = eventMap.values().iterator().next().getClusterSpec();
-    final ComputeServiceContext computeServiceContext = getCompute().apply(clusterSpec);
-    final ComputeService computeService = computeServiceContext.getComputeService();
-
-    final Credentials credentials = new Credentials(
-        clusterSpec.getClusterUser(), clusterSpec.getPrivateKey());
 
+    final RunScriptOptions options = overrideLoginCredentials(LoginCredentials.builder().user(clusterSpec.getClusterUser())
+          .privateKey(clusterSpec.getPrivateKey()).build());
     for (Entry<InstanceTemplate, ClusterActionEvent> entry : eventMap.entrySet()) {
       if (shouldIgnoreInstanceTemplate(entry.getKey())) {
         continue; // skip if not in the target
@@ -178,61 +178,36 @@ public abstract class ScriptBasedCluster
         continue; // skip execution if we have an empty list
       }
 
-      Set<Instance> instances = cluster.getInstancesMatching(onlyRolesIn(entry.getKey().getRoles()));
-      LOG.info("Starting to run scripts on cluster for phase {} "
-          + "on instances: {}", phaseName, asString(instances));
-
-      for (final Instance instance : instances) {
-        if (instanceIsNotInTarget(instance)) {
-          continue; // skip the script execution
-        }
-        final Statement statement = statementBuilder.build(clusterSpec, instance);
-
-        futures.add(executorService.submit(new Callable<ExecResponse>() {
-          @Override
-          public ExecResponse call() {
+      Set<Instance> instances = cluster.getInstancesMatching(Predicates.<Instance> and(onlyRolesIn(entry.getKey()
+          .getRoles()), not(instanceIsNotInTarget())));
+      LOG.info("Starting to run scripts on cluster for phase {} " + "on instances: {}", phaseName,
+          asString(instances));
 
-            LOG.info("Running {} phase script on: {}", phaseName, instance.getId());
-            if (LOG.isDebugEnabled()) {
-              LOG.debug("{} phase script on: {}\n{}", new Object[]{phaseName,
-                  instance.getId(), statement.render(OsFamily.UNIX)});
-            }
-
-            try {
-              return computeService.runScriptOnNode(
-                  instance.getId(),
-                  statement,
-                  overrideCredentialsWith(credentials).runAsRoot(true)
-                      .nameTask(
-                          phaseName + "-"
-                              + Joiner.on('_').join(instance.getRoles())));
-            } finally {
-              LOG.info("{} phase script run completed on: {}", phaseName,
-                  instance.getId());
-            }
-          }
-        }));
+      for (Instance instance : instances) {
+        futures.add(runStatementOnInstanceInCluster(statementBuilder, instance, clusterSpec, options));
       }
     }
-
     for (Future<ExecResponse> future : futures) {
       try {
-        ExecResponse execResponse = future.get();
-        if (execResponse.getExitCode() != 0) {
-          LOG.error("Error running " + phaseName + " script: {}", execResponse);
-        } else {
-          LOG.info("Successfully executed {} script: {}", phaseName, execResponse);
-        }
+        future.get();
       } catch (ExecutionException e) {
         throw new IOException(e.getCause());
       }
     }
-
-    executorService.shutdown();
-    LOG.info("Finished running {} phase scripts on all cluster instances",
-        phaseName);
+    LOG.info("Finished running {} phase scripts on all cluster instances", phaseName);
   }
-
+  
+  public ListenableFuture<ExecResponse> runStatementOnInstanceInCluster(StatementBuilder statementBuilder,
+      Instance instance, ClusterSpec clusterSpec, RunScriptOptions options) {
+    Statement statement = statementBuilder.name(getAction() + "-"
+          + Joiner.on('_').join(instance.getRoles())).build(clusterSpec, instance);
+    ComputeService compute = getCompute().apply(clusterSpec).getComputeService();
+    return compute.submitScriptOnNode(
+              instance.getId(),
+              statement,
+              options);
+  }
+  
   private String asString(Set<Instance> instances) {
     return Joiner.on(", ").join(
         Iterables.transform(instances, new Function<Instance, String>() {
@@ -251,14 +226,26 @@ public abstract class ScriptBasedCluster
     return targetRoles.size() == 0 || targetRoles.contains(role);
   }
 
-  protected boolean instanceIsNotInTarget(Instance instance) {
-    if (targetInstanceIds.size() != 0) {
-      return ! targetInstanceIds.contains(instance.getId());
-    }
-    if (targetRoles.size() != 0) {
-      return containsNoneOf(instance.getRoles(), targetRoles);
-    }
-    return false;
+  protected Predicate<Instance> instanceIsNotInTarget() {
+    return new Predicate<Instance>() {
+
+      @Override
+      public boolean apply(Instance arg0) {
+        if (targetInstanceIds.size() != 0) {
+          return !targetInstanceIds.contains(arg0.getId());
+        }
+        if (targetRoles.size() != 0) {
+          return containsNoneOf(arg0.getRoles(), targetRoles);
+        }
+        return false;
+      }
+
+      @Override
+      public String toString() {
+        return "instanceIsNotInTarget()";
+      }
+    };
+
   }
 
   private boolean containsNoneOf(Set<String> querySet, final Set<String> target) {
@@ -289,9 +276,10 @@ public abstract class ScriptBasedCluster
         throw new IllegalArgumentException("No handler for role " + role);
       }
       return handler;
-
-    } catch (ComputationException e) {
-      throw new IllegalArgumentException(e.getCause());
+    } catch (UncheckedExecutionException e) {
+       throw Throwables.propagate(e.getCause());
+    } catch (ExecutionException e) {
+       throw new IllegalArgumentException(e.getCause());
     }
   }
 

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/StartServicesAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/StartServicesAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/StartServicesAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/StartServicesAction.java Tue Mar 27 22:00:24 2012
@@ -18,33 +18,30 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
+import java.util.Set;
+
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.service.ClusterActionHandler;
 import org.jclouds.compute.ComputeServiceContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.Map;
-import java.util.Set;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
 
 /**
  * A {@link ClusterAction} for starting the cluster services
  */
 public class StartServicesAction extends ScriptBasedClusterAction {
 
-  private static final Logger LOG = LoggerFactory.getLogger(StartServicesAction.class);
-
   public StartServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap
+      LoadingCache<String, ClusterActionHandler> handlerMap
   ) {
     super(getCompute, handlerMap);
   }
 
   public StartServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap,
+      LoadingCache<String, ClusterActionHandler> handlerMap,
       Set<String> targetRoles,
       Set<String> targetInstanceIds
   ) {

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/actions/StopServicesAction.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/actions/StopServicesAction.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/actions/StopServicesAction.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/actions/StopServicesAction.java Tue Mar 27 22:00:24 2012
@@ -18,33 +18,30 @@
 
 package org.apache.whirr.actions;
 
-import com.google.common.base.Function;
+import java.util.Set;
+
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.service.ClusterActionHandler;
 import org.jclouds.compute.ComputeServiceContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.Map;
-import java.util.Set;
+import com.google.common.base.Function;
+import com.google.common.cache.LoadingCache;
 
 /**
  * A {@link ClusterAction} for stopping the cluster services
  */
 public class StopServicesAction extends ScriptBasedClusterAction {
 
-  private static final Logger LOG = LoggerFactory.getLogger(StopServicesAction.class);
-
   public StopServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap
+      LoadingCache<String, ClusterActionHandler> handlerMap
   ) {
     super(getCompute, handlerMap);
   }
 
   public StopServicesAction(
       Function<ClusterSpec, ComputeServiceContext> getCompute,
-      Map<String, ClusterActionHandler> handlerMap,
+      LoadingCache<String, ClusterActionHandler> handlerMap,
       Set<String> targetRoles,
       Set<String> targetInstanceIds
   ) {

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/command/AbstractClusterCommand.java Tue Mar 27 22:00:24 2012
@@ -18,15 +18,23 @@
 
 package org.apache.whirr.command;
 
-import com.google.common.collect.Maps;
+import static org.apache.whirr.ClusterSpec.Property.CLUSTER_NAME;
+import static org.apache.whirr.ClusterSpec.Property.CREDENTIAL;
+import static org.apache.whirr.ClusterSpec.Property.IDENTITY;
+import static org.apache.whirr.ClusterSpec.Property.INSTANCE_TEMPLATES;
+import static org.apache.whirr.ClusterSpec.Property.PRIVATE_KEY_FILE;
+import static org.apache.whirr.ClusterSpec.Property.PROVIDER;
+
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.EnumSet;
 import java.util.Map;
+
 import joptsimple.ArgumentAcceptingOptionSpec;
 import joptsimple.OptionParser;
 import joptsimple.OptionSet;
 import joptsimple.OptionSpec;
+
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
@@ -36,17 +44,13 @@ import org.apache.whirr.ClusterControlle
 import org.apache.whirr.ClusterControllerFactory;
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.ClusterSpec.Property;
-import static org.apache.whirr.ClusterSpec.Property.CLUSTER_NAME;
-import static org.apache.whirr.ClusterSpec.Property.CREDENTIAL;
-import static org.apache.whirr.ClusterSpec.Property.IDENTITY;
-import static org.apache.whirr.ClusterSpec.Property.INSTANCE_TEMPLATES;
-import static org.apache.whirr.ClusterSpec.Property.PRIVATE_KEY_FILE;
-import static org.apache.whirr.ClusterSpec.Property.PROVIDER;
 import org.apache.whirr.state.ClusterStateStore;
 import org.apache.whirr.state.ClusterStateStoreFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Maps;
+
 /**
  * An abstract command for interacting with clusters.
  */

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java Tue Mar 27 22:00:24 2012
@@ -19,9 +19,14 @@
 package org.apache.whirr.compute;
 
 import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
+import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
+import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
+import static org.jclouds.scriptbuilder.domain.Statements.interpret;
+import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
+
 import org.apache.whirr.ClusterSpec;
 import org.apache.whirr.InstanceTemplate;
 import org.apache.whirr.service.jclouds.StatementBuilder;
@@ -32,19 +37,11 @@ import org.jclouds.compute.ComputeServic
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.domain.TemplateBuilder;
-import org.jclouds.scriptbuilder.InitBuilder;
 import org.jclouds.scriptbuilder.domain.OsFamily;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import java.net.MalformedURLException;
-
-import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
-import static org.jclouds.scriptbuilder.domain.Statements.appendFile;
-import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
-import static org.jclouds.scriptbuilder.domain.Statements.interpret;
-import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
+import com.google.common.base.Joiner;
 import static org.jclouds.scriptbuilder.statements.ssh.SshStatements.sshdConfig;
 
 public class BootstrapTemplate {
@@ -53,27 +50,27 @@ public class BootstrapTemplate {
     LoggerFactory.getLogger(BootstrapTemplate.class);
 
   public static Template build(
-    ClusterSpec clusterSpec,
+    final ClusterSpec clusterSpec,
     ComputeService computeService,
     StatementBuilder statementBuilder,
     TemplateBuilderStrategy strategy,
     InstanceTemplate instanceTemplate
-  ) throws MalformedURLException {
+  ) {
+    String name = "bootstrap-" + Joiner.on('_').join(instanceTemplate.getRoles());
 
-    LOG.info("Configuring template");
+    LOG.info("Configuring template for {}", name);
 
-    Statement runScript = addUserAndAuthorizeSudo(
-        clusterSpec.getClusterUser(),
-        clusterSpec.getPublicKey(),
-        clusterSpec.getPrivateKey(),
-        statementBuilder.build(clusterSpec));
+    statementBuilder.name(name);
+    ensureUserExistsAndAuthorizeSudo(statementBuilder, clusterSpec.getClusterUser(),
+        clusterSpec.getPublicKey(), clusterSpec.getPrivateKey());
+    Statement bootstrap = statementBuilder.build(clusterSpec);
 
     if (LOG.isDebugEnabled()) {
-      LOG.debug("Running script:\n{}", runScript.render(OsFamily.UNIX));
+      LOG.debug("Running script {}:\n{}", name, bootstrap.render(OsFamily.UNIX));
     }
 
     TemplateBuilder templateBuilder = computeService.templateBuilder()
-      .options(runScript(runScript));
+      .options(runScript(bootstrap));
     strategy.configureTemplateBuilder(clusterSpec, templateBuilder, instanceTemplate);
 
     return setSpotInstancePriceIfSpecified(
@@ -81,19 +78,15 @@ public class BootstrapTemplate {
     );
   }
 
-  private static Statement addUserAndAuthorizeSudo(
-    String user, String publicKey, String privateKey, Statement statement
+  private static void ensureUserExistsAndAuthorizeSudo(
+      StatementBuilder builder, String user, String publicKey, String privateKey
   ) {
-    return new InitBuilder(
-      "setup-" + user,// name of the script
-      "/tmp",// working directory
-      "/tmp/logs",// location of stdout.log and stderr.log
-      ImmutableMap.of("newUser", user, "defaultHome", "/home/users"), // variables
-      ImmutableList.<Statement> of(
+    builder.addExport("newUser", user);
+    builder.addExport("defaultHome", "/home/users");
+    builder.addStatement(0, newStatementList(
         ensureUserExistsWithPublicAndPrivateKey(user, publicKey, privateKey),
         makeSudoersOnlyPermitting(user),
-        disablePasswordBasedAuth(),
-        statement)
+        disablePasswordBasedAuth())
     );
   }
 
@@ -140,7 +133,7 @@ public class BootstrapTemplate {
         Splitter.on('\n').split(publicKey)),
       createOrOverwriteFile(
         "$USER_HOME/.ssh/id_rsa.pub",
-        Splitter.on('\n').split(publicKey)),      
+        Splitter.on('\n').split(publicKey)),
       createOrOverwriteFile(
         "$USER_HOME/.ssh/id_rsa",
         Splitter.on('\n').split(privateKey)),

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarter.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarter.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarter.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarter.java Tue Mar 27 22:00:24 2012
@@ -18,15 +18,15 @@
 
 package org.apache.whirr.compute;
 
+import java.util.Set;
+import java.util.concurrent.Callable;
+
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Set;
-import java.util.concurrent.Callable;
-
 public class NodeStarter implements Callable<Set<NodeMetadata>> {
 
   private static final Logger LOG =

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarterFactory.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarterFactory.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarterFactory.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/compute/NodeStarterFactory.java Tue Mar 27 22:00:24 2012
@@ -18,11 +18,11 @@
 
 package org.apache.whirr.compute;
 
+import java.util.Set;
+
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.Template;
 
-import java.util.Set;
-
 public class NodeStarterFactory {
   public NodeStarter create(final ComputeService computeService, final String clusterName,
       final Set<String> roles, final int num, final Template template) {

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/compute/StartupProcess.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/compute/StartupProcess.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/compute/StartupProcess.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/compute/StartupProcess.java Tue Mar 27 22:00:24 2012
@@ -18,16 +18,6 @@
 
 package org.apache.whirr.compute;
 
-import com.google.common.base.Predicates;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.RunNodesException;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.Template;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.IOException;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -37,6 +27,17 @@ import java.util.concurrent.ExecutionExc
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.RunNodesException;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.Template;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
 public class StartupProcess implements Callable<Set<? extends NodeMetadata>> {
 
   private static final Logger LOG =

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/net/DnsException.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/net/DnsException.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/net/DnsException.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/net/DnsException.java Tue Mar 27 22:00:24 2012
@@ -22,6 +22,9 @@ package org.apache.whirr.net;
  * Generic dns resolution exception
  */
 public class DnsException extends RuntimeException {
+
+  private static final long serialVersionUID = 3615182336811732309L;
+
   public DnsException(Throwable e) {
     super(e);
   }

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/net/FastDnsResolver.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/net/FastDnsResolver.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/net/FastDnsResolver.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/net/FastDnsResolver.java Tue Mar 27 22:00:24 2012
@@ -18,6 +18,8 @@
 
 package org.apache.whirr.net;
 
+import static org.xbill.DNS.Message.newQuery;
+
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.SocketTimeoutException;
@@ -32,8 +34,6 @@ import org.xbill.DNS.ReverseMap;
 import org.xbill.DNS.Section;
 import org.xbill.DNS.Type;
 
-import static org.xbill.DNS.Message.newQuery;
-
 /**
  * Fast DNS resolver
  */

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/service/BlobStoreContextBuilder.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/service/BlobStoreContextBuilder.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/service/BlobStoreContextBuilder.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/service/BlobStoreContextBuilder.java Tue Mar 27 22:00:24 2012
@@ -18,7 +18,6 @@
 
 package org.apache.whirr.service;
 
-import java.util.Map;
 import java.util.Properties;
 
 import org.apache.commons.configuration.Configuration;
@@ -43,10 +42,12 @@ import org.slf4j.LoggerFactory;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Objects;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ForwardingObject;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.MapMaker;
 import com.google.inject.Module;
 
 public class BlobStoreContextBuilder {
@@ -59,17 +60,17 @@ public class BlobStoreContextBuilder {
 
     @Override
     public BlobStoreContext apply(ClusterSpec arg0) {
-      return cache.get(new Key(arg0));
+      return cache.getUnchecked(new Key(arg0));
     }
 
     // this should prevent recreating the same compute context twice
     @VisibleForTesting
-    final Map<Key, BlobStoreContext> cache = new MapMaker().makeComputingMap(
-       new Function<Key, BlobStoreContext>(){
+    final LoadingCache<Key, BlobStoreContext> cache = CacheBuilder.newBuilder().build(
+       new CacheLoader<Key, BlobStoreContext>(){
         private final BlobStoreContextFactory factory =  new BlobStoreContextFactory();
         
         @Override
-        public BlobStoreContext apply(Key arg0) {
+        public BlobStoreContext load(Key arg0) {
           LOG.debug("creating new BlobStoreContext {}", arg0);
           BlobStoreContext context = new IgnoreCloseBlobStoreContext(
               factory.createContext(arg0.provider, arg0.identity, arg0.credential,

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/service/ClusterActionHandlerSupport.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/service/ClusterActionHandlerSupport.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/service/ClusterActionHandlerSupport.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/service/ClusterActionHandlerSupport.java Tue Mar 27 22:00:24 2012
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 
-import com.google.common.base.Objects;
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
@@ -35,6 +34,8 @@ import org.jclouds.scriptbuilder.domain.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Objects;
+
 /**
  * This is a utility class to make it easier to implement
  * {@link ClusterActionHandler}. For each 'before' and 'after' action type there

Modified: whirr/trunk/core/src/main/java/org/apache/whirr/service/ComputeCache.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/service/ComputeCache.java?rev=1306027&r1=1306026&r2=1306027&view=diff
==============================================================================
--- whirr/trunk/core/src/main/java/org/apache/whirr/service/ComputeCache.java (original)
+++ whirr/trunk/core/src/main/java/org/apache/whirr/service/ComputeCache.java Tue Mar 27 22:00:24 2012
@@ -18,14 +18,10 @@
 
 package org.apache.whirr.service;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.collect.ForwardingObject;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.MapMaker;
-import com.google.inject.Module;
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
+import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
 
 import java.util.Map;
 import java.util.Properties;
@@ -38,18 +34,31 @@ import org.jclouds.compute.ComputeServic
 import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.compute.ComputeServiceContextFactory;
 import org.jclouds.compute.Utils;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.events.StatementOnNodeCompletion;
+import org.jclouds.compute.events.StatementOnNodeFailure;
+import org.jclouds.compute.events.StatementOnNodeSubmission;
 import org.jclouds.domain.Credentials;
 import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
 import org.jclouds.providers.ProviderMetadata;
 import org.jclouds.providers.Providers;
 import org.jclouds.rest.RestContext;
+import org.jclouds.scriptbuilder.domain.OsFamily;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
-import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
-import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ForwardingObject;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Module;
 
 /**
  * A convenience class for building jclouds {@link ComputeServiceContext} objects.
@@ -63,28 +72,60 @@ public enum ComputeCache implements Func
 
   @Override
   public ComputeServiceContext apply(ClusterSpec arg0) {
-    return cache.get(new Key(arg0));
+    return cache.getUnchecked(new Key(arg0));
   }
   
   // this should prevent recreating the same compute context twice
   @VisibleForTesting
-  final Map<Key, ComputeServiceContext> cache = new MapMaker().makeComputingMap(
-      new Function<Key, ComputeServiceContext>(){
+  final LoadingCache<Key, ComputeServiceContext> cache = CacheBuilder.newBuilder().build(
+        new CacheLoader<Key, ComputeServiceContext>(){
         private final ComputeServiceContextFactory factory =  new ComputeServiceContextFactory();
                
         @Override
-        public ComputeServiceContext apply(Key arg0) {
+        public ComputeServiceContext load(Key arg0) {
           LOG.debug("creating new ComputeServiceContext {}", arg0);
           ComputeServiceContext context = new IgnoreCloseComputeServiceContext(factory.createContext(
             arg0.provider, arg0.identity, arg0.credential,
             ImmutableSet.<Module>of(), arg0.overrides));
           LOG.debug("created new ComputeServiceContext {}", context);
+          context.utils().eventBus().register(ComputeCache.this);
           return context;
         }
     
     }
   );
-   
+
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onStart(StatementOnNodeSubmission event) {
+    LOG.info(">> running {} on node({})", event.getStatement(), event.getNode().getId());
+    if (LOG.isDebugEnabled()) {
+      LOG.debug(">> script for {} on node({})\n{}", new Object[] { event.getStatement(), event.getNode().getId(),
+          event.getStatement().render(OsFamily.UNIX) });
+    }
+  }
+
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onFailure(StatementOnNodeFailure event) {
+    LOG.error("<< error running {} on node({}): {}", new Object[] { event.getStatement(), event.getNode().getId(),
+        event.getCause().getMessage() }, event.getCause());
+  }
+
+  @Subscribe
+  @AllowConcurrentEvents
+  public void onSuccess(StatementOnNodeCompletion event) {
+    ExecResponse arg0 = event.getResponse();
+    if (arg0.getExitStatus() != 0) {
+      LOG.error("<< error running {} on node({}): {}", new Object[] { event.getStatement(), event.getNode().getId(),
+          arg0 });
+    } else {
+      LOG.info("<< success executing {} on node({}): {}", new Object[] { event.getStatement(),
+          event.getNode().getId(), arg0 });
+    }
+
+  }
+  
   private static class IgnoreCloseComputeServiceContext
     extends ForwardingObject implements ComputeServiceContext {