aws_tracker 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +111 -0
- data/Rakefile +9 -0
- data/aws_tracker.gemspec +33 -0
- data/bin/tracker +104 -0
- data/config/database.yml.example +4 -0
- data/db/migrate/20110331145142_create_aws_accounts.rb +16 -0
- data/db/migrate/20110331152735_create_instances.rb +38 -0
- data/db/migrate/20110403041402_create_security_groups.rb +16 -0
- data/db/migrate/20110403060000_create_instance_groups.rb +14 -0
- data/db/migrate/20110404014218_create_ebs_volumes.rb +23 -0
- data/db/migrate/20110408193824_create_tags.rb +17 -0
- data/lib/aws_tracker/models/aws_account.rb +69 -0
- data/lib/aws_tracker/models/ebs_volume.rb +55 -0
- data/lib/aws_tracker/models/instance.rb +71 -0
- data/lib/aws_tracker/models/security_group.rb +34 -0
- data/lib/aws_tracker/models/tag.rb +66 -0
- data/lib/aws_tracker/tracker.rb +64 -0
- data/lib/aws_tracker/version.rb +3 -0
- data/lib/aws_tracker.rb +17 -0
- data/lib/tasks/bundler.rake +1 -0
- data/lib/tasks/database.rake +21 -0
- data/lib/tasks/rspec.rake +6 -0
- data/spec/lib/aws_tracker/models/aws_account_spec.rb +103 -0
- data/spec/lib/aws_tracker/models/ebs_volume_spec.rb +97 -0
- data/spec/lib/aws_tracker/models/instance_spec.rb +96 -0
- data/spec/lib/aws_tracker/models/security_group_spec.rb +71 -0
- data/spec/lib/aws_tracker/models/tag_spec.rb +76 -0
- data/spec/lib/aws_tracker/tracker_spec.rb +50 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/_configure_logging.rb +8 -0
- data/spec/support/create_testing_objects.rb +30 -0
- metadata +178 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
AWS Tracker
|
2
|
+
================
|
3
|
+
Models the state of one or more Amazon Web Services accounts in an ActiveRecord object graph.
|
4
|
+
|
5
|
+
*ALPHA VERSION - not yet fully functional*
|
6
|
+
|
7
|
+
|
8
|
+
----------------
|
9
|
+
What is it?
|
10
|
+
----------------
|
11
|
+
The AWS Tracker monitors one or more AWS accounts and the current state of their associated "resources" -- Instances, EBS volumes, RDS servers, and so on. The Tracker periodically polls the Amazon Web Services API for the latest information on each account's resources, and then maintains the corresponding rows in an ActiveRecord-compatible database. Users of the library can thereafter run multiple complex queries on the state of their AWS assets, with no network overhead.
|
12
|
+
|
13
|
+
|
14
|
+
----------------
|
15
|
+
Why is it?
|
16
|
+
----------------
|
17
|
+
The AWS Tracker is intended to be a foundation library, on top of which more complex AWS applications can be built. It decouples the process of downloading AWS state information from the process of displaying and/or acting on that information. Although an executable 'tracker' command-line program is included, the library is primarily intended for use from within Rails, or some other ActiveRecord context. An ActiveRecord database connection must be initialized before the aws_tracker library is loaded from within Ruby.
|
18
|
+
|
19
|
+
|
20
|
+
----------------
|
21
|
+
Installation
|
22
|
+
----------------
|
23
|
+
1) Install the AWS Tracker gem (use _sudo_ as necessary).
|
24
|
+
|
25
|
+
gem install aws_tracker
|
26
|
+
|
27
|
+
2) Install your database adaptor of choice. Sqlite3 is installed with AWS Tracker, so this step may be optional.
|
28
|
+
|
29
|
+
|
30
|
+
----------------
|
31
|
+
Usage [from the command line]
|
32
|
+
----------------
|
33
|
+
1) First, generate an ActiveRecord-style configuration file.
|
34
|
+
|
35
|
+
Here are the sample contents of `tracker_db.yml`:
|
36
|
+
|
37
|
+
adapter: sqlite3
|
38
|
+
database: aws_tracker.sqlite3
|
39
|
+
pool: 5
|
40
|
+
timeout: 5000
|
41
|
+
|
42
|
+
2) Create the database to contain the data. This is not necessary if using sqlite.
|
43
|
+
|
44
|
+
3) To store your AWS account information in the database, export the credentials as environment variables. This is only needed the first time you run.
|
45
|
+
|
46
|
+
export AWS_ACCOUNT_NUMBER=[your AWS account number]
|
47
|
+
export AWS_ACCESS_KEY_ID=[your EC2 access key ID]
|
48
|
+
export AWS_ACCESS_KEY_SECRET=[your EC2 access key secret]
|
49
|
+
|
50
|
+
4) Run the tracker, and point it at the database config file
|
51
|
+
|
52
|
+
tracker tracker_db.yml --migrate --create-account
|
53
|
+
|
54
|
+
* The `--migrate` argument updates the database to the latest version of the schema, and is only necessary for new databases, or when upgrading to a new version of the Tracker gem.
|
55
|
+
* The `--create-account` argument stores the above environment values as an AWSAccount object in the tracker database.
|
56
|
+
|
57
|
+
|
58
|
+
----------------
|
59
|
+
Usage [from within Ruby]
|
60
|
+
----------------
|
61
|
+
1) Insert the necessary tables into your database.
|
62
|
+
First, `require 'AWSTracker/tasks'` from your Rakefile, then run
|
63
|
+
|
64
|
+
rake db:migrate:tracker
|
65
|
+
|
66
|
+
2) In your Ruby app, first set up an ActiveRecord connection. In Rails, this is done for you automatically, but here's an example for a non-Rails app:
|
67
|
+
|
68
|
+
require 'active_record'
|
69
|
+
ActiveRecord::Base.establish_connection({
|
70
|
+
:adapter => 'sqlite3', :database => 'aws_tracker.sqlite3'
|
71
|
+
})
|
72
|
+
|
73
|
+
3) Now `require 'aws_tracker'`. This will load the models and allow you to perform queries on the following AWS resources and their relationships:
|
74
|
+
|
75
|
+
* AWSTracker::AWSAccount
|
76
|
+
* AWSTracker::SecurityGroup
|
77
|
+
* AWSTracker::Instance
|
78
|
+
* AWSTracker::EBSVolume
|
79
|
+
|
80
|
+
But first, you need to create an AWSAccount, and use a Tracker object to fetch its status from AWS:
|
81
|
+
|
82
|
+
include AWSTracker # Load model class names into namespace
|
83
|
+
a = AWSAccount.from_memory # Create an account (see command-line usage)
|
84
|
+
a.save! # Save it in the database
|
85
|
+
t = Tracker.new # A Tracker updates all accounts in the DB
|
86
|
+
t.delay = 15 # Update every 15 seconds
|
87
|
+
t.start # Runs in the background. Call 'stop' later
|
88
|
+
|
89
|
+
|
90
|
+
----------------
|
91
|
+
Development
|
92
|
+
----------------
|
93
|
+
This project is still in its early stages, but most of the framework is in place. More AWS resources need to be modeled, but the patterns for the code to do so are now laid out. Helping hands are appreciated!
|
94
|
+
|
95
|
+
1) Fetch the project code and bundle up...
|
96
|
+
|
97
|
+
git clone https://github.com/benton/aws_tracker.git
|
98
|
+
cd aws_tracker
|
99
|
+
bundle install
|
100
|
+
|
101
|
+
2) Create a database config and the necessary tables
|
102
|
+
|
103
|
+
cp config/database.yml.example config/database.yml
|
104
|
+
rake db:migrate:tracker
|
105
|
+
|
106
|
+
3) To run the tests, first export the credentials as environment variables, then `rake spec`.
|
107
|
+
|
108
|
+
export AWS_ACCOUNT_NUMBER=[your AWS account number]
|
109
|
+
export AWS_ACCESS_KEY_ID=[your EC2 access key ID]
|
110
|
+
export AWS_ACCESS_KEY_SECRET=[your EC2 access key secret]
|
111
|
+
rake spec
|
data/Rakefile
ADDED
data/aws_tracker.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "aws_tracker/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "aws_tracker"
|
7
|
+
s.version = AwsTracker::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Benton Roberts"]
|
10
|
+
s.email = ["benton@bentonroberts.com"]
|
11
|
+
s.homepage = "http://github.com/benton/aws_tracker"
|
12
|
+
s.summary = %q{Models the state of Amazon Web Services accounts in ActiveRecord}
|
13
|
+
s.description = %q{This gem peridically queries AWS for information about }+
|
14
|
+
%q{Instances, SecurityGroups, EBSVolumes, etc., and saves }+
|
15
|
+
%q{the data as interconnected ActiveRecord objects.}+
|
16
|
+
|
17
|
+
s.rubyforge_project = "aws_tracker"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
# Runtime dependencies
|
25
|
+
s.add_dependency "activerecord"
|
26
|
+
s.add_dependency "right_aws"
|
27
|
+
s.add_dependency "sqlite3"
|
28
|
+
|
29
|
+
# Development / Test dependencies
|
30
|
+
s.add_development_dependency "rake"
|
31
|
+
s.add_development_dependency "rspec"
|
32
|
+
|
33
|
+
end
|
data/bin/tracker
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# == Synopsis
|
4
|
+
# Monitors one or more AWS accounts and pushes their status into a database.
|
5
|
+
#
|
6
|
+
# == Usage
|
7
|
+
# tracker.rb [options] DB_CONFIG_FILE.YML
|
8
|
+
#
|
9
|
+
# == Options (all options can be put into the config file)
|
10
|
+
# -d, --delay [INTEGER] Seconds between status updates. default = 180
|
11
|
+
# -l, --log-level [LEVEL] Sets Log4r level for console output. default = INFO
|
12
|
+
# -m, --migrate Update database schema
|
13
|
+
# -c, --create-account Create a new Account from environment variables
|
14
|
+
# -h, --help Displays help message
|
15
|
+
#
|
16
|
+
# == Author
|
17
|
+
# Benton Roberts
|
18
|
+
|
19
|
+
require 'logger'
|
20
|
+
require 'optparse'
|
21
|
+
require 'yaml'
|
22
|
+
LOG_LVLS = {
|
23
|
+
"DEBUG" => ::Logger::DEBUG,
|
24
|
+
"INFO" => ::Logger::INFO,
|
25
|
+
"WARN" => ::Logger::WARN,
|
26
|
+
"ERROR" => ::Logger::ERROR,
|
27
|
+
"FATAL" => ::Logger::FATAL
|
28
|
+
}
|
29
|
+
|
30
|
+
class AWSTrackerConsoleApp
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@log = ::Logger.new(STDOUT)
|
34
|
+
@log.formatter = proc {|lvl, time, prog, msg|
|
35
|
+
"#{lvl} #{time.strftime '%Y-%m-%d %H:%M:%S %Z'}: #{msg}\n"
|
36
|
+
}
|
37
|
+
parse_options
|
38
|
+
(@log.error "A database config file must be specified" ; exit) if ARGV.empty?
|
39
|
+
db_config_file = ARGV.first
|
40
|
+
@log.info "Loading database configuration from #{db_config_file}"
|
41
|
+
db_config = YAML::load(File.open(db_config_file))
|
42
|
+
connect_to_database(db_config)
|
43
|
+
create_account if @opts[:create_account]
|
44
|
+
go
|
45
|
+
end
|
46
|
+
|
47
|
+
def connect_to_database(db_config)
|
48
|
+
@log.info "Connecting to database #{db_config['database']}"
|
49
|
+
require 'active_record'
|
50
|
+
::ActiveRecord::Base.establish_connection(db_config)
|
51
|
+
migrate if @opts[:migrate]
|
52
|
+
require 'aws_tracker'
|
53
|
+
end
|
54
|
+
|
55
|
+
def go
|
56
|
+
@tracker = AWSTracker::Tracker.new(:logger => @log)
|
57
|
+
@tracker.delay = @opts[:delay]
|
58
|
+
@tracker.start
|
59
|
+
while true do
|
60
|
+
sleep @opts[:delay] # Loop forever
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_options
|
65
|
+
@opts = { :delay => 180, :log_level => 'INFO' }
|
66
|
+
optparse = OptionParser.new do |opts|
|
67
|
+
opts.on('-d', '--delay SECONDS', Integer,
|
68
|
+
'Number of seconds between status updates') do |delay|
|
69
|
+
@opts[:delay] = delay
|
70
|
+
end
|
71
|
+
opts.on('-l', '--log-level LEVEL', 'Set logging level') do |log_level|
|
72
|
+
@opts[:log_level] = log_level.upcase
|
73
|
+
end
|
74
|
+
opts.on('-m', '--migrate', 'Update database schema') do
|
75
|
+
@opts[:migrate] = true
|
76
|
+
end
|
77
|
+
acct_help = "Create a new AWSAccount object from ENV varaibles"
|
78
|
+
opts.on('-c', '--create-account', acct_help) do
|
79
|
+
@opts[:create_account] = true
|
80
|
+
end
|
81
|
+
opts.on('-h', '--help', 'Display this help message') do
|
82
|
+
puts opts and exit
|
83
|
+
end
|
84
|
+
end
|
85
|
+
optparse.parse!
|
86
|
+
@log.level = LOG_LVLS[@opts[:log_level]] if LOG_LVLS[@opts[:log_level]]
|
87
|
+
end
|
88
|
+
|
89
|
+
def migrate
|
90
|
+
@log.info "Updating database schema..."
|
91
|
+
migration_dir = File.expand_path('../../db/migrate', __FILE__)
|
92
|
+
ActiveRecord::Migrator.migrate migration_dir
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_account
|
96
|
+
@log.info "Creating account from environment..."
|
97
|
+
a = AWSTracker::AWSAccount.from_memory
|
98
|
+
a.log.info "Loaded account #'#{a.account_id}' from memory"
|
99
|
+
a.save!
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
myApp = AWSTrackerConsoleApp.new
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateAwsAccounts < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :aws_accounts do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :account_id
|
6
|
+
t.string :access_key_id
|
7
|
+
t.string :secret_access_key
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :aws_accounts
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class CreateInstances < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :instances do |t|
|
4
|
+
t.integer :aws_account_id
|
5
|
+
t.string :instance_id
|
6
|
+
t.string :image_id
|
7
|
+
t.string :instance_state
|
8
|
+
t.integer :state_code
|
9
|
+
t.string :private_dns_name
|
10
|
+
t.string :dns_name
|
11
|
+
t.string :key_name
|
12
|
+
t.integer :ami_launch_index
|
13
|
+
t.string :instance_type
|
14
|
+
t.datetime :launch_time
|
15
|
+
t.datetime :termination_time
|
16
|
+
t.string :availability_zone
|
17
|
+
t.string :kernel_id
|
18
|
+
t.string :ramdisk_id
|
19
|
+
t.string :private_ip_address
|
20
|
+
t.string :ip_address
|
21
|
+
t.string :architecture
|
22
|
+
t.string :root_device_type
|
23
|
+
t.string :root_device_name
|
24
|
+
t.string :instance_life_cycle
|
25
|
+
t.string :spot_instance_request_id
|
26
|
+
t.string :virtualization_type
|
27
|
+
t.string :reason
|
28
|
+
t.string :state_reason_message
|
29
|
+
t.string :vpc_id
|
30
|
+
|
31
|
+
t.timestamps
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.down
|
36
|
+
drop_table :instances
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateSecurityGroups < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :security_groups do |t|
|
4
|
+
t.integer :aws_account_id
|
5
|
+
t.string :name
|
6
|
+
t.string :description
|
7
|
+
t.string :owner
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :security_groups
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateInstanceGroups < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :instances_security_groups, :id => false do |t|
|
4
|
+
t.integer :instance_id
|
5
|
+
t.integer :security_group_id
|
6
|
+
|
7
|
+
# t.timestamps
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :instances_security_groups
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateEbsVolumes < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :ebs_volumes do |t|
|
4
|
+
t.integer :aws_account_id
|
5
|
+
t.string :volume_id
|
6
|
+
t.integer :size
|
7
|
+
t.string :status
|
8
|
+
t.string :availability_zone
|
9
|
+
t.string :snapshot_id
|
10
|
+
t.datetime :create_time
|
11
|
+
t.datetime :attach_time
|
12
|
+
t.string :attachment_status
|
13
|
+
t.string :device
|
14
|
+
t.integer :instance_id
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
drop_table :ebs_volumes
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateTags < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :tags do |t|
|
4
|
+
t.integer :aws_account_id
|
5
|
+
t.string :key
|
6
|
+
t.string :value
|
7
|
+
t.string :resource_type
|
8
|
+
t.integer :resource_id
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
drop_table :tags
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'right_aws'
|
2
|
+
|
3
|
+
module AWSTracker
|
4
|
+
class AWSAccount < ActiveRecord::Base
|
5
|
+
|
6
|
+
# Relationships
|
7
|
+
has_many :instances, :dependent => :destroy
|
8
|
+
has_many :security_groups, :dependent => :destroy
|
9
|
+
has_many :ebs_volumes, {:dependent => :destroy, :class_name => 'EBSVolume'}
|
10
|
+
has_many :tags, :dependent => :destroy
|
11
|
+
# Validations
|
12
|
+
validates_presence_of :account_id, :access_key_id, :secret_access_key
|
13
|
+
validates_uniqueness_of :name, :account_id
|
14
|
+
|
15
|
+
# Configure logging
|
16
|
+
attr_accessor :log
|
17
|
+
after_initialize :setup_default_logger
|
18
|
+
def setup_default_logger
|
19
|
+
@log ||= AWSTracker.default_logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_status
|
23
|
+
update_security_groups
|
24
|
+
update_instances
|
25
|
+
update_ebs_volumes
|
26
|
+
update_tags
|
27
|
+
end
|
28
|
+
|
29
|
+
# Fetches Security Group data and saves to database
|
30
|
+
def update_security_groups
|
31
|
+
SecurityGroup.refresh_from_account self
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fetches Instance data and saves to database
|
35
|
+
def update_instances
|
36
|
+
Instance.refresh_from_account self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Fetches EBS Volume data and saves to database
|
40
|
+
def update_ebs_volumes
|
41
|
+
EBSVolume.refresh_from_account self
|
42
|
+
end
|
43
|
+
|
44
|
+
# Fetches Tags and saves to database
|
45
|
+
def update_tags
|
46
|
+
Tag.refresh_from_account self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a right_aws connection to EC2, creating it on demand
|
50
|
+
attr_accessor :ec2 # Allow replacement of the connection for efficiency
|
51
|
+
def ec2
|
52
|
+
@ec2 ||= RightAws::Ec2.new(
|
53
|
+
access_key_id, secret_access_key, {:logger => @log}
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates and returns an account based on the environment variables:
|
58
|
+
# AWS_ACCOUNT_NUMBER, AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY_SECRET
|
59
|
+
def self.from_memory
|
60
|
+
account_id = ENV['AWS_ACCOUNT_NUMBER']
|
61
|
+
AWSAccount.find_or_initialize_by_account_id(account_id) do |acc|
|
62
|
+
acc.name = "M-R #{account_id}"
|
63
|
+
acc.access_key_id = ENV['AWS_ACCESS_KEY_ID']
|
64
|
+
acc.secret_access_key = ENV['AWS_ACCESS_KEY_SECRET']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module AWSTracker
|
2
|
+
class EBSVolume < ActiveRecord::Base
|
3
|
+
|
4
|
+
belongs_to :account,
|
5
|
+
:class_name => 'AWSAccount',
|
6
|
+
:foreign_key => "aws_account_id"
|
7
|
+
belongs_to :instance
|
8
|
+
has_many :tags, :as => :resource, :dependent => :destroy
|
9
|
+
|
10
|
+
validates_presence_of :account, :volume_id, :size, :status
|
11
|
+
validates_uniqueness_of :volume_id
|
12
|
+
|
13
|
+
def self.refresh_from_account(acc)
|
14
|
+
acc.log.info "Updating EBS volumes for account '#{acc.name}'"
|
15
|
+
right_aws_array = acc.ec2.describe_volumes
|
16
|
+
right_aws_array.each do |right_aws_hash|
|
17
|
+
aws_id = right_aws_hash[:aws_id]
|
18
|
+
volume = EBSVolume.find_or_initialize_by_volume_id(aws_id) do |vol|
|
19
|
+
acc.ebs_volumes << vol
|
20
|
+
vol.account = acc
|
21
|
+
end
|
22
|
+
volume.update_from_right_hash(right_aws_hash)
|
23
|
+
if not volume.save
|
24
|
+
acc.log.error "Failed to save volume #{aws_id}: #{volume.errors}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
acc.log.info "Account '#{acc.name}' reports "+
|
28
|
+
"#{right_aws_array.count} EBS volumes"
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_from_right_hash(right_hash)
|
32
|
+
self.volume_id = right_hash[:aws_id]
|
33
|
+
self.size = right_hash[:aws_size]
|
34
|
+
self.status = right_hash[:aws_status]
|
35
|
+
self.availability_zone = right_hash[:zone]
|
36
|
+
self.snapshot_id = right_hash[:snapshot_id]
|
37
|
+
self.create_time = right_hash[:aws_created_at]
|
38
|
+
self.attach_time = right_hash[:aws_attached_at]
|
39
|
+
self.attachment_status = right_hash[:aws_attachment_status]
|
40
|
+
self.device = right_hash[:aws_device]
|
41
|
+
self.update_instance right_hash[:aws_instance_id]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Resets the instance attribute given an AWS instance ID
|
45
|
+
def update_instance(instance_id)
|
46
|
+
if instance_id == nil
|
47
|
+
self.instance = nil
|
48
|
+
else
|
49
|
+
self.instance = self.account.instances.find(:first,
|
50
|
+
:conditions => {:instance_id => instance_id})
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module AWSTracker
|
2
|
+
class Instance < ActiveRecord::Base
|
3
|
+
|
4
|
+
belongs_to :account,
|
5
|
+
:class_name => 'AWSAccount',
|
6
|
+
:foreign_key => "aws_account_id"
|
7
|
+
has_and_belongs_to_many :security_groups
|
8
|
+
has_many :ebs_volumes, :class_name => 'EBSVolume'
|
9
|
+
has_many :tags, :as => :resource, :dependent => :destroy
|
10
|
+
|
11
|
+
validates_presence_of :account, :instance_id, :image_id, :instance_state
|
12
|
+
validates_uniqueness_of :instance_id
|
13
|
+
|
14
|
+
def self.refresh_from_account(acc)
|
15
|
+
acc.log.info "Updating instances for account '#{acc.name}'"
|
16
|
+
right_aws_array = acc.ec2.describe_instances
|
17
|
+
right_aws_array.each do |right_aws_hash|
|
18
|
+
aws_id = right_aws_hash[:aws_instance_id]
|
19
|
+
instance = Instance.find_or_initialize_by_instance_id(aws_id) do |inst|
|
20
|
+
acc.instances << inst
|
21
|
+
inst.account = acc
|
22
|
+
end
|
23
|
+
instance.update_from_right_hash(right_aws_hash)
|
24
|
+
instance.save
|
25
|
+
end
|
26
|
+
acc.log.info "Account '#{acc.name}' reports #{right_aws_array.count} instances"
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_from_right_hash(rs_instance)
|
30
|
+
self.instance_id = rs_instance[:aws_instance_id]
|
31
|
+
self.image_id = rs_instance[:aws_image_id]
|
32
|
+
self.instance_state = rs_instance[:aws_state]
|
33
|
+
self.state_code = rs_instance[:aws_state_code]
|
34
|
+
self.instance_type = rs_instance[:aws_instance_type]
|
35
|
+
self.private_dns_name = rs_instance[:private_dns_name]
|
36
|
+
self.dns_name = rs_instance[:dns_name]
|
37
|
+
self.key_name = rs_instance[:ssh_key_name]
|
38
|
+
self.ami_launch_index = rs_instance[:ami_launch_index]
|
39
|
+
self.launch_time = rs_instance[:aws_launch_time]
|
40
|
+
self.termination_time = rs_instance[:aws_termination_time]
|
41
|
+
self.availability_zone = rs_instance[:aws_availability_zone]
|
42
|
+
self.kernel_id = rs_instance[:aws_kernel_id]
|
43
|
+
self.ramdisk_id = rs_instance[:aws_ramdisk_id]
|
44
|
+
self.private_ip_address = rs_instance[:private_ip_address]
|
45
|
+
self.ip_address = rs_instance[:ip_address]
|
46
|
+
self.architecture = rs_instance[:architecture]
|
47
|
+
self.root_device_type = rs_instance[:root_device_type]
|
48
|
+
self.root_device_name = rs_instance[:root_device_name]
|
49
|
+
self.virtualization_type = rs_instance[:virtualization_type]
|
50
|
+
self.reason = rs_instance[:aws_reason]
|
51
|
+
self.state_reason_message = rs_instance[:state_reason_message]
|
52
|
+
self.vpc_id = rs_instance[:vpc_id]
|
53
|
+
#:instance_life_cycle = rs_instance[:XXXXXXXXX]
|
54
|
+
#:spot_instance_request_id = rs_instance[:XXXXXXXXX]
|
55
|
+
update_security_groups(rs_instance[:aws_groups])
|
56
|
+
end
|
57
|
+
|
58
|
+
# Updates this Instance's ActiveRecord relationship security_groups
|
59
|
+
# based on group_names, an array of strings
|
60
|
+
def update_security_groups(group_names)
|
61
|
+
new_groups = []
|
62
|
+
group_names.each do |name|
|
63
|
+
new_group = self.account.security_groups.find(:first,
|
64
|
+
:conditions => {:name => name})
|
65
|
+
new_groups.push(new_group) if new_group
|
66
|
+
end
|
67
|
+
self.security_groups = new_groups
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AWSTracker
|
2
|
+
class SecurityGroup < ActiveRecord::Base
|
3
|
+
|
4
|
+
belongs_to :account,
|
5
|
+
:class_name => 'AWSAccount',
|
6
|
+
:foreign_key => "aws_account_id"
|
7
|
+
has_and_belongs_to_many :instances
|
8
|
+
|
9
|
+
validates_presence_of :account, :name, :description, :owner
|
10
|
+
validates_uniqueness_of :name, :scope => "aws_account_id"
|
11
|
+
|
12
|
+
def self.refresh_from_account(acc)
|
13
|
+
acc.log.info "Updating security groups for account '#{acc.name}'"
|
14
|
+
right_aws_array = acc.ec2.describe_security_groups
|
15
|
+
right_aws_array.each do |rs_group|
|
16
|
+
group_to_update = (acc.security_groups.select() do |grp|
|
17
|
+
grp.name == rs_group[:aws_group_name]
|
18
|
+
end).first
|
19
|
+
group_to_update ||= SecurityGroup.new(:account => acc)
|
20
|
+
acc.security_groups << group_to_update
|
21
|
+
group_to_update.update_from_right_hash(rs_group)
|
22
|
+
group_to_update.save
|
23
|
+
end
|
24
|
+
acc.log.info "Account '#{acc.name}' reports #{right_aws_array.count} groups"
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_from_right_hash(rs_group)
|
28
|
+
self.name = rs_group[:aws_group_name]
|
29
|
+
self.description = rs_group[:aws_description]
|
30
|
+
self.owner = rs_group[:aws_owner]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|