Author: asavu
Date: Mon Jan 2 13:48:51 2012
New Revision: 1226416
URL: http://svn.apache.org/viewvc?rev=1226416&view=rev
Log:
WHIRR-332. Need to specify different instance size/type depending on role
(asavu)
Modified:
whirr/trunk/CHANGES.txt
whirr/trunk/cli/src/test/java/org/apache/whirr/cli/command/LaunchClusterCommandTest.java
whirr/trunk/core/src/main/java/org/apache/whirr/ClusterSpec.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/compute/BootstrapTemplate.java
whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/TemplateBuilderStrategy.java
whirr/trunk/core/src/test/java/org/apache/whirr/ClusterSpecTest.java
whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java
whirr/trunk/core/src/test/java/org/apache/whirr/service/TemplateBuilderStrategyTest.java
whirr/trunk/recipes/hadoop-ec2.properties
Modified: whirr/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/whirr/trunk/CHANGES.txt?rev=1226416&r1=1226415&r2=1226416&view=diff
==============================================================================
--- whirr/trunk/CHANGES.txt (original)
+++ whirr/trunk/CHANGES.txt Mon Jan 2 13:48:51 2012
@@ -11,6 +11,9 @@ Trunk (unreleased changes)
WHIRR-458. Remove deprecated code and aliasing mechanism (asavu)
+ WHIRR-332. Need to specify different instance size/type
+ depending on role (asavu)
+
BUG FIXES
WHIRR-367. Wrong groupId for zookeeper (Joe Crobak via asavu)
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=1226416&r1=1226415&r2=1226416&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
Mon Jan 2 13:48:51 2012
@@ -26,9 +26,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -105,8 +103,8 @@ public class LaunchClusterCommandTest {
ClusterSpec expectedClusterSpec = ClusterSpec.withTemporaryKeys(conf);
expectedClusterSpec.setInstanceTemplates(Lists.newArrayList(
- new InstanceTemplate(1, ImmutableSet.of("role1", "role2")),
- new InstanceTemplate(2, ImmutableSet.of("role3"))
+ InstanceTemplate.builder().numberOfInstance(1).roles("role1",
"role2").build(),
+ InstanceTemplate.builder().numberOfInstance(2).roles("role3").build()
));
expectedClusterSpec.setServiceName("test-service");
expectedClusterSpec.setProvider("rackspace");
@@ -139,8 +137,8 @@ public class LaunchClusterCommandTest {
int rc = command.run(null, out, null, Lists.newArrayList(
"--service-name", "hadoop",
"--cluster-name", "test-cluster",
- "--instance-templates", "1 jt+nn,3 dn+tt",
- "--instance-templates-max-percent-failures", "60 dn+tt",
+ "--instance-templates", "1 hadoop-namenode+hadoop-jobtracker,3
hadoop-datanode+hadoop-tasktracker",
+ "--instance-templates-max-percent-failures", "60
hadoop-datanode+hadoop-tasktracker",
"--provider", "ec2",
"--identity", "myusername", "--credential", "mypassword",
"--private-key-file", keys.get("private").getAbsolutePath(),
@@ -151,12 +149,14 @@ public class LaunchClusterCommandTest {
Configuration conf = new PropertiesConfiguration();
conf.addProperty("whirr.version", "version-string");
- conf.addProperty("whirr.instance-templates-max-percent-failure", "60
dn+tt");
+ conf.addProperty("whirr.instance-templates-max-percent-failure", "60
hadoop-datanode+hadoop-tasktracker");
ClusterSpec expectedClusterSpec = ClusterSpec.withTemporaryKeys(conf);
expectedClusterSpec.setInstanceTemplates(Lists.newArrayList(
- new InstanceTemplate(1, 1, Sets.newHashSet("jt", "nn")),
- new InstanceTemplate(3, 2, Sets.newHashSet("dn", "tt"))
+ InstanceTemplate.builder().numberOfInstance(1).minNumberOfInstances(1)
+ .roles("hadoop-namenode", "hadoop-jobtracker").build(),
+ InstanceTemplate.builder().numberOfInstance(3).minNumberOfInstances(2)
+ .roles("hadoop-datanode", "hadoop-tasktracker").build()
));
expectedClusterSpec.setServiceName("hadoop");
expectedClusterSpec.setProvider("ec2");
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=1226416&r1=1226415&r2=1226416&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 Mon Jan 2
13:48:51 2012
@@ -141,7 +141,7 @@ public class ClusterSpec {
HARDWARE_MIN_RAM(Integer.class, false, "The minimum amount of " +
"instance memory. E.g. 1024"),
-
+
LOCATION_ID(String.class, false, "The location to launch " +
"instances in. If not specified then an arbitrary location " +
"will be chosen."),
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=1226416&r1=1226415&r2=1226416&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 Mon
Jan 2 13:48:51 2012
@@ -18,53 +18,101 @@
package org.apache.whirr;
import static com.google.common.base.Preconditions.checkArgument;
+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.Lists;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
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 org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* 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.
*/
public class InstanceTemplate {
- private static final Logger LOG =
LoggerFactory.getLogger(InstanceTemplate.class);
-
- private Set<String> roles;
- private int numberOfInstances;
- private int minNumberOfInstances; // some instances may fail, at least a
minimum number is required
- public InstanceTemplate(int numberOfInstances, String... roles) {
- this(numberOfInstances, numberOfInstances,
Sets.newLinkedHashSet(Lists.newArrayList(roles)));
+ public static Builder builder() {
+ return new Builder();
}
- public InstanceTemplate(int numberOfInstances, Set<String> roles) {
- this(numberOfInstances, numberOfInstances, roles);
- }
+ public static class Builder {
+ private int numberOfInstances = -1;
+ private int minNumberOfInstances = -1;
+ private String hardwareId;
+ private String imageId;
+ private Set<String> roles;
+
+ public Builder numberOfInstance(int numberOfInstances) {
+ this.numberOfInstances = numberOfInstances;
+ return this;
+ }
+
+ public Builder minNumberOfInstances(int minNumberOfInstances) {
+ this.minNumberOfInstances = minNumberOfInstances;
+ return this;
+ }
+
+ public Builder hardwareId(String hardwareId) {
+ this.hardwareId = hardwareId;
+ return this;
+ }
- public InstanceTemplate(int numberOfInstances, int minNumberOfInstances,
String... roles) {
- this(numberOfInstances, minNumberOfInstances,
Sets.newLinkedHashSet(Lists.newArrayList(roles)));
+ public Builder imageId(String imageId) {
+ this.imageId = imageId;
+ return this;
+ }
+
+ public Builder roles(String... roles) {
+ this.roles = newLinkedHashSet(newArrayList(roles));
+ return this;
+ }
+
+ public Builder roles(Set<String> roles) {
+ this.roles = newLinkedHashSet(roles);
+ return this;
+ }
+
+ public InstanceTemplate build() {
+ if (minNumberOfInstances == -1) {
+ minNumberOfInstances = numberOfInstances;
+ }
+ return new InstanceTemplate(numberOfInstances, minNumberOfInstances,
roles, hardwareId, imageId);
+ }
}
- public InstanceTemplate(int numberOfInstances, int minNumberOfInstances,
Set<String> roles) {
+ private int numberOfInstances;
+ private int minNumberOfInstances; // some instances may fail, at least a
minimum number is required
+ private String hardwareId;
+ private String imageId;
+ private Set<String> roles;
+
+
+ private InstanceTemplate(int numberOfInstances, int minNumberOfInstances,
+ Set<String> roles, String hardwareId, String
imageId) {
for (String role : roles) {
checkArgument(!StringUtils.contains(role, " "),
- "Role '%s' may not contain space characters.", role);
+ "Role '%s' may not contain space characters.", role);
}
- this.roles = roles;
this.numberOfInstances = numberOfInstances;
this.minNumberOfInstances = minNumberOfInstances;
+ this.hardwareId = hardwareId;
+ this.imageId = imageId;
+ this.roles = roles;
}
public Set<String> getRoles() {
@@ -79,58 +127,80 @@ public class InstanceTemplate {
return minNumberOfInstances;
}
+ public String getHardwareId() {
+ return hardwareId;
+ }
+
+ public String getImageId() {
+ return imageId;
+ }
+
public boolean equals(Object o) {
if (o instanceof InstanceTemplate) {
InstanceTemplate that = (InstanceTemplate) o;
- return Objects.equal(numberOfInstances, that.numberOfInstances)
- && Objects.equal(minNumberOfInstances, that.minNumberOfInstances)
+ return numberOfInstances == that.numberOfInstances
+ && minNumberOfInstances == that.minNumberOfInstances
+ && Objects.equal(hardwareId, that.hardwareId)
+ && Objects.equal(imageId, that.imageId)
&& Objects.equal(roles, that.roles);
}
return false;
}
public int hashCode() {
- return Objects.hashCode(numberOfInstances, minNumberOfInstances, roles);
+ return Objects.hashCode(numberOfInstances, minNumberOfInstances,
+ hardwareId, imageId, roles);
}
public String toString() {
return Objects.toStringHelper(this)
.add("numberOfInstances", numberOfInstances)
.add("minNumberOfInstances", minNumberOfInstances)
+ .add("hardwareId", hardwareId)
+ .add("imageId", imageId)
.add("roles", roles)
.toString();
}
public static Map<String, String> parse(String... strings) {
- Set<String> roles = Sets.newLinkedHashSet(Lists.newArrayList(strings));
+ Set<String> roles = newLinkedHashSet(newArrayList(strings));
Map<String, String> templates = Maps.newHashMap();
for (String s : roles) {
String[] parts = s.split(" ");
checkArgument(parts.length == 2,
- "Invalid instance template syntax for '%s'. Does not match " +
+ "Invalid instance template syntax for '%s'. Does not match " +
"'<number> <role1>+<role2>+<role3>...', e.g. '1
hadoop-namenode+hadoop-jobtracker'.", s);
templates.put(parts[1], parts[0]);
}
return templates;
}
- public static List<InstanceTemplate> parse(Configuration cconf) {
- final String[] strings =
cconf.getStringArray(ClusterSpec.Property.INSTANCE_TEMPLATES.getConfigName());
- Map<String, String> maxPercentFailures =
parse(cconf.getStringArray(ClusterSpec.Property.INSTANCE_TEMPLATES_MAX_PERCENT_FAILURES.getConfigName()));
- Map<String, String> minInstances =
parse(cconf.getStringArray(ClusterSpec.Property.INSTANCE_TEMPLATES_MINIMUM_NUMBER_OF_INSTANCES.getConfigName()));
- List<InstanceTemplate> templates = Lists.newArrayList();
+ public static List<InstanceTemplate> parse(Configuration configuration)
throws ConfigurationException {
+ final String[] strings = 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) {
String[] parts = s.split(" ");
checkArgument(parts.length == 2,
- "Invalid instance template syntax for '%s'. Does not match " +
+ "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;
- final String maxPercentFail = maxPercentFailures.get(parts[1]);
+ String maxPercentFail = maxPercentFailures.get(parts[1]);
+ String templateGroup = parts[1];
+
if (maxPercentFail != null) {
// round up integer division (a + b -1) / b
minNumberOfInstances = (Integer.parseInt(maxPercentFail) * num + 99) /
100;
}
+
String minNumberOfInst = minInstances.get(parts[1]);
if (minNumberOfInst != null) {
int minExplicitlySet = Integer.parseInt(minNumberOfInst);
@@ -140,11 +210,52 @@ public class InstanceTemplate {
minNumberOfInstances = minExplicitlySet;
}
}
+
if (minNumberOfInstances == 0 || minNumberOfInstances > num) {
minNumberOfInstances = num;
}
- templates.add(new InstanceTemplate(num, minNumberOfInstances,
parts[1].split("\\+")));
+
+ 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()
+ );
}
+ validateThatWeHaveNoOtherOverrides(templates, configuration);
return templates;
}
+
+ private static void validateThatWeHaveNoOtherOverrides(
+ 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());
+ }
+ }));
+
+ Pattern pattern = Pattern.compile("^whirr\\.templates\\.([^.]+)\\..*$");
+ Iterator iterator = configuration.getKeys("whirr.templates");
+
+ while(iterator.hasNext()) {
+ String key = String.class.cast(iterator.next());
+ Matcher matcher = pattern.matcher(key);
+
+ if (matcher.find() && !groups.contains(matcher.group(1))) {
+ throw new ConfigurationException(String.format("'%s' is referencing a
" +
+ "template group not present in 'whirr.instance-templates'", key));
+ }
+ }
+ }
}
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=1226416&r1=1226415&r2=1226416&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
Mon Jan 2 13:48:51 2012
@@ -98,7 +98,7 @@ public class BootstrapClusterAction exte
computeServiceContext.getComputeService();
final Template template = BootstrapTemplate.build(clusterSpec,
computeService,
- statementBuilder, entry.getValue().getTemplateBuilderStrategy());
+ statementBuilder, entry.getValue().getTemplateBuilderStrategy(),
entry.getKey());
if (template.getOptions() != null) {
template.getOptions()
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=1226416&r1=1226415&r2=1226416&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
Mon Jan 2 13:48:51 2012
@@ -23,6 +23,7 @@ import com.google.common.collect.Immutab
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
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;
@@ -53,7 +54,8 @@ public class BootstrapTemplate {
ClusterSpec clusterSpec,
ComputeService computeService,
StatementBuilder statementBuilder,
- TemplateBuilderStrategy strategy
+ TemplateBuilderStrategy strategy,
+ InstanceTemplate instanceTemplate
) throws MalformedURLException {
LOG.info("Configuring template");
@@ -70,7 +72,7 @@ public class BootstrapTemplate {
TemplateBuilder templateBuilder = computeService.templateBuilder()
.options(runScript(runScript));
- strategy.configureTemplateBuilder(clusterSpec, templateBuilder);
+ strategy.configureTemplateBuilder(clusterSpec, templateBuilder,
instanceTemplate);
return setSpotInstancePriceIfSpecified(
computeService.getContext(), clusterSpec, templateBuilder.build()
Modified:
whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/TemplateBuilderStrategy.java
URL:
http://svn.apache.org/viewvc/whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/TemplateBuilderStrategy.java?rev=1226416&r1=1226415&r2=1226416&view=diff
==============================================================================
---
whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/TemplateBuilderStrategy.java
(original)
+++
whirr/trunk/core/src/main/java/org/apache/whirr/service/jclouds/TemplateBuilderStrategy.java
Mon Jan 2 13:48:51 2012
@@ -19,8 +19,10 @@
package org.apache.whirr.service.jclouds;
import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.InstanceTemplate;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.TemplateBuilder;
+import org.jclouds.javax.annotation.Nullable;
/**
* A class to configure a {@link TemplateBuilder}.
@@ -28,10 +30,12 @@ import org.jclouds.compute.domain.Templa
public class TemplateBuilderStrategy {
public void configureTemplateBuilder(ClusterSpec clusterSpec,
- TemplateBuilder templateBuilder) {
+ TemplateBuilder templateBuilder, InstanceTemplate instanceTemplate) {
- if (clusterSpec.getImageId() != null) {
- templateBuilder.imageId(clusterSpec.getImageId());
+ if (clusterSpec.getImageId() != null || instanceTemplate.getImageId() !=
null) {
+ templateBuilder.imageId(
+ or(instanceTemplate.getImageId(), clusterSpec.getImageId())
+ );
} else {
templateBuilder.osFamily(OsFamily.UBUNTU);
templateBuilder.osVersionMatches("10.04");
@@ -41,8 +45,10 @@ public class TemplateBuilderStrategy {
templateBuilder.imageDescriptionMatches("ubuntu-images/");
}
- if (clusterSpec.getHardwareId() != null) {
- templateBuilder.hardwareId(clusterSpec.getHardwareId());
+ if (clusterSpec.getHardwareId() != null ||
instanceTemplate.getHardwareId() != null) {
+ templateBuilder.hardwareId(
+ or(instanceTemplate.getHardwareId(), clusterSpec.getHardwareId())
+ );
} else if(clusterSpec.getHardwareMinRam() != 0) {
templateBuilder.minRam(clusterSpec.getHardwareMinRam());
@@ -55,4 +61,9 @@ public class TemplateBuilderStrategy {
templateBuilder.locationId(clusterSpec.getLocationId());
}
}
+
+ private String or(@Nullable String a, @Nullable String b) {
+ return (a == null) ? b : a;
+ }
+
}
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=1226416&r1=1226415&r2=1226416&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 Mon
Jan 2 13:48:51 2012
@@ -18,7 +18,9 @@
package org.apache.whirr;
+import static com.google.common.collect.Iterables.get;
import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import com.google.common.collect.Iterables;
@@ -47,10 +49,10 @@ import org.junit.Assert;
import org.junit.Test;
public class ClusterSpecTest {
-
+
@Test
public void testDefaultsAreSet()
- throws ConfigurationException, JSchException, IOException {
+ throws ConfigurationException, JSchException, IOException {
ClusterSpec spec = ClusterSpec.withTemporaryKeys();
assertThat(spec.getClusterUser(),
is(System.getProperty("user.name")));
@@ -59,27 +61,27 @@ public class ClusterSpecTest {
@Test
public void testDefaultsCanBeOverridden()
- throws ConfigurationException, JSchException, IOException {
+ throws ConfigurationException, JSchException, IOException {
Configuration conf = new PropertiesConfiguration();
conf.setProperty(ClusterSpec.Property.RUN_URL_BASE.getConfigName(),
- "http://example.org");
+ "http://example.org");
ClusterSpec spec = ClusterSpec.withNoDefaults(conf);
assertThat(spec.getRunUrlBase(), is("http://example.org"));
}
@Test
public void testLoginUserSetsSystemProperty()
- throws ConfigurationException {
+ throws ConfigurationException {
Configuration conf = new PropertiesConfiguration();
conf.setProperty(ClusterSpec.Property.LOGIN_USER.getConfigName(),
- "ubuntu");
+ "ubuntu");
ClusterSpec.withNoDefaults(conf);
assertThat(System.getProperty("whirr.login-user"), is("ubuntu"));
}
-
+
@Test
public void testGetConfigurationForKeysWithPrefix()
- throws ConfigurationException, JSchException, IOException {
+ throws ConfigurationException, JSchException, IOException {
Configuration conf = new PropertiesConfiguration();
conf.setProperty("a.b", 1);
conf.setProperty("b.a", 2);
@@ -95,7 +97,7 @@ public class ClusterSpecTest {
assertThat(prefixKeys.get(0), is("a.b"));
assertThat(prefixKeys.get(1), is("a.c"));
}
-
+
@Test
public void testEnvVariableInterpolation() {
Map<String, String> envMap = System.getenv();
@@ -111,12 +113,12 @@ public class ClusterSpecTest {
assertThat(conf.getString("a"), is(firstEntry.getValue()));
assertThat(conf.getString("b"),
- is(String.format("${env:%s}", undefinedEnvVar)));
+ is(String.format("${env:%s}", undefinedEnvVar)));
}
@Test
public void testDefaultPublicKey()
- throws ConfigurationException, JSchException, IOException {
+ throws ConfigurationException, JSchException, IOException {
Map<String, File> keys = KeyPair.generateTemporaryFiles();
Configuration conf = new PropertiesConfiguration();
@@ -125,17 +127,17 @@ public class ClusterSpecTest {
ClusterSpec spec = ClusterSpec.withNoDefaults(conf);
Assert.assertEquals(IOUtils.toString(
- new FileReader(keys.get("public"))), spec.getPublicKey());
+ new FileReader(keys.get("public"))), spec.getPublicKey());
}
@Test(expected = ConfigurationException.class)
public void testDummyPrivateKey()
- throws JSchException, IOException, ConfigurationException {
+ throws JSchException, IOException, ConfigurationException {
File privateKeyFile = File.createTempFile("private", "key");
privateKeyFile.deleteOnExit();
Files.write(("-----BEGIN RSA PRIVATE KEY-----\n" +
- "DUMMY FILE\n" +
- "-----END RSA PRIVATE KEY-----").getBytes(), privateKeyFile);
+ "DUMMY FILE\n" +
+ "-----END RSA PRIVATE KEY-----").getBytes(), privateKeyFile);
Configuration conf = new PropertiesConfiguration();
conf.setProperty("whirr.private-key-file",
privateKeyFile.getAbsolutePath());
@@ -145,7 +147,7 @@ public class ClusterSpecTest {
@Test(expected = ConfigurationException.class)
public void testEncryptedPrivateKey()
- throws JSchException, IOException, ConfigurationException {
+ throws JSchException, IOException, ConfigurationException {
File privateKey = KeyPair.generateTemporaryFiles("dummy").get("private");
Configuration conf = new PropertiesConfiguration();
@@ -159,7 +161,7 @@ public class ClusterSpecTest {
Configuration conf = new PropertiesConfiguration();
conf.setProperty("whirr.private-key-file",
"/dummy/path/that/does/not/exists");
- ClusterSpec.withNoDefaults(conf);
+ ClusterSpec.withNoDefaults(conf);
}
@Test(expected = ConfigurationException.class)
@@ -197,20 +199,23 @@ public class ClusterSpecTest {
conf.setProperty("whirr.private-key-file",
first.get("private").getAbsolutePath());
conf.setProperty("whirr.public-key-file",
second.get("public").getAbsolutePath());
- ClusterSpec.withNoDefaults(conf);
+ ClusterSpec.withNoDefaults(conf);
}
-
+
@Test(expected = IllegalArgumentException.class)
public void testMissingCommaInInstanceTemplates() throws Exception {
Configuration conf = new PropertiesConfiguration();
conf.setProperty(ClusterSpec.Property.INSTANCE_TEMPLATES.getConfigName(),
- "1 a+b 2 c+d"); // missing comma
+ "1 a+b 2 c+d"); // missing comma
ClusterSpec.withTemporaryKeys(conf);
}
@Test(expected = IllegalArgumentException.class)
public void testRoleMayNotContainSpaces() {
- new InstanceTemplate(1, "a b");
+ InstanceTemplate.builder()
+ .numberOfInstance(1)
+ .minNumberOfInstances(1)
+ .roles("a b").build();
}
@Test(expected = IllegalArgumentException.class)
@@ -225,7 +230,7 @@ public class ClusterSpecTest {
InstanceTemplate t2 = templates.get(1);
assertThat(t2.getMinNumberOfInstances(), is(2));
}
-
+
@Test(expected = NumberFormatException.class)
public void testNumberFormatExceptionOnInstancesTemplates() throws Exception
{
Configuration conf = new PropertiesConfiguration();
@@ -238,7 +243,7 @@ public class ClusterSpecTest {
InstanceTemplate t2 = templates.get(1);
assertThat(t2.getMinNumberOfInstances(), is(2));
}
-
+
@Test
public void testNumberOfInstancesPerTemplate() throws Exception {
Configuration conf = new PropertiesConfiguration();
@@ -250,7 +255,7 @@ public class ClusterSpecTest {
assertThat(t1.getMinNumberOfInstances(), is(1));
InstanceTemplate t2 = templates.get(1);
assertThat(t2.getMinNumberOfInstances(), is(2));
-
+
conf.setProperty("whirr.instance-templates-max-percent-failures", "60
hadoop-datanode+hadoop-tasktracker");
expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
templates = expectedClusterSpec.getInstanceTemplates();
@@ -284,13 +289,13 @@ public class ClusterSpecTest {
@Test
public void testDefaultBlobStoreforComputeProvider() throws Exception {
- for(String pair : new String[]{
- "ec2:aws-s3",
- "aws-ec2:aws-s3",
- "cloudservers:cloudfiles-us",
- "cloudservers-us:cloudfiles-us",
- "cloudservers-uk:cloudfiles-uk"
- }) {
+ for (String pair : new String[]{
+ "ec2:aws-s3",
+ "aws-ec2:aws-s3",
+ "cloudservers:cloudfiles-us",
+ "cloudservers-us:cloudfiles-us",
+ "cloudservers-uk:cloudfiles-uk"
+ }) {
String[] parts = pair.split(":");
Configuration config = new PropertiesConfiguration();
@@ -300,22 +305,22 @@ public class ClusterSpecTest {
assertThat(spec.getBlobStoreProvider(), is(parts[1]));
}
}
-
+
@Test
- public void testApplySubroleAliases() {
+ public void testApplySubroleAliases() throws ConfigurationException {
CompositeConfiguration c = new CompositeConfiguration();
Configuration config = new PropertiesConfiguration();
- config.addProperty("whirr.instance-templates",
- "1 puppet:somepup::pet+something-else, 1 something-else-only");
- c.addConfiguration(config);
+ config.addProperty("whirr.instance-templates",
+ "1 puppet:somepup::pet+something-else, 1 something-else-only");
+ c.addConfiguration(config);
InstanceTemplate template = InstanceTemplate.parse(c).get(0);
Set<String> expected = Sets.newLinkedHashSet(Arrays.asList(new String[]{
- "puppet:somepup::pet", "something-else"}));
+ "puppet:somepup::pet", "something-else"}));
assertThat(template.getRoles(), is(expected));
-
+
InstanceTemplate template2 = InstanceTemplate.parse(c).get(1);
Set<String> expected2 = Sets.newLinkedHashSet(Arrays.asList(new String[]{
- "something-else-only"}));
+ "something-else-only"}));
assertThat(template2.getRoles(), is(expected2));
}
@@ -329,18 +334,52 @@ public class ClusterSpecTest {
assertThat(spec.copy(), is(spec));
assertThat(spec.copy().hashCode(), is(spec.hashCode()));
}
-
+
@Test
public void testFirewallRules() throws Exception {
PropertiesConfiguration conf = new
PropertiesConfiguration("whirr-core-test.properties");
conf.setProperty("whirr.firewall-rules", "8000,8001");
conf.setProperty("whirr.firewall-rules.serviceA", "9000,9001");
- ClusterSpec spec = ClusterSpec.withTemporaryKeys(
- conf);
-
+ ClusterSpec spec = ClusterSpec.withTemporaryKeys(conf);
+
Map<String, List<String>> firewallRules = spec.getFirewallRules();
-
assertThat(firewallRules.get(null).equals(Lists.<String>newArrayList("8000","8001")),
is(true));
-
assertThat(firewallRules.get("serviceA").equals(Lists.<String>newArrayList("9000","9001")),
is(true));
+
assertThat(firewallRules.get(null).equals(Lists.<String>newArrayList("8000",
"8001")), is(true));
+
assertThat(firewallRules.get("serviceA").equals(Lists.<String>newArrayList("9000",
"9001")), is(true));
+ }
+
+ @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.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");
+
+ ClusterSpec spec = ClusterSpec.withTemporaryKeys(conf);
+ List<InstanceTemplate> templates = spec.getInstanceTemplates();
+
+ InstanceTemplate noops = get(templates, 0);
+ assert noops.getRoles().contains("noop");
+ assertEquals(noops.getHardwareId(), "m1.large");
+ assertEquals(noops.getImageId(), null);
+
+ InstanceTemplate second = get(templates, 1);
+ assertEquals(second.getHardwareId(), "t1.micro");
+ assertEquals(second.getImageId(), "us-east-1/ami-123324");
+
+ InstanceTemplate third = get(templates, 2);
+ assertEquals(third.getHardwareId(), null);
+ assertEquals(third.getImageId(), null);
}
+ @Test(expected = ConfigurationException.class)
+ public void testInstanceTemplateNotFoundForHardwareId() throws Exception {
+ PropertiesConfiguration conf = new
PropertiesConfiguration("whirr-core-test.properties");
+ conf.setProperty("whirr.instance-templates", "1 role1+role2");
+ conf.setProperty("whirr.templates.role1.hardware-id", "m1.large");
+
+ ClusterSpec.withTemporaryKeys(conf);
+ }
}
Modified:
whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java
URL:
http://svn.apache.org/viewvc/whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java?rev=1226416&r1=1226415&r2=1226416&view=diff
==============================================================================
---
whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java
(original)
+++
whirr/trunk/core/src/test/java/org/apache/whirr/actions/BootstrapClusterActionTest.java
Mon Jan 2 13:48:51 2012
@@ -87,7 +87,8 @@ public class BootstrapClusterActionTest
Configuration conf = new PropertiesConfiguration();
conf.addProperty("whirr.service-name", "test-service");
conf.addProperty("whirr.cluster-name", "test-cluster");
- conf.addProperty("whirr.instance-templates", "1
hadoop-namenode+hadoop-jobtracker,4 hadoop-datanode+hadoop-tasktracker");
+ conf.addProperty("whirr.instance-templates",
+ "1 hadoop-namenode+hadoop-jobtracker,4
hadoop-datanode+hadoop-tasktracker");
conf.addProperty("whirr.instance-templates-max-percent-failures", "60
hadoop-datanode+hadoop-tasktracker");
conf.addProperty("whirr.provider", "ec2");
config.addConfiguration(conf);
@@ -152,7 +153,8 @@ public class BootstrapClusterActionTest
Configuration conf = new PropertiesConfiguration();
conf.addProperty("whirr.service-name", "test-service");
conf.addProperty("whirr.cluster-name", "test-cluster");
- conf.addProperty("whirr.instance-templates", "1
hadoop-namenode+hadoop-jobtracker,4 hadoop-datanode+hadoop-tasktracker");
+ conf.addProperty("whirr.instance-templates",
+ "1 hadoop-namenode+hadoop-jobtracker,4
hadoop-datanode+hadoop-tasktracker");
conf.addProperty("whirr.instance-templates-max-percent-failures", "60
hadoop-datanode+hadoop-tasktracker");
conf.addProperty("whirr.provider", "ec2");
config.addConfiguration(conf);
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=1226416&r1=1226415&r2=1226416&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
Mon Jan 2 13:48:51 2012
@@ -20,6 +20,7 @@ package org.apache.whirr.service;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import com.jcraft.jsch.JSchException;
@@ -27,34 +28,38 @@ import java.io.IOException;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.InstanceTemplate;
import org.apache.whirr.service.jclouds.TemplateBuilderStrategy;
+import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.TemplateBuilder;
import org.junit.Before;
import org.junit.Test;
public class TemplateBuilderStrategyTest {
-
+
private TemplateBuilderStrategy strategy = new TemplateBuilderStrategy();
+ private InstanceTemplate template;
private ClusterSpec spec;
-
+
@Before
public void setUp() throws ConfigurationException, JSchException,
IOException {
spec = ClusterSpec.withTemporaryKeys();
+ template = mock(InstanceTemplate.class);
}
-
+
@Test
public void testImageIdIsPassedThrough() {
spec.setImageId("my-image-id");
TemplateBuilder builder = mock(TemplateBuilder.class);
- strategy.configureTemplateBuilder(spec, builder);
+ strategy.configureTemplateBuilder(spec, builder, template);
verify(builder).imageId("my-image-id");
}
-
+
@Test
public void testHardwareIdIsPassedThrough() {
spec.setHardwareId("my-hardware-id");
TemplateBuilder builder = mock(TemplateBuilder.class);
- strategy.configureTemplateBuilder(spec, builder);
+ strategy.configureTemplateBuilder(spec, builder, template);
verify(builder).hardwareId("my-hardware-id");
}
@@ -62,8 +67,47 @@ public class TemplateBuilderStrategyTest
public void testLocationIdIsPassedThrough() {
spec.setLocationId("my-location-id");
TemplateBuilder builder = mock(TemplateBuilder.class);
- strategy.configureTemplateBuilder(spec, builder);
+ strategy.configureTemplateBuilder(spec, builder, template);
verify(builder).locationId("my-location-id");
}
+ @Test
+ public void testOverrideHardwareId() {
+ spec.setHardwareId("m1.large");
+ spec.setImageId("us-east-1/ami-333");
+
+ when(template.getHardwareId()).thenReturn("t1.micro");
+
+ TemplateBuilder builder = mock(TemplateBuilder.class);
+ strategy.configureTemplateBuilder(spec, builder, template);
+
+ verify(builder).hardwareId("t1.micro");
+ verify(builder).imageId("us-east-1/ami-333");
+ }
+
+ @Test
+ public void testOverrideImageId() {
+ spec.setHardwareId("m1.large");
+ spec.setImageId("us-east-1/ami-333");
+
+ when(template.getImageId()).thenReturn("us-east-1/ami-111");
+
+ TemplateBuilder builder = mock(TemplateBuilder.class);
+ strategy.configureTemplateBuilder(spec, builder, template);
+
+ verify(builder).hardwareId("m1.large");
+ verify(builder).imageId("us-east-1/ami-111");
+ }
+
+ @Test
+ public void testOverrideOnlyHardwareForInstanceTemplate() {
+ when(template.getHardwareId()).thenReturn("t1.micro");
+
+ TemplateBuilder builder = mock(TemplateBuilder.class);
+ strategy.configureTemplateBuilder(spec, builder, template);
+
+ verify(builder).hardwareId("t1.micro");
+ verify(builder).osFamily(OsFamily.UBUNTU);
+ }
+
}
Modified: whirr/trunk/recipes/hadoop-ec2.properties
URL:
http://svn.apache.org/viewvc/whirr/trunk/recipes/hadoop-ec2.properties?rev=1226416&r1=1226415&r2=1226416&view=diff
==============================================================================
--- whirr/trunk/recipes/hadoop-ec2.properties (original)
+++ whirr/trunk/recipes/hadoop-ec2.properties Mon Jan 2 13:48:51 2012
@@ -28,6 +28,10 @@ whirr.cluster-name=hadoop
# Change the number of machines in the cluster here
whirr.instance-templates=1 hadoop-namenode+hadoop-jobtracker,5
hadoop-datanode+hadoop-tasktracker
+# Customise instance type or AMI per instance template
+# whirr.templates.hadoop-namenode+hadoop.jobtracker.hardware-id=m1.xlarge
+#
whirr.templates.hadoop-datanode+hadoop.tasktracker.image-id=us-east-1/ami-da0cf8b3
+
# Uncomment out these lines to run CDH
#whirr.hadoop.install-function=install_cdh_hadoop
#whirr.hadoop.configure-function=configure_cdh_hadoop