Issue 191: updated to fix an attribute bug and added RunListBuilder

This commit is contained in:
Adrian Cole 2010-09-03 11:40:14 -07:00
parent 0b11e7d652
commit df6d350820
13 changed files with 522 additions and 30 deletions

View File

@ -20,6 +20,12 @@
package org.jclouds.chef.compute; package org.jclouds.chef.compute;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.getLast;
import static org.jclouds.chef.predicates.CookbookVersionPredicates.containsRecipe;
import static org.jclouds.chef.predicates.CookbookVersionPredicates.containsRecipes;
import static org.jclouds.compute.options.TemplateOptions.Builder.runScript;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.File; import java.io.File;
@ -27,16 +33,17 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.Collections; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.jclouds.chef.ChefContext; import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefContextFactory; import org.jclouds.chef.ChefContextFactory;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.util.RunListBuilder;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory; import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -48,7 +55,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.inject.Module; import com.google.inject.Module;
@ -101,24 +107,38 @@ public class ChefComputeServiceLiveTest {
@Test @Test
public void testCanUpdateRunList() throws IOException { public void testCanUpdateRunList() throws IOException {
chefContext.getChefService().updateRunListForTag(Collections.singleton("recipe[apache2]"), tag); String recipe = "apache2";
assertEquals(chefContext.getChefService().getRunListForTag(tag), Collections.singleton("recipe[apache2]"));
Iterable<? extends CookbookVersion> cookbookVersions = chefContext.getChefService().listCookbookVersions();
if (any(cookbookVersions, containsRecipe(recipe))) {
List<String> runList = new RunListBuilder().addRecipe(recipe).build();
chefContext.getChefService().updateRunListForTag(runList, tag);
assertEquals(chefContext.getChefService().getRunListForTag(tag), runList);
} else {
assert false : String.format("recipe %s not in %s", recipe, cookbookVersions);
}
// TODO move this to a unit test
assert any(cookbookVersions, containsRecipe("apache2::mod_proxy"));
assert any(cookbookVersions, containsRecipes("apache2", "apache2::mod_proxy", "apache2::mod_proxy_http"));
assert !any(cookbookVersions, containsRecipe("apache2::bar"));
assert !any(cookbookVersions, containsRecipe("foo::bar"));
} }
@Test(dependsOnMethods = "testCanUpdateRunList") @Test(dependsOnMethods = "testCanUpdateRunList")
public void testRunNodesWithBootstrap() throws IOException { public void testRunNodesWithBootstrap() throws IOException {
Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag); Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag);
TemplateOptions options = computeContext.getComputeService().templateOptions().runScript(bootstrap);
try { try {
nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, options); nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, runScript(bootstrap));
} catch (RunNodesException e) { } catch (RunNodesException e) {
nodes = Iterables.concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet()); nodes = concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet());
} }
for (NodeMetadata node : nodes) { for (NodeMetadata node : nodes) {
URI uri = URI.create("http://" + Iterables.getLast(node.getPublicAddresses())); URI uri = URI.create("http://" + getLast(node.getPublicAddresses()));
InputStream content = computeContext.utils().http().get(uri); InputStream content = computeContext.utils().http().get(uri);
String string = Utils.toStringAndClose(content); String string = Utils.toStringAndClose(content);
assert string.indexOf("It works!") >= 0 : string; assert string.indexOf("It works!") >= 0 : string;

View File

@ -129,7 +129,37 @@ unit testing"
"Retrieve the existing nodes in your chef server including all details." "Retrieve the existing nodes in your chef server including all details."
([] (nodes *chef*)) ([] (nodes *chef*))
([#^ChefService chef] ([#^ChefService chef]
(seq (.listNodesDetails chef)))) (seq (.listNodes chef))))
(defn clients
"Retrieve the names of the existing clients in your chef server."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients (as-chef-api chef)))))
(defn clients-with-details
"Retrieve the existing clients in your chef server including all details."
([] (clients *chef*))
([#^ChefService chef]
(seq (.listClients chef))))
(defn cookbooks
"Retrieve the names of the existing cookbooks in your chef server."
([] (cookbooks *chef*))
([#^ChefService chef]
(seq (.listCookbooks (as-chef-api chef)))))
(defn cookbook-versions
"Retrieve the versions of an existing cookbook in your chef server."
([name] (cookbook-versions *chef*))
([#^ChefService name chef]
(seq (.getVersionsOfCookbook (as-chef-api chef) name))))
(defn cookbook-versions-with-details
"Retrieve the existing cookbook versions in your chef server including all details."
([] (cookbook-versions *chef*))
([#^ChefService chef]
(seq (.listCookbookVersions chef))))
(defn update-run-list (defn update-run-list
"Updates the run-list associated with a tag" "Updates the run-list associated with a tag"

View File

@ -24,6 +24,7 @@ import java.io.InputStream;
import java.util.List; import java.util.List;
import org.jclouds.chef.domain.Client; import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Node; import org.jclouds.chef.domain.Node;
import org.jclouds.chef.internal.BaseChefService; import org.jclouds.chef.internal.BaseChefService;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
@ -97,9 +98,9 @@ public interface ChefService {
void deleteAllNodesInList(Iterable<String> names); void deleteAllNodesInList(Iterable<String> names);
Iterable<? extends Node> listNodesDetails(); Iterable<? extends Node> listNodes();
Iterable<? extends Node> listNodesDetailsMatching(Predicate<String> nodeNameSelector); Iterable<? extends Node> listNodesMatching(Predicate<String> nodeNameSelector);
Iterable<? extends Node> listNodesNamed(Iterable<String> names); Iterable<? extends Node> listNodesNamed(Iterable<String> names);
@ -111,5 +112,11 @@ public interface ChefService {
Iterable<? extends Client> listClientsNamed(Iterable<String> names); Iterable<? extends Client> listClientsNamed(Iterable<String> names);
Iterable<? extends CookbookVersion> listCookbookVersions();
Iterable<? extends CookbookVersion> listCookbookVersionsMatching(Predicate<String> cookbookNameSelector);
Iterable<? extends CookbookVersion> listCookbookVersionsNamed(Iterable<String> cookbookNames);
void updateAutomaticAttributesOnNode(String nodeName); void updateAutomaticAttributesOnNode(String nodeName);
} }

View File

@ -22,6 +22,8 @@ package org.jclouds.chef.domain;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.jclouds.domain.JsonBall;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
@ -37,14 +39,14 @@ public class Attribute {
private boolean calculated; private boolean calculated;
private List<String> choice = Lists.newArrayList(); private List<String> choice = Lists.newArrayList();
@SerializedName("default") @SerializedName("default")
private String defaultValue; private JsonBall defaultValue;
private String type; private String type;
private List<String> recipes = Lists.newArrayList(); private List<String> recipes = Lists.newArrayList();
@SerializedName("display_name") @SerializedName("display_name")
private String displayName; private String displayName;
private String description; private String description;
public Attribute(String required, boolean calculated, Set<String> choice, String defaultValue, String type, public Attribute(String required, boolean calculated, Set<String> choice, JsonBall defaultValue, String type,
List<String> recipes, String displayName, String description) { List<String> recipes, String displayName, String description) {
this.required = required; this.required = required;
this.calculated = calculated; this.calculated = calculated;
@ -71,7 +73,7 @@ public class Attribute {
return choice; return choice;
} }
public String getDefaultValue() { public JsonBall getDefaultValue() {
return defaultValue; return defaultValue;
} }

View File

@ -34,7 +34,7 @@ public class CookbookVersion {
private String name; private String name;
private Set<Resource> definitions = Sets.newLinkedHashSet(); private Set<Resource> definitions = Sets.newLinkedHashSet();
private Set<Resource> attributes = Sets.newLinkedHashSet(); private Set<Attribute> attributes = Sets.newLinkedHashSet();
private Set<Resource> files = Sets.newLinkedHashSet(); private Set<Resource> files = Sets.newLinkedHashSet();
private Metadata metadata = new Metadata(); private Metadata metadata = new Metadata();
private Set<Resource> providers = Sets.newLinkedHashSet(); private Set<Resource> providers = Sets.newLinkedHashSet();
@ -62,10 +62,10 @@ public class CookbookVersion {
this.name = cookbookName + "-" + version; this.name = cookbookName + "-" + version;
} }
public CookbookVersion(String name, Set<Resource> definitions, Set<Resource> attributes, Set<Resource> files, public CookbookVersion(String name, Set<Resource> definitions, Set<Attribute> attributes, Set<Resource> files,
Metadata metadata, Set<Resource> providers, String cookbookName, Set<Resource> resources, Metadata metadata, Set<Resource> providers, String cookbookName, Set<Resource> resources,
Set<Resource> templates, Set<Resource> libraries, String version, Set<Resource> recipes, Set<Resource> templates, Set<Resource> libraries, String version, Set<Resource> recipes,
Set<Resource> rootFiles) { Set<Resource> rootFiles) {
this.name = name; this.name = name;
Iterables.addAll(this.definitions, definitions); Iterables.addAll(this.definitions, definitions);
Iterables.addAll(this.attributes, attributes); Iterables.addAll(this.attributes, attributes);
@ -94,7 +94,7 @@ public class CookbookVersion {
return definitions; return definitions;
} }
public Set<Resource> getAttributes() { public Set<Attribute> getAttributes() {
return attributes; return attributes;
} }
@ -238,9 +238,9 @@ public class CookbookVersion {
@Override @Override
public String toString() { public String toString() {
return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName + ", definitions=" + definitions return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName + ", definitions=" + definitions
+ ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name + ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name
+ ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles=" + ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles="
+ rootFiles + ", templates=" + templates + ", version=" + version + "]"; + rootFiles + ", templates=" + templates + ", version=" + version + "]";
} }
} }

View File

@ -36,6 +36,7 @@ import javax.inject.Singleton;
import org.jclouds.chef.ChefContext; import org.jclouds.chef.ChefContext;
import org.jclouds.chef.ChefService; import org.jclouds.chef.ChefService;
import org.jclouds.chef.domain.Client; import org.jclouds.chef.domain.Client;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.DatabagItem; import org.jclouds.chef.domain.DatabagItem;
import org.jclouds.chef.domain.Node; import org.jclouds.chef.domain.Node;
import org.jclouds.chef.functions.RunListForTag; import org.jclouds.chef.functions.RunListForTag;
@ -46,6 +47,7 @@ import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
import org.jclouds.chef.strategy.DeleteAllClientsInList; import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.chef.strategy.DeleteAllNodesInList; import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.chef.strategy.ListClients; import org.jclouds.chef.strategy.ListClients;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.chef.strategy.ListNodes; import org.jclouds.chef.strategy.ListNodes;
import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode; import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
@ -83,14 +85,16 @@ public class BaseChefService implements ChefService {
private final TagToBootScript tagToBootScript; private final TagToBootScript tagToBootScript;
private final String databag; private final String databag;
private final RunListForTag runListForTag; private final RunListForTag runListForTag;
private final ListCookbookVersions listCookbookVersions;
@Inject @Inject
protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients, protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients,
CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes, CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes,
DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes, DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes,
DeleteAllClientsInList deleteAllClientsInList, ListClients listClients, DeleteAllClientsInList deleteAllClientsInList, ListClients listClients,
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Provider<PrivateKey> privateKey, ListCookbookVersions listCookbookVersions, UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode,
@Named(CHEF_BOOTSTRAP_DATABAG) String databag, TagToBootScript tagToBootScript, RunListForTag runListForTag) { Provider<PrivateKey> privateKey, @Named(CHEF_BOOTSTRAP_DATABAG) String databag,
TagToBootScript tagToBootScript, RunListForTag runListForTag) {
this.chefContext = checkNotNull(chefContext, "chefContext"); this.chefContext = checkNotNull(chefContext, "chefContext");
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients"); this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes, this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes,
@ -99,6 +103,7 @@ public class BaseChefService implements ChefService {
this.listNodes = checkNotNull(listNodes, "listNodes"); this.listNodes = checkNotNull(listNodes, "listNodes");
this.deleteAllClientsInList = checkNotNull(deleteAllClientsInList, "deleteAllClientsInList"); this.deleteAllClientsInList = checkNotNull(deleteAllClientsInList, "deleteAllClientsInList");
this.listClients = checkNotNull(listClients, "listClients"); this.listClients = checkNotNull(listClients, "listClients");
this.listCookbookVersions = checkNotNull(listCookbookVersions, "listCookbookVersions");
this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode, this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode,
"updateAutomaticAttributesOnNode"); "updateAutomaticAttributesOnNode");
this.privateKey = checkNotNull(privateKey, "privateKey"); this.privateKey = checkNotNull(privateKey, "privateKey");
@ -123,12 +128,12 @@ public class BaseChefService implements ChefService {
} }
@Override @Override
public Iterable<? extends Node> listNodesDetails() { public Iterable<? extends Node> listNodes() {
return listNodes.execute(); return listNodes.execute();
} }
@Override @Override
public Iterable<? extends Node> listNodesDetailsMatching(Predicate<String> nodeNameSelector) { public Iterable<? extends Node> listNodesMatching(Predicate<String> nodeNameSelector) {
return listNodes.execute(nodeNameSelector); return listNodes.execute(nodeNameSelector);
} }
@ -157,6 +162,22 @@ public class BaseChefService implements ChefService {
return listClients.execute(names); return listClients.execute(names);
} }
@Override
public Iterable<? extends CookbookVersion> listCookbookVersions() {
return listCookbookVersions.execute();
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsMatching(Predicate<String> cookbookNameSelector) {
return listCookbookVersions.execute(cookbookNameSelector);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsNamed(Iterable<String> names) {
return listCookbookVersions.execute(names);
}
@Override @Override
public void updateAutomaticAttributesOnNode(String nodeName) { public void updateAutomaticAttributesOnNode(String nodeName) {
updateAutomaticAttributesOnNode.execute(nodeName); updateAutomaticAttributesOnNode.execute(nodeName);

View File

@ -0,0 +1,97 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.chef.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.get;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Resource;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
/**
* Container for cookbook filters (predicates).
*
* This class has static methods that create customized predicates to use with
* {@link org.jclouds.chef.ChefService}.
*
* @author Adrian Cole
*/
public class CookbookVersionPredicates {
/**
* @see #containsRecipes
*/
public static Predicate<CookbookVersion> containsRecipe(String recipe) {
return containsRecipes(checkNotNull(recipe, "recipe must be defined"));
}
/**
* Note that the default recipe of a cookbook is its name. Otherwise, you prefix the recipe with
* the name of the cookbook. ex. {@code apache2} will be the default recipe where {@code
* apache2::mod_proxy} is a specific one in the cookbook.
*
* @param recipes
* names of the recipes.
* @return true if the cookbook version contains a recipe in the list.
*/
public static Predicate<CookbookVersion> containsRecipes(String... recipes) {
checkNotNull(recipes, "recipes must be defined");
final Multimap<String, String> search = LinkedListMultimap.create();
for (String recipe : recipes) {
if (recipe.indexOf("::") != -1) {
Iterable<String> nameRecipe = Splitter.on("::").split(recipe);
search.put(get(nameRecipe, 0), get(nameRecipe, 1) + ".rb");
} else {
search.put(recipe, "default.rb");
}
}
return new Predicate<CookbookVersion>() {
@Override
public boolean apply(final CookbookVersion cookbookVersion) {
return search.containsKey(cookbookVersion.getCookbookName())
&& any(search.get(cookbookVersion.getCookbookName()), new Predicate<String>() {
@Override
public boolean apply(final String recipeName) {
return any(cookbookVersion.getRecipes(), new Predicate<Resource>() {
@Override
public boolean apply(Resource resource) {
return resource.getName().equals(recipeName);
}
});
}
});
}
@Override
public String toString() {
return "containsRecipes(" + search + ")";
}
};
}
}

View File

@ -0,0 +1,41 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.chef.strategy;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.internal.ListCookbookVersionsImpl;
import com.google.common.base.Predicate;
import com.google.inject.ImplementedBy;
/**
*
*
* @author Adrian Cole
*/
@ImplementedBy(ListCookbookVersionsImpl.class)
public interface ListCookbookVersions {
Iterable<? extends CookbookVersion> execute();
Iterable<? extends CookbookVersion> execute(Predicate<String> cookbookNameSelector);
Iterable<? extends CookbookVersion> execute(Iterable<String> cookbookNames);
}

View File

@ -0,0 +1,104 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.chef.strategy.internal;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.concurrent.FutureIterables.transformParallel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefAsyncClient;
import org.jclouds.chef.ChefClient;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.reference.ChefConstants;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
/**
*
*
* @author Adrian Cole
*/
@Singleton
public class ListCookbookVersionsImpl implements ListCookbookVersions {
protected final ChefClient chefClient;
protected final ChefAsyncClient chefAsyncClient;
protected final ExecutorService userExecutor;
@Resource
@Named(ChefConstants.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject(optional = true)
@Named(Constants.PROPERTY_REQUEST_TIMEOUT)
protected Long maxTime;
@Inject
ListCookbookVersionsImpl(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userExecutor,
ChefClient getAllCookbookVersion, ChefAsyncClient ablobstore) {
this.userExecutor = userExecutor;
this.chefAsyncClient = ablobstore;
this.chefClient = getAllCookbookVersion;
}
@Override
public Iterable<? extends CookbookVersion> execute() {
return execute(chefClient.listCookbooks());
}
@Override
public Iterable<? extends CookbookVersion> execute(Predicate<String> cookbookNameSelector) {
return execute(filter(chefClient.listCookbooks(), cookbookNameSelector));
}
@Override
public Iterable<? extends CookbookVersion> execute(Iterable<String> toGet) {
return concat(transform(toGet, new Function<String, Iterable<? extends CookbookVersion>>() {
@Override
public Iterable<? extends CookbookVersion> apply(final String cookbook) {
// TODO getting each version could also go parallel
return transformParallel(chefClient.getVersionsOfCookbook(cookbook),
new Function<String, Future<CookbookVersion>>() {
@Override
public Future<CookbookVersion> apply(String version) {
return chefAsyncClient.getCookbook(cookbook, version);
}
}, userExecutor, maxTime, logger, "getting versions of cookbook " + cookbook);
}
}));
}
}

View File

@ -0,0 +1,88 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.chef.util;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
/**
* builds a run list in the correct syntax for chef.
*
* @author Adrian Cole
*/
public class RunListBuilder {
private List<String> list = newArrayList();
/**
* Add the following recipe to the run list
*/
public RunListBuilder addRecipe(String recipe) {
return addRecipes(checkNotNull(recipe, "recipe"));
}
/**
* Add the following recipes to the run list
*/
public RunListBuilder addRecipes(String... recipes) {
addAll(list, transform(Arrays.asList(checkNotNull(recipes, "recipes")), new Function<String, String>() {
@Override
public String apply(String from) {
return "recipe[" + from + "]";
}
}));
return this;
}
/**
* Add the following role to the run list
*/
public RunListBuilder addRole(String role) {
return addRoles(checkNotNull(role, "role"));
}
/**
* Add the following roles to the run list
*/
public RunListBuilder addRoles(String... roles) {
addAll(list, transform(Arrays.asList(checkNotNull(roles, "roles")), new Function<String, String>() {
@Override
public String apply(String from) {
return "role[" + from + "]";
}
}));
return this;
}
public List<String> build() {
return ImmutableList.copyOf(list);
}
}

View File

@ -20,12 +20,14 @@
package org.jclouds.chef; package org.jclouds.chef;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import org.jclouds.chef.config.ChefParserModule; import org.jclouds.chef.config.ChefParserModule;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.json.Json; import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule;
@ -76,7 +78,7 @@ public class ChefClientLiveTest extends BaseChefClientLiveTest {
Properties props = new Properties(); Properties props = new Properties();
props.setProperty("chef.endpoint", endpoint); props.setProperty("chef.endpoint", endpoint);
return new ChefContextFactory().createContext(identity, key, ImmutableSet.<Module> of(new Log4JLoggingModule()), return new ChefContextFactory().createContext(identity, key, ImmutableSet.<Module> of(new Log4JLoggingModule()),
props); props);
} }
@Override @Override
@ -106,6 +108,12 @@ public class ChefClientLiveTest extends BaseChefClientLiveTest {
clientConnection = createConnection(PREFIX, clientKey); clientConnection = createConnection(PREFIX, clientKey);
} }
@Test
public void testListCookbookVersionsWithChefService() throws Exception {
Iterable<? extends CookbookVersion> cookbooks = adminConnection.getChefService().listCookbookVersions();
assertNotNull(cookbooks);
}
@Override @Override
protected void closeContexts() { protected void closeContexts() {
if (clientConnection != null) if (clientConnection != null)

View File

@ -103,7 +103,7 @@ public class ParseCookbookVersionFromJsonTest {
new CookbookVersion( new CookbookVersion(
"apache-chef-demo-0.0.0", "apache-chef-demo-0.0.0",
ImmutableSet.<Resource> of(), ImmutableSet.<Resource> of(),
ImmutableSet.<Resource> of(), ImmutableSet.<Attribute> of(),
ImmutableSet.<Resource> of(), ImmutableSet.<Resource> of(),
new Metadata("Apache v2.0", "Your Name", ImmutableMap.<String, String> of(), ImmutableMap new Metadata("Apache v2.0", "Your Name", ImmutableMap.<String, String> of(), ImmutableMap
.<String, Set<String>> of(), "youremail@example.com", ImmutableMap .<String, Set<String>> of(), "youremail@example.com", ImmutableMap

View File

@ -0,0 +1,74 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.chef.util;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests possible uses of RunListBuilder
*
* @author Adrian Cole
*/
public class RunListBuilderTest {
@Test
public void testRecipeAndRole() {
RunListBuilder options = new RunListBuilder();
options.addRecipe("recipe").addRole("role");
assertEquals(options.build(),ImmutableList.of("recipe[recipe]","role[role]"));
}
@Test
public void testRecipe() {
RunListBuilder options = new RunListBuilder();
options.addRecipe("test");
assertEquals(options.build(),ImmutableList.of("recipe[test]"));
}
@Test
public void testRecipes() {
RunListBuilder options = new RunListBuilder();
options.addRecipes("test", "test2");
assertEquals(options.build(),ImmutableList.of("recipe[test]","recipe[test2]"));
}
@Test
public void testRole() {
RunListBuilder options = new RunListBuilder();
options.addRole("test");
assertEquals(options.build(),ImmutableList.of("role[test]"));
}
@Test
public void testRoles() {
RunListBuilder options = new RunListBuilder();
options.addRoles("test", "test2");
assertEquals(options.build(),ImmutableList.of("role[test]","role[test2]"));
}
@Test
public void testNoneRecipe() {
RunListBuilder options = new RunListBuilder();
assertEquals(options.build(), ImmutableList.<String>of());
}
}