cloud_cost_tracker 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/Guardfile +10 -0
- data/LICENSE.TXT +10 -0
- data/README.md +123 -0
- data/Rakefile +15 -0
- data/billing issues.md +4 -0
- data/bin/cloud_cost_tracker +94 -0
- data/cloud_cost_tracker.gemspec +36 -0
- data/config/accounts.example.yml +45 -0
- data/config/billing/compute-aws-servers/us-east-on_demand.yml +44 -0
- data/config/billing/compute-aws-snapshots.yml +5 -0
- data/config/billing/compute-aws-volumes.yml +5 -0
- data/config/billing/elasticache-aws.yml +15 -0
- data/config/billing/rds-aws-servers/us-east-on_demand-mysql.yml +26 -0
- data/config/billing/rds-aws-servers/us-east-on_demand-storage.yml +10 -0
- data/config/billing/storage-aws-directories.yml +5 -0
- data/config/database.example.yml +18 -0
- data/db/migrate/20120118000000_create_billing_records.rb +22 -0
- data/db/migrate/20120119000000_create_billing_codes.rb +20 -0
- data/lib/cloud_cost_tracker/billing/account_billing_policy.rb +106 -0
- data/lib/cloud_cost_tracker/billing/compute/aws/servers.rb +30 -0
- data/lib/cloud_cost_tracker/billing/compute/aws/snapshots.rb +43 -0
- data/lib/cloud_cost_tracker/billing/compute/aws/volumes.rb +30 -0
- data/lib/cloud_cost_tracker/billing/elasticache/clusters.rb +33 -0
- data/lib/cloud_cost_tracker/billing/rds/server_storage.rb +30 -0
- data/lib/cloud_cost_tracker/billing/rds/servers.rb +31 -0
- data/lib/cloud_cost_tracker/billing/resource_billing_policy.rb +119 -0
- data/lib/cloud_cost_tracker/billing/storage/aws/directories.rb +47 -0
- data/lib/cloud_cost_tracker/coding/account_coding_policy.rb +73 -0
- data/lib/cloud_cost_tracker/coding/compute/aws/account_coding_policy.rb +38 -0
- data/lib/cloud_cost_tracker/coding/compute/aws/servers.rb +26 -0
- data/lib/cloud_cost_tracker/coding/compute/aws/volumes.rb +26 -0
- data/lib/cloud_cost_tracker/coding/rds/account_coding_policy.rb +25 -0
- data/lib/cloud_cost_tracker/coding/rds/servers.rb +59 -0
- data/lib/cloud_cost_tracker/coding/resource_coding_policy.rb +25 -0
- data/lib/cloud_cost_tracker/extensions/fog_model.rb +41 -0
- data/lib/cloud_cost_tracker/models/billing_code.rb +14 -0
- data/lib/cloud_cost_tracker/models/billing_record.rb +88 -0
- data/lib/cloud_cost_tracker/tasks.rb +3 -0
- data/lib/cloud_cost_tracker/tracker.rb +86 -0
- data/lib/cloud_cost_tracker/util/module_instrospection.rb +13 -0
- data/lib/cloud_cost_tracker/version.rb +3 -0
- data/lib/cloud_cost_tracker.rb +113 -0
- data/lib/tasks/database.rake +25 -0
- data/lib/tasks/rspec.rake +6 -0
- data/lib/tasks/track.rake +19 -0
- data/spec/lib/cloud_cost_tracker/billing/account_billing_policy_spec.rb +33 -0
- data/spec/lib/cloud_cost_tracker/billing/resource_billing_policy_spec.rb +102 -0
- data/spec/lib/cloud_cost_tracker/cloud_cost_tracker_spec.rb +57 -0
- data/spec/lib/cloud_cost_tracker/coding/account_coding_policy_spec.rb +32 -0
- data/spec/lib/cloud_cost_tracker/coding/resource_coding_policy_spec.rb +23 -0
- data/spec/lib/cloud_cost_tracker/models/billing_code_spec.rb +35 -0
- data/spec/lib/cloud_cost_tracker/models/billing_record_spec.rb +206 -0
- data/spec/lib/cloud_cost_tracker/tracker_spec.rb +37 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/_configure_logging.rb +6 -0
- data/writing-billing-policies.md +8 -0
- data/writing-coding-policies.md +7 -0
- 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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|
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:
|