Skip to content

Instantly share code, notes, and snippets.

@alandipert
Last active July 31, 2018 16:33
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save alandipert/d2cb38ee869448182c4b to your computer and use it in GitHub Desktop.
Save alandipert/d2cb38ee869448182c4b to your computer and use it in GitHub Desktop.
Example of querying AWS infrastructure with Amazonica and Datomic, in Clojure with Boot-clj
#!/usr/bin/env boot
;; or `BOOT_FILE=ec2query.boot boot repl' for interactive use
(set-env! :dependencies '[[amazonica "0.3.23"]
[com.datomic/datomic-free "0.9.5344"]])
(require '[amazonica.aws.ec2 :as ec2]
'[amazonica.core :refer [defcredential]]
'[boot.cli :refer [defclifn]]
'[boot.util :refer [info]]
'[datomic.api :refer [db q] :as d])
(defcredential
{:access-key (System/getenv "AWS_ACCESS_KEY")
:secret-key (System/getenv "AWS_SECRET_KEY")
:endpoint "us-east-1"})
(defn paths
"Enumerate set of paths in a nested map/vector."
([root]
(when (or (map? root) (vector? root))
(paths [] root)))
([parent x]
(cond (map? x)
(mapcat (fn [[k v]] (paths (conj parent k) v)) x)
(vector? x)
(mapcat #(paths (conj parent %1) %2) (range) x)
:else [parent])))
(defn map->tuples
"Returns every path and value in the map as a set of tuples, each prefixed
with the supplied id."
[id m]
(mapv #(conj % (get-in {id m} %)) (paths {id m})))
(def instances
(reify clojure.lang.IDeref
(deref [_]
(->> (ec2/describe-instances)
:reservations
(mapcat :instances)))))
(defn make-db [maps]
(mapcat #(map->tuples %1 %2) (range) maps))
(def +instance-states+
#{"pending" "running" "stopping" "stopped" "shutting-down" "terminated" "rebooting"})
(defn tags->tuples [id tag-map]
(when (seq tag-map)
(reduce-kv
#(let [e (gensym "?e")]
(into %1 [[id :tags e :key %2]
[id :tags e :value %3]]))
[]
tag-map)))
(defn get-instances [db state tag-map]
{:pre [(contains? +instance-states+ state)]}
(q (concat '[:find ?instance-id ?public-dns
:in $ ?state
:where
[?id :state :name ?state]
[?id :instance-id ?instance-id]
[?id :public-dns-name ?public-dns]]
(tags->tuples '?id tag-map))
db
state))
(defclifn -main
"Print out instance ids and public DNS names (if available) of instances in a particular state."
[s state STATE str "State of the instances to search for."
t tags KEY=VALUE {str str} "Tags to filter by (optional). For example: ./ec2query.boot -s running -t System=Reporting"]
(let [state (or state (do (info "No state supplied, defaulting to 'running'\n") "running"))]
(doseq [[id dns] (get-instances (make-db @instances) state tags)]
(println id dns))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment