aws_auditor 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a8fb7ab9b3d04b41fb21c6640e2c4de2a469799
4
- data.tar.gz: b2ab26ed6fc4707deb07ae35d3f149d7e0340c7a
3
+ metadata.gz: 3aaac3737b9cf61e89d42dc0bb7d553a60190e79
4
+ data.tar.gz: e1b1852944cdf66ea8f4766ddcb297ad001e5ebe
5
5
  SHA512:
6
- metadata.gz: d8826b6b49c204399655aa81c10be4364ff898f52c9318434fe20165b943927d9afe0d93bdb773c0b6de9e4c366d688ebb9c3caac4ab982dbcd15a3cc9a69d6f
7
- data.tar.gz: eae728c9c0221dbc66d7d7559c588f5dfe15e79346ce77b77ed00dddbd6125b4ff5b98cf84833a4eef8ce77d62440cc381a46b0e30e2c93aae2dc7d08f2128af
6
+ metadata.gz: edb9b18f94fd362a32eefa44577cdb050985338bbcf93bed4c281103bb60578a42ebce033bbabf08187966a06971e72ab84b3b94bf1f87d77d1c338959d10711
7
+ data.tar.gz: 1d51d364acc3d5152a1da77e4e1d9ecfa5041ba0843d99a8ac437a814164143f165e9bbaddb186d98a5034f08da714728b34759b6e0d2f8444b67c0fe2f174b2
data/.gitignore CHANGED
@@ -14,4 +14,5 @@
14
14
  mkmf.log
15
15
 
16
16
  .aws.yml
17
+ .google.yml
17
18
  *.gem
data/README.md CHANGED
@@ -18,27 +18,45 @@ Or install it yourself as:
18
18
 
19
19
  $ gem install aws_auditor
20
20
 
21
- ## Usage
21
+ ## How-to
22
22
 
23
- Create a `.aws.yml` file in the root directory, with the following structure.
23
+ ### AWS Setup
24
+ Create a `.aws.yml` file in the root directory with the following structure.
24
25
 
25
26
  ```yaml
26
27
  ---
27
28
  account1:
28
29
  access_key_id: 'ACCESS_KEY_ID'
29
- secret_access_key: 'SECRET_ACCESS_KEY
30
+ secret_access_key: 'SECRET_ACCESS_KEY'
30
31
  account2:
31
32
  access_key_id: 'ACCESS_KEY_ID'
32
33
  secret_access_key: 'SECRET_ACCESS_KEY
33
34
  ```
34
35
 
36
+ ### Google Setup (optional)
37
+ You can export audit information to a Google Spreadsheet, but you must first create a `.google.yml` in the root directory with the following structure.
38
+
39
+ ```yaml
40
+ ---
41
+ login:
42
+ email: 'GOOGLE_EMAIL_ADDRESS'
43
+ password: 'GOOGLE_EMAIL_PASSWORD'
44
+ file:
45
+ path: 'DESIRED_PATH_TO_FILE' #optional, creates in root directory otherwise
46
+ name: 'NAME_OF_FILE'
47
+ ```
48
+
35
49
  To find discrepancies between number of running instances and purchased instances, run:
36
50
 
37
51
  $ aws_auditor audit account1
38
52
 
39
- To list instances for all stacks in your account, run:
53
+ To list running instances for all stacks in your account, run:
54
+
55
+ $ aws_auditor inspect account1
56
+
57
+ To export audit information to a Google Spreadsheet, make sure you added a `.google.yml` and run:
40
58
 
41
- $ aws_auditor stack-audit account1
59
+ $ aws_auditor export account1
42
60
 
43
61
  ## Contributing
44
62
 
data/aws_auditor.gemspec CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency 'aws-sdk', '~>1'
22
22
  spec.add_dependency 'hashie', '~> 3.3'
23
23
  spec.add_dependency 'gli', '~> 2.10'
24
+ spec.add_dependency 'highline', '~> 1.6'
25
+ spec.add_dependency 'google_drive', '~> 0.3'
24
26
 
25
27
  spec.add_development_dependency "bundler", "~> 1.7"
26
28
  spec.add_development_dependency "rake", "~> 10.0"
@@ -0,0 +1,38 @@
1
+ require_relative './instance_helper'
2
+
3
+ module AwsAuditor
4
+ class CacheInstance
5
+ extend InstanceHelper
6
+ extend CacheWrapper
7
+
8
+ attr_accessor :id, :name, :instance_type, :engine, :count
9
+ def initialize(cache_instance)
10
+ @id = cache_instance[:cache_cluster_id] || cache_instance[:reserved_cache_node_id]
11
+ @name = cache_instance[:cache_cluster_id] || cache_instance[:reserved_cache_node_id]
12
+ @instance_type = cache_instance[:cache_node_type]
13
+ @engine = cache_instance[:engine] || cache_instance[:product_description]
14
+ @count = cache_instance[:cache_node_count] || 1
15
+ end
16
+
17
+ def to_s
18
+ "#{engine} #{instance_type}"
19
+ end
20
+
21
+ def self.get_instances
22
+ instances = cache.describe_cache_clusters[:cache_clusters]
23
+ instances.map do |instance|
24
+ next unless instance[:cache_cluster_status].to_s == 'available'
25
+ new(instance)
26
+ end if instances
27
+ end
28
+
29
+ def self.get_reserved_instances
30
+ instances = cache.describe_reserved_cache_nodes[:reserved_db_instances]
31
+ instances.map do |instance|
32
+ next unless instance[:state].to_s == 'active'
33
+ new(instance)
34
+ end if instances
35
+ end
36
+
37
+ end
38
+ end
@@ -1,7 +1,14 @@
1
+ arg :aws_account
1
2
  desc 'Reviews Reserved Instances'
2
3
  command 'audit' do |c|
4
+ c.switch [:e, :ec2], :desc => "Only audit EC2 instances"
5
+ c.switch [:d, :rds], :desc => "Only audit RDS instances"
6
+ c.switch [:c, :cache], :desc => "Only audit ElastiCache instances"
7
+ c.switch [:r, :reserved], :desc => "Shows reserved instance counts"
8
+ c.switch [:i, :instances], :desc => "Shows current instance counts"
3
9
  c.action do |global_options, options, args|
4
10
  require_relative '../scripts/audit'
5
- AwsAuditor::Scripts::Audit.execute args.first
11
+ raise ArgumentError, 'You must specify an AWS account' unless args.first
12
+ AwsAuditor::Scripts::Audit.execute(args.first,options)
6
13
  end
7
14
  end
@@ -0,0 +1,9 @@
1
+ arg :aws_account
2
+ desc 'Reviews Reserved Instances'
3
+ command 'export' do |c|
4
+ c.action do |global_options, options, args|
5
+ require_relative '../scripts/export'
6
+ raise ArgumentError, 'You must specify an AWS account' unless args.first
7
+ AwsAuditor::Scripts::Export.execute(args.first, options)
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ arg :aws_account
2
+ desc 'Reviews Stack Instances'
3
+ command 'inspect' do |c|
4
+ c.switch [:e, :ec2], :desc => "Only audit EC2 instances"
5
+ c.switch [:d, :rds], :desc => "Only audit RDS instances"
6
+ c.switch [:c, :cache], :desc => "Only audit ElastiCache instances"
7
+ c.action do |global_options, options, args|
8
+ require_relative '../scripts/inspect'
9
+ raise ArgumentError, 'You must specify an AWS account' unless args.first
10
+ AwsAuditor::Scripts::Inspect.execute(args.first,options)
11
+ end
12
+ end
@@ -1,4 +1,5 @@
1
1
  require_relative './aws'
2
+ require_relative './google'
2
3
 
3
4
  module AwsAuditor
4
5
  module AWSWrapper
@@ -13,7 +14,7 @@ module AwsAuditor
13
14
  attr_accessor :ec2
14
15
 
15
16
  def ec2
16
- @ec2 ||= AWS::EC2.new()
17
+ @ec2 ||= AWS::EC2.new
17
18
  end
18
19
  end
19
20
 
@@ -24,5 +25,29 @@ module AwsAuditor
24
25
  @opsworks ||= AWS::OpsWorks.new.client
25
26
  end
26
27
  end
28
+
29
+ module RDSWrapper
30
+ attr_accessor :rds
31
+
32
+ def rds
33
+ @rds ||= AWS::RDS.new.client
34
+ end
35
+ end
36
+
37
+ module CacheWrapper
38
+ attr_accessor :cache
39
+
40
+ def cache
41
+ @cache ||= AWS::ElastiCache.new.client
42
+ end
43
+ end
44
+
45
+ module GoogleWrapper
46
+ attr_accessor :google
47
+
48
+ def google
49
+ @google ||= AwsAuditor::Google.configuration
50
+ end
51
+ end
27
52
 
28
53
  end
@@ -1,13 +1,16 @@
1
+ require_relative './instance_helper'
2
+
1
3
  module AwsAuditor
2
- class Instance
4
+ class EC2Instance
5
+ extend InstanceHelper
3
6
  extend EC2Wrapper
4
7
 
5
8
  attr_accessor :id, :platform, :availability_zone, :instance_type, :count
6
- def initialize(aws_instance, count=1)
7
- @id = aws_instance.id
8
- @platform = platform_helper(aws_instance)
9
- @availability_zone = aws_instance.availability_zone
10
- @instance_type = aws_instance.instance_type
9
+ def initialize(ec2_instance, count=1)
10
+ @id = ec2_instance.id
11
+ @platform = platform_helper(ec2_instance)
12
+ @availability_zone = ec2_instance.availability_zone
13
+ @instance_type = ec2_instance.instance_type
11
14
  @count = count
12
15
  end
13
16
 
@@ -15,12 +18,12 @@ module AwsAuditor
15
18
  "#{@platform} #{@availability_zone} #{@instance_type}"
16
19
  end
17
20
 
18
- def platform_helper(aws_instance)
19
- if aws_instance.class.to_s == 'AWS::EC2::Instance'
20
- if aws_instance.vpc?
21
+ def platform_helper(ec2_instance)
22
+ if ec2_instance.class.to_s == 'AWS::EC2::Instance'
23
+ if ec2_instance.vpc?
21
24
  return 'VPC'
22
- elsif aws_instance.platform
23
- if aws_instance.platform.downcase.include? 'windows'
25
+ elsif ec2_instance.platform
26
+ if ec2_instance.platform.downcase.include? 'windows'
24
27
  return 'Windows'
25
28
  else
26
29
  return 'Linux'
@@ -28,10 +31,10 @@ module AwsAuditor
28
31
  else
29
32
  return 'Linux'
30
33
  end
31
- elsif aws_instance.class.to_s == 'AWS::EC2::ReservedInstances'
32
- if aws_instance.product_description.downcase.include? 'vpc'
34
+ elsif ec2_instance.class.to_s == 'AWS::EC2::ReservedInstances'
35
+ if ec2_instance.product_description.downcase.include? 'vpc'
33
36
  return 'VPC'
34
- elsif aws_instance.product_description.downcase.include? 'windows'
37
+ elsif ec2_instance.product_description.downcase.include? 'windows'
35
38
  return 'Windows'
36
39
  else
37
40
  return 'Linux'
@@ -43,7 +46,7 @@ module AwsAuditor
43
46
  instances = ec2.instances
44
47
  instances.map do |instance|
45
48
  next unless instance.status.to_s == 'running'
46
- Instance.new(instance)
49
+ new(instance)
47
50
  end if instances
48
51
  end
49
52
 
@@ -51,12 +54,9 @@ module AwsAuditor
51
54
  reserved_instances = ec2.reserved_instances
52
55
  reserved_instances.map do |ri|
53
56
  next unless ri.state == 'active'
54
- Instance.new(ri, ri.instance_count)
57
+ new(ri, ri.instance_count)
55
58
  end if reserved_instances
56
59
  end
57
60
 
58
- def self.instance_hash
59
- Hash[get_instances.map {|instance| [instance.id, instance]}]
60
- end
61
61
  end
62
62
  end
@@ -0,0 +1,40 @@
1
+ module AwsAuditor
2
+ class GoogleConfig < Hash
3
+ include Hashie::Extensions::IndifferentAccess
4
+ end
5
+
6
+ class Google
7
+ FILE_NAMES = %w[.google.yml]
8
+
9
+ def self.configuration
10
+ credentials = load_config[:login]
11
+ GoogleDrive.login(credentials[:email],credentials[:password])
12
+ end
13
+
14
+ def self.file
15
+ load_config[:file]
16
+ end
17
+
18
+ def self.load_config
19
+ return @config if @config
20
+ @config = GoogleConfig[YAML.load_file(config_path)]
21
+ end
22
+
23
+ def self.config_path
24
+ if filepath = FILE_NAMES.detect {|filename| File.exists?(filename)}
25
+ File.join(Dir.pwd, filepath)
26
+ else
27
+ old_dir = Dir.pwd
28
+ Dir.chdir('..')
29
+ if old_dir != Dir.pwd
30
+ config_path
31
+ else
32
+ puts "Could not find #{FILE_NAMES.join(' or ')}"
33
+ exit
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+
@@ -0,0 +1,80 @@
1
+ require 'google_drive'
2
+
3
+ module AwsAuditor
4
+ class GoogleSheet
5
+ extend GoogleWrapper
6
+
7
+ attr_accessor :sheet, :worksheet, :path
8
+ def initialize(title, path, environment)
9
+ @sheet = self.class.create_sheet(title, path)
10
+ @worksheet = self.class.worksheet(sheet, environment)
11
+ end
12
+
13
+ def write_header(header)
14
+ worksheet.list.keys = header.unshift('name')
15
+ worksheet.save
16
+ end
17
+
18
+ def write_row(value_hash)
19
+ worksheet.list.push(value_hash)
20
+ worksheet.save
21
+ end
22
+
23
+ def self.first_or_create(title)
24
+ spreadsheet = google.root_collection.files("title" => title, "title-exact" => true)[0]
25
+ spreadsheet ? spreadsheet : google.create_spreadsheet(title)
26
+ end
27
+
28
+ #returns a spreadsheet object
29
+ def self.create_sheet(title, path)
30
+ folder = go_to_collection(path) if path
31
+ if folder
32
+ spreadsheet = folder.files("title" => title, "title-exact" => true)[0]
33
+ if spreadsheet
34
+ return spreadsheet
35
+ else
36
+ file = first_or_create(title)
37
+ folder.add(file)
38
+ google.root_collection.remove(file)
39
+ return folder.files("title" => title, "title-exact" => true)[0]
40
+ end
41
+ else
42
+ first_or_create(title)
43
+ end
44
+ end
45
+
46
+ #returns a worksheet object
47
+ def self.worksheet(spreadsheet, title)
48
+ worksheet = spreadsheet.worksheet_by_title(title)
49
+ worksheet ? delete_all_rows(worksheet) : spreadsheet.add_worksheet(title)
50
+ end
51
+
52
+ #returns a collection object
53
+ def self.go_to_collection(directory)
54
+ if directory
55
+ path = directory.split('/')
56
+ go_to_subcollection(google.collection_by_title(path[0]),path[1..-1])
57
+ end
58
+ end
59
+
60
+ #returns a collection object
61
+ def self.go_to_subcollection(base, subs)
62
+ puts "Folder doesn't exist in specified path" and exit if base.nil?
63
+ if subs.empty?
64
+ return base
65
+ else
66
+ base = base.subcollection_by_title(subs[0])
67
+ go_to_subcollection(base,subs[1..-1])
68
+ end
69
+ end
70
+
71
+ def self.delete_all_rows(worksheet)
72
+ worksheet.list.each do |row|
73
+ row.clear
74
+ end
75
+ worksheet.save
76
+ worksheet
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ module AwsAuditor
2
+ module InstanceHelper
3
+ def instance_hash
4
+ Hash[get_instances.map { |instance| instance.nil? ? next : [instance.id, instance]}.compact]
5
+ end
6
+
7
+ def instance_count_hash(instances)
8
+ instance_hash = Hash.new()
9
+ instances.each do |instance|
10
+ next if instance.nil?
11
+ instance_hash[instance.to_s] = instance_hash.has_key?(instance.to_s) ? instance_hash[instance.to_s] + instance.count : instance.count
12
+ end if instances
13
+ instance_hash
14
+ end
15
+
16
+ def compare
17
+ differences = Hash.new()
18
+ instances = instance_count_hash(get_instances)
19
+ ris = instance_count_hash(get_reserved_instances)
20
+ instances.keys.concat(ris.keys).uniq.each do |key|
21
+ instance_count = instances.has_key?(key) ? instances[key] : 0
22
+ ris_count = ris.has_key?(key) ? ris[key] : 0
23
+ differences[key] = ris_count - instance_count
24
+ end
25
+ differences
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ require_relative './instance_helper'
2
+
3
+ module AwsAuditor
4
+ class RDSInstance
5
+ extend InstanceHelper
6
+ extend RDSWrapper
7
+
8
+ attr_accessor :id, :name, :multi_az, :instance_type, :engine, :count
9
+ def initialize(rds_instance)
10
+ @id = rds_instance[:db_instance_identifier] || rds_instance[:reserved_db_instances_offering_id]
11
+ @name = rds_instance[:db_instance_identifier] || rds_instance[:db_name]
12
+ @multi_az = rds_instance[:multi_az]
13
+ @instance_type = rds_instance[:db_instance_class]
14
+ @engine = rds_instance[:engine] || rds_instance[:product_description]
15
+ @count = rds_instance[:db_instance_count] || 1
16
+ end
17
+
18
+ def to_s
19
+ "#{engine_helper} #{multi_az?} #{instance_type}"
20
+ end
21
+
22
+ def multi_az?
23
+ multi_az ? "Multi-AZ" : "Single-AZ"
24
+ end
25
+
26
+ def engine_helper
27
+ if engine.downcase.include? "post"
28
+ return "PostgreSQL"
29
+ elsif engine.downcase.include? "mysql"
30
+ return "MySQL"
31
+ end
32
+ end
33
+
34
+ def self.get_instances
35
+ instances = rds.describe_db_instances[:db_instances]
36
+ instances.map do |instance|
37
+ next unless instance[:db_instance_status].to_s == 'available'
38
+ new(instance)
39
+ end
40
+ end
41
+
42
+ def self.get_reserved_instances
43
+ instances = rds.describe_reserved_db_instances[:reserved_db_instances]
44
+ instances.map do |instance|
45
+ next unless instance[:state].to_s == 'active'
46
+ new(instance)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -1,36 +1,87 @@
1
+ require 'highline/import'
2
+
1
3
  module AwsAuditor
2
4
  module Scripts
3
5
  class Audit
4
6
  extend AWSWrapper
5
- extend EC2Wrapper
6
7
 
7
- def self.execute(environment)
8
+ def self.execute(environment, options=nil)
8
9
  aws(environment)
9
- compare.each do |key,value|
10
- puts "#{key}: #{value}"
10
+ if options[:ec2]
11
+ audit_ec2(options)
12
+ elsif options[:rds]
13
+ audit_rds(options)
14
+ elsif options[:cache]
15
+ audit_cache(options)
16
+ else
17
+ audit_ec2(options)
18
+ audit_rds(options)
19
+ audit_cache(options)
20
+ end
21
+
22
+ end
23
+
24
+ def self.audit_rds(options)
25
+ puts "=============== RDS ==============="
26
+ if options[:instances]
27
+ RDSInstance.instance_count_hash(RDSInstance.get_instances).each do |key,value|
28
+ say "<%= color('#{key}: #{value}', :white) %>"
29
+ end
30
+ elsif options[:reserved]
31
+ RDSInstance.instance_count_hash(RDSInstance.get_reserved_instances).each do |key,value|
32
+ say "<%= color('#{key}: #{value}', :white) %>"
33
+ end
34
+ else
35
+ RDSInstance.compare.each do |key, value|
36
+ colorize(key,value)
37
+ end
11
38
  end
12
39
  end
13
40
 
14
- def self.create_instance_hash(instance_type)
15
- instance_hash = Hash.new()
16
- instance_type.each do |instance|
17
- next if instance.nil?
18
- instance_hash[instance.to_s] = instance_hash.has_key?(instance.to_s) ? instance_hash[instance.to_s] + instance.count : instance.count
41
+ def self.audit_ec2(options)
42
+ puts "=============== EC2 ==============="
43
+ if options[:instances]
44
+ EC2Instance.instance_count_hash(EC2Instance.get_instances).each do |key,value|
45
+ say "<%= color('#{key}: #{value}', :white) %>"
46
+ end
47
+ elsif options[:reserved]
48
+ EC2Instance.instance_count_hash(EC2Instance.get_reserved_instances).each do |key,value|
49
+ say "<%= color('#{key}: #{value}', :white) %>"
50
+ end
51
+ else
52
+ EC2Instance.compare.each do |key,value|
53
+ colorize(key,value)
54
+ end
19
55
  end
20
- instance_hash
21
56
  end
22
57
 
23
- def self.compare
24
- differences = Hash.new()
25
- instances = create_instance_hash(Instance.get_instances)
26
- ris = create_instance_hash(Instance.get_reserved_instances)
27
- instances.keys.concat(ris.keys).uniq.each do |key|
28
- instance_count = instances.has_key?(key) ? instances[key] : 0
29
- ris_count = ris.has_key?(key) ? ris[key] : 0
30
- differences[key] = ris_count - instance_count
58
+ def self.audit_cache(options)
59
+ puts "============== CACHE =============="
60
+ if options[:instances]
61
+ CacheInstance.instance_count_hash(CacheInstance.get_instances).each do |key,value|
62
+ say "<%= color('#{key}: #{value}', :white) %>"
63
+ end
64
+ elsif options[:reserved]
65
+ CacheInstance.instance_count_hash(CacheInstance.get_reserved_instances).each do |key,value|
66
+ say "<%= color('#{key}: #{value}', :white) %>"
67
+ end
68
+ else
69
+ CacheInstance.compare.each do |key,value|
70
+ colorize(key,value)
71
+ end
31
72
  end
32
- differences
33
73
  end
74
+
75
+ def self.colorize(key,value)
76
+ if value < 0
77
+ say "<%= color('#{key}: #{value}', :yellow) %>"
78
+ elsif value == 0
79
+ say "<%= color('#{key}: #{value}', :green) %>"
80
+ elsif value > 0
81
+ say "<%= color('#{key}: #{value}', :red) %>"
82
+ end
83
+ end
84
+
34
85
  end
35
86
  end
36
87
  end
@@ -0,0 +1,98 @@
1
+ require_relative "../google"
2
+
3
+ module AwsAuditor
4
+ module Scripts
5
+ class Export
6
+ extend GoogleWrapper
7
+ extend AWSWrapper
8
+
9
+ def self.execute(environment, options = nil)
10
+ aws(environment)
11
+ file = GoogleSheet.new(Google.file[:name], Google.file[:path], environment)
12
+ file.write_header(get_all_keys)
13
+ write_opsworks_stacks(file)
14
+ write_rds(file)
15
+ write_cache(file)
16
+ write_totals(file)
17
+ `open #{file.sheet.human_url}`
18
+ end
19
+
20
+ def self.write_opsworks_stacks(file)
21
+ file.write_row({name: "EC2"})
22
+ opsworks_stacks.each do |stack|
23
+ next if stack.instances.empty?
24
+ value_hash = EC2Instance.instance_count_hash(stack.instances)
25
+ value_hash[:name] = stack.name
26
+ file.write_row(value_hash)
27
+ end
28
+ end
29
+
30
+ def self.write_rds(file)
31
+ file.write_row({name: "RDS"})
32
+ rds_instances.each do |db|
33
+ value_hash = Hash({:name => db.name, :"#{db.to_s}" => '1'})
34
+ file.write_row(value_hash)
35
+ end
36
+ end
37
+
38
+ def self.write_cache(file)
39
+ file.write_row({name: "CACHE"})
40
+ cache_instances.each do |cache|
41
+ value_hash = Hash({:name => cache.name, :"#{cache.to_s}" => '1'})
42
+ file.write_row(value_hash)
43
+ end
44
+ end
45
+
46
+ def self.write_totals(file)
47
+ file.write_row({name: "TOTALS"})
48
+ instance_counts = get_all_instance_counts.merge({name: "Running Instances"})
49
+ file.write_row(instance_counts)
50
+ reserved_counts = get_all_reserved_counts.merge({name: "Reserved Instances"})
51
+ file.write_row(reserved_counts)
52
+ differences = get_difference_counts.merge({name: "Differences"})
53
+ file.write_row(differences)
54
+ end
55
+
56
+ def self.get_all_keys
57
+ ec2 = EC2Instance.instance_hash.values.map{ |x| x.to_s }.uniq.sort! { |a,b| a.downcase <=> b.downcase }
58
+ rds = RDSInstance.instance_hash.values.map{ |x| x.to_s }.uniq.sort! { |a,b| a.downcase <=> b.downcase }
59
+ cache = CacheInstance.instance_hash.values.map{ |x| x.to_s }.uniq.sort! { |a,b| a.downcase <=> b.downcase }
60
+ ec2.concat(rds).concat(cache).compact
61
+ end
62
+
63
+ def self.get_all_instance_counts
64
+ ec2 = EC2Instance.instance_count_hash(EC2Instance.get_instances)
65
+ rds = RDSInstance.instance_count_hash(RDSInstance.get_instances)
66
+ cache = CacheInstance.instance_count_hash(CacheInstance.get_instances)
67
+ ec2.merge(rds).merge(cache)
68
+ end
69
+
70
+ def self.get_all_reserved_counts
71
+ ec2 = EC2Instance.instance_count_hash(EC2Instance.get_reserved_instances)
72
+ rds = RDSInstance.instance_count_hash(RDSInstance.get_reserved_instances)
73
+ cache = CacheInstance.instance_count_hash(CacheInstance.get_reserved_instances)
74
+ ec2.merge(rds).merge(cache)
75
+ end
76
+
77
+ def self.get_difference_counts
78
+ ec2 = EC2Instance.compare
79
+ rds = RDSInstance.compare
80
+ cache = CacheInstance.compare
81
+ ec2.merge(rds).merge(cache)
82
+ end
83
+
84
+ def self.opsworks_stacks
85
+ @opsworks_stacks ||= Stack.all
86
+ end
87
+
88
+ def self.rds_instances
89
+ @rds_instances ||= RDSInstance.get_instances
90
+ end
91
+
92
+ def self.cache_instances
93
+ @cache_instances ||= CacheInstance.get_instances
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,48 @@
1
+ module AwsAuditor
2
+ module Scripts
3
+ class Inspect
4
+ extend AWSWrapper
5
+ extend OpsWorksWrapper
6
+
7
+ def self.execute(environment, options=nil)
8
+ aws(environment)
9
+ if options[:ec2]
10
+ inspect_stacks
11
+ elsif options[:rds]
12
+ inspect_dbs
13
+ elsif options[:cache]
14
+ inspect_caches
15
+ else
16
+ puts "You must use a switch. See `aws-auditor inspect --help` for more info."
17
+ end
18
+ end
19
+
20
+ def self.inspect_stacks
21
+ Stack.all.each do |stack|
22
+ stack.pretty_print
23
+ end
24
+ end
25
+
26
+ def self.inspect_dbs
27
+ RDSInstance.get_instances.each do |db|
28
+ puts "========================"
29
+ puts "#{db.name}"
30
+ puts "========================"
31
+ puts db.to_s
32
+ puts "\n"
33
+ end
34
+ end
35
+
36
+ def self.inspect_caches
37
+ CacheInstance.get_instances.each do |cache|
38
+ puts "========================"
39
+ puts "#{cache.name}"
40
+ puts "========================"
41
+ puts cache.to_s
42
+ puts "\n"
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,5 @@
1
+ require 'highline/import'
2
+
1
3
  module AwsAuditor
2
4
  class Stack
3
5
  extend OpsWorksWrapper
@@ -14,7 +16,13 @@ module AwsAuditor
14
16
  instances = self.class.opsworks.describe_instances({stack_id: id})[:instances]
15
17
  instances.map do |instance|
16
18
  next unless instance[:status].to_s == 'online'
17
- all_instances[instance[:ec2_instance_id]].to_s
19
+ self.class.all_instances[instance[:ec2_instance_id]]
20
+ end
21
+ end
22
+
23
+ def print_instances
24
+ EC2Instance.instance_count_hash(self.instances).each do |key,value|
25
+ say "<%= color('#{key}: #{value}', :white) %>"
18
26
  end
19
27
  end
20
28
 
@@ -22,14 +30,19 @@ module AwsAuditor
22
30
  puts "----------------------------------"
23
31
  puts "#{@name}"
24
32
  puts "----------------------------------"
25
- instances.each do |instance|
26
- puts instance.to_s
27
- end
33
+ print_instances
28
34
  puts "\n"
29
35
  end
36
+
37
+ def self.all
38
+ stacks = opsworks.describe_stacks
39
+ stacks.data[:stacks].map do |stack|
40
+ new(stack)
41
+ end.sort! { |a,b| a.name.downcase <=> b.name.downcase } if stacks
42
+ end
30
43
 
31
- def all_instances
32
- @all_instances ||= Instance.instance_hash
44
+ def self.all_instances
45
+ @all_instances ||= EC2Instance.instance_hash
33
46
  end
34
47
 
35
48
  end
@@ -1,3 +1,3 @@
1
1
  module AwsAuditor
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/aws_auditor.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  require 'aws_auditor/version'
2
2
  require_relative 'aws_auditor/convenience_wrappers'
3
- require_relative 'aws_auditor/instance'
3
+ require_relative 'aws_auditor/ec2_instance'
4
+ require_relative 'aws_auditor/rds_instance'
5
+ require_relative 'aws_auditor/cache_instance'
4
6
  require_relative 'aws_auditor/stack'
7
+ require_relative 'aws_auditor/google_sheet'
5
8
 
6
9
  module AwsAuditor
7
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_auditor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elliot Hursh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-27 00:00:00.000000000 Z
11
+ date: 2014-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: highline
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: google_drive
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.3'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: bundler
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -99,12 +127,19 @@ files:
99
127
  - bin/aws-auditor
100
128
  - lib/aws_auditor.rb
101
129
  - lib/aws_auditor/aws.rb
130
+ - lib/aws_auditor/cache_instance.rb
102
131
  - lib/aws_auditor/commands/audit.rb
103
- - lib/aws_auditor/commands/stack-audit.rb
132
+ - lib/aws_auditor/commands/export.rb
133
+ - lib/aws_auditor/commands/inspect.rb
104
134
  - lib/aws_auditor/convenience_wrappers.rb
105
- - lib/aws_auditor/instance.rb
135
+ - lib/aws_auditor/ec2_instance.rb
136
+ - lib/aws_auditor/google.rb
137
+ - lib/aws_auditor/google_sheet.rb
138
+ - lib/aws_auditor/instance_helper.rb
139
+ - lib/aws_auditor/rds_instance.rb
106
140
  - lib/aws_auditor/scripts/audit.rb
107
- - lib/aws_auditor/scripts/stack-audit.rb
141
+ - lib/aws_auditor/scripts/export.rb
142
+ - lib/aws_auditor/scripts/inspect.rb
108
143
  - lib/aws_auditor/stack.rb
109
144
  - lib/aws_auditor/version.rb
110
145
  homepage: https://github.com/elliothursh/aws_auditor
@@ -1,8 +0,0 @@
1
- arg :environment
2
- desc 'Reviews Stack Instances'
3
- command 'stack-audit' do |c|
4
- c.action do |global_options, options, args|
5
- require_relative '../scripts/stack-audit'
6
- AwsAuditor::Scripts::StackAudit.execute args.first
7
- end
8
- end
@@ -1,24 +0,0 @@
1
- module AwsAuditor
2
- module Scripts
3
- class StackAudit
4
- extend AWSWrapper
5
- extend EC2Wrapper
6
- extend OpsWorksWrapper
7
-
8
- def self.execute(environment)
9
- aws(environment)
10
- get_stacks
11
- end
12
-
13
- def self.get_stacks
14
- stacks = opsworks.describe_stacks
15
- stacks.data[:stacks].map do |stack|
16
- stck = Stack.new(stack)
17
- stck.pretty_print
18
- stck
19
- end if stacks
20
- end
21
-
22
- end
23
- end
24
- end