A Clojure client for etcd. The main goal of this lib is to fully cover API of etcd and to stay simple and performant.
[etcd-clj "0.2.3"]
see HISTORY.md
(require '[etcd-clj.core :as etcd])
Full API (generated by codox) http://narma.github.io/etcd-clj/
etcd API https://github.com/coreos/etcd/blob/master/Documentation/api.md
etcd-clj
doesn't require set connection if you use default configuration.
Otherwrise call set-connection!
(etcd/set-connection! :host myhost)
;; also valid options are :port and :protocol
user> (etcd/set :a 1)
{:action "set",
:node
{:key "/:a",
:modifiedIndex 10,
:createdIndex 10,
:value "1",
:prevValue "1"}}
Also etcd/set!
do some, but throws exception if error occurs.
user> (etcd/get :a)
{:action "get",
:node {:key "/:a", :modifiedIndex 10, :createdIndex 10, :value "1"}}
Get actual value using the simplified API
user> (etcd/sget :a)
"1"
In etcd get
command works for regular keys and dirs.
See etcd documentation for how it works.
etcd/list
fn is a helper which returns hash-map for a directory.
It has two options:
-
:recursive
- lists subdirectories recursively, default isfalse
. -
:with-dirs
- Includes dirs in result withnil
values.makes sence only when option `:recursive` is `false`. Default is `true`.
Notice that etcd
didn't preserve the type of the key's value. This job is left to the caller:
user> (etcd/set :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
user> (etcd/del :a)
{:action "delete",
:node
{:key "/:a", :modifiedIndex 11, :createdIndex 10, :prevValue "1"}}
Everything that etcd
does can be accomplished with the set
, get
, and del
functions above, by passing in the proper keyword args. There are also a few helper functions to keep things a bit cleaner.
(etcd/mkdir "mydir")
It's alias for (set "mydir" nil :dir true)
Use set with conditional options:
:prev-value
- checks the previous value of the key.:prev-index
- checks the previous modifiedIndex of the key.:prev-exist
- checks existence of the key.
user> (etcd/set :a 2 :prev-value 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/set :a 2 :prev-alue 1)
{:errorCode 101, :message "Test Failed", :cause "[1 != 2] [0 != 22]", :index 22}
Same as CAS but without :prev-exist
user> (etcd/del :key :prev-value 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 2)
{:action "set", :node {:key "/:cad-key", :value "2", :modifiedIndex 49, :createdIndex 49}}
user> (etcd/del :key :prev-value 1)
{:errorCode 101, :message "Compare failed", :cause "[1 != 2] [0 != 49]", :index 49}
user> (future (println "new value is:" (-> (etcd/wait :a) :node :value)))
#<core$future_call$reify__6267@ddd23bc: :pending>
user> (etcd/set :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 immediately return with a promise:
user> (def watchvalue (atom nil)) ;; give us a place store the resp in the callback
#'user/watchvalue
user> (etcd/wait :a :callback (fn [resp]
(reset! watchvalue resp)))
#<core$promise$reify__6310@144d3f4b: :pending>
user> (etcd/set :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}}>