cloud_cost_tracker 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.
Files changed (61) hide show
  1. data/.gitignore +16 -0
  2. data/.yardopts +1 -0
  3. data/Gemfile +4 -0
  4. data/Guardfile +10 -0
  5. data/LICENSE.TXT +10 -0
  6. data/README.md +123 -0
  7. data/Rakefile +15 -0
  8. data/billing issues.md +4 -0
  9. data/bin/cloud_cost_tracker +94 -0
  10. data/cloud_cost_tracker.gemspec +36 -0
  11. data/config/accounts.example.yml +45 -0
  12. data/config/billing/compute-aws-servers/us-east-on_demand.yml +44 -0
  13. data/config/billing/compute-aws-snapshots.yml +5 -0
  14. data/config/billing/compute-aws-volumes.yml +5 -0
  15. data/config/billing/elasticache-aws.yml +15 -0
  16. data/config/billing/rds-aws-servers/us-east-on_demand-mysql.yml +26 -0
  17. data/config/billing/rds-aws-servers/us-east-on_demand-storage.yml +10 -0
  18. data/config/billing/storage-aws-directories.yml +5 -0
  19. data/config/database.example.yml +18 -0
  20. data/db/migrate/20120118000000_create_billing_records.rb +22 -0
  21. data/db/migrate/20120119000000_create_billing_codes.rb +20 -0
  22. data/lib/cloud_cost_tracker/billing/account_billing_policy.rb +106 -0
  23. data/lib/cloud_cost_tracker/billing/compute/aws/servers.rb +30 -0
  24. data/lib/cloud_cost_tracker/billing/compute/aws/snapshots.rb +43 -0
  25. data/lib/cloud_cost_tracker/billing/compute/aws/volumes.rb +30 -0
  26. data/lib/cloud_cost_tracker/billing/elasticache/clusters.rb +33 -0
  27. data/lib/cloud_cost_tracker/billing/rds/server_storage.rb +30 -0
  28. data/lib/cloud_cost_tracker/billing/rds/servers.rb +31 -0
  29. data/lib/cloud_cost_tracker/billing/resource_billing_policy.rb +119 -0
  30. data/lib/cloud_cost_tracker/billing/storage/aws/directories.rb +47 -0
  31. data/lib/cloud_cost_tracker/coding/account_coding_policy.rb +73 -0
  32. data/lib/cloud_cost_tracker/coding/compute/aws/account_coding_policy.rb +38 -0
  33. data/lib/cloud_cost_tracker/coding/compute/aws/servers.rb +26 -0
  34. data/lib/cloud_cost_tracker/coding/compute/aws/volumes.rb +26 -0
  35. data/lib/cloud_cost_tracker/coding/rds/account_coding_policy.rb +25 -0
  36. data/lib/cloud_cost_tracker/coding/rds/servers.rb +59 -0
  37. data/lib/cloud_cost_tracker/coding/resource_coding_policy.rb +25 -0
  38. data/lib/cloud_cost_tracker/extensions/fog_model.rb +41 -0
  39. data/lib/cloud_cost_tracker/models/billing_code.rb +14 -0
  40. data/lib/cloud_cost_tracker/models/billing_record.rb +88 -0
  41. data/lib/cloud_cost_tracker/tasks.rb +3 -0
  42. data/lib/cloud_cost_tracker/tracker.rb +86 -0
  43. data/lib/cloud_cost_tracker/util/module_instrospection.rb +13 -0
  44. data/lib/cloud_cost_tracker/version.rb +3 -0
  45. data/lib/cloud_cost_tracker.rb +113 -0
  46. data/lib/tasks/database.rake +25 -0
  47. data/lib/tasks/rspec.rake +6 -0
  48. data/lib/tasks/track.rake +19 -0
  49. data/spec/lib/cloud_cost_tracker/billing/account_billing_policy_spec.rb +33 -0
  50. data/spec/lib/cloud_cost_tracker/billing/resource_billing_policy_spec.rb +102 -0
  51. data/spec/lib/cloud_cost_tracker/cloud_cost_tracker_spec.rb +57 -0
  52. data/spec/lib/cloud_cost_tracker/coding/account_coding_policy_spec.rb +32 -0
  53. data/spec/lib/cloud_cost_tracker/coding/resource_coding_policy_spec.rb +23 -0
  54. data/spec/lib/cloud_cost_tracker/models/billing_code_spec.rb +35 -0
  55. data/spec/lib/cloud_cost_tracker/models/billing_record_spec.rb +206 -0
  56. data/spec/lib/cloud_cost_tracker/tracker_spec.rb +37 -0
  57. data/spec/spec_helper.rb +58 -0
  58. data/spec/support/_configure_logging.rb +6 -0
  59. data/writing-billing-policies.md +8 -0
  60. data/writing-coding-policies.md +7 -0
  61. metadata +224 -0
@@ -0,0 +1,35 @@
1
+ module CloudCostTracker
2
+ module Billing
3
+ describe BillingCode do
4
+ before(:each) do
5
+ @existing_code = BillingCode.create!(
6
+ :key => 'fake key', :value => 'fake value'
7
+ )
8
+ end
9
+
10
+ after(:each) do
11
+ @existing_code.destroy
12
+ end
13
+
14
+ it "is valid with valid attributes" do
15
+ @existing_code.should be_valid
16
+ end
17
+
18
+ it "is not valid without a key" do
19
+ @existing_code.key = nil
20
+ @existing_code.should_not be_valid
21
+ end
22
+ it "is valid without a value" do
23
+ @existing_code.value = nil
24
+ @existing_code.should be_valid
25
+ end
26
+
27
+ #it "is not valid if an identical code is already saved" do
28
+ # BillingCode.new(
29
+ # :key => 'fake key', :value => 'fake value'
30
+ # ).should_not be_valid
31
+ #end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,206 @@
1
+ module CloudCostTracker
2
+ module Billing
3
+ describe BillingRecord do
4
+
5
+ # some constants for a generic BillingRecord
6
+ @stop_time = Time.now
7
+ @start_time = Time.now - FogTracker::DEFAULT_POLLING_TIME
8
+ @hourly_rate = 5.0
9
+ RECORD_PARAMETERS = {
10
+ :provider => "fake_provider_name",
11
+ :service => "fake_service_name",
12
+ :account => "fake_account_ID",
13
+ :resource_id => "fake_resource_ID",
14
+ :resource_type => "fake_resource_type",
15
+ :billing_type => "fake_billing_type",
16
+ :start_time => @start_time,
17
+ :stop_time => @stop_time,
18
+ :cost_per_hour => @hourly_rate,
19
+ :total_cost => ((@stop_time - @start_time) * @hourly_rate) / 3600,
20
+ }
21
+ # A day in the distant future
22
+ NEW_YEARS_DAY_3000 = Time.gm(3000, 1, 1, 0, 0, 0)
23
+
24
+ before(:each) do
25
+ BillingRecord.delete_all ; BillingCode.delete_all # clean database
26
+ # Make a "current" billing record
27
+ @existing_bill = BillingRecord.create!(RECORD_PARAMETERS)
28
+ # Make a billing record that follows the existing one in time
29
+ @next_bill = BillingRecord.new(RECORD_PARAMETERS.merge(
30
+ :start_time => RECORD_PARAMETERS[:stop_time],
31
+ :stop_time => RECORD_PARAMETERS[:stop_time] + 3600
32
+ ))
33
+ end
34
+
35
+ after(:each) do
36
+ BillingRecord.delete_all ; BillingCode.delete_all # clean database
37
+ end
38
+
39
+ it "is valid with valid attributes" do
40
+ @existing_bill.should be_valid
41
+ end
42
+
43
+ it "is not valid without a provider name" do
44
+ @existing_bill.provider = nil
45
+ @existing_bill.should_not be_valid
46
+ end
47
+ it "is not valid without a service name" do
48
+ @existing_bill.service = nil
49
+ @existing_bill.should_not be_valid
50
+ end
51
+ it "is not valid without an account name" do
52
+ @existing_bill.account = nil
53
+ @existing_bill.should_not be_valid
54
+ end
55
+ it "is not valid without a resource ID" do
56
+ @existing_bill.resource_id = nil
57
+ @existing_bill.should_not be_valid
58
+ end
59
+ it "is not valid without a resource type" do
60
+ @existing_bill.resource_type = nil
61
+ @existing_bill.should_not be_valid
62
+ end
63
+ it "is not valid without a billing type" do
64
+ @existing_bill.billing_type = nil
65
+ @existing_bill.should_not be_valid
66
+ end
67
+ it "is not valid without a start time" do
68
+ @existing_bill.start_time = nil
69
+ @existing_bill.should_not be_valid
70
+ end
71
+ it "is not valid without a stop time" do
72
+ @existing_bill.stop_time = nil
73
+ @existing_bill.should_not be_valid
74
+ end
75
+ it "is not valid without an hourly cost" do
76
+ @existing_bill.cost_per_hour = nil
77
+ @existing_bill.should_not be_valid
78
+ end
79
+ it "is not valid without a total cost" do
80
+ @existing_bill.total_cost = nil
81
+ @existing_bill.should_not be_valid
82
+ end
83
+ it "validates its associated billing codes" do
84
+ new_record = BillingRecord.new(RECORD_PARAMETERS)
85
+ new_record.billing_codes = [BillingCode.new]
86
+ new_record.should_not be_valid
87
+ end
88
+
89
+ describe '#most_recent_like' do
90
+ context "when invoked with a BillingRecord" do
91
+ context "and a record for the same resource / billing type exists" do
92
+ it 'returns the most recent BillingRecord for the same resource' do
93
+ BillingRecord.most_recent_like(@next_bill).should == @existing_bill
94
+ end
95
+ end
96
+ context "and no record for the same resource / billing type exists" do
97
+ it 'returns nil' do
98
+ BillingRecord.delete_all
99
+ BillingRecord.most_recent_like(@next_bill).should == nil
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#overlaps_with' do
106
+ context "when invoked with a BillingRecord far away in time" do
107
+ it "returns false" do
108
+ @next_bill.start_time = NEW_YEARS_DAY_3000
109
+ @next_bill.stop_time = NEW_YEARS_DAY_3000 + 3600
110
+ @existing_bill.overlaps_with(@next_bill).should == false
111
+ end
112
+
113
+ end
114
+ context "when invoked with a BillingRecord adjacent in time" do
115
+ it "returns true" do
116
+ @existing_bill.overlaps_with(@next_bill).should == true
117
+ end
118
+ end
119
+ context "when invoked with a BillingRecord overlapping in time" do
120
+ it "returns true" do
121
+ @next_bill.start_time = RECORD_PARAMETERS[:stop_time] - 1
122
+ @next_bill.stop_time = RECORD_PARAMETERS[:stop_time] + 3600
123
+ @existing_bill.overlaps_with(@next_bill).should == true
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '#merge_with with an existing BillingRecord' do
129
+ it "copies the stop time of the current record onto the existing record" do
130
+ @next_bill.stop_time = NEW_YEARS_DAY_3000
131
+ @existing_bill.merge_with @next_bill
132
+ @existing_bill.stop_time.should == NEW_YEARS_DAY_3000
133
+ end
134
+ it "updates the total for the existing record" do
135
+ # Run an update that causes the @existing_bill's total to double
136
+ duration = (@existing_bill.stop_time - @existing_bill.start_time)
137
+ @next_bill.stop_time = @existing_bill.stop_time + duration
138
+ @existing_bill.merge_with @next_bill
139
+ @existing_bill.total_cost.should == 2 * RECORD_PARAMETERS[:total_cost]
140
+ end
141
+ end
142
+
143
+ describe '#set_codes' do
144
+ context 'when invoked on a saved (existing) BillingRecord' do
145
+ before(:each) {@existing_code = BillingCode.create!(:key=>'k', :value=>'v')}
146
+ context "with a key, value pair that matches an existing BillingCode" do
147
+ it "associates with the existing BillingCode" do
148
+ @existing_bill.set_codes [['k', 'v']]
149
+ @existing_bill.billing_codes.should == [@existing_code]
150
+ @existing_bill.should be_valid
151
+ end
152
+ end
153
+ context "with a key, value pair that matches no existing BillingCode" do
154
+ it "creates a new BillingCode and associates with it" do
155
+ @existing_bill.billing_codes.should == Array.new
156
+ @existing_bill.set_codes [['k', 'v']]
157
+ @existing_bill.billing_codes.should == [@existing_code]
158
+ @existing_bill.should be_valid
159
+ end
160
+ end
161
+ end
162
+ context 'when invoked on a new, unsaved BillingRecord' do
163
+ before(:each) { @new_bill = BillingRecord.new(RECORD_PARAMETERS) }
164
+ context "with a key, value pair that matches an existing BillingCode" do
165
+ it "associates with the existing BillingCode" do
166
+ BillingCode.all.should == Array.new
167
+ existing_code = BillingCode.create!(:key => 'k', :value => 'v')
168
+ @new_bill.set_codes [['k', 'v']]
169
+ @new_bill.billing_codes.should == [existing_code]
170
+ @new_bill.should be_valid
171
+ end
172
+ end
173
+ context "with a key, value pair that matches no existing BillingCode" do
174
+ it "creates a new BillingCode and associates with it" do
175
+ BillingCode.all.should == Array.new
176
+ @new_bill.billing_codes.should == Array.new
177
+ @new_bill.set_codes [['k', 'v']]
178
+ @new_bill.billing_codes.size.should == 1
179
+ @new_bill.billing_codes.first.key.should == 'k'
180
+ @new_bill.billing_codes.first.value.should == 'v'
181
+ @new_bill.should be_valid
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '#to_hash' do
188
+ it "returns a Hash of the record's attributes" do
189
+ @existing_bill.billing_codes = [
190
+ BillingCode.new(:key => 'key1', :value => 'val1'),
191
+ BillingCode.new(:key => 'key2', :value => 'val2'),
192
+ ]
193
+ @existing_bill.to_hash['provider'].should == "fake_provider_name"
194
+ @existing_bill.to_hash['service'].should == "fake_service_name"
195
+ @existing_bill.to_hash['account'].should == "fake_account_ID"
196
+ @existing_bill.to_hash['resource_id'].should == "fake_resource_ID"
197
+ @existing_bill.to_hash['resource_type'].should == "fake_resource_type"
198
+ @existing_bill.to_hash['billing_type'].should == "fake_billing_type"
199
+ @existing_bill.to_hash['billing_codes'].should ==
200
+ [['key1', 'val1'], ['key2', 'val2']]
201
+ end
202
+ end
203
+
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,37 @@
1
+ module CloudCostTracker
2
+ describe Tracker do
3
+
4
+ before(:each) do
5
+ @tracker = Tracker.new(FAKE_ACCOUNTS)
6
+ Billing::BillingRecord.delete_all
7
+ end
8
+
9
+ after(:each) do
10
+ Billing::BillingRecord.delete_all
11
+ end
12
+
13
+ describe '#update' do
14
+ before(:each) do
15
+ @resource = FAKE_AWS.servers.new
16
+ @resource.stub(:tracker_account).and_return(FAKE_ACCOUNT)
17
+ @resource.stub(:identity).and_return "fake server ID"
18
+ @resource.stub(:status).and_return "running"
19
+ FogTracker::AccountTracker.any_instance.stub(:all_resources).
20
+ and_return([ @resource ])
21
+ end
22
+
23
+ it "Generates BillingRecords for all Resources in its accounts" do
24
+ @tracker.update
25
+ Billing::BillingRecord.all.count.should == 1
26
+ end
27
+
28
+ it "Generates billing codes for all Resources in its accounts" do
29
+ @resource.stub(:tags).and_return('environment' => 'sandbox')
30
+ @tracker.update
31
+ @tracker['*::Compute::AWS::servers'].first.billing_codes.should ==
32
+ [['environment', 'sandbox']]
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,58 @@
1
+ ENV['RACK_ENV'] ||= 'test'
2
+ Bundler.require # Load all gems and libs
3
+
4
+ Fog.mock! # Don't try to connect to the network
5
+
6
+ FAKE_ACCOUNT_NAME = 'Fake EC2 Account'
7
+ FAKE_ACCOUNT = {
8
+ :name => FAKE_ACCOUNT_NAME,
9
+ :provider => 'AWS',
10
+ :service => 'Compute',
11
+ :delay => 10,
12
+ :credentials => {
13
+ :aws_access_key_id => "fake user",
14
+ :aws_secret_access_key => 'fake password'
15
+ },
16
+ :exclude_resources => [
17
+ :spot_requests, # No Fog mocks for this resource
18
+ ],
19
+ }
20
+ FAKE_ACCOUNTS = {FAKE_ACCOUNT_NAME => FAKE_ACCOUNT}
21
+ FAKE_AWS = Fog::Compute.new(
22
+ :provider => 'AWS',
23
+ :aws_access_key_id => 'XXXXXXXXXXXXXXXXXXXX',
24
+ :aws_secret_access_key => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
25
+ )
26
+ FAKE_RDS = Fog::AWS::RDS.new(
27
+ :aws_access_key_id => 'XXXXXXXXXXXXXXXXXXXX',
28
+ :aws_secret_access_key => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
29
+ )
30
+
31
+ ## Establish ActiveRecord connection and Migrate database
32
+ # The following db config files are used, in order of preference:
33
+ # 1. ENV['DB_CONFIG_FILE']
34
+ # 2. ./config/database.yml
35
+ # 3. ./config/database.example.yml
36
+ db_conf_file = './config/database.example.yml'
37
+ db_conf_file = './config/database.yml' if File.exists? './config/database.yml'
38
+ if ENV['DB_CONFIG_FILE']
39
+ db_conf_file = ENV['DB_CONFIG_FILE']
40
+ else
41
+ ENV['DB_CONFIG_FILE'] = db_conf_file
42
+ end
43
+ puts "Reading DB config file #{db_conf_file}..."
44
+ db_config = YAML::load(File.open(db_conf_file))[CloudCostTracker.env]
45
+ puts "Using DB #{db_config['database']}..."
46
+ ActiveRecord::Base.establish_connection(db_config)
47
+ migration_dir = File.expand_path('../../db/migrate', __FILE__)
48
+ ActiveRecord::Migrator.migrate migration_dir
49
+
50
+ # Require RSpec support files. Logging is configured there
51
+ support_files = Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")]
52
+ support_files.sort.each {|f| require f}
53
+
54
+ # RSpec configuration block
55
+ RSpec.configure do |config|
56
+ config.mock_with :rspec # == Mock Framework
57
+ #config.fixture_path = "#{::Rails.root}/spec/fixtures"
58
+ end
@@ -0,0 +1,6 @@
1
+ # Setup a global Logger for all tests
2
+ LOG_LEVEL = ::Logger::WARN
3
+ LOG = FogTracker.default_logger(STDOUT)
4
+ LOG.info "Logging configured in #{File.basename __FILE__}."
5
+ LOG.level = LOG_LEVEL
6
+ ActiveRecord::Base.logger = LOG # Uncomment for ActiveRecord outputs
@@ -0,0 +1,8 @@
1
+ How to write a Billing Policy
2
+ ================
3
+
4
+ *(coming soon)*
5
+
6
+ EXAMPLE: See the source code for
7
+ {CloudCostTracker::Billing::Compute::AWS::ServerBillingPolicy}
8
+
@@ -0,0 +1,7 @@
1
+ How to write a Bill Coding Policy
2
+ ================
3
+
4
+ *(coming soon)*
5
+
6
+ EXAMPLE: See the source code for
7
+ {CloudCostTracker::Coding::Compute::AWS::VolumeCodingPolicy}
metadata ADDED
@@ -0,0 +1,224 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloud_cost_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benton Roberts
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: fog_tracker
16
+ requirement: &70113161132220 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.3.9
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70113161132220
25
+ - !ruby/object:Gem::Dependency
26
+ name: activerecord
27
+ requirement: &70113161130840 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70113161130840
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70113161098660 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70113161098660
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &70113161096820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70113161096820
58
+ - !ruby/object:Gem::Dependency
59
+ name: yard
60
+ requirement: &70113161095120 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70113161095120
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: &70113161094320 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70113161094320
80
+ - !ruby/object:Gem::Dependency
81
+ name: guard-rspec
82
+ requirement: &70113161092700 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70113161092700
91
+ - !ruby/object:Gem::Dependency
92
+ name: ruby_gntp
93
+ requirement: &70113160454700 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70113160454700
102
+ - !ruby/object:Gem::Dependency
103
+ name: sqlite3
104
+ requirement: &70113160454200 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *70113160454200
113
+ description: Periodically polls one or more cloud computing accounts using the fog
114
+ gem, and generates ActiveRecord rows representing BillingRecords for each discovered
115
+ resource.
116
+ email:
117
+ - benton@bentonroberts.com
118
+ executables:
119
+ - cloud_cost_tracker
120
+ extensions: []
121
+ extra_rdoc_files: []
122
+ files:
123
+ - .gitignore
124
+ - .yardopts
125
+ - Gemfile
126
+ - Guardfile
127
+ - LICENSE.TXT
128
+ - README.md
129
+ - Rakefile
130
+ - billing issues.md
131
+ - bin/cloud_cost_tracker
132
+ - cloud_cost_tracker.gemspec
133
+ - config/accounts.example.yml
134
+ - config/billing/compute-aws-servers/us-east-on_demand.yml
135
+ - config/billing/compute-aws-snapshots.yml
136
+ - config/billing/compute-aws-volumes.yml
137
+ - config/billing/elasticache-aws.yml
138
+ - config/billing/rds-aws-servers/us-east-on_demand-mysql.yml
139
+ - config/billing/rds-aws-servers/us-east-on_demand-storage.yml
140
+ - config/billing/storage-aws-directories.yml
141
+ - config/database.example.yml
142
+ - db/migrate/20120118000000_create_billing_records.rb
143
+ - db/migrate/20120119000000_create_billing_codes.rb
144
+ - lib/cloud_cost_tracker.rb
145
+ - lib/cloud_cost_tracker/billing/account_billing_policy.rb
146
+ - lib/cloud_cost_tracker/billing/compute/aws/servers.rb
147
+ - lib/cloud_cost_tracker/billing/compute/aws/snapshots.rb
148
+ - lib/cloud_cost_tracker/billing/compute/aws/volumes.rb
149
+ - lib/cloud_cost_tracker/billing/elasticache/clusters.rb
150
+ - lib/cloud_cost_tracker/billing/rds/server_storage.rb
151
+ - lib/cloud_cost_tracker/billing/rds/servers.rb
152
+ - lib/cloud_cost_tracker/billing/resource_billing_policy.rb
153
+ - lib/cloud_cost_tracker/billing/storage/aws/directories.rb
154
+ - lib/cloud_cost_tracker/coding/account_coding_policy.rb
155
+ - lib/cloud_cost_tracker/coding/compute/aws/account_coding_policy.rb
156
+ - lib/cloud_cost_tracker/coding/compute/aws/servers.rb
157
+ - lib/cloud_cost_tracker/coding/compute/aws/volumes.rb
158
+ - lib/cloud_cost_tracker/coding/rds/account_coding_policy.rb
159
+ - lib/cloud_cost_tracker/coding/rds/servers.rb
160
+ - lib/cloud_cost_tracker/coding/resource_coding_policy.rb
161
+ - lib/cloud_cost_tracker/extensions/fog_model.rb
162
+ - lib/cloud_cost_tracker/models/billing_code.rb
163
+ - lib/cloud_cost_tracker/models/billing_record.rb
164
+ - lib/cloud_cost_tracker/tasks.rb
165
+ - lib/cloud_cost_tracker/tracker.rb
166
+ - lib/cloud_cost_tracker/util/module_instrospection.rb
167
+ - lib/cloud_cost_tracker/version.rb
168
+ - lib/tasks/database.rake
169
+ - lib/tasks/rspec.rake
170
+ - lib/tasks/track.rake
171
+ - spec/lib/cloud_cost_tracker/billing/account_billing_policy_spec.rb
172
+ - spec/lib/cloud_cost_tracker/billing/resource_billing_policy_spec.rb
173
+ - spec/lib/cloud_cost_tracker/cloud_cost_tracker_spec.rb
174
+ - spec/lib/cloud_cost_tracker/coding/account_coding_policy_spec.rb
175
+ - spec/lib/cloud_cost_tracker/coding/resource_coding_policy_spec.rb
176
+ - spec/lib/cloud_cost_tracker/models/billing_code_spec.rb
177
+ - spec/lib/cloud_cost_tracker/models/billing_record_spec.rb
178
+ - spec/lib/cloud_cost_tracker/tracker_spec.rb
179
+ - spec/spec_helper.rb
180
+ - spec/support/_configure_logging.rb
181
+ - writing-billing-policies.md
182
+ - writing-coding-policies.md
183
+ homepage: http://github.com/benton/cloud_cost_tracker
184
+ licenses: []
185
+ post_install_message:
186
+ rdoc_options: []
187
+ require_paths:
188
+ - lib
189
+ required_ruby_version: !ruby/object:Gem::Requirement
190
+ none: false
191
+ requirements:
192
+ - - ! '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ segments:
196
+ - 0
197
+ hash: 2940390420287301713
198
+ required_rubygems_version: !ruby/object:Gem::Requirement
199
+ none: false
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ segments:
205
+ - 0
206
+ hash: 2940390420287301713
207
+ requirements: []
208
+ rubyforge_project: cloud_cost_tracker
209
+ rubygems_version: 1.8.15
210
+ signing_key:
211
+ specification_version: 3
212
+ summary: Records expenses for cloud computing resources in an ActiveRecord database
213
+ test_files:
214
+ - spec/lib/cloud_cost_tracker/billing/account_billing_policy_spec.rb
215
+ - spec/lib/cloud_cost_tracker/billing/resource_billing_policy_spec.rb
216
+ - spec/lib/cloud_cost_tracker/cloud_cost_tracker_spec.rb
217
+ - spec/lib/cloud_cost_tracker/coding/account_coding_policy_spec.rb
218
+ - spec/lib/cloud_cost_tracker/coding/resource_coding_policy_spec.rb
219
+ - spec/lib/cloud_cost_tracker/models/billing_code_spec.rb
220
+ - spec/lib/cloud_cost_tracker/models/billing_record_spec.rb
221
+ - spec/lib/cloud_cost_tracker/tracker_spec.rb
222
+ - spec/spec_helper.rb
223
+ - spec/support/_configure_logging.rb
224
+ has_rdoc: