Last active
July 31, 2018 16:33
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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