Skip to content

Instantly share code, notes, and snippets.

@franzinc
Created April 15, 2015 21:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save franzinc/acde9fd04a6b07745db3 to your computer and use it in GitHub Desktop.
Save franzinc/acde9fd04a6b07745db3 to your computer and use it in GitHub Desktop.
My script to alert me to Amazon AWS usage via email
#! /fi/cl/9.0/bin/linuxamd64.64/mlisp -#D
(in-package :user)
(defparameter *instance-exceptions*
;; these instances are known to be running and are exceptions:
...)
(defparameter *volume-exceptions*
;; these instances are known to be running and are exceptions:
'...)
(eval-when (compile eval load)
(require :ssl)
(require :ec2 (probe-file "~/src/ec2.utils/ec2.fasl"))
(require :smtp)
(use-package :net.ec2)
(load "~/src/aws.cl"))
(defun string-to-keyword (string)
(intern string (load-time-value (find-package :keyword))))
(defun calculate-cost (instance)
(let ((hours (float (/ (- (get-universal-time)
(ec2-instance-launch-time instance))
3600))))
;; Return dollars
(* hours
(ecase (string-to-keyword (ec2-instance-instance-type instance))
;;;; from http://aws.amazon.com/ec2/pricing/
;; Current generation
(:t2.micro 0.013)
(:t2.small 0.026)
(:t2.medium 0.052)
(:m3.medium 0.070)
(:m3.large 0.140)
(:m3.xlarge 0.280)
(:m3.2xlarge 0.560)
(:c3.large 0.105)
(:c3.xlarge 0.210)
(:c3.2xlarge 0.420)
(:c3.4xlarge 0.840)
(:c3.8xlarge 1.680)
(:g2.2xlarge 0.650)
(:r3.large 0.175)
(:r3.xlarge 0.350)
(:r3.2xlarge 0.750)
(:r3.4xlarge 1.400)
(:r3.8xlarge 2.800)
(:i2.xlarge 0.853)
(:i2.2xlarge 1.705)
(:i2.4xlarge 3.410)
(:i2.8xlarge 6.820)
(:hs1.8xlarge 4.600)
;; Older generations
(:t1.micro 0.02)
(:m1.small 0.08)
(:m1.large 0.32)
(:m1.xlarge 0.64)
(:m2.xlarge 0.24)
(:m2.2xlarge 0.90)
(:m2.4xlarge 1.80)
(:c1.medium 0.165)
(:c1.xlarge 0.66)
(:cc1.4xlarge 1.30)
(:cc1.8xlarge 2.40) ;; not listed in 2011-12-15 API
(:cg1.4xlarge 2.10)
(:hi1.4xlarge 3.10)
))))
(defun my-describe-instance (instance &optional type)
(format t "~@[~a: ~]~a instance is ~a~%"
type
(ec2-instance-instance-type instance)
(ec2-instance-state-name instance))
(format t " IDENTITY: ~a~%"
(ec2-identity-keypair-name (ec2-instance-identity instance)))
(format t " instance: ~a~%" (ec2-instance-id instance))
(format t " hostname: ~a~%" (ec2-instance-dns-name instance))
(format t " state: ~a~%" (ec2-instance-state-name instance))
(format t " launched: ~:@/locale-format-time/~%"
(ec2-instance-launch-time instance))
(format t " key-name: ~a~%"
(ec2-instance-key-name instance))
(let ((load (ignore-errors ;; depends on the state of the instance
(query-load instance))))
(when load (format t " load: ~a~%" load)))
(format t " approximate cost: $~,2f~%" (calculate-cost instance))
(format t " (does not include S3, EBS, etc)~%")
(format t "~%"))
(defun my-describe-volume (vol &optional type)
(format t "~@[~a: ~]~a, ~a GB, ~a, ~a~%"
type
(ec2-volume-id vol)
(ec2-volume-size vol)
(ec2-volume-status vol)
(ec2-volume-create-time vol)))
(defun my-describe-snapshot (snap image)
(format t "~a, volid ~a, ~a, ~a~%"
(ec2-snapshot-id snap)
(ec2-snapshot-volume-id snap)
(ec2-snapshot-status snap)
(ec2-snapshot-start-time snap))
(when image
(format t " AMI: ~a: ~a~%"
(ec2-image-id image)
(ec2-image-location image))))
(defun snapshot-to-image (snap images)
(dolist (image images)
(dolist (bdm (ec2-image-block-device-mapping image))
(when (and (ec2-block-device-mapping-snapshot-id bdm)
(string= (ec2-snapshot-id snap)
(ec2-block-device-mapping-snapshot-id bdm)))
(return-from snapshot-to-image image)))))
;; Over each identity and region, print the instances and volumes that
;; exist.
;;
(sys:with-command-line-arguments ("sv" snapshots verbose) (rest)
(declare (ignore rest))
;; force to non-nil on first day of the month
(setq snapshots
(or snapshots
(= 1 (nth-value 3 (decode-universal-time (get-universal-time))))))
(let (instance-exceptions volume-exceptions)
(dolist (identity *identities*)
(setq instance-exceptions
(cdr (assoc (ec2-identity-keypair-name identity)
*instance-exceptions*
:test #'string=)))
(setq volume-exceptions
(cdr (assoc (ec2-identity-keypair-name identity)
*volume-exceptions*
:test #'string=)))
(dolist (region (describe-regions :identity identity))
(let* ((announce (lambda ()
(format t "~%;; Identity: ~a, Region ~a:~%"
(ec2-identity-keypair-name identity)
(ec2-region-name region))))
(id (copy-ec2-identity identity :region region))
images)
(dolist (instance (describe-instances :identity id))
(if* (member (ec2-instance-id instance) instance-exceptions
:test #'string=)
then (when verbose
(when announce (funcall announce) (setq announce nil))
(my-describe-instance instance "Excluded"))
else (when announce (funcall announce) (setq announce nil))
(my-describe-instance instance)))
(dolist (volume (describe-volumes :identity id))
(if* (member (ec2-volume-id volume) volume-exceptions
:test #'string=)
then (when verbose
(when announce (funcall announce) (setq announce nil))
(my-describe-volume volume "Excluded"))
else (when announce (funcall announce) (setq announce nil))
(my-describe-volume volume)))
(when snapshots
(setq images
(describe-images
:identity id
:filters `(("owner-id" ,(ec2-identity-account-number id)))))
(dolist (snapshot (describe-snapshots
:identity id
:filters `(("owner-id"
,(ec2-identity-account-number id)))))
(when announce (funcall announce) (setq announce nil))
(my-describe-snapshot snapshot
(snapshot-to-image snapshot images)))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment