 
 (def mesos-datomic
   (fnk [[:settings mesos-datomic-uri]]
-       ((lazy-load-var 'datomic.api/create-database) mesos-datomic-uri)
-       (let [conn ((lazy-load-var 'datomic.api/connect) mesos-datomic-uri)]
-         (doseq [txn (deref (lazy-load-var 'cook.mesos.schema/work-item-schema))]
-           (deref ((lazy-load-var 'datomic.api/transact) conn txn))
-           ((lazy-load-var 'metatransaction.core/install-metatransaction-support) conn)
-           ((lazy-load-var 'metatransaction.utils/install-utils-support) conn))
-         conn)))
+    ((lazy-load-var 'datomic.api/create-database) mesos-datomic-uri)
+    (let [conn ((lazy-load-var 'datomic.api/connect) mesos-datomic-uri)]
+      (doseq [txn (deref (lazy-load-var 'cook.mesos.schema/work-item-schema))]
+        (deref ((lazy-load-var 'datomic.api/transact) conn txn))
+        ((lazy-load-var 'metatransaction.core/install-metatransaction-support) conn)
+        ((lazy-load-var 'metatransaction.utils/install-utils-support) conn))
+      conn)))
 
 (def curator-framework
   (fnk [[:settings zookeeper] local-zookeeper]
-       (let [retry-policy (BoundedExponentialBackoffRetry. 100 120000 10)
-             ;; The 180s session and 30s connection timeouts were pulled from a google group
-             ;; recommendation
-             curator-framework (CuratorFrameworkFactory/newClient zookeeper 180000 30000 retry-policy)
-             ]
-         (.. curator-framework
-             getConnectionStateListenable
-             (addListener (reify ConnectionStateListener
-                            (stateChanged [_ client newState]
-                              (log/info "Curator state changed:"
-                                        (str newState))))))
-         (.start curator-framework)
-         curator-framework)))
+    (let [retry-policy (BoundedExponentialBackoffRetry. 100 120000 10)
+          ;; The 180s session and 30s connection timeouts were pulled from a google group
+          ;; recommendation
+          curator-framework (CuratorFrameworkFactory/newClient zookeeper 180000 30000 retry-policy)
+          ]
+      (.. curator-framework
+          getConnectionStateListenable
+          (addListener (reify ConnectionStateListener
+                         (stateChanged [_ client newState]
+                           (log/info "Curator state changed:"
+                                     (str newState))))))
+      (.start curator-framework)
+      curator-framework)))
 
 (defn tell-jetty-about-usename [h]
   "Our auth in cook.spnego doesn't hook in to Jetty - this handler

  ([{:keys [file] :or {file "log/cook.log"} {:keys [default] :or {default :info} :as overrides} :levels}]
   (try
     (.. (org.apache.log4j.Logger/getRootLogger)
       (getLoggerRepository)
       (resetConfiguration))
   ;; This lets you inspect which loggers have which appenders turned on
   ;;(clojure.pprint/pprint (map #(select-keys % [:allAppenders :name]) (log4j-conf/get-loggers)))
   (let [overrides (->> overrides
                        (filter (comp string? key))
                        (mapcat (fn [[logger level]]
                                  [[logger] {:level level}])))]
     (apply log4j-conf/set-loggers!
            (org.apache.log4j.Logger/getRootLogger)
            {:out (org.apache.log4j.DailyRollingFileAppender.
                    (org.apache.log4j.PatternLayout.
                      "%d{ISO8601} %-5p %c [%t] - %m%n")
                    file
                    "'.'yyyy-MM-dd")
             :level default}
            overrides))
     (catch Throwable t
       (.println System/err "Failed to initialize logging!")
       (.printCauseTrace t)

  "Parses the settings out of a config file"
  (graph/eager-compile
    {:server-port (fnk [[:config port]]
                    port)
     :is-authorized-fn (fnk [[:config {authorization-config default-authorization}]]
                         (partial (lazy-load-var 'cook.authorization/is-authorized?)
                                  authorization-config))
     :authorization-middleware (fnk [[:config [:authorization {one-user false} {kerberos false} {http-basic false}]]]
                                 (cond
                                   http-basic
                                   (let [validation (get http-basic :validation :none)
                                         user-password-valid?
                                         ((lazy-load-var 'cook.basic-auth/make-user-password-valid?) validation http-basic)]
                                     (log/info "Using http basic authorization with validation" validation)
                                     ((lazy-load-var 'cook.basic-auth/create-http-basic-middleware) user-password-valid?))

                                   one-user
                                   (do
                                     (log/info "Using single user authorization")
                                     (fn one-user-middleware [h]
                                       (fn one-user-auth-wrapper [req]
                                         (h (assoc req :authorization/user one-user)))))

                                   kerberos
                                   (do
                                     (log/info "Using kerberos middleware")
                                     (lazy-load-var 'cook.spnego/require-gss))
                                   :else (throw (ex-info "Missing authorization configuration" {}))))
     :rate-limit (fnk [[:config {rate-limit nil}]]
                   (let [{:keys [user-limit-per-m]
                          :or {user-limit-per-m 600}} rate-limit]
                     {:user-limit (->UserRateLimit :user-limit user-limit-per-m (t/minutes 1))}))
     :sim-agent-path (fnk [] "/usr/bin/sim-agent")
     :mesos-datomic-uri (fnk [[:config [:database datomic-uri]]]
                          (when-not datomic-uri
                            (throw (ex-info "Must set a the :database's :datomic-uri!" {})))
                          datomic-uri)
     :dns-name simple-dns-name
     :hostname (fnk [] (.getCanonicalHostName (java.net.InetAddress/getLocalHost)))
     :local-zk-port (fnk [[:config [:zookeeper {local-port 3291}]]]
                      local-port)
     :zookeeper-server (fnk [[:config [:zookeeper {local? false}]] local-zk-port]
                         (when local?
                           (log/info "Created local ZooKeeper; not yet started")
                           (org.apache.curator.test.TestingServer. local-zk-port false)))
     :zookeeper (fnk [[:config [:zookeeper {local? false} {connection nil}]] local-zk-port]
                  (cond
                    local? (str "localhost:" local-zk-port)
                    connection connection
                    :else (throw (ex-info "Must specify a zookeeper connection" {}))))
     :task-constraints (fnk [[:config [:scheduler {task-constraints nil}]]]
                         ;; Trying to pick conservative defaults
                         (merge
                           {:timeout-hours 1
                            :timeout-interval-minutes 1
                            :retry-limit 20
                            :memory-gb 12
                            :cpus 4}
                           task-constraints))
     :offer-incubate-time-ms (fnk [[:config [:scheduler {offer-incubate-ms 15000}]]]
                               offer-incubate-ms)
     :offer-cache (fnk [[:config [:scheduler {offer-cache nil}]]]
                    (merge
                      {:max-size 2000
                       :ttl-ms 15000}
                      offer-cache))
     :mea-culpa-failure-limit (fnk [[:config [:scheduler {mea-culpa-failure-limit nil}]]]
                                mea-culpa-failure-limit)
     :fenzo-max-jobs-considered (fnk [[:config [:scheduler {fenzo-max-jobs-considered 1000}]]]
                                  fenzo-max-jobs-considered)
     :fenzo-scaleback (fnk [[:config [:scheduler {fenzo-scaleback 0.95}]]]
                        fenzo-scaleback)
     :fenzo-floor-iterations-before-warn (fnk [[:config [:scheduler {fenzo-floor-iterations-before-warn 10}]]]
                                           fenzo-floor-iterations-before-warn)
     :fenzo-floor-iterations-before-reset (fnk [[:config [:scheduler {fenzo-floor-iterations-before-reset 1000}]]]
                                            fenzo-floor-iterations-before-reset)
     :mesos-gpu-enabled (fnk [[:config [:mesos {enable-gpu-support false}]]]
                          (boolean enable-gpu-support))
     :good-enough-fitness (fnk [[:config [:scheduler {good-enough-fitness 0.8}]]]
                            good-enough-fitness)
     :mesos-master (fnk [[:config [:mesos master]]]
                     master)
     :mesos-master-hosts (fnk [[:config [:mesos master {master-hosts nil}]]]
                           (if master-hosts
                             (if (and (sequential? master-hosts) (every? string? master-hosts))
                               master-hosts
                               (throw (ex-info ":mesos-master should be a list of hostnames (e.g. [\"host1.example.com\", ...])" {})))
                             (->> master
                                  (re-seq #"[/|,]?([^/,:]+):\d+")
                                  (mapv second))))
     :mesos-failover-timeout (fnk [[:config [:mesos {failover-timeout-ms nil}]]]
                               failover-timeout-ms)
     :mesos-leader-path (fnk [[:config [:mesos leader-path]]]
                          leader-path)
     :mesos-principal (fnk [[:config [:mesos {principal nil}]]]
                        principal)
     :mesos-role (fnk [[:config [:mesos {role "*"}]]]
                   role)
     :mesos-framework-name (fnk [[:config [:mesos {framework-name "Cook"}]]]
                             framework-name)
     ;:riemann-metrics (fnk [[:config [:metrics {riemann nil}]]]
     ;                  (when riemann
     ;                    (when-not (= 4 (count (select-keys riemann [:host :port])))
     ;                      (throw (ex-info "You must specify the riemann :host and :port!" riemann)))
     ;                    ((lazy-load-var 'cook.reporter/riemann-reporter) riemann)))
     :jmx-metrics (fnk [[:config [:metrics {jmx false}]]]
                    (when jmx
                      ((lazy-load-var 'cook.reporter/jmx-reporter))))
     :graphite-metrics (fnk [[:config [:metrics {graphite nil}]]]
                         (when graphite
                           (when-not (:host graphite)
                             (throw (ex-info "You must specify the graphite host!" {:graphite graphite})))
                           (let [config (merge {:port 2003 :pickled? true} graphite)]
                             ((lazy-load-var 'cook.reporter/graphite-reporter) config))))
     :riemann (fnk [[:config [:metrics {riemann nil}]]]
                riemann)
     :riemann-metrics (fnk [[:config [:metrics {riemann nil}]]]
                        (when riemann
                          (when-not (:host riemann)
                            (throw (ex-info "You must specific the :host to send the riemann metrics to!" {:riemann riemann})))
                          (when-not (every? string? (:tags riemann))
                            (throw (ex-info "Riemann tags must be a [\"list\", \"of\", \"strings\"]" riemann)))
                          (let [config (merge {:port 5555
                                               :local-host (.getHostName
                                                             (java.net.InetAddress/getLocalHost))}
                                              riemann)]
                            ((lazy-load-var 'cook.reporter/riemann-reporter) config))))

     :rebalancer (fnk [[:config {rebalancer nil}]]
                   (merge {:interval-seconds 300
                           :dru-scale 1.0}
                          rebalancer))

     :nrepl-server (fnk [[:config [:nrepl {enabled? false} {port 0}]]]
                     (when enabled?
                       (when (zero? port)
                         (throw (ex-info "You enabled nrepl but didn't configure a port. Please configure a port in your config file." {})))
                       ((lazy-load-var 'clojure.tools.nrepl.server/start-server) :port port)))}))

(defn- init-logger
  ([] (init-logger {:levels {"datomic.db" :warn
