Created
April 15, 2015 21:19
-
-
Save franzinc/acde9fd04a6b07745db3 to your computer and use it in GitHub Desktop.
My script to alert me to Amazon AWS usage via email
This file contains hidden or 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
#! /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