diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
index d14e9d8ed5..d478690668 100755
--- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
@@ -450,7 +450,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
blob = context.getBlobStore().getBlob(containerName, blob.getMetadata().getName());
String returnedString = getContentAsStringOrNullAndClose(blob);
assertEquals(returnedString, "foo");
- assertEquals(blob.getPayload().getContentType(), "text/csv");
+ assert blob.getPayload().getContentType().startsWith("text/csv") : blob.getPayload().getContentType();
PageSet extends StorageMetadata> set = context.getBlobStore().list(containerName);
assert set.size() == 1 : set;
} finally {
diff --git a/chef/core/pom.xml b/chef/core/pom.xml
index 46a4da6608..5f368957d8 100644
--- a/chef/core/pom.xml
+++ b/chef/core/pom.xml
@@ -91,5 +91,11 @@
${project.version}
test
+
+ org.danlarkin
+ clojure-json
+ 1.1
+ true
+
diff --git a/chef/core/src/main/clojure/org/jclouds/chef.clj b/chef/core/src/main/clojure/org/jclouds/chef.clj
index 0a7dc356de..76424eea9f 100644
--- a/chef/core/src/main/clojure/org/jclouds/chef.clj
+++ b/chef/core/src/main/clojure/org/jclouds/chef.clj
@@ -21,10 +21,12 @@
:doc "A clojure binding to the jclouds chef interface."}
org.jclouds.chef
(:use org.jclouds.core (core))
+ (:require (org.danlarkin [json :as json]))
(:import
java.util.Properties
[org.jclouds.chef ChefClient
- ChefService ChefContext ChefContextFactory]))
+ ChefService ChefContext ChefContextFactory]
+ [org.jclouds.chef.domain DatabagItem]))
(try
(use '[clojure.contrib.reflect :only [get-field]])
(catch Exception e
@@ -71,6 +73,14 @@
(chef-context? (first args)) (.getChefService (first args))
:else (apply chef-service args)))
+(defn as-chef-api
+ "Tries hard to produce a chef client from its input arguments"
+ [& args]
+ (cond
+ (chef-service? (first args)) (.getApi (.getContext (first args)))
+ (chef-context? (first args)) (.getApi (first args))
+ :else (.getApi (.getContext (apply chef-service args)))))
+
(def *chef*)
(defmacro with-chef-service
@@ -83,10 +93,71 @@
"Retrieve the names of the existing nodes in your chef server."
([] (nodes *chef*))
([#^ChefService chef]
- (seq (.listNodes (.getApi (.getContext chef))))))
+ (seq (.listNodes (as-chef-api chef)))))
(defn nodes-with-details
"Retrieve the existing nodes in your chef server including all details."
([] (nodes *chef*))
([#^ChefService chef]
- (seq (.listNodesDetails chef))))
\ No newline at end of file
+ (seq (.listNodesDetails chef))))
+
+(defn databags
+ "Retrieve the names of the existing data bags in your chef server."
+ ([] (databags *chef*))
+ ([#^ChefService chef]
+ (seq (.listDatabags (as-chef-api chef)))))
+
+(defn delete-databag
+ "Delete a data bag, including its items"
+ ([databag]
+ (delete-databag databag *chef*))
+ ([databag chef]
+ (.deleteDatabag (as-chef-api chef) databag)))
+
+(defn create-databag
+ "create a data bag"
+ ([databag]
+ (create-databag databag *chef*))
+ ([databag chef]
+ (.createDatabag (as-chef-api chef) databag)))
+
+(defn databag-items
+ "Retrieve the names of the existing items in a data bag in your chef server."
+ ([databag]
+ (databag-items databag *chef*))
+ ([databag chef]
+ (seq (.listDatabagItems (as-chef-api chef) databag))))
+
+(defn databag-item
+ "Get an item from the data bag"
+ ([databag item-id]
+ (databag-item databag item-id *chef*))
+ ([databag item-id chef]
+ (json/decode-from-str (str (.getDatabagItem (as-chef-api chef) databag item-id)))))
+
+(defn delete-databag-item
+ "delete an item from the data bag"
+ ([databag item-id]
+ (delete-databag-item databag item-id *chef*))
+ ([databag item-id chef]
+ (.deleteDatabagItem (as-chef-api chef) databag item-id)))
+
+(defn create-databag-item
+ "put a new item in the data bag"
+ ([databag value]
+ (create-databag-item databag value *chef*))
+ ([databag value chef]
+ (let [value-str (json/encode-to-str value)]
+ (let [value-json (json/decode-from-str value-str)]
+ (json/decode-from-str (str (.createDatabagItem (as-chef-api chef) databag
+ (DatabagItem. (get value-json :id) value-str))))))))
+
+(defn update-databag-item
+ "updates an existing item in the data bag"
+ ([databag value]
+ (update-databag-item databag value *chef*))
+ ([databag value chef]
+ (let [value-str (json/encode-to-str value)]
+ (let [value-json (json/decode-from-str value-str)]
+ (json/decode-from-str (str (.updateDatabagItem (as-chef-api chef) databag
+ (DatabagItem. (get value-json :id) value-str))))))))
diff --git a/chef/core/src/main/java/org/jclouds/chef/ChefClient.java b/chef/core/src/main/java/org/jclouds/chef/ChefClient.java
index 3e48609d9f..1c7809ad2e 100644
--- a/chef/core/src/main/java/org/jclouds/chef/ChefClient.java
+++ b/chef/core/src/main/java/org/jclouds/chef/ChefClient.java
@@ -383,7 +383,7 @@ public interface ChefClient {
Set listDatabags();
/**
- * gets an existing databag.
+ * creates a databag.
*
* @throws AuthorizationException
*