         :else
         (do
           (Thread/sleep 10000)
-          (recur (dec n)))))))r
-
-(defn internal-ips [is]
-(let [ds (:reservations (describe-instances :instance-ids is))]
-    (map #(get-in % [:instances 0 :private-ip-address]) ds)))
-
-(defn terminate [is]
-  (terminate-instances :instance-ids is))
-
-(defn cancel [rs]
-  (:cancelled-spot-instance-requests
-   (cancel-spot-instance-requests :spot-instance-request-ids rs)))
-
-(def ag (ssh/ssh-agent {}))
-
-(defn ssh-sessions [hosts]
-  (let [sess (map #(ssh/session ag % {:strict-host-key-checking :no
-                                      :username "ec2-user"})
-                  hosts)]
-    (loop [n 10]
-           (let [o (map #(or (ssh/connected? %) (ssh/connect %)) sess)]
-             (if (or (every? o)
-                     (zero? n)) sess
-                 (do 
-                   (Thread/sleep 1000)
-                   (recur (dec n))))))))
-
-
-(defn bring-up-aws
-  "Bring up n AWS t1.micro instances and return channel that will contain a single map
-of {:instance ids :hosts names and :sessions objects}."
-  [n & opts]
-  (let [c    (chan)
-        tout (timeout (* 60 1000 10))]
+          (recur (dec n)))))))
+
+#_(defn request-spots [n & {:keys [zone itype price image key profile group subnet]}]
+  (let [zone   (or zone "us-east-1c")
+        itype  (or itype "t1.micro")
+        price  (str (or price "0.005"))
+        image  (or image "BLEH")
+        sgs    (if (seq sg) sg [sg])
+        req    [:spot-price 			price
+                :instance-count 		n
+                :type 			"one-time"
+                :launch-specification 
+                {:image-id 			image
+                 :instance-type 		itype
+                 :placement {:availability-zone      zone}
+                 :key-name			key
+                 :security-groups-ids	     sgs
+                 :subnet-id                  (get my-subnets zone)
+                 :iam-instance-profile       {:arn "arn:aws:iam::633840533036:instance-profile/girder-peer"}}]
+        (apply request-spot-instances req)]
+    (println req)
+    (map :spot-instance-request-id  (:spot-instance-requests r))))
+
+#_(defn patience
+  "Invoke (genfn) every time-wait sec until predicate returns true or time-limit sec has passed.
+Returns result of genfn, or nil in the case of timeout."
+  [pred genfn time-limit time-wait]
+  (let [t1     (if (number? time-limit) (timeout (* 1000 time-limit)) time-limit)
+        out    (chan)]
+    (async/go-loop []
+      (let [r   (genfn)
+            p   (pred r)]
+        (if p
+         (do (debug "Returning" r)
+              (>! out r) (close! r))
+         (let [t2     (timeout (* 1000  time-wait))
+               _      (debug "Still" r "Waiting" time-wait "sec")
+               [v c] (async/alts! [t1 t2])]
+           (if (= c t1)
+             (do 
+               (debug time-limit "seconds expired.  Returning nil.")
+               (close! out))
+             (recur))))))
+    out))
+
+
+#_(defn patience-every [pred collfn time-limit time-wait]
+  (patience #(every? pred %) collfn time-limit time-wait))
+
+
+#_(defn- add-sessions [res]
+  (let [out   (chan)
+        tout  (timeout 60000)
+        rs    (:rs res)
+        hosts (:hosts res)
+        sess  (map #(ssh/session ag % {:strict-host-key-checking :no
+                                                  :username "ec2-user"})
+                   hosts)]
+    (async/go-loop []
+      (if (every? ssh/connected? sess)
+        (do (debug "All connected.  Returning.")
+            (>! out (assoc res :sessions sess)))
+        (let 
+          (if (= c tout)
+            (do
+              (debug "Failed to establish connections after timeout.  Terminating.")
+              (cancel rs)
+              (close! out))
+            (if #(every? ssh/connected? sess)
+              (do (debug "Returning connected" sess)
+                  (>! out (assoc res :sessions sess)))
+              (do
+                (debug "Waiting 10 sec")
+                (<! (timeout 10000))
+                (recur)))))))
+    out))
+
+
+#_(defn- add-requests [res]
+  (let [req (:req res)
+        out (chan)]
     (go 
-      (let [_        (println opts)
-            rs       (apply request-spots n opts)
-            _        (println "requests" rs)
-            _        (<! (timeout 1000))
-            ss       (<! (patience-every #(= "active" %) #(request-status rs) 60000 tout))
-            _        (println "Requesting instances for" rs)
-            is       (request-instances rs)
-            _        (println "instances" is)
-            hosts    (dns-names is)
-            ips      (internal-ips is)
-            _        (println "hosts" hosts)
-            sessions (ssh-sessions hosts)
-            opn      (map #(or (ssh/connected? %) (ssh/connect %)) sessions)
-            
-            _        (println "Done!")]
-        (>! c {:instances is :hosts hosts :sessions sessions :ips ips :rs requests}) (close! c)))
-    [c tout]))
-
-
-(defn EDNify
-"EDN-ify an arbitrary object, leaving it alone if its an innocuous string."
-  [x] 
-  (let [x (if (string? x) x (pr-str x))
-        x (if (re-matches #"[0-9a-zA-z-_\.]+" x) x (pr-str x))]
-    x))
-
-
-(defn commandify
-  "If cmd is a sequence, convert it into a space-delimited string, EDNifying as necessary."
-  [cmd]
-  (cond (string? cmd) cmd
-        (seq cmd) (clojure.string/join " " (map EDNify cmd))))
-
-(defn ex
-  "Make sure the session is connected and run the command remotely via
-ssh-exec, yielding a map of :exit code, :out string and :err string."
-  [sess cmd]
-  (or (ssh/connected? sess) (ssh/connect sess))
-  (ssh/ssh-exec sess (commandify cmd) "" "" {}))
-
-(defn ex-async [sess cmd]
-  "As ex, but returns a channel that will contain the map."
-  (or (ssh/connected? sess) (ssh/connect sess))
-  (let [c (chan)]
-    (go (let [cmd (commandify cmd)
-              _   (println "Running in" sess cmd)
-              res (ssh/ssh-exec sess cmd "" "" {})]
-          (println "Returning from" sess res)
-          (>! c res) (close! c)))
-    c))
+      (let [rs  (request-spots req)]
+        (debug "waiting for" rs "to be active")
+        (<! (timeout 1000))
+        (if (<! (patience-every #(= "active" %) #(request-status rs) 600 60))
+          (do (debug "All instances active! Returning" (assoc res :rs rs))
+              (>! out (assoc res :rs rs)))
+          (give-up-and-cancel res out "Requests failed.")
+)))
+    out))

                  (reset! a x))))
    a))

(defn request-status [rs]
  (let [d (describe-spot-instance-requests :spot-instance-request-ids rs)]
    (map :state (:spot-instance-requests d))))

(defn request-instances [rs]
  (let [d (describe-spot-instance-requests :spot-instance-request-ids rs)]
    (map :instance-id (:spot-instance-requests d))))

(defn dns-names [is]
  (loop [n 5]
    (let [ds    (:reservations (describe-instances :instance-ids is))
          names (map #(get-in % [:instances 0 :public-dns-name]) ds)]

(ns acyclic.awstools.core
  (:use [amazonica.core]
        [amazonica.aws.ec2]
        acyclic.utils.pinhole)
  (:require [clj-ssh.ssh :as ssh]
            [taoensso.timbre :as timbre]
            [ clojure.core.async :as async 
             :refer [<! >! <!! >!! timeout chan alt!! go close!]]))
(timbre/refer-timbre)

(def cred (read-string (slurp "AWS.clj")))

(apply defcredential (map cred [:access-key :secret-key :endpoint]))



(def ^{:private true} paths {:zone  [:launch-specification :placement :availability-zone]
                             :itype  [:launch-specification :instance-type]
                             :price [:spot-price]
                             :n     [:instance-count]})

(defmacro go-try [& forms]
  `(go (try (do ~@forms)
            (catch Exception e#
              (do (debug "Caught exception" e#) nil)))))

(defn patience
  "Invoke (genfn) every time-wait sec until predicate returns true or time-limit sec has passed.
Returns result of genfn, or nil in the case of timeout."
  [genfn pred failure time-limit time-wait]
  (let [t1     (timeout (* 1000 time-limit))
        out    (chan)]
    (async/go-loop []
      (let [rc     (go-try (genfn))
            [v c]  (async/alts! [rc t1 out])]
        (cond
         (= c out)                    (do (debug "Canceled")
                                          (when failure (failure)))
         (= c t1)                     (do (debug time-limit "sec expired")
                                          (when failure (failure))
                                          (close! out))
         (and (= c rc) v (pred v))    (do (debug "Returning" v)
                                          (>! out v))
         :else                        (do (debug "Still" v "Waiting" time-wait)
                                          (<! (timeout (* 1000 time-wait)))
                                          (recur)))))
    out))



(defn pluck [c]
  (let [a (atom nil)]
