dwwoelfel / cetcd

Clojure wrapper for etcd
Eclipse Public License 1.0
13 stars 5 forks source link

cetcd

A Clojure wrapper for etcd. Uses http-kit to talk to etcd, so we get callbacks for free.

Build Status

Installation

cetcd is available as a Maven artifact from Clojars.

[cetcd "0.2.2"]

Changelog

Version 0.2.2

Version 0.2.1

Version 0.2.0

Usage

Set the value to a key

user> (require '[cetcd.core :as etcd])
nil
user> (etcd/set-key! :a 1)
{:action "set",
 :node
 {:key "/:a",
  :modifiedIndex 10,
  :createdIndex 10,
  :value "1",
  :prevValue "1"}}

Get the value of a key

user> (etcd/get-key :a)
{:action "get",
 :node {:key "/:a", :modifiedIndex 10, :createdIndex 10, :value "1"}}

Let's get the actual value:

user> (-> (etcd/get-key :a) :node :value)
"1"

Notice that cetcd didn't preserve the type of the key's value. That's a job that's left to the caller:

user> (etcd/set-key! :clojure-key (pr-str 1))
{:action "set", :node {:key "/:clojure-key", :value "1", :modifiedIndex 14, :createdIndex 14}
user> (-> (etcd/get-key :clojure-key)
          :node
          :value
          (clojure.edn/read-string))
1

cetcd also doesn't do much to help you if the key doesn't exist:

user> (etcd/get-key :b)
{:errorCode 100, :message "Key Not Found", :cause "/:b", :index 22}

But sane callers should be fine:

user> (-> (etcd/get-key :b) :node :value) ;; return nil if key doesn't exist
nil

cetcd purposely doesn't return the value because directories require you to know about nodes

user> (do
        (etcd/set-key! :foo/bar 1)
        (etcd/set-key! :foo/baz 2)
        (etcd/get-key :foo))
{:action "get",
 :node
 {:key "/:foo",
  :dir true,
  :nodes
  [{:key "/:foo/bar", :value "1", :modifiedIndex 26, :createdIndex 26}
   {:key "/:foo/baz",
    :value "2",
    :modifiedIndex 27,
    :createdIndex 27}],
  :modifiedIndex 24,
  :createdIndex 24}}

Delete a key

user> (etcd/delete-key! :a)
{:action "delete",
 :node
 {:key "/:a", :modifiedIndex 11, :createdIndex 10, :prevValue "1"}}

Everything that etcd does can be accomplished with the set-key!, get-key, and delete-key! functions above, by passing in the proper keyword args. There are also a few helper functions to keep things a bit cleaner.

Compare and swap

user> (etcd/compare-and-swap! :a 2 {:prevValue 1})
{:action "compareAndSwap", :node {:key "/:a", :prevValue "1", :value "2", :modifiedIndex 15, :createdIndex 13}}

You have to check manually if the condition failed:

user> (etcd/compare-and-swap! :a 2 {:prevValue 1})
{:errorCode 101, :message "Test Failed", :cause "[1 != 2] [0 != 22]", :index 22}

Compare and delete

user> (etcd/set-key! :cad-key 2)
{:action "set", :node {:key "/:cad-key", :value "2", :modifiedIndex 47, :createdIndex 47}}
user> (etcd/compare-and-delete! :cad-key {:prevValue 2})
{:action "compareAndDelete", :node {:key "/:cad-key", :modifiedIndex 48, :createdIndex 47}, :prevNode {:key "/:cad-key", :value "2", :modifiedIndex 47, :createdIndex 47}}

You have to check manually if the condition failed:

user> (etcd/set-key! :cad-key 2)
{:action "set", :node {:key "/:cad-key", :value "2", :modifiedIndex 49, :createdIndex 49}}
user> (etcd/compare-and-delete! :cad-key {:prevValue 1})
{:errorCode 101, :message "Compare failed", :cause "[1 != 2] [0 != 49]", :index 49}

Wait for a value

user> (future (println "new value is:" (-> (etcd/watch-key :a) :node :value)))
#<core$future_call$reify__6267@ddd23bc: :pending>
user> (etcd/set-key! :a 3)
new value is: 3
{:action "set", :node {:key "/:a", :prevValue "2", :value "3", :modifiedIndex 16, :createdIndex 16}}

If you provide a callback function, then it will return immediately with a promise:

user> (def watchvalue (atom nil)) ;; give us a place store the resp in the callback
#'user/watchvalue
user> (etcd/watch-key :a :callback (fn [resp]
                                       (reset! watchvalue resp)))
#<core$promise$reify__6310@144d3f4b: :pending>
user> (etcd/set-key! :a 4)
{:action "set", :node {:key "/:a", :prevValue "3", :value "4", :modifiedIndex 20, :createdIndex 20}}
user> watchvalue
#<Atom@69bcc736: {:action "set", :node {:key "/:a", :prevValue "3", :value "4", :modifiedIndex 20, :createdIndex 20}}>

Create a directory

user> (etcd/create-dir! "foo/bar/baz")
{:action "set",
 :node
 {:key "/foo/bar/baz", :dir true, :modifiedIndex 37, :createdIndex 37}}

License

Copyright © 2013

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.