From df6d35082001ed7b9036c5686013290faa789252 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Fri, 3 Sep 2010 11:40:14 -0700 Subject: [PATCH] Issue 191: updated to fix an attribute bug and added RunListBuilder --- .../compute/ChefComputeServiceLiveTest.java | 38 +++++-- .../src/main/clojure/org/jclouds/chef.clj | 32 +++++- .../java/org/jclouds/chef/ChefService.java | 11 +- .../org/jclouds/chef/domain/Attribute.java | 8 +- .../jclouds/chef/domain/CookbookVersion.java | 18 +-- .../chef/internal/BaseChefService.java | 29 ++++- .../predicates/CookbookVersionPredicates.java | 97 ++++++++++++++++ .../chef/strategy/ListCookbookVersions.java | 41 +++++++ .../internal/ListCookbookVersionsImpl.java | 104 ++++++++++++++++++ .../org/jclouds/chef/util/RunListBuilder.java | 88 +++++++++++++++ .../org/jclouds/chef/ChefClientLiveTest.java | 10 +- .../ParseCookbookVersionFromJsonTest.java | 2 +- .../jclouds/chef/util/RunListBuilderTest.java | 74 +++++++++++++ 13 files changed, 522 insertions(+), 30 deletions(-) create mode 100644 chef/core/src/main/java/org/jclouds/chef/predicates/CookbookVersionPredicates.java create mode 100644 chef/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java create mode 100644 chef/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java create mode 100644 chef/core/src/main/java/org/jclouds/chef/util/RunListBuilder.java create mode 100644 chef/core/src/test/java/org/jclouds/chef/util/RunListBuilderTest.java diff --git a/chef/compute/src/test/java/org/jclouds/chef/compute/ChefComputeServiceLiveTest.java b/chef/compute/src/test/java/org/jclouds/chef/compute/ChefComputeServiceLiveTest.java index 0e8103a1ef..c94a3a3629 100644 --- a/chef/compute/src/test/java/org/jclouds/chef/compute/ChefComputeServiceLiveTest.java +++ b/chef/compute/src/test/java/org/jclouds/chef/compute/ChefComputeServiceLiveTest.java @@ -20,6 +20,12 @@ package org.jclouds.chef.compute; 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 java.io.File; @@ -27,16 +33,17 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; -import java.util.Collections; +import java.util.List; import java.util.Properties; import org.jclouds.chef.ChefContext; 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.ComputeServiceContextFactory; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.io.Payload; 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.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.common.io.Files; import com.google.inject.Module; @@ -101,24 +107,38 @@ public class ChefComputeServiceLiveTest { @Test public void testCanUpdateRunList() throws IOException { - chefContext.getChefService().updateRunListForTag(Collections.singleton("recipe[apache2]"), tag); - assertEquals(chefContext.getChefService().getRunListForTag(tag), Collections.singleton("recipe[apache2]")); + String recipe = "apache2"; + + Iterable cookbookVersions = chefContext.getChefService().listCookbookVersions(); + + if (any(cookbookVersions, containsRecipe(recipe))) { + List 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") public void testRunNodesWithBootstrap() throws IOException { Payload bootstrap = chefContext.getChefService().createClientAndBootstrapScriptForTag(tag); - TemplateOptions options = computeContext.getComputeService().templateOptions().runScript(bootstrap); try { - nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, options); + nodes = computeContext.getComputeService().runNodesWithTag(tag, 1, runScript(bootstrap)); } catch (RunNodesException e) { - nodes = Iterables.concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet()); + nodes = concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet()); } 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); String string = Utils.toStringAndClose(content); assert string.indexOf("It works!") >= 0 : string; diff --git a/chef/core/src/main/clojure/org/jclouds/chef.clj b/chef/core/src/main/clojure/org/jclouds/chef.clj index fdeb12f590..6503e6d59c 100644 --- a/chef/core/src/main/clojure/org/jclouds/chef.clj +++ b/chef/core/src/main/clojure/org/jclouds/chef.clj @@ -129,7 +129,37 @@ unit testing" "Retrieve the existing nodes in your chef server including all details." ([] (nodes *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 "Updates the run-list associated with a tag" diff --git a/chef/core/src/main/java/org/jclouds/chef/ChefService.java b/chef/core/src/main/java/org/jclouds/chef/ChefService.java index 09dcb2ca6b..12c968daec 100644 --- a/chef/core/src/main/java/org/jclouds/chef/ChefService.java +++ b/chef/core/src/main/java/org/jclouds/chef/ChefService.java @@ -24,6 +24,7 @@ import java.io.InputStream; import java.util.List; import org.jclouds.chef.domain.Client; +import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.chef.domain.Node; import org.jclouds.chef.internal.BaseChefService; import org.jclouds.io.Payload; @@ -97,9 +98,9 @@ public interface ChefService { void deleteAllNodesInList(Iterable names); - Iterable listNodesDetails(); + Iterable listNodes(); - Iterable listNodesDetailsMatching(Predicate nodeNameSelector); + Iterable listNodesMatching(Predicate nodeNameSelector); Iterable listNodesNamed(Iterable names); @@ -111,5 +112,11 @@ public interface ChefService { Iterable listClientsNamed(Iterable names); + Iterable listCookbookVersions(); + + Iterable listCookbookVersionsMatching(Predicate cookbookNameSelector); + + Iterable listCookbookVersionsNamed(Iterable cookbookNames); + void updateAutomaticAttributesOnNode(String nodeName); } diff --git a/chef/core/src/main/java/org/jclouds/chef/domain/Attribute.java b/chef/core/src/main/java/org/jclouds/chef/domain/Attribute.java index dda2f64833..9a2fe6e584 100644 --- a/chef/core/src/main/java/org/jclouds/chef/domain/Attribute.java +++ b/chef/core/src/main/java/org/jclouds/chef/domain/Attribute.java @@ -22,6 +22,8 @@ package org.jclouds.chef.domain; import java.util.List; import java.util.Set; +import org.jclouds.domain.JsonBall; + import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.gson.annotations.SerializedName; @@ -37,14 +39,14 @@ public class Attribute { private boolean calculated; private List choice = Lists.newArrayList(); @SerializedName("default") - private String defaultValue; + private JsonBall defaultValue; private String type; private List recipes = Lists.newArrayList(); @SerializedName("display_name") private String displayName; private String description; - public Attribute(String required, boolean calculated, Set choice, String defaultValue, String type, + public Attribute(String required, boolean calculated, Set choice, JsonBall defaultValue, String type, List recipes, String displayName, String description) { this.required = required; this.calculated = calculated; @@ -71,7 +73,7 @@ public class Attribute { return choice; } - public String getDefaultValue() { + public JsonBall getDefaultValue() { return defaultValue; } diff --git a/chef/core/src/main/java/org/jclouds/chef/domain/CookbookVersion.java b/chef/core/src/main/java/org/jclouds/chef/domain/CookbookVersion.java index e9bb1a039e..470c7b29d6 100644 --- a/chef/core/src/main/java/org/jclouds/chef/domain/CookbookVersion.java +++ b/chef/core/src/main/java/org/jclouds/chef/domain/CookbookVersion.java @@ -34,7 +34,7 @@ public class CookbookVersion { private String name; private Set definitions = Sets.newLinkedHashSet(); - private Set attributes = Sets.newLinkedHashSet(); + private Set attributes = Sets.newLinkedHashSet(); private Set files = Sets.newLinkedHashSet(); private Metadata metadata = new Metadata(); private Set providers = Sets.newLinkedHashSet(); @@ -62,10 +62,10 @@ public class CookbookVersion { this.name = cookbookName + "-" + version; } - public CookbookVersion(String name, Set definitions, Set attributes, Set files, - Metadata metadata, Set providers, String cookbookName, Set resources, - Set templates, Set libraries, String version, Set recipes, - Set rootFiles) { + public CookbookVersion(String name, Set definitions, Set attributes, Set files, + Metadata metadata, Set providers, String cookbookName, Set resources, + Set templates, Set libraries, String version, Set recipes, + Set rootFiles) { this.name = name; Iterables.addAll(this.definitions, definitions); Iterables.addAll(this.attributes, attributes); @@ -94,7 +94,7 @@ public class CookbookVersion { return definitions; } - public Set getAttributes() { + public Set getAttributes() { return attributes; } @@ -238,9 +238,9 @@ public class CookbookVersion { @Override public String toString() { return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName + ", definitions=" + definitions - + ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name - + ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles=" - + rootFiles + ", templates=" + templates + ", version=" + version + "]"; + + ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name + + ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles=" + + rootFiles + ", templates=" + templates + ", version=" + version + "]"; } } diff --git a/chef/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java b/chef/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java index 2efe227a9f..c87ae96190 100644 --- a/chef/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java +++ b/chef/core/src/main/java/org/jclouds/chef/internal/BaseChefService.java @@ -36,6 +36,7 @@ import javax.inject.Singleton; import org.jclouds.chef.ChefContext; import org.jclouds.chef.ChefService; import org.jclouds.chef.domain.Client; +import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.chef.domain.DatabagItem; import org.jclouds.chef.domain.Node; 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.DeleteAllNodesInList; import org.jclouds.chef.strategy.ListClients; +import org.jclouds.chef.strategy.ListCookbookVersions; import org.jclouds.chef.strategy.ListNodes; import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode; import org.jclouds.io.Payload; @@ -83,14 +85,16 @@ public class BaseChefService implements ChefService { private final TagToBootScript tagToBootScript; private final String databag; private final RunListForTag runListForTag; + private final ListCookbookVersions listCookbookVersions; @Inject protected BaseChefService(ChefContext chefContext, CleanupStaleNodesAndClients cleanupStaleNodesAndClients, CreateNodeAndPopulateAutomaticAttributes createNodeAndPopulateAutomaticAttributes, DeleteAllNodesInList deleteAllNodesInList, ListNodes listNodes, DeleteAllClientsInList deleteAllClientsInList, ListClients listClients, - UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Provider privateKey, - @Named(CHEF_BOOTSTRAP_DATABAG) String databag, TagToBootScript tagToBootScript, RunListForTag runListForTag) { + ListCookbookVersions listCookbookVersions, UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, + Provider privateKey, @Named(CHEF_BOOTSTRAP_DATABAG) String databag, + TagToBootScript tagToBootScript, RunListForTag runListForTag) { this.chefContext = checkNotNull(chefContext, "chefContext"); this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients"); this.createNodeAndPopulateAutomaticAttributes = checkNotNull(createNodeAndPopulateAutomaticAttributes, @@ -99,6 +103,7 @@ public class BaseChefService implements ChefService { this.listNodes = checkNotNull(listNodes, "listNodes"); this.deleteAllClientsInList = checkNotNull(deleteAllClientsInList, "deleteAllClientsInList"); this.listClients = checkNotNull(listClients, "listClients"); + this.listCookbookVersions = checkNotNull(listCookbookVersions, "listCookbookVersions"); this.updateAutomaticAttributesOnNode = checkNotNull(updateAutomaticAttributesOnNode, "updateAutomaticAttributesOnNode"); this.privateKey = checkNotNull(privateKey, "privateKey"); @@ -123,12 +128,12 @@ public class BaseChefService implements ChefService { } @Override - public Iterable listNodesDetails() { + public Iterable listNodes() { return listNodes.execute(); } @Override - public Iterable listNodesDetailsMatching(Predicate nodeNameSelector) { + public Iterable listNodesMatching(Predicate nodeNameSelector) { return listNodes.execute(nodeNameSelector); } @@ -157,6 +162,22 @@ public class BaseChefService implements ChefService { return listClients.execute(names); } + @Override + public Iterable listCookbookVersions() { + return listCookbookVersions.execute(); + } + + @Override + public Iterable listCookbookVersionsMatching(Predicate cookbookNameSelector) { + return listCookbookVersions.execute(cookbookNameSelector); + } + + @Override + public Iterable listCookbookVersionsNamed(Iterable names) { + return listCookbookVersions.execute(names); + } + + @Override public void updateAutomaticAttributesOnNode(String nodeName) { updateAutomaticAttributesOnNode.execute(nodeName); diff --git a/chef/core/src/main/java/org/jclouds/chef/predicates/CookbookVersionPredicates.java b/chef/core/src/main/java/org/jclouds/chef/predicates/CookbookVersionPredicates.java new file mode 100644 index 0000000000..e0d298caf7 --- /dev/null +++ b/chef/core/src/main/java/org/jclouds/chef/predicates/CookbookVersionPredicates.java @@ -0,0 +1,97 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 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 containsRecipes(String... recipes) { + checkNotNull(recipes, "recipes must be defined"); + final Multimap search = LinkedListMultimap.create(); + for (String recipe : recipes) { + if (recipe.indexOf("::") != -1) { + Iterable nameRecipe = Splitter.on("::").split(recipe); + search.put(get(nameRecipe, 0), get(nameRecipe, 1) + ".rb"); + } else { + search.put(recipe, "default.rb"); + } + } + return new Predicate() { + @Override + public boolean apply(final CookbookVersion cookbookVersion) { + return search.containsKey(cookbookVersion.getCookbookName()) + && any(search.get(cookbookVersion.getCookbookName()), new Predicate() { + + @Override + public boolean apply(final String recipeName) { + return any(cookbookVersion.getRecipes(), new Predicate() { + + @Override + public boolean apply(Resource resource) { + return resource.getName().equals(recipeName); + } + + }); + } + + }); + } + + @Override + public String toString() { + return "containsRecipes(" + search + ")"; + } + }; + } +} diff --git a/chef/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java b/chef/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java new file mode 100644 index 0000000000..4ef353cf16 --- /dev/null +++ b/chef/core/src/main/java/org/jclouds/chef/strategy/ListCookbookVersions.java @@ -0,0 +1,41 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 execute(); + + Iterable execute(Predicate cookbookNameSelector); + + Iterable execute(Iterable cookbookNames); +} \ No newline at end of file diff --git a/chef/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java b/chef/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java new file mode 100644 index 0000000000..dff73418fd --- /dev/null +++ b/chef/core/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java @@ -0,0 +1,104 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 execute() { + return execute(chefClient.listCookbooks()); + } + + @Override + public Iterable execute(Predicate cookbookNameSelector) { + return execute(filter(chefClient.listCookbooks(), cookbookNameSelector)); + } + + @Override + public Iterable execute(Iterable toGet) { + return concat(transform(toGet, new Function>() { + + @Override + public Iterable apply(final String cookbook) { + // TODO getting each version could also go parallel + return transformParallel(chefClient.getVersionsOfCookbook(cookbook), + new Function>() { + + @Override + public Future apply(String version) { + return chefAsyncClient.getCookbook(cookbook, version); + } + + }, userExecutor, maxTime, logger, "getting versions of cookbook " + cookbook); + } + + })); + } + +} \ No newline at end of file diff --git a/chef/core/src/main/java/org/jclouds/chef/util/RunListBuilder.java b/chef/core/src/main/java/org/jclouds/chef/util/RunListBuilder.java new file mode 100644 index 0000000000..96f1910119 --- /dev/null +++ b/chef/core/src/main/java/org/jclouds/chef/util/RunListBuilder.java @@ -0,0 +1,88 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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 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() { + + @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() { + + @Override + public String apply(String from) { + return "role[" + from + "]"; + } + + })); + return this; + } + + public List build() { + return ImmutableList.copyOf(list); + } +} \ No newline at end of file diff --git a/chef/core/src/test/java/org/jclouds/chef/ChefClientLiveTest.java b/chef/core/src/test/java/org/jclouds/chef/ChefClientLiveTest.java index 215e12f2be..416277b112 100644 --- a/chef/core/src/test/java/org/jclouds/chef/ChefClientLiveTest.java +++ b/chef/core/src/test/java/org/jclouds/chef/ChefClientLiveTest.java @@ -20,12 +20,14 @@ package org.jclouds.chef; import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertNotNull; import java.io.File; import java.io.IOException; import java.util.Properties; import org.jclouds.chef.config.ChefParserModule; +import org.jclouds.chef.domain.CookbookVersion; import org.jclouds.json.Json; import org.jclouds.json.config.GsonModule; import org.jclouds.logging.log4j.config.Log4JLoggingModule; @@ -76,7 +78,7 @@ public class ChefClientLiveTest extends BaseChefClientLiveTest { Properties props = new Properties(); props.setProperty("chef.endpoint", endpoint); return new ChefContextFactory().createContext(identity, key, ImmutableSet. of(new Log4JLoggingModule()), - props); + props); } @Override @@ -106,6 +108,12 @@ public class ChefClientLiveTest extends BaseChefClientLiveTest { clientConnection = createConnection(PREFIX, clientKey); } + @Test + public void testListCookbookVersionsWithChefService() throws Exception { + Iterable cookbooks = adminConnection.getChefService().listCookbookVersions(); + assertNotNull(cookbooks); + } + @Override protected void closeContexts() { if (clientConnection != null) diff --git a/chef/core/src/test/java/org/jclouds/chef/functions/ParseCookbookVersionFromJsonTest.java b/chef/core/src/test/java/org/jclouds/chef/functions/ParseCookbookVersionFromJsonTest.java index 2753a96b66..4a2be9e550 100644 --- a/chef/core/src/test/java/org/jclouds/chef/functions/ParseCookbookVersionFromJsonTest.java +++ b/chef/core/src/test/java/org/jclouds/chef/functions/ParseCookbookVersionFromJsonTest.java @@ -103,7 +103,7 @@ public class ParseCookbookVersionFromJsonTest { new CookbookVersion( "apache-chef-demo-0.0.0", ImmutableSet. of(), - ImmutableSet. of(), + ImmutableSet. of(), ImmutableSet. of(), new Metadata("Apache v2.0", "Your Name", ImmutableMap. of(), ImmutableMap .> of(), "youremail@example.com", ImmutableMap diff --git a/chef/core/src/test/java/org/jclouds/chef/util/RunListBuilderTest.java b/chef/core/src/test/java/org/jclouds/chef/util/RunListBuilderTest.java new file mode 100644 index 0000000000..864dd90cfa --- /dev/null +++ b/chef/core/src/test/java/org/jclouds/chef/util/RunListBuilderTest.java @@ -0,0 +1,74 @@ +/** + * + * Copyright (C) 2010 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.of()); + } + +}