Added support for all command line arguments in Chef Solo

This commit is contained in:
Ignasi Barrera 2012-11-10 14:20:10 +01:00
parent 12453a66a1
commit 8f839ba2d9
2 changed files with 616 additions and 164 deletions

View File

@ -33,6 +33,7 @@ import org.jclouds.scriptbuilder.domain.chef.DataBag;
import org.jclouds.scriptbuilder.domain.chef.DataBag.Item;
import org.jclouds.scriptbuilder.domain.chef.Role;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
@ -48,38 +49,163 @@ import com.google.common.collect.Lists;
*/
public class ChefSolo implements Statement {
public static final String DEFAULT_SOLO_PATH = "/var/chef";
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String fileCachePath = DEFAULT_SOLO_PATH;
private String rolePath;
private String databagPath;
private List<String> cookbookPath = Lists.newArrayList();
private String cookbooksArchiveLocation;
private String jsonAttributes;
private String group;
private Integer interval;
private String logLevel;
private String logFile;
private String nodeName;
private Integer splay;
private String user;
private List<Role> roles = Lists.newArrayList();
private List<DataBag> databags = Lists.newArrayList();
private List<String> runlist = Lists.newArrayList();
/**
* Directory where Chef Solo will store files.
*/
public Builder fileCachePath(String fileCachePath) {
this.fileCachePath = checkNotNull(fileCachePath, "fileCachePath");
return this;
}
/**
* Directory where Chef Solo will store roles.
*/
public Builder rolePath(String rolePath) {
this.rolePath = checkNotNull(rolePath, "rolePath");
return this;
}
/**
* Directory where Chef Solo will store data bags.
*/
public Builder dataBagPath(String dataBagPath) {
this.databagPath = checkNotNull(dataBagPath, "dataBagPath");
return this;
}
/**
* Directory where Chef Solo will look for cookbooks.
*/
public Builder cookbookPath(String cookbookPath) {
this.cookbookPath.add(checkNotNull(cookbookPath, "cookbookPath"));
return this;
}
/**
* Directories where Chef Solo will look for cookbooks.
*/
public Builder cookbookPaths(Iterable<String> cookbookPaths) {
this.cookbookPath = ImmutableList.<String> copyOf(checkNotNull(cookbookPaths, "cookbookPaths"));
return this;
}
/**
* Local file path or remote URL of a cookbook tar file. Chef solo will
* download and unpack its contents in the {@link #fileCachePath}
* directory.
*/
public Builder cookbooksArchiveLocation(String cookbooksArchiveLocation) {
this.cookbooksArchiveLocation = checkNotNull(cookbooksArchiveLocation, "cookbooksArchiveLocation");
return this;
}
/**
* JSON attributes to customize cookbook values.
*/
public Builder jsonAttributes(String jsonAttributes) {
this.jsonAttributes = checkNotNull(jsonAttributes, "jsonAttributes");
return this;
}
/**
* The goup to set privilege to.
*/
public Builder group(String group) {
this.group = checkNotNull(group, "group");
return this;
}
/**
* Run chef-client periodically, in seconds.
*/
public Builder interval(Integer interval) {
this.interval = checkNotNull(interval, "interval");
return this;
}
/**
* Set he Log level (debug, info, warn, error, fatal).
*/
public Builder logLevel(String logLevel) {
this.logLevel = checkNotNull(logLevel, "logLevel");
return this;
}
/**
* Set the log file location, by default STDOUT.
*/
public Builder logFile(String logFile) {
this.logFile = checkNotNull(logFile, "logFile");
return this;
}
/**
* Set the name for the node. By default the hostname will be used.
*/
public Builder nodeName(String nodeName) {
this.nodeName = checkNotNull(nodeName, "nodeName");
return this;
}
/**
* The splay time for running at intervals, in seconds.
*/
public Builder splay(Integer splay) {
this.splay = checkNotNull(splay, "splay");
return this;
}
/**
* The user to set privilege to.
*/
public Builder user(String user) {
this.user = checkNotNull(user, "user");
return this;
}
/**
* Creates a role.
*/
public Builder defineRole(Role role) {
this.roles.add(checkNotNull(role, "role"));
return this;
}
/**
* Creates a set of roles.
*/
public Builder defineRoles(Iterable<Role> roles) {
this.roles = ImmutableList.<Role> copyOf(checkNotNull(roles, "roles"));
return this;
}
/**
* Creates a data bag.
*
* @since Chef 0.10.4
*/
public Builder defineDataBag(DataBag dataBag) {
@ -88,6 +214,8 @@ public class ChefSolo implements Statement {
}
/**
* Creates a set of data bags.
*
* @since Chef 0.10.4
*/
public Builder defineDataBags(Iterable<DataBag> databags) {
@ -95,11 +223,17 @@ public class ChefSolo implements Statement {
return this;
}
/**
* Adds the given recipe to the run list of the node.
*/
public Builder installRecipe(String recipe) {
this.runlist.add("recipe[" + checkNotNull(recipe, "recipe") + "]");
return this;
}
/**
* Adds the given recipes to the run list of the node.
*/
public Builder installRecipes(Iterable<String> recipes) {
this.runlist.addAll(Lists.newArrayList(transform(checkNotNull(recipes, "recipes"),
new Function<String, String>() {
@ -111,11 +245,17 @@ public class ChefSolo implements Statement {
return this;
}
/**
* Adds the given role to the run list of the node.
*/
public Builder installRole(String role) {
this.runlist.add("role[" + checkNotNull(role, "role") + "]");
return this;
}
/**
* Adds the given roles to the run list of the node.
*/
public Builder installRoles(Iterable<String> roles) {
this.runlist.addAll(Lists.newArrayList(transform(checkNotNull(roles, "roles"), new Function<String, String>() {
@Override
@ -127,26 +267,59 @@ public class ChefSolo implements Statement {
}
public ChefSolo build() {
return new ChefSolo(cookbooksArchiveLocation, Optional.fromNullable(jsonAttributes), Optional.of(roles),
Optional.of(databags), runlist);
if (cookbookPath.isEmpty()) {
cookbookPath.add(fileCachePath + "/cookbooks");
}
return new ChefSolo(Optional.of(fileCachePath), Optional.fromNullable(rolePath),
Optional.fromNullable(databagPath), Optional.of(cookbookPath),
Optional.fromNullable(cookbooksArchiveLocation), Optional.fromNullable(jsonAttributes),
Optional.fromNullable(group), Optional.fromNullable(interval), Optional.fromNullable(logLevel),
Optional.fromNullable(logFile), Optional.fromNullable(nodeName), Optional.fromNullable(splay),
Optional.fromNullable(user), Optional.of(roles), Optional.of(databags), runlist);
}
}
private String cookbooksArchiveLocation;
private String fileCachePath;
private String rolePath;
private String databagPath;
private List<String> cookbookPath;
private Optional<String> cookbooksArchiveLocation;
private Optional<String> jsonAttributes;
private Optional<String> group;
private Optional<Integer> interval;
private Optional<String> logLevel;
private Optional<String> logFile;
private Optional<String> nodeName;
private Optional<Integer> splay;
private Optional<String> user;
private Optional<List<Role>> roles;
private Optional<List<DataBag>> databags;
private List<String> runlist;
private final InstallChefGems installChefGems = new InstallChefGems();
public ChefSolo(String cookbooksArchiveLocation, Optional<String> jsonAttributes, Optional<List<Role>> roles,
Optional<List<DataBag>> databags, List<String> runlist) {
public ChefSolo(Optional<String> fileCachePath, Optional<String> rolePath, Optional<String> databagPath,
Optional<List<String>> cookbookPath, Optional<String> cookbooksArchiveLocation,
Optional<String> jsonAttributes, Optional<String> group, Optional<Integer> interval,
Optional<String> logLevel, Optional<String> logFile, Optional<String> nodeName, Optional<Integer> splay,
Optional<String> user, Optional<List<Role>> roles, Optional<List<DataBag>> databags, List<String> runlist) {
this.fileCachePath = checkNotNull(fileCachePath, "fileCachePath must be set").or(DEFAULT_SOLO_PATH);
this.rolePath = checkNotNull(rolePath, "rolePath must be set").or(this.fileCachePath + "/roles");
this.databagPath = checkNotNull(databagPath, "databagPath must be set").or(this.fileCachePath + "/data_bags");
this.cookbookPath = checkNotNull(cookbookPath, "cookbookPath must be set").or(
Lists.<String> newArrayList(this.fileCachePath + "/cookbooks"));
this.cookbooksArchiveLocation = checkNotNull(cookbooksArchiveLocation, "cookbooksArchiveLocation must be set");
this.jsonAttributes = checkNotNull(jsonAttributes, "jsonAttributes must be set");
this.group = checkNotNull(group, "group must be set");
this.interval = checkNotNull(interval, "interval must be set");
this.logLevel = checkNotNull(logLevel, "logLevel must be set");
this.logFile = checkNotNull(logFile, "logFile must be set");
this.nodeName = checkNotNull(nodeName, "nodeName must be set");
this.splay = checkNotNull(splay, "splay must be set");
this.user = checkNotNull(user, "user must be set");
this.roles = checkNotNull(roles, "roles must be set");
this.databags = checkNotNull(databags, "databags must be set");
this.runlist = ImmutableList.copyOf(checkNotNull(runlist, "runlist must be set"));
this.jsonAttributes = checkNotNull(jsonAttributes, "jsonAttributes must be set");
}
@Override
@ -157,46 +330,41 @@ public class ChefSolo implements Statement {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
statements.add(installChefGems);
statements.add(exec("{md} /var/chef"));
// The roles directory must contain one file for each role definition
if (roles.isPresent() && !roles.get().isEmpty()) {
statements.add(exec("{md} /var/chef/roles"));
for (Role role : roles.get()) {
statements.add(createOrOverwriteFile("/var/chef/roles/" + role.getName() + ".json",
ImmutableSet.of(role.toJsonString())));
}
createSoloConfiguration(statements);
createRolesIfNecessary(statements);
createDatabagsIfNecessary(statements);
createNodeConfiguration(statements);
ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
options.put("-c", fileCachePath + "/solo.rb");
options.put("-j", fileCachePath + "/node.json");
options.put("-N", nodeName.or("`hostname`"));
if (group.isPresent()) {
options.put("-g", group.get());
}
if (interval.isPresent()) {
options.put("-i", interval.get().toString());
}
if (logLevel.isPresent()) {
options.put("-l", logLevel.get());
}
if (logFile.isPresent()) {
options.put("-L", logFile.get());
}
if (cookbooksArchiveLocation.isPresent()) {
options.put("-r", cookbooksArchiveLocation.get());
}
if (splay.isPresent()) {
options.put("-s", splay.get().toString());
}
if (user.isPresent()) {
options.put("-u", user.get());
}
// Each data bag item must be defined in a file inside the data bag
// directory
if (databags.isPresent() && !databags.get().isEmpty()) {
statements.add(exec("{md} /var/chef/data_bags"));
for (DataBag databag : databags.get()) {
String databagFolder = "/var/chef/data_bags/" + databag.getName();
statements.add(exec("{md} " + databagFolder));
for (Item item : databag.getItems()) {
statements.add(createOrOverwriteFile(databagFolder + "/" + item.getName() + ".json",
ImmutableSet.of(item.getJsonData())));
}
}
}
ImmutableMap.Builder<String, String> chefSoloOptions = ImmutableMap.builder();
chefSoloOptions.put("-N", "`hostname`");
chefSoloOptions.put("-r", cookbooksArchiveLocation);
if (jsonAttributes.isPresent()) {
statements.add(createOrOverwriteFile("/var/chef/node.json", jsonAttributes.asSet()));
chefSoloOptions.put("-j", "/var/chef/node.json");
}
if (!runlist.isEmpty()) {
chefSoloOptions.put("-o", Joiner.on(',').join(runlist));
}
String options = Joiner.on(' ').withKeyValueSeparator(" ").join(chefSoloOptions.build());
statements.add(Statements.exec(String.format("chef-solo %s", options)));
String strOptions = Joiner.on(' ').withKeyValueSeparator(" ").join(options.build());
statements.add(Statements.exec(String.format("chef-solo %s", strOptions)));
return new StatementList(statements.build()).render(family);
}
@ -206,4 +374,74 @@ public class ChefSolo implements Statement {
return installChefGems.functionDependencies(family);
}
@VisibleForTesting
void createSoloConfiguration(ImmutableList.Builder<Statement> statements) {
statements.add(exec("{md} " + fileCachePath));
for (String path : cookbookPath) {
statements.add(exec("{md} " + path));
}
String cookbookPathJoined = Joiner.on(',').join(transform(cookbookPath, quote()));
statements.add(createOrOverwriteFile(
fileCachePath + "/solo.rb",
ImmutableSet.of("file_cache_path \"" + fileCachePath + "\"", //
"cookbook_path [" + cookbookPathJoined + "]", "role_path \"" + rolePath + "\"", "data_bag_path \""
+ databagPath + "\"")));
}
@VisibleForTesting
void createNodeConfiguration(ImmutableList.Builder<Statement> statements) {
StringBuffer json = new StringBuffer();
if (jsonAttributes.isPresent()) {
// Start the node configuration with the attributes, but remove the
// last bracket to append the run list to the json configuration
json.append(jsonAttributes.get().substring(0, jsonAttributes.get().lastIndexOf('}')));
json.append(",");
} else {
json.append("{");
}
json.append("\"run_list\":[");
json.append(Joiner.on(',').join(transform(runlist, quote())));
json.append("]");
json.append("}");
statements.add(createOrOverwriteFile(fileCachePath + "/node.json", ImmutableSet.of(json.toString())));
}
@VisibleForTesting
void createRolesIfNecessary(ImmutableList.Builder<Statement> statements) {
// The roles directory must contain one file for each role definition
if (roles.isPresent() && !roles.get().isEmpty()) {
statements.add(exec("{md} " + rolePath));
for (Role role : roles.get()) {
statements.add(createOrOverwriteFile(rolePath + "/" + role.getName() + ".json",
ImmutableSet.of(role.toJsonString())));
}
}
}
@VisibleForTesting
void createDatabagsIfNecessary(ImmutableList.Builder<Statement> statements) {
// Each data bag item must be defined in a file inside the data bag
// directory, and each data bag item must have its own JSON file.
if (databags.isPresent() && !databags.get().isEmpty()) {
statements.add(exec("{md} " + databagPath));
for (DataBag databag : databags.get()) {
String databagFolder = databagPath + "/" + databag.getName();
statements.add(exec("{md} " + databagFolder));
for (Item item : databag.getItems()) {
statements.add(createOrOverwriteFile(databagFolder + "/" + item.getName() + ".json",
ImmutableSet.of(item.getJsonData())));
}
}
}
}
private static Function<String, String> quote() {
return new Function<String, String>() {
@Override
public String apply(String input) {
return "\"" + input + "\"";
}
};
}
}

View File

@ -18,26 +18,303 @@
*/
package org.jclouds.scriptbuilder.statements.chef;
import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile;
import static org.jclouds.scriptbuilder.domain.Statements.exec;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.chef.DataBag;
import org.jclouds.scriptbuilder.domain.chef.Role;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Resources;
/**
* Unit tests for the {@link ChefSoloTest} statement.
*
* @author Ignasi Barrera
*/
@Test(groups = "unit", testName = "ChefSoloTest")
public class ChefSoloTest {
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "cookbooksArchiveLocation must be set")
public void testChefSoloWithoutCookbooksLocation() {
ChefSolo.builder().build();
public void testCreateDefaultSoloConfiguration() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().build();
solo.createSoloConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
assertEquals(statementList.size(), 3);
assertEquals(statementList.get(0), exec("{md} " + ChefSolo.DEFAULT_SOLO_PATH));
assertEquals(statementList.get(1), exec("{md} " + ChefSolo.DEFAULT_SOLO_PATH + "/cookbooks"));
Statement expected = createOrOverwriteFile(
ChefSolo.DEFAULT_SOLO_PATH + "/solo.rb",
ImmutableSet.of("file_cache_path \"" + ChefSolo.DEFAULT_SOLO_PATH + "\"", //
"cookbook_path [\"" + ChefSolo.DEFAULT_SOLO_PATH + "/cookbooks\"]", "role_path \""
+ ChefSolo.DEFAULT_SOLO_PATH + "/roles\"", "data_bag_path \"" + ChefSolo.DEFAULT_SOLO_PATH
+ "/data_bags\""));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateCustomSoloConfiguration() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().fileCachePath("/tmp").cookbookPath("/tmp/foo").cookbookPath("/tmp/bar")
.rolePath("/tmp/roles").dataBagPath("/tmp/databags").build();
solo.createSoloConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
assertEquals(statementList.size(), 4);
assertEquals(statementList.get(0), exec("{md} /tmp"));
assertEquals(statementList.get(1), exec("{md} /tmp/foo"));
assertEquals(statementList.get(2), exec("{md} /tmp/bar"));
Statement expected = createOrOverwriteFile("/tmp/solo.rb", ImmutableSet.of("file_cache_path \"/tmp\"", //
"cookbook_path [\"/tmp/foo\",\"/tmp/bar\"]", "role_path \"/tmp/roles\"", "data_bag_path \"/tmp/databags\""));
assertEquals(statementList.get(3).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateDefaultNodeConfiguration() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().build();
solo.createNodeConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/node.json",
ImmutableSet.of("{\"run_list\":[]}"));
assertEquals(statementList.size(), 1);
assertEquals(statementList.get(0).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateNodeConfigurationWithJsonAttributes() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().jsonAttributes("{\"foo\":\"bar\"}").build();
solo.createNodeConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/node.json",
ImmutableSet.of("{\"foo\":\"bar\",\"run_list\":[]}"));
assertEquals(statementList.size(), 1);
assertEquals(statementList.get(0).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateNodeConfigurationWithRunList() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().installRecipe("foo").installRole("bar").build();
solo.createNodeConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/node.json",
ImmutableSet.of("{\"run_list\":[\"recipe[foo]\",\"role[bar]\"]}"));
assertEquals(statementList.size(), 1);
assertEquals(statementList.get(0).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateNodeConfigurationWithJsonAttributesAndRunList() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().jsonAttributes("{\"foo\":\"bar\"}").installRecipe("foo").installRole("bar")
.build();
solo.createNodeConfiguration(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/node.json",
ImmutableSet.of("{\"foo\":\"bar\",\"run_list\":[\"recipe[foo]\",\"role[bar]\"]}"));
assertEquals(statementList.size(), 1);
assertEquals(statementList.get(0).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateRolesIfNecessaryWithDefaultValues() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().build();
solo.createRolesIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
assertTrue(statementList.isEmpty());
}
public void testCreateRolesIfNecessaryWithOneRole() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
Role role = Role.builder().name("foo").installRecipe("bar").build();
ChefSolo solo = ChefSolo.builder().defineRole(role).build();
solo.createRolesIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/roles/" + role.getName() + ".json",
ImmutableSet.of(role.toJsonString()));
assertEquals(statementList.size(), 2);
assertEquals(statementList.get(0), exec("{md} " + ChefSolo.DEFAULT_SOLO_PATH + "/roles"));
assertEquals(statementList.get(1).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateRolesIfNecessaryWithOneRoleAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
Role role = Role.builder().name("foo").installRecipe("bar").build();
ChefSolo solo = ChefSolo.builder().rolePath("/tmp/roles").defineRole(role).build();
solo.createRolesIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile("/tmp/roles/" + role.getName() + ".json",
ImmutableSet.of(role.toJsonString()));
assertEquals(statementList.size(), 2);
assertEquals(statementList.get(0), exec("{md} /tmp/roles"));
assertEquals(statementList.get(1).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateRolesIfNecessaryWithMultipleRoleAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
Role roleFoo = Role.builder().name("foo").installRecipe("bar").build();
Role roleBar = Role.builder().name("bar").installRecipe("foo").build();
ChefSolo solo = ChefSolo.builder().rolePath("/tmp/roles").defineRole(roleFoo).defineRole(roleBar).build();
solo.createRolesIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expectedFoo = createOrOverwriteFile("/tmp/roles/" + roleFoo.getName() + ".json",
ImmutableSet.of(roleFoo.toJsonString()));
Statement expectedBar = createOrOverwriteFile("/tmp/roles/" + roleBar.getName() + ".json",
ImmutableSet.of(roleBar.toJsonString()));
assertEquals(statementList.size(), 3);
assertEquals(statementList.get(0), exec("{md} /tmp/roles"));
assertEquals(statementList.get(1).render(OsFamily.UNIX), expectedFoo.render(OsFamily.UNIX));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expectedBar.render(OsFamily.UNIX));
}
public void testCreateDatabagsIfNecessaryWithDefaultValues() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
ChefSolo solo = ChefSolo.builder().build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
assertTrue(statementList.isEmpty());
}
public void testCreateDatabagsIfNecessaryWithOneDatabag() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
DataBag databag = DataBag.builder().name("foo").item("item", "{\"foo\":\"bar\"}").build();
ChefSolo solo = ChefSolo.builder().defineDataBag(databag).build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile(ChefSolo.DEFAULT_SOLO_PATH + "/data_bags/foo/item.json",
ImmutableSet.of("{\"foo\":\"bar\"}"));
assertEquals(statementList.size(), 3);
assertEquals(statementList.get(0), exec("{md} " + ChefSolo.DEFAULT_SOLO_PATH + "/data_bags"));
assertEquals(statementList.get(1), exec("{md} " + ChefSolo.DEFAULT_SOLO_PATH + "/data_bags/" + databag.getName()));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateDatabagsIfNecessaryWithOneDatabagAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
DataBag databag = DataBag.builder().name("foo").item("item", "{\"foo\":\"bar\"}").build();
ChefSolo solo = ChefSolo.builder().dataBagPath("/tmp/databags").defineDataBag(databag).build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expected = createOrOverwriteFile("/tmp/databags/foo/item.json", ImmutableSet.of("{\"foo\":\"bar\"}"));
assertEquals(statementList.size(), 3);
assertEquals(statementList.get(0), exec("{md} /tmp/databags"));
assertEquals(statementList.get(1), exec("{md} /tmp/databags/" + databag.getName()));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expected.render(OsFamily.UNIX));
}
public void testCreateDatabagsIfNecessaryWithOneDatabagWithMultipleItemsAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
DataBag databag = DataBag.builder().name("foo").item("item1", "{\"foo\":\"bar\"}")
.item("item2", "{\"bar\":\"foo\"}").build();
ChefSolo solo = ChefSolo.builder().dataBagPath("/tmp/databags").defineDataBag(databag).build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expectedItem1 = createOrOverwriteFile("/tmp/databags/foo/item1.json",
ImmutableSet.of("{\"foo\":\"bar\"}"));
Statement expectedItem2 = createOrOverwriteFile("/tmp/databags/foo/item2.json",
ImmutableSet.of("{\"bar\":\"foo\"}"));
assertEquals(statementList.size(), 4);
assertEquals(statementList.get(0), exec("{md} /tmp/databags"));
assertEquals(statementList.get(1), exec("{md} /tmp/databags/" + databag.getName()));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expectedItem1.render(OsFamily.UNIX));
assertEquals(statementList.get(3).render(OsFamily.UNIX), expectedItem2.render(OsFamily.UNIX));
}
public void testCreateDatabagsIfNecessaryWithMultipleDatabagsAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
DataBag databagFoo = DataBag.builder().name("foo").item("itemFoo", "{\"foo\":\"bar\"}").build();
DataBag databagBar = DataBag.builder().name("bar").item("itemBar", "{\"bar\":\"foo\"}").build();
ChefSolo solo = ChefSolo.builder().dataBagPath("/tmp/databags").defineDataBag(databagFoo)
.defineDataBag(databagBar).build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expectedFoo = createOrOverwriteFile("/tmp/databags/foo/itemFoo.json",
ImmutableSet.of("{\"foo\":\"bar\"}"));
Statement expectedBar = createOrOverwriteFile("/tmp/databags/bar/itemBar.json",
ImmutableSet.of("{\"bar\":\"foo\"}"));
assertEquals(statementList.size(), 5);
assertEquals(statementList.get(0), exec("{md} /tmp/databags"));
assertEquals(statementList.get(1), exec("{md} /tmp/databags/" + databagFoo.getName()));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expectedFoo.render(OsFamily.UNIX));
assertEquals(statementList.get(3), exec("{md} /tmp/databags/" + databagBar.getName()));
assertEquals(statementList.get(4).render(OsFamily.UNIX), expectedBar.render(OsFamily.UNIX));
}
public void testCreateDatabagsIfNecessaryWithMultipleDatabagsAndMultipleItemsAndCustomPath() {
ImmutableList.Builder<Statement> statements = ImmutableList.builder();
DataBag databagFoo = DataBag.builder().name("foo").item("itemFoo", "{\"foo\":\"bar\"}").build();
DataBag databagBar = DataBag.builder().name("bar").item("itemBar", "{\"bar\":\"foo\"}")
.item("extra", "{\"extra\":[]}").build();
ChefSolo solo = ChefSolo.builder().dataBagPath("/tmp/databags").defineDataBag(databagFoo)
.defineDataBag(databagBar).build();
solo.createDatabagsIfNecessary(statements);
ImmutableList<Statement> statementList = statements.build();
Statement expectedFoo = createOrOverwriteFile("/tmp/databags/foo/itemFoo.json",
ImmutableSet.of("{\"foo\":\"bar\"}"));
Statement expectedBar = createOrOverwriteFile("/tmp/databags/bar/itemBar.json",
ImmutableSet.of("{\"bar\":\"foo\"}"));
Statement expectedExtra = createOrOverwriteFile("/tmp/databags/bar/extra.json", ImmutableSet.of("{\"extra\":[]}"));
assertEquals(statementList.size(), 6);
assertEquals(statementList.get(0), exec("{md} /tmp/databags"));
assertEquals(statementList.get(1), exec("{md} /tmp/databags/" + databagFoo.getName()));
assertEquals(statementList.get(2).render(OsFamily.UNIX), expectedFoo.render(OsFamily.UNIX));
assertEquals(statementList.get(3), exec("{md} /tmp/databags/" + databagBar.getName()));
assertEquals(statementList.get(4).render(OsFamily.UNIX), expectedBar.render(OsFamily.UNIX));
assertEquals(statementList.get(5).render(OsFamily.UNIX), expectedExtra.render(OsFamily.UNIX));
}
@Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented")
@ -45,136 +322,73 @@ public class ChefSoloTest {
ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").build().render(OsFamily.WINDOWS);
}
public void testChefWoloWithDefaultConfiguration() throws IOException {
String script = ChefSolo.builder().build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname`\n");
}
public void testChefWoloWithNodeName() throws IOException {
String script = ChefSolo.builder().nodeName("foo").build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N foo\n");
}
public void testChefSoloWithGroup() throws IOException {
String script = ChefSolo.builder().group("foo").build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -g foo\n");
}
public void testChefSoloWithInterval() throws IOException {
String script = ChefSolo.builder().interval(15).build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -i 15\n");
}
public void testChefSoloWithLogLevel() throws IOException {
String script = ChefSolo.builder().logLevel("debug").build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -l debug\n");
}
public void testChefSoloWithLogFile() throws IOException {
String script = ChefSolo.builder().logFile("/var/log/solo.log").build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -L /var/log/solo.log\n");
}
public void testChefSoloWithCookbooksLocation() throws IOException {
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\nmkdir -p /var/chef\nchef-solo -N `hostname` -r /tmp/cookbooks\n");
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -r /tmp/cookbooks\n");
}
public void testChefSoloWithCookbooksLocationAndSingleRecipe() throws IOException {
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").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\nmkdir -p /var/chef\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2]\n");
public void testChefSoloWithSplay() throws IOException {
String script = ChefSolo.builder().splay(15).build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -s 15\n");
}
public void testChefSoloWithCookbooksLocationAndMultipleRecipes() throws IOException {
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").installRecipe("apache2")
.installRecipe("mysql").build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\nmkdir -p /var/chef\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2],recipe[mysql]\n");
public void testChefSoloWithUser() throws IOException {
String script = ChefSolo.builder().user("foo").build().render(OsFamily.UNIX);
assertEquals(script, installChefGems() + createConfigFile() + createNodeFile()
+ "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -u foo\n");
}
public void testChefSoloWithCookbooksLocationAndMultipleRecipesInList() throws IOException {
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks")
.installRecipes(ImmutableList.<String> of("apache2", "mysql")).build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\nmkdir -p /var/chef\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2],recipe[mysql]\n");
private static String installChefGems() throws IOException {
return Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8) + "installChefGems || return 1\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");
private static String createConfigFile() {
return "mkdir -p /var/chef\nmkdir -p /var/chef/cookbooks\ncat > /var/chef/solo.rb <<-'END_OF_JCLOUDS_FILE'\n"
+ "\tfile_cache_path \"/var/chef\"\n\tcookbook_path [\"/var/chef/cookbooks\"]\n"
+ "\trole_path \"/var/chef/roles\"\n\tdata_bag_path \"/var/chef/data_bags\"\nEND_OF_JCLOUDS_FILE\n";
}
public void testChefSoloWithRoleDefinitionAndRecipe() throws IOException {
Role role = Role.builder().name("foo").installRecipe("apache2").build();
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").defineRole(role)
.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\nmkdir -p /var/chef\nmkdir -p /var/chef/roles\n"
+ "cat > /var/chef/roles/foo.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"name\": \"foo\",\"description\":\"\",\"default_attributes\":{},\"override_attributes\":{},"
+ "\"json_class\":\"Chef::Role\",\"chef_type\":\"role\",\"run_list\":[\"recipe[apache2]\"]}"
+ "\nEND_OF_JCLOUDS_FILE\nchef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2]\n");
private static String createNodeFile() {
return "cat > /var/chef/node.json <<-'END_OF_JCLOUDS_FILE'\n\t{\"run_list\":[]}\nEND_OF_JCLOUDS_FILE\n";
}
public void testChefSoloWithRoleDefinitionAndRole() throws IOException {
Role role = Role.builder().name("foo").installRecipe("apache2").build();
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").defineRole(role).installRole("foo")
.build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\nmkdir -p /var/chef\nmkdir -p /var/chef/roles\n"
+ "cat > /var/chef/roles/foo.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"name\": \"foo\",\"description\":\"\",\"default_attributes\":{},\"override_attributes\":{},"
+ "\"json_class\":\"Chef::Role\",\"chef_type\":\"role\",\"run_list\":[\"recipe[apache2]\"]}"
+ "\nEND_OF_JCLOUDS_FILE\nchef-solo -N `hostname` -r /tmp/cookbooks -o role[foo]\n");
}
public void testChefSoloWithRoleDefinitionAndRoleAndRecipe() throws IOException {
Role role = Role.builder().name("foo").installRecipe("apache2").build();
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").defineRole(role).installRole("foo")
.installRecipe("git").build().render(OsFamily.UNIX);
assertEquals(
script,
Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)
+ "installChefGems || return 1\nmkdir -p /var/chef\nmkdir -p /var/chef/roles\n"
+ "cat > /var/chef/roles/foo.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"name\": \"foo\",\"description\":\"\",\"default_attributes\":{},\"override_attributes\":{},"
+ "\"json_class\":\"Chef::Role\",\"chef_type\":\"role\",\"run_list\":[\"recipe[apache2]\"]}"
+ "\nEND_OF_JCLOUDS_FILE\nchef-solo -N `hostname` -r /tmp/cookbooks -o role[foo],recipe[git]\n");
}
public void testChefSoloWithDataBag() throws IOException {
DataBag databag = DataBag.builder().name("foo").item("item", "{\"foo\":\"bar\"}").build();
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").defineDataBag(databag)
.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\nmkdir -p /var/chef\n"
+ "mkdir -p /var/chef/data_bags\nmkdir -p /var/chef/data_bags/foo\n"
+ "cat > /var/chef/data_bags/foo/item.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"foo\":\"bar\"}\nEND_OF_JCLOUDS_FILE\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2]\n");
}
public void testChefSoloWithDataBagAndMultipleItems() throws IOException {
DataBag databag = DataBag.builder().name("foo").item("item", "{\"foo\":\"bar\"}")
.item("item2", "{\"foo2\":\"bar2\"}").build();
String script = ChefSolo.builder().cookbooksArchiveLocation("/tmp/cookbooks").defineDataBag(databag)
.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\nmkdir -p /var/chef\n"
+ "mkdir -p /var/chef/data_bags\nmkdir -p /var/chef/data_bags/foo\n"
+ "cat > /var/chef/data_bags/foo/item.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"foo\":\"bar\"}\nEND_OF_JCLOUDS_FILE\n"
+ "cat > /var/chef/data_bags/foo/item2.json <<-'END_OF_JCLOUDS_FILE'\n"
+ "\t{\"foo2\":\"bar2\"}\nEND_OF_JCLOUDS_FILE\n"
+ "chef-solo -N `hostname` -r /tmp/cookbooks -o recipe[apache2]\n");
}
}