dynamo-autoscale 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +58 -0
  4. data/LICENSE +21 -0
  5. data/README.md +400 -0
  6. data/Rakefile +9 -0
  7. data/aws.sample.yml +16 -0
  8. data/bin/dynamo-autoscale +131 -0
  9. data/config/environment/common.rb +114 -0
  10. data/config/environment/console.rb +2 -0
  11. data/config/environment/test.rb +3 -0
  12. data/config/logger.yml +11 -0
  13. data/config/services/aws.rb +20 -0
  14. data/config/services/logger.rb +35 -0
  15. data/data/.gitkeep +0 -0
  16. data/dynamo-autoscale.gemspec +29 -0
  17. data/lib/dynamo-autoscale/actioner.rb +265 -0
  18. data/lib/dynamo-autoscale/cw_poller.rb +49 -0
  19. data/lib/dynamo-autoscale/dispatcher.rb +39 -0
  20. data/lib/dynamo-autoscale/dynamo_actioner.rb +59 -0
  21. data/lib/dynamo-autoscale/ext/active_support/duration.rb +7 -0
  22. data/lib/dynamo-autoscale/local_actioner.rb +39 -0
  23. data/lib/dynamo-autoscale/local_data_poll.rb +51 -0
  24. data/lib/dynamo-autoscale/logger.rb +15 -0
  25. data/lib/dynamo-autoscale/metrics.rb +192 -0
  26. data/lib/dynamo-autoscale/poller.rb +41 -0
  27. data/lib/dynamo-autoscale/pretty_formatter.rb +27 -0
  28. data/lib/dynamo-autoscale/rule.rb +180 -0
  29. data/lib/dynamo-autoscale/rule_set.rb +69 -0
  30. data/lib/dynamo-autoscale/table_tracker.rb +329 -0
  31. data/lib/dynamo-autoscale/unit_cost.rb +41 -0
  32. data/lib/dynamo-autoscale/version.rb +3 -0
  33. data/lib/dynamo-autoscale.rb +1 -0
  34. data/rlib/dynamodb_graph.r +15 -0
  35. data/rlib/dynamodb_scatterplot.r +13 -0
  36. data/rulesets/default.rb +5 -0
  37. data/rulesets/erroneous.rb +1 -0
  38. data/rulesets/gradual_tail.rb +11 -0
  39. data/rulesets/none.rb +0 -0
  40. data/script/console +3 -0
  41. data/script/historic_data +46 -0
  42. data/script/hourly_wastage +40 -0
  43. data/script/monitor +55 -0
  44. data/script/simulator +40 -0
  45. data/script/test +52 -0
  46. data/script/validate_ruleset +20 -0
  47. data/spec/actioner_spec.rb +244 -0
  48. data/spec/rule_set_spec.rb +89 -0
  49. data/spec/rule_spec.rb +491 -0
  50. data/spec/spec_helper.rb +4 -0
  51. data/spec/table_tracker_spec.rb +256 -0
  52. metadata +178 -0
@@ -0,0 +1,256 @@
1
+ require 'spec_helper'
2
+
3
+ describe DynamoAutoscale::TableTracker do
4
+ let(:table_name) { "test_table" }
5
+ let(:table) { DynamoAutoscale::TableTracker.new(table_name) }
6
+ subject { table }
7
+
8
+ before do
9
+ table.tick(5.seconds.ago, {
10
+ provisioned_reads: 600.0,
11
+ provisioned_writes: 800.0,
12
+ consumed_reads: 20.0,
13
+ consumed_writes: 30.0,
14
+ })
15
+
16
+ table.tick(5.minutes.ago, {
17
+ provisioned_reads: 600.0,
18
+ provisioned_writes: 800.0,
19
+ consumed_reads: 20.0,
20
+ consumed_writes: 30.0,
21
+ })
22
+
23
+ table.tick(15.seconds.ago, {
24
+ provisioned_reads: 600.0,
25
+ provisioned_writes: 800.0,
26
+ consumed_reads: 20.0,
27
+ consumed_writes: 30.0,
28
+ })
29
+ end
30
+
31
+ describe 'storing data' do
32
+ specify "should be done in order" do
33
+ table.data.keys.should == table.data.keys.sort
34
+ end
35
+ end
36
+
37
+ describe 'retrieving data' do
38
+ let(:now) { Time.now }
39
+
40
+ before do
41
+ table.tick(now, {
42
+ provisioned_reads: 100.0,
43
+ provisioned_writes: 200.0,
44
+ consumed_reads: 20.0,
45
+ consumed_writes: 30.0,
46
+ })
47
+ end
48
+
49
+ describe "#name" do
50
+ subject { table.name }
51
+ it { should == table_name }
52
+ end
53
+
54
+ describe "#last 3.seconds, :consumed_reads" do
55
+ subject { table.last 3.seconds, :consumed_reads }
56
+ it { should == [20.0] }
57
+ end
58
+
59
+ describe "#last 1, :consumed_writes" do
60
+ subject { table.last 1, :consumed_writes }
61
+ it { should == [30.0] }
62
+ end
63
+
64
+ describe "#last_provisioned_for :reads" do
65
+ subject { table.last_provisioned_for :reads }
66
+ it { should == 100.0 }
67
+ end
68
+
69
+ describe "#last_provisioned_for :writes, at: now" do
70
+ subject { table.last_provisioned_for :writes, at: now }
71
+ it { should == 200.0 }
72
+ end
73
+
74
+ describe "#last_provisioned_for :writes, at: 3.minutes.ago" do
75
+ subject { table.last_provisioned_for :writes, at: 3.minutes.ago }
76
+ it { should == 800.0 }
77
+ end
78
+
79
+ describe "#all_times" do
80
+ subject { table.all_times }
81
+ its(:length) { should == 4 }
82
+
83
+ specify("is ordered") { subject.should == subject.sort }
84
+ end
85
+ end
86
+
87
+ describe 'clearing data' do
88
+ before { table.clear_data }
89
+
90
+ specify "table.data should be totally empty" do
91
+ table.data.keys.each do |key|
92
+ table.data[key].should be_empty
93
+ end
94
+ end
95
+ end
96
+
97
+ describe 'stats' do
98
+ before do
99
+ table.clear_data
100
+
101
+ table.tick(3.seconds.ago, {
102
+ provisioned_reads: 100.0,
103
+ consumed_reads: 99.0,
104
+
105
+ provisioned_writes: 200.0,
106
+ consumed_writes: 198.0,
107
+ })
108
+
109
+ table.tick(12.seconds.ago, {
110
+ provisioned_reads: 100.0,
111
+ consumed_reads: 99.0,
112
+
113
+ provisioned_writes: 200.0,
114
+ consumed_writes: 198.0,
115
+ })
116
+ end
117
+
118
+ describe 'wasted_read_units' do
119
+ subject { table.wasted_read_units }
120
+ it { should == 2.0 }
121
+ end
122
+
123
+ describe 'wasted_write_units' do
124
+ subject { table.wasted_write_units }
125
+ it { should == 4.0 }
126
+ end
127
+
128
+ describe 'lost_read_units' do
129
+ before do
130
+ table.clear_data
131
+ table.tick(12.seconds.ago, {
132
+ provisioned_reads: 100.0,
133
+ consumed_reads: 102.0,
134
+ })
135
+ end
136
+
137
+ subject { table.lost_read_units }
138
+ it { should == 2.0 }
139
+ end
140
+
141
+ describe 'lost_write_units' do
142
+ before do
143
+ table.clear_data
144
+ table.tick(12.seconds.ago, {
145
+ provisioned_writes: 100.0,
146
+ consumed_writes: 105.0,
147
+ })
148
+ end
149
+
150
+ subject { table.lost_write_units }
151
+ it { should == 5.0 }
152
+ end
153
+ end
154
+
155
+ describe 'no data' do
156
+ before { table.clear_data }
157
+
158
+ describe 'lost_write_units' do
159
+ subject { table.lost_write_units }
160
+ it { should == 0.0 }
161
+ end
162
+
163
+ describe 'lost_read_units' do
164
+ subject { table.lost_read_units }
165
+ it { should == 0.0 }
166
+ end
167
+
168
+ describe 'wasted_read_units' do
169
+ subject { table.wasted_read_units }
170
+ it { should == 0.0 }
171
+ end
172
+
173
+ describe 'wasted_write_units' do
174
+ subject { table.wasted_write_units }
175
+ it { should == 0.0 }
176
+ end
177
+
178
+ describe "#all_times" do
179
+ subject { table.all_times }
180
+ its(:length) { should == 0 }
181
+ end
182
+
183
+ describe "#last 3.seconds, :consumed_reads" do
184
+ subject { table.last 3.seconds, :consumed_reads }
185
+ it { should == [] }
186
+ end
187
+
188
+ describe "#last 1, :consumed_writes" do
189
+ subject { table.last 1, :consumed_writes }
190
+ it { should == [] }
191
+ end
192
+
193
+ describe "#last_provisioned_for :reads" do
194
+ subject { table.last_provisioned_for :reads }
195
+ it { should be_nil }
196
+ end
197
+
198
+ describe "#last_provisioned_for :writes" do
199
+ subject { table.last_provisioned_for :writes }
200
+ it { should be_nil }
201
+ end
202
+ end
203
+
204
+ describe 'time window' do
205
+ describe 'inserting data outside of time window' do
206
+ before do
207
+ table.clear_data
208
+ table.tick(12.weeks.ago, {
209
+ provisioned_reads: 600.0,
210
+ provisioned_writes: 800.0,
211
+ consumed_reads: 20.0,
212
+ consumed_writes: 30.0,
213
+ })
214
+ end
215
+
216
+ it 'should not work' do
217
+ table.all_times.should be_empty
218
+ end
219
+ end
220
+
221
+ describe 'data time based cleanup' do
222
+ before do
223
+ table.clear_data
224
+ Timecop.travel(2.weeks.ago)
225
+
226
+ table.tick(Time.now, {
227
+ provisioned_reads: 600.0,
228
+ provisioned_writes: 800.0,
229
+ consumed_reads: 20.0,
230
+ consumed_writes: 30.0,
231
+ })
232
+
233
+ to_the_future = Time.now + DynamoAutoscale::TableTracker::TIME_WINDOW +
234
+ 2.minutes
235
+
236
+ Timecop.travel(to_the_future)
237
+
238
+ table.tick(Time.now, {
239
+ provisioned_reads: 600.0,
240
+ provisioned_writes: 800.0,
241
+ consumed_reads: 20.0,
242
+ consumed_writes: 30.0,
243
+ })
244
+ end
245
+
246
+ it 'should remove data outside of the time window' do
247
+ table.all_times.length.should == 1
248
+ end
249
+
250
+ it 'should not remove data inside of the time window' do
251
+ table.tick(2.seconds.from_now, {})
252
+ table.all_times.length.should == 2
253
+ end
254
+ end
255
+ end
256
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynamo-autoscale
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - InvisibleHand
9
+ autorequire:
10
+ bindir:
11
+ - bin
12
+ cert_chain: []
13
+ date: 2013-07-02 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: aws-sdk
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rbtree
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: ruby-prof
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: colored
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: activesupport
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Will automatically monitor DynamoDB tables and scale them based on rules.
96
+ email: developers@getinvisiblehand.com
97
+ executables:
98
+ - dynamo-autoscale
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - .gitignore
103
+ - Gemfile
104
+ - Gemfile.lock
105
+ - LICENSE
106
+ - README.md
107
+ - Rakefile
108
+ - aws.sample.yml
109
+ - bin/dynamo-autoscale
110
+ - config/environment/common.rb
111
+ - config/environment/console.rb
112
+ - config/environment/test.rb
113
+ - config/logger.yml
114
+ - config/services/aws.rb
115
+ - config/services/logger.rb
116
+ - data/.gitkeep
117
+ - dynamo-autoscale.gemspec
118
+ - lib/dynamo-autoscale.rb
119
+ - lib/dynamo-autoscale/actioner.rb
120
+ - lib/dynamo-autoscale/cw_poller.rb
121
+ - lib/dynamo-autoscale/dispatcher.rb
122
+ - lib/dynamo-autoscale/dynamo_actioner.rb
123
+ - lib/dynamo-autoscale/ext/active_support/duration.rb
124
+ - lib/dynamo-autoscale/local_actioner.rb
125
+ - lib/dynamo-autoscale/local_data_poll.rb
126
+ - lib/dynamo-autoscale/logger.rb
127
+ - lib/dynamo-autoscale/metrics.rb
128
+ - lib/dynamo-autoscale/poller.rb
129
+ - lib/dynamo-autoscale/pretty_formatter.rb
130
+ - lib/dynamo-autoscale/rule.rb
131
+ - lib/dynamo-autoscale/rule_set.rb
132
+ - lib/dynamo-autoscale/table_tracker.rb
133
+ - lib/dynamo-autoscale/unit_cost.rb
134
+ - lib/dynamo-autoscale/version.rb
135
+ - rlib/dynamodb_graph.r
136
+ - rlib/dynamodb_scatterplot.r
137
+ - rulesets/default.rb
138
+ - rulesets/erroneous.rb
139
+ - rulesets/gradual_tail.rb
140
+ - rulesets/none.rb
141
+ - script/console
142
+ - script/historic_data
143
+ - script/hourly_wastage
144
+ - script/monitor
145
+ - script/simulator
146
+ - script/test
147
+ - script/validate_ruleset
148
+ - spec/actioner_spec.rb
149
+ - spec/rule_set_spec.rb
150
+ - spec/rule_spec.rb
151
+ - spec/spec_helper.rb
152
+ - spec/table_tracker_spec.rb
153
+ homepage: http://github.com/invisiblehand/dynamo-autoscale
154
+ licenses:
155
+ - MIT
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ! '>='
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 1.8.23
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: Autoscaling for DynamoDB provisioned throughputs.
178
+ test_files: []