Added support for custom json attributes in Chef Solo

This commit is contained in:
Ignasi Barrera 2012-11-06 17:50:41 +01:00
parent a6b94c9fa2
commit e4fd8f2995
2 changed files with 45 additions and 6 deletions

View File

@ -20,6 +20,8 @@ package org.jclouds.scriptbuilder.statements.chef;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import java.util.List; import java.util.List;
@ -30,6 +32,7 @@ import org.jclouds.scriptbuilder.domain.Statements;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -46,6 +49,7 @@ public class ChefSolo implements Statement {
public static class Builder { public static class Builder {
private String cookbooksArchiveLocation; private String cookbooksArchiveLocation;
private String jsonAttributes;
private List<String> recipes = Lists.newArrayList(); private List<String> recipes = Lists.newArrayList();
public Builder cookbooksArchiveLocation(String cookbooksArchiveLocation) { public Builder cookbooksArchiveLocation(String cookbooksArchiveLocation) {
@ -53,6 +57,11 @@ public class ChefSolo implements Statement {
return this; return this;
} }
public Builder jsonAttributes(String jsonAttributes) {
this.jsonAttributes = checkNotNull(jsonAttributes, "jsonAttributes");
return this;
}
public Builder installRecipe(String recipe) { public Builder installRecipe(String recipe) {
this.recipes.add(checkNotNull(recipe, "recipe")); this.recipes.add(checkNotNull(recipe, "recipe"));
return this; return this;
@ -64,18 +73,20 @@ public class ChefSolo implements Statement {
} }
public ChefSolo build() { public ChefSolo build() {
return new ChefSolo(cookbooksArchiveLocation, recipes); return new ChefSolo(cookbooksArchiveLocation, recipes, Optional.fromNullable(jsonAttributes));
} }
} }
private String cookbooksArchiveLocation; private String cookbooksArchiveLocation;
private Optional<String> jsonAttributes;
private List<String> recipes; private List<String> recipes;
private final InstallChefGems installChefGems = new InstallChefGems(); private final InstallChefGems installChefGems = new InstallChefGems();
public ChefSolo(String cookbooksArchiveLocation, List<String> recipes) { public ChefSolo(String cookbooksArchiveLocation, List<String> recipes, Optional<String> jsonAttributes) {
this.cookbooksArchiveLocation = checkNotNull(cookbooksArchiveLocation, "cookbooksArchiveLocation must be set"); this.cookbooksArchiveLocation = checkNotNull(cookbooksArchiveLocation, "cookbooksArchiveLocation must be set");
this.recipes = checkNotNull(recipes, "recipes must be set"); this.recipes = ImmutableList.copyOf(checkNotNull(recipes, "recipes must be set"));
this.jsonAttributes = checkNotNull(jsonAttributes, "jsonAttributes must be set");
} }
@Override @Override
@ -84,17 +95,25 @@ public class ChefSolo implements Statement {
throw new UnsupportedOperationException("windows not yet implemented"); throw new UnsupportedOperationException("windows not yet implemented");
} }
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
statements.add(installChefGems);
ImmutableMap.Builder<String, String> chefSoloOptions = ImmutableMap.builder(); ImmutableMap.Builder<String, String> chefSoloOptions = ImmutableMap.builder();
chefSoloOptions.put("-N", "`hostname`"); chefSoloOptions.put("-N", "`hostname`");
chefSoloOptions.put("-r", cookbooksArchiveLocation); chefSoloOptions.put("-r", cookbooksArchiveLocation);
if (jsonAttributes.isPresent()) {
statements.add(exec("{md} /var/chef"));
statements.add(createOrOverwriteFile("/var/chef/node.json", jsonAttributes.asSet()));
chefSoloOptions.put("-j", "/var/chef/node.json");
}
if (!recipes.isEmpty()) { if (!recipes.isEmpty()) {
chefSoloOptions.put("-o", recipesToRunlistString(recipes)); chefSoloOptions.put("-o", recipesToRunlistString(recipes));
} }
String options = Joiner.on(' ').withKeyValueSeparator(" ").join(chefSoloOptions.build()); String options = Joiner.on(' ').withKeyValueSeparator(" ").join(chefSoloOptions.build());
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
statements.add(installChefGems);
statements.add(Statements.exec(String.format("chef-solo %s", options))); statements.add(Statements.exec(String.format("chef-solo %s", options)));
return new StatementList(statements.build()).render(family); return new StatementList(statements.build()).render(family);

View File

@ -27,7 +27,9 @@ import org.jclouds.scriptbuilder.domain.ShellToken;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.Resources; import com.google.common.io.Resources;
@Test(groups = "unit", testName = "ChefSoloTest") @Test(groups = "unit", testName = "ChefSoloTest")
@ -40,7 +42,12 @@ public class ChefSoloTest {
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "recipes must be set") @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "recipes must be set")
public void testChefSoloWithoutRecipes() { public void testChefSoloWithoutRecipes() {
new ChefSolo("/tmp/foo", null); new ChefSolo("/tmp/foo", null, Optional.<String> absent());
}
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "jsonAttributes must be set")
public void testChefSoloWithoutAttributes() {
new ChefSolo("/tmp/foo", Lists.<String> newArrayList(), null);
} }
@Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented") @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented")
@ -86,4 +93,17 @@ public class ChefSoloTest {
+ "installChefGems || return 1\nchef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2],recipe[mysql]\n"); + "installChefGems || return 1\nchef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2],recipe[mysql]\n");
} }
public void testChefSoloWithCookbooksLocationAndAttributes() throws IOException {
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").jsonAttributes("{\"foo\":\"bar\"}")
.installRecipe("apache2").build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\n"
+ "mkdir -p /var/chef\n"
+ "cat > /var/chef/node.json <<-'END_OF_JCLOUDS_FILE'\n\t{\"foo\":\"bar\"}\nEND_OF_JCLOUDS_FILE\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -j /var/chef/node.json -o recipe[apache2]\n");
}
} }