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/01/05 19:57:30 UTC

svn commit: r1227757 - in /whirr/trunk: ./ core/src/main/java/org/apache/whirr/ core/src/main/java/org/apache/whirr/compute/ core/src/test/java/org/apache/whirr/ core/src/test/java/org/apache/whirr/compute/ core/src/test/java/org/apache/whirr/service/

Author: asavu
Date: Thu Jan  5 18:57:29 2012
New Revision: 1227757

URL: http://svn.apache.org/viewvc?rev=1227757&view=rev
Log:
WHIRR-461. Allow user to specify spot instance price per instance template group (asavu)

Added:
    whirr/trunk/core/src/test/java/org/apache/whirr/compute/
    whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java
Modified:
    whirr/trunk/CHANGES.txt
    whirr/trunk/core/src/main/java/org/apache/whirr/InstanceTemplate.java
    whirr/trunk/core/src/main/java/org/apache/whirr/compute/BootstrapTemplate.java
    whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java
    whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java

Modified: whirr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/whirr/trunk/CHANGES.txt?rev=1227757&r1=1227756&r2=1227757&view=diff
==============================================================================
--- whirr/trunk/CHANGES.txt (original)
+++ whirr/trunk/CHANGES.txt Thu Jan  5 18:57:29 2012
@@ -14,6 +14,9 @@ Trunk (unreleased changes)
     WHIRR-332. Need to specify different instance size/type 
     depending on role (asavu)
 
+    WHIRR-461. Allow user to specify spot instance price per 
+    instance template group (asavu)
+
   BUG FIXES
 
     WHIRR-367. Wrong groupId for zookeeper (Joe Crobak via asavu)

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=1227757&r1=1227756&r2=1227757&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 Thu Jan  5 18:57:29 2012
@@ -54,6 +54,7 @@ public class InstanceTemplate {
     private int minNumberOfInstances = -1;
     private String hardwareId;
     private String imageId;
+    private float awsEc2SpotPrice = 0;
     private Set<String> roles;
 
     public Builder numberOfInstance(int numberOfInstances) {
@@ -76,6 +77,11 @@ public class InstanceTemplate {
       return this;
     }
 
+    public Builder awsEc2SpotPrice(float awsEc2SpotPrice) {
+      this.awsEc2SpotPrice = awsEc2SpotPrice;
+      return this;
+    }
+
     public Builder roles(String... roles) {
       this.roles = newLinkedHashSet(newArrayList(roles));
       return this;
@@ -90,7 +96,8 @@ public class InstanceTemplate {
       if (minNumberOfInstances == -1) {
         minNumberOfInstances = numberOfInstances;
       }
-      return new InstanceTemplate(numberOfInstances, minNumberOfInstances, roles, hardwareId, imageId);
+      return new InstanceTemplate(numberOfInstances, minNumberOfInstances, roles,
+        hardwareId, imageId, awsEc2SpotPrice);
     }
   }
 
@@ -98,11 +105,12 @@ public class InstanceTemplate {
   private int minNumberOfInstances;  // some instances may fail, at least a minimum number is required
   private String hardwareId;
   private String imageId;
+  private float awsEc2SpotPrice;
   private Set<String> roles;
 
 
   private InstanceTemplate(int numberOfInstances, int minNumberOfInstances,
-                           Set<String> roles, String hardwareId, String imageId) {
+      Set<String> roles, String hardwareId, String imageId, float awsEc2SpotPrice) {
     for (String role : roles) {
       checkArgument(!StringUtils.contains(role, " "),
         "Role '%s' may not contain space characters.", role);
@@ -112,6 +120,7 @@ public class InstanceTemplate {
     this.minNumberOfInstances = minNumberOfInstances;
     this.hardwareId = hardwareId;
     this.imageId = imageId;
+    this.awsEc2SpotPrice = awsEc2SpotPrice;
     this.roles = roles;
   }
 
@@ -135,6 +144,10 @@ public class InstanceTemplate {
     return imageId;
   }
 
+  public float getAwsEc2SpotPrice() {
+    return awsEc2SpotPrice;
+  }
+
   public boolean equals(Object o) {
     if (o instanceof InstanceTemplate) {
       InstanceTemplate that = (InstanceTemplate) o;
@@ -142,6 +155,7 @@ public class InstanceTemplate {
         && minNumberOfInstances == that.minNumberOfInstances
         && Objects.equal(hardwareId, that.hardwareId)
         && Objects.equal(imageId, that.imageId)
+        && awsEc2SpotPrice == that.awsEc2SpotPrice
         && Objects.equal(roles, that.roles);
     }
     return false;
@@ -149,7 +163,7 @@ public class InstanceTemplate {
 
   public int hashCode() {
     return Objects.hashCode(numberOfInstances, minNumberOfInstances,
-      hardwareId, imageId, roles);
+      hardwareId, imageId, awsEc2SpotPrice, roles);
   }
 
   public String toString() {
@@ -158,6 +172,7 @@ public class InstanceTemplate {
       .add("minNumberOfInstances", minNumberOfInstances)
       .add("hardwareId", hardwareId)
       .add("imageId", imageId)
+      .add("awsEc2SpotPrice", awsEc2SpotPrice)
       .add("roles", roles)
       .toString();
   }
@@ -175,70 +190,93 @@ public class InstanceTemplate {
     return templates;
   }
 
-  public static List<InstanceTemplate> parse(Configuration configuration) throws ConfigurationException {
-    final String[] strings = configuration.getStringArray(
+  public static List<InstanceTemplate> parse(Configuration configuration)
+      throws ConfigurationException {
+    final String[] instanceTemplates = configuration.getStringArray(
       ClusterSpec.Property.INSTANCE_TEMPLATES.getConfigName());
 
-    Map<String, String> maxPercentFailures = parse(configuration.getStringArray(
-      ClusterSpec.Property.INSTANCE_TEMPLATES_MAX_PERCENT_FAILURES.getConfigName()));
-    Map<String, String> minInstances = parse(configuration.getStringArray(
-      ClusterSpec.Property.INSTANCE_TEMPLATES_MINIMUM_NUMBER_OF_INSTANCES.getConfigName()));
-
     List<InstanceTemplate> templates = newArrayList();
-    for (String s : strings) {
+    for (String s : instanceTemplates) {
       String[] parts = s.split(" ");
-      checkArgument(parts.length == 2,
-        "Invalid instance template syntax for '%s'. Does not match " +
-          "'<number> <role1>+<role2>+<role3>...', e.g. '1 hadoop-namenode+hadoop-jobtracker'.", s);
 
-      int num = Integer.parseInt(parts[0]);
-      int minNumberOfInstances = 0;
-      String maxPercentFail = maxPercentFailures.get(parts[1]);
+      checkArgument(parts.length == 2, "Invalid instance template syntax for '%s'. Does not match " +
+        "'<number> <role1>+<role2>+<role3>...', e.g. '1 hadoop-namenode+hadoop-jobtracker'.", s);
+
+      int numberOfInstances = Integer.parseInt(parts[0]);
       String templateGroup = parts[1];
 
-      if (maxPercentFail != null) {
-        // round up integer division (a + b -1) / b
-        minNumberOfInstances = (Integer.parseInt(maxPercentFail) * num + 99) / 100;
-      }
+      InstanceTemplate.Builder templateBuilder = InstanceTemplate.builder()
+        .numberOfInstance(numberOfInstances)
+        .roles(templateGroup.split("\\+"))
+        .minNumberOfInstances(
+          parseMinNumberOfInstances(configuration, templateGroup, numberOfInstances)
+        );
+      parseInstanceTemplateGroupOverrides(configuration, templateGroup, templateBuilder);
 
-      String minNumberOfInst = minInstances.get(parts[1]);
-      if (minNumberOfInst != null) {
-        int minExplicitlySet = Integer.parseInt(minNumberOfInst);
-        if (minNumberOfInstances > 0) { // maximum between two minims
-          minNumberOfInstances = Math.max(minNumberOfInstances, minExplicitlySet);
-        } else {
-          minNumberOfInstances = minExplicitlySet;
-        }
-      }
+      templates.add(templateBuilder.build());
+    }
+    validateThatWeHaveNoOtherOverrides(templates, configuration);
+    return templates;
+  }
+
+  private static void parseInstanceTemplateGroupOverrides(
+    Configuration configuration, String templateGroup, Builder templateBuilder
+  ) {
+
+    String hardwareId = configuration.getString(
+      "whirr.templates." + templateGroup + ".hardware-id", null);
+    String imageId = configuration.getString(
+      "whirr.templates." + templateGroup + ".image-id", null);
+    float awsEc2SpotPrice = configuration.getFloat(
+      "whirr.templates." + templateGroup + ".aws-ec2-spot-price", 0);
+
+    templateBuilder.hardwareId(hardwareId).imageId(imageId)
+      .awsEc2SpotPrice(awsEc2SpotPrice);
+  }
+
+  private static int parseMinNumberOfInstances(
+    Configuration configuration, String templateGroup, int numberOfInstances
+  ) {
+
+    Map<String, String> maxPercentFailures = parse(configuration.getStringArray(
+      ClusterSpec.Property.INSTANCE_TEMPLATES_MAX_PERCENT_FAILURES.getConfigName()));
+
+    Map<String, String> minInstances = parse(configuration.getStringArray(
+      ClusterSpec.Property.INSTANCE_TEMPLATES_MINIMUM_NUMBER_OF_INSTANCES.getConfigName()));
+
+    int minNumberOfInstances = 0;
+    String maxPercentFail = maxPercentFailures.get(templateGroup);
 
-      if (minNumberOfInstances == 0 || minNumberOfInstances > num) {
-        minNumberOfInstances = num;
+    if (maxPercentFail != null) {
+      // round up integer division (a + b -1) / b
+      minNumberOfInstances = (Integer.parseInt(maxPercentFail) * numberOfInstances + 99) / 100;
+    }
+
+    String minNumberOfInst = minInstances.get(templateGroup);
+    if (minNumberOfInst != null) {
+      int minExplicitlySet = Integer.parseInt(minNumberOfInst);
+      if (minNumberOfInstances > 0) { // maximum between two minims
+        minNumberOfInstances = Math.max(minNumberOfInstances, minExplicitlySet);
+      } else {
+        minNumberOfInstances = minExplicitlySet;
       }
+    }
 
-      String hardwareId = configuration.getString(
-        "whirr.templates." + templateGroup + ".hardware-id", null);
-      String imageId = configuration.getString(
-        "whirr.templates." + templateGroup + ".image-id", null);
-
-      templates.add(InstanceTemplate.builder()
-        .numberOfInstance(num)
-        .minNumberOfInstances(minNumberOfInstances)
-        .hardwareId(hardwareId)
-        .imageId(imageId)
-        .roles(templateGroup.split("\\+"))
-        .build()
-      );
+    if (minNumberOfInstances == 0 || minNumberOfInstances > numberOfInstances) {
+      minNumberOfInstances = numberOfInstances;
     }
-    validateThatWeHaveNoOtherOverrides(templates, configuration);
-    return templates;
+
+    return minNumberOfInstances;
   }
 
   private static void validateThatWeHaveNoOtherOverrides(
-    List<InstanceTemplate> templates, Configuration configuration) throws ConfigurationException {
+    List<InstanceTemplate> templates, Configuration configuration
+  ) throws ConfigurationException {
 
     Set<String> groups = Sets.newHashSet(Iterables.transform(templates,
       new Function<InstanceTemplate, String>() {
         private final Joiner plusJoiner = Joiner.on("+");
+
         @Override
         public String apply(InstanceTemplate instance) {
           return plusJoiner.join(instance.getRoles());
@@ -248,7 +286,7 @@ public class InstanceTemplate {
     Pattern pattern = Pattern.compile("^whirr\\.templates\\.([^.]+)\\..*$");
     Iterator iterator = configuration.getKeys("whirr.templates");
 
-    while(iterator.hasNext()) {
+    while (iterator.hasNext()) {
       String key = String.class.cast(iterator.next());
       Matcher matcher = pattern.matcher(key);
 

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=1227757&r1=1227756&r2=1227757&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 Thu Jan  5 18:57:29 2012
@@ -75,7 +75,7 @@ public class BootstrapTemplate {
     strategy.configureTemplateBuilder(clusterSpec, templateBuilder, instanceTemplate);
 
     return setSpotInstancePriceIfSpecified(
-      computeService.getContext(), clusterSpec, templateBuilder.build()
+      computeService.getContext(), clusterSpec, templateBuilder.build(), instanceTemplate
     );
   }
 
@@ -98,18 +98,30 @@ public class BootstrapTemplate {
    * Set maximum spot instance price based on the configuration
    */
   private static Template setSpotInstancePriceIfSpecified(
-      ComputeServiceContext context, ClusterSpec spec, Template template) {
+      ComputeServiceContext context, ClusterSpec spec, Template template, InstanceTemplate instanceTemplate
+  ) {
 
     if (context != null && context.getProviderSpecificContext().getApi() instanceof AWSEC2Client) {
-      if (spec.getAwsEc2SpotPrice() > 0) {
-        template.getOptions().as(AWSEC2TemplateOptions.class)
-          .spotPrice(spec.getAwsEc2SpotPrice());
+      float spotPrice = firstPositiveOrDefault(
+        0,  /* by default use regular instances */
+        instanceTemplate.getAwsEc2SpotPrice(),
+        spec.getAwsEc2SpotPrice()
+      );
+      if (spotPrice > 0) {
+        template.getOptions().as(AWSEC2TemplateOptions.class).spotPrice(spotPrice);
       }
     }
 
     return template;
   }
 
+  private static float firstPositiveOrDefault(float defaultValue, float... listOfValues) {
+    for(float value : listOfValues) {
+      if (value > 0) return value;
+    }
+    return defaultValue;
+  }
+
   // must be used inside InitBuilder, as this sets the shell variables used in this statement
   private static Statement createUserWithPublicAndPrivateKey(String username,
      String publicKey, String privateKey) {

Modified: whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java?rev=1227757&r1=1227756&r2=1227757&view=diff
==============================================================================
--- whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java (original)
+++ whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java Thu Jan  5 18:57:29 2012
@@ -350,12 +350,13 @@ public class ClusterSpecTest {
   @Test
   public void testHardwareIdPerInstanceTemplate() throws Exception {
     PropertiesConfiguration conf = new PropertiesConfiguration("whirr-core-test.properties");
-    conf.setProperty("whirr.instance-templates", "2 noop, 1 role1+role2, 1 role1");
+    conf.setProperty("whirr.instance-templates", "2 noop, 1 role1+role2, 1 role1, 3 spots");
     conf.setProperty("whirr.hardware-id", "c1.xlarge");
 
     conf.setProperty("whirr.templates.noop.hardware-id", "m1.large");
     conf.setProperty("whirr.templates.role1+role2.hardware-id", "t1.micro");
     conf.setProperty("whirr.templates.role1+role2.image-id", "us-east-1/ami-123324");
+    conf.setProperty("whirr.templates.spots.aws-ec2-spot-price", 0.5f);
 
     ClusterSpec spec = ClusterSpec.withTemporaryKeys(conf);
     List<InstanceTemplate> templates = spec.getInstanceTemplates();
@@ -372,6 +373,9 @@ public class ClusterSpecTest {
     InstanceTemplate third = get(templates, 2);
     assertEquals(third.getHardwareId(), null);
     assertEquals(third.getImageId(), null);
+
+    InstanceTemplate spots = get(templates, 3);
+    assertEquals(spots.getAwsEc2SpotPrice(), 0.5f, 0.001);
   }
 
   @Test(expected = ConfigurationException.class)

Added: whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java?rev=1227757&view=auto
==============================================================================
--- whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java (added)
+++ whirr/trunk/core/src/test/java/org/apache/whirr/compute/BootstrapTemplateTest.java Thu Jan  5 18:57:29 2012
@@ -0,0 +1,143 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.whirr.compute;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.InstanceTemplate;
+import org.apache.whirr.service.jclouds.StatementBuilder;
+import org.apache.whirr.service.jclouds.TemplateBuilderStrategy;
+import org.jclouds.aws.ec2.AWSEC2Client;
+import org.jclouds.aws.ec2.compute.AWSEC2ComputeService;
+import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.rest.RestContext;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BootstrapTemplateTest {
+
+  private StatementBuilder statementBuilder;
+  private TemplateBuilderStrategy templateBuilderStrategy;
+
+  @Before
+  public void setUp() throws Exception {
+    statementBuilder = new StatementBuilder();
+    templateBuilderStrategy = new TemplateBuilderStrategy();
+  }
+
+  @Test
+  public void testSetGlobalSpotPrice() throws Exception {
+    ClusterSpec clusterSpec = buildClusterSpecWith(ImmutableMap.of(
+      "whirr.instance-templates", "1 role1",
+      "whirr.aws-ec2-spot-price", "0.3"
+    ));
+    assertSpotPriceIs(clusterSpec, "role1", 0.3f);
+  }
+
+  @Test
+  public void testOverrideSpotPrice() throws Exception {
+    ClusterSpec clusterSpec = buildClusterSpecWith(ImmutableMap.of(
+      "whirr.instance-templates", "1 role1",
+      "whirr.aws-ec2-spot-price", "0.1",
+      "whirr.templates.role1.aws-ec2-spot-price", "0.3"
+    ));
+    assertSpotPriceIs(clusterSpec, "role1", 0.3f);
+  }
+
+  @Test
+  public void testDifferentPrices() throws Exception {
+    ClusterSpec clusterSpec = buildClusterSpecWith(ImmutableMap.of(
+      "whirr.instance-templates", "1 role1, 1 role2",
+      "whirr.aws-ec2-spot-price", "0.1",
+      "whirr.templates.role2.aws-ec2-spot-price", "0.3"
+    ));
+    assertSpotPriceIs(clusterSpec, "role1", 0.1f);
+    assertSpotPriceIs(clusterSpec, "role2", 0.3f);
+  }
+
+  private ClusterSpec buildClusterSpecWith(Map<String, String> overrides) throws Exception {
+    CompositeConfiguration config = new CompositeConfiguration();
+    config.setProperty("whirr.image-id", "us-east-1/ami-123");
+    for (String key : overrides.keySet()) {
+      config.setProperty(key, overrides.get(key));
+    }
+    return ClusterSpec.withTemporaryKeys(config);
+  }
+
+  private void assertSpotPriceIs(
+    ClusterSpec clusterSpec, final String templateGroup, float spotPrice
+  ) throws MalformedURLException {
+
+    InstanceTemplate instanceTemplate = getOnlyElement(filter(
+      clusterSpec.getInstanceTemplates(),
+      new Predicate<InstanceTemplate>() {
+        private Joiner plusJoiner = Joiner.on("+");
+
+        @Override
+        public boolean apply(InstanceTemplate group) {
+          return plusJoiner.join(group.getRoles()).equals(templateGroup);
+        }
+      }));
+
+    ComputeService computeService = mock(AWSEC2ComputeService.class);
+    ComputeServiceContext context = mock(ComputeServiceContext.class);
+    when(computeService.getContext()).thenReturn(context);
+
+    RestContext restContext = mock(RestContext.class);
+    when(context.getProviderSpecificContext()).thenReturn(restContext);
+
+    AWSEC2Client awsEc2Client = mock(AWSEC2Client.class);
+    when(restContext.getApi()).thenReturn(awsEc2Client);
+
+    TemplateBuilder templateBuilder = mock(TemplateBuilder.class);
+    when(computeService.templateBuilder()).thenReturn(templateBuilder);
+    when(templateBuilder.options((TemplateOptions)any())).thenReturn(templateBuilder);
+
+    Template template = mock(Template.class);
+    TemplateOptions options = mock(TemplateOptions.class);
+    when(templateBuilder.build()).thenReturn(template);
+    when(template.getOptions()).thenReturn(options);
+
+    AWSEC2TemplateOptions awsEec2TemplateOptions = mock(AWSEC2TemplateOptions.class);
+    when(options.as((Class<TemplateOptions>) any())).thenReturn(awsEec2TemplateOptions);
+
+    BootstrapTemplate.build(clusterSpec, computeService,
+      statementBuilder, templateBuilderStrategy, instanceTemplate);
+
+    verify(awsEec2TemplateOptions).spotPrice(spotPrice);
+  }
+}

Modified: whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java
URL: http://svn.apache.org/viewvc/whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java?rev=1227757&r1=1227756&r2=1227757&view=diff
==============================================================================
--- whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java (original)
+++ whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java Thu Jan  5 18:57:29 2012
@@ -38,20 +38,20 @@ import org.junit.Test;
 public class TemplateBuilderStrategyTest {
 
   private TemplateBuilderStrategy strategy = new TemplateBuilderStrategy();
-  private InstanceTemplate template;
+  private InstanceTemplate instanceTemplate;
   private ClusterSpec spec;
 
   @Before
   public void setUp() throws ConfigurationException, JSchException, IOException {
     spec = ClusterSpec.withTemporaryKeys();
-    template = mock(InstanceTemplate.class);
+    instanceTemplate = mock(InstanceTemplate.class);
   }
 
   @Test
   public void testImageIdIsPassedThrough() {
     spec.setImageId("my-image-id");
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
     verify(builder).imageId("my-image-id");
   }
 
@@ -59,7 +59,7 @@ public class TemplateBuilderStrategyTest
   public void testHardwareIdIsPassedThrough() {
     spec.setHardwareId("my-hardware-id");
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
     verify(builder).hardwareId("my-hardware-id");
   }
 
@@ -67,7 +67,7 @@ public class TemplateBuilderStrategyTest
   public void testLocationIdIsPassedThrough() {
     spec.setLocationId("my-location-id");
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
     verify(builder).locationId("my-location-id");
   }
 
@@ -76,10 +76,10 @@ public class TemplateBuilderStrategyTest
     spec.setHardwareId("m1.large");
     spec.setImageId("us-east-1/ami-333");
 
-    when(template.getHardwareId()).thenReturn("t1.micro");
+    when(instanceTemplate.getHardwareId()).thenReturn("t1.micro");
 
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
 
     verify(builder).hardwareId("t1.micro");
     verify(builder).imageId("us-east-1/ami-333");
@@ -90,10 +90,10 @@ public class TemplateBuilderStrategyTest
     spec.setHardwareId("m1.large");
     spec.setImageId("us-east-1/ami-333");
 
-    when(template.getImageId()).thenReturn("us-east-1/ami-111");
+    when(instanceTemplate.getImageId()).thenReturn("us-east-1/ami-111");
 
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
 
     verify(builder).hardwareId("m1.large");
     verify(builder).imageId("us-east-1/ami-111");
@@ -101,13 +101,12 @@ public class TemplateBuilderStrategyTest
 
   @Test
   public void testOverrideOnlyHardwareForInstanceTemplate() {
-    when(template.getHardwareId()).thenReturn("t1.micro");
+    when(instanceTemplate.getHardwareId()).thenReturn("t1.micro");
 
     TemplateBuilder builder = mock(TemplateBuilder.class);
-    strategy.configureTemplateBuilder(spec, builder, template);
+    strategy.configureTemplateBuilder(spec, builder, instanceTemplate);
 
     verify(builder).hardwareId("t1.micro");
     verify(builder).osFamily(OsFamily.UBUNTU);
   }
-
 }