Skip to content

Commit

Permalink
consul: add support for --consistency levels and bump 0.1.16
Browse files Browse the repository at this point in the history
  • Loading branch information
mkcp committed Jan 31, 2020
1 parent 061258b commit 5d1b151
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 37 deletions.
2 changes: 1 addition & 1 deletion consul/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.10.0"]
[jepsen "0.1.15"]
[jepsen "0.1.16"]
[base64-clj "0.1.1"]
[clj-http "3.10.0"]
[cheshire "5.9.0"]]
Expand Down
16 changes: 14 additions & 2 deletions consul/src/jepsen/consul.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
[jepsen.consul.client :as cc]
[jepsen.consul.db :as db]))

;; Default is nil
(def consistency-levels
#{"stale" "consistent"})

(def workloads
{"none" (fn [_] tests/noop-test)
"register" register/workload})
Expand Down Expand Up @@ -55,15 +59,21 @@
(gen/sleep 10)
(gen/clients (:final-generator workload)))})))

(defn all-tests
"TODO This doesn't do anything now, but will be important when we have
multiple workloads and want to run comprehensive CI"
[])

(def cli-opts
"Additional command line options."
[["-v" "--version STRING" "What version of etcd should we install?"
:default "1.6.1"]
["-w" "--workload NAME" "What workload should we run?"
:missing (str "--workload " (cli/one-of workloads))
:validate [workloads (cli/one-of workloads)]]
;; TODO Double check the config on cosistency levels here.
#_["-s" "--consistency" "Which consistency level to use."]
[nil "--consistency LEVEL" "What consistency level to set on kv store requests. Leave empty for default"
:default nil
:validate [consistency-levels (cli/one-of consistency-levels)]]
["-r" "--rate HZ" "Approximate number of requests per second, per thread."
:default 10
:parse-fn read-string
Expand All @@ -80,6 +90,8 @@
(cli/run! (merge (cli/single-test-cmd
{:test-fn consul-test
:opt-spec cli-opts})
(cli/test-all-cmd {:tests-fn (partial all-tests consul-test)
:opt-spec cli-opts})
(cli/serve-cmd))
args))

57 changes: 37 additions & 20 deletions consul/src/jepsen/consul/client.clj
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,46 @@
([url]
(http/get url))
([url key]
(http/get (str url key))))
(http/get (str url key)))
([url key consistency]
(http/get (str url key)
{:query-params {(keyword consistency) nil}})))

(defn put! [url key value]
(http/put (str url key) {:body value}))
(defn put!
([url key value]
(http/put (str url key) {:body value}))
([url key value consistency]
(http/put (str url key)
{:body value
:query-params {(keyword consistency) nil}})))

(defn cas!
"Consul uses an index based CAS so we must first get the existing value for
this key and then use the index for a CAS!"
[url key value new-value]
(let [res (parse (get url key))
existing-value (str (:value res))
index (:index res)]
(if (= existing-value value)
(let [params {:body new-value :query-params {:cas index}}
body (:body (http/put (str url key) params))]
(= body "true"))
false)))
"Consul uses an index based CAS, not a value-based CAS, so we must first get
the existing index for this the current key and then use the index to issue a
CAS request."
([url key value new-value]
(let [res (parse (get url key))
existing-value (str (:value res))
index (:index res)]
(if (= existing-value value)
(let [params {:body new-value :query-params {:cas index}}
body (:body (http/put (str url key) params))]
(= body "true"))
false)))

([url key value new-value consistency]
(let [res (parse (get url key consistency))
existing-value (str (:value res))
index (:index res)]
(if (= existing-value value)
(let [params {:body new-value :query-params {:cas index
:query-params {(keyword consistency) nil}}}
body (:body (http/put (str url key) params))]
(= body "true"))
false))))

(defn txn
"TODO"
"TODO Model txn requests when we get to testing that part of Consul"
[])

(defmacro with-errors
Expand All @@ -84,13 +104,10 @@
#"500" (assoc ~op :type type# :error :server-unavailable)
(throw e#))))))

;; FIXME simplify this whole thing, it's repetitive
(defn await-cluster-ready
"Blocks until cluster index matches count of nodes on test"
"Blocks until cluster index matches count of nodes on test."
[node count]

;; FIXME Maybe we use the index count here?
(let [url (str "http://" (net/ip (name node)) ":8500/v1/catalog/nodes?index=1")]
(let [url (str "http://" (net/ip (name node)) ":8500/v1/catalog/nodes?index=" count)]
(with-retry [attempts 5]
(get url)

Expand Down
1 change: 1 addition & 0 deletions consul/src/jepsen/consul/db.clj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
:-data-dir data-dir
:-node (name node)
:-retry-interval retry-interval
;; TODO Enable this when we're giving the system on-disk config
#_(when (= node (jepsen/primary test))
[:-config-file config-file])

Expand Down
37 changes: 23 additions & 14 deletions consul/src/jepsen/consul/register.clj
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,33 @@
crash (if (= :read (:f op)) :fail :info)]
(c/with-errors op #{:read}
(case (:f op)
:read (let [v (-> client
(c/get k)
c/parse
:value)]
:read (let [consistency (:consistency test)
res (if consistency
(c/get client k consistency)
(c/get client k))
v (-> res c/parse :value)]
(assoc op :type :ok :value (independent/tuple k v)))

:write (let [v (->> value
json/generate-string
(c/put! client k))]
:write (let [consistency (:consistency test)
body (json/generate-string value)
_ (if consistency
(c/put! client k body consistency)
(c/put! client k body))]
(assoc op :type :ok))

:cas (let [[value value'] value]
(assoc op :type (if (c/cas! client
k
(json/generate-string value)
(json/generate-string value'))
:ok
:fail)))))))
:cas (let [consistency (:consistency test)
[value value'] value
res (if consistency
(c/cas! client
k
(json/generate-string value)
(json/generate-string value')
consistency)
(c/cas! client
k
(json/generate-string value)
(json/generate-string value')))]
(assoc op :type (if res :ok :fail)))))))

;; HTTP clients are stateless
(close! [_ _])
Expand Down

0 comments on commit 5d1b151

Please sign in to comment.