dynamo-autoscale 0.1.4 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/CHANGELOG +6 -0
- data/Gemfile.lock +27 -8
- data/README.md +85 -47
- data/bin/dynamo-autoscale +15 -113
- data/config/dynamo-autoscale-test.yml +11 -0
- data/config/environment/common.rb +100 -25
- data/config/environment/test.rb +3 -0
- data/config/services/aws.rb +2 -19
- data/config/services/logger.rb +23 -27
- data/config/services/signals.rb +15 -0
- data/dynamo-autoscale.gemspec +1 -0
- data/dynamo-autoscale.sample.yml +79 -0
- data/lib/dynamo-autoscale/actioner.rb +27 -13
- data/lib/dynamo-autoscale/cw_poller.rb +1 -0
- data/lib/dynamo-autoscale/dispatcher.rb +10 -2
- data/lib/dynamo-autoscale/dynamo_actioner.rb +6 -5
- data/lib/dynamo-autoscale/local_actioner.rb +15 -2
- data/lib/dynamo-autoscale/local_data_poll.rb +2 -0
- data/lib/dynamo-autoscale/logger.rb +4 -0
- data/lib/dynamo-autoscale/metrics.rb +1 -1
- data/lib/dynamo-autoscale/poller.rb +7 -5
- data/lib/dynamo-autoscale/rule.rb +1 -0
- data/lib/dynamo-autoscale/rule_set.rb +4 -0
- data/lib/dynamo-autoscale/scale_report.rb +39 -0
- data/lib/dynamo-autoscale/table_tracker.rb +26 -19
- data/lib/dynamo-autoscale/version.rb +1 -1
- data/script/historic_data +17 -8
- data/script/monitor +9 -26
- data/script/simulator +16 -14
- data/script/test +29 -23
- data/script/validate_ruleset +1 -3
- data/spec/actioner_spec.rb +6 -0
- data/spec/rule_spec.rb +6 -0
- data/templates/scale_report_email.erb +17 -0
- metadata +23 -3
- data/config/logger.yml +0 -11
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
v0.2
|
2
|
+
|
3
|
+
- Completely reworked configuration. Got rid of the massive number of flags and
|
4
|
+
options required to launch dynamo-autoscale and moved them into a config file.
|
5
|
+
- Added the ability to send and email whenever a scale happens.
|
6
|
+
|
1
7
|
v0.1.4
|
2
8
|
|
3
9
|
- Fixed a bug that stopped all rule evaluation after the first rule passed. Now
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dynamo-autoscale (0.1)
|
4
|
+
dynamo-autoscale (0.1.4)
|
5
|
+
activesupport
|
5
6
|
aws-sdk
|
6
7
|
colored
|
8
|
+
pony
|
7
9
|
rbtree
|
8
10
|
ruby-prof
|
9
11
|
|
10
12
|
GEM
|
11
13
|
remote: https://rubygems.org/
|
12
14
|
specs:
|
13
|
-
activesupport (
|
14
|
-
i18n (
|
15
|
-
|
16
|
-
|
15
|
+
activesupport (4.0.0)
|
16
|
+
i18n (~> 0.6, >= 0.6.4)
|
17
|
+
minitest (~> 4.2)
|
18
|
+
multi_json (~> 1.3)
|
19
|
+
thread_safe (~> 0.1)
|
20
|
+
tzinfo (~> 0.3.37)
|
21
|
+
atomic (1.1.10)
|
22
|
+
aws-sdk (1.11.3)
|
17
23
|
json (~> 1.4)
|
18
24
|
nokogiri (< 1.6.0)
|
19
25
|
uuidtools (~> 2.1)
|
@@ -21,11 +27,19 @@ GEM
|
|
21
27
|
coderay (1.0.9)
|
22
28
|
colored (1.2)
|
23
29
|
diff-lcs (1.2.4)
|
24
|
-
i18n (0.6.
|
30
|
+
i18n (0.6.4)
|
25
31
|
json (1.8.0)
|
32
|
+
mail (2.5.4)
|
33
|
+
mime-types (~> 1.16)
|
34
|
+
treetop (~> 1.4.8)
|
26
35
|
method_source (0.8.1)
|
27
|
-
|
36
|
+
mime-types (1.23)
|
37
|
+
minitest (4.7.5)
|
38
|
+
multi_json (1.7.7)
|
28
39
|
nokogiri (1.5.10)
|
40
|
+
polyglot (0.3.3)
|
41
|
+
pony (1.5)
|
42
|
+
mail (> 2.0)
|
29
43
|
pry (0.9.12.2)
|
30
44
|
coderay (~> 1.0.5)
|
31
45
|
method_source (~> 0.8)
|
@@ -43,14 +57,19 @@ GEM
|
|
43
57
|
rspec-mocks (2.13.1)
|
44
58
|
ruby-prof (0.13.0)
|
45
59
|
slop (3.4.5)
|
60
|
+
thread_safe (0.1.0)
|
61
|
+
atomic
|
46
62
|
timecop (0.6.1)
|
63
|
+
treetop (1.4.14)
|
64
|
+
polyglot
|
65
|
+
polyglot (>= 0.3.1)
|
66
|
+
tzinfo (0.3.37)
|
47
67
|
uuidtools (2.1.4)
|
48
68
|
|
49
69
|
PLATFORMS
|
50
70
|
ruby
|
51
71
|
|
52
72
|
DEPENDENCIES
|
53
|
-
activesupport
|
54
73
|
dynamo-autoscale!
|
55
74
|
pry
|
56
75
|
ripl
|
data/README.md
CHANGED
@@ -37,7 +37,26 @@ This project aims to take all of this into consideration and automatically scale
|
|
37
37
|
your throughputs to enable you to deal with spikes and save money where
|
38
38
|
possible.
|
39
39
|
|
40
|
-
#
|
40
|
+
# Usage
|
41
|
+
|
42
|
+
First of all, you'll need to install this project as a gem:
|
43
|
+
|
44
|
+
$ gem install dynamo-autoscale
|
45
|
+
|
46
|
+
This will give you access to the `dynamo-autoscale` executable. The executable
|
47
|
+
takes a single argument, the path to a config file.
|
48
|
+
|
49
|
+
## Configuration
|
50
|
+
|
51
|
+
The configuration file is the central thing that `dynamo-autoscale` requires to
|
52
|
+
function. It specifies what tables to monitor, maximum and minimum throughputs
|
53
|
+
and where your ruleset is located.
|
54
|
+
|
55
|
+
The `dynamo-autoscale` executable takes a single argument, and that is the path
|
56
|
+
to the configuration file you want to use.
|
57
|
+
|
58
|
+
**A sample config can be found in the project root directory.** It documents all
|
59
|
+
of the options you can specify.
|
41
60
|
|
42
61
|
This library requires AWS keys that have access to both CloudWatch and DynamoDB,
|
43
62
|
for retriving data and sending scaling requests. Using IAM, create a new user, and
|
@@ -52,29 +71,30 @@ The ARN for the custom policy can be specified as '\*' to allow access to all ta
|
|
52
71
|
or alternatively you can refer to the IAM documentation to limit access to specific
|
53
72
|
tables only.
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
- ./aws.yml
|
58
|
-
- ENV['AWS_CONFIG']
|
59
|
-
|
60
|
-
If it doesn't find an AWS YAML config in any of those locations, the process
|
61
|
-
prints an error and exits.
|
62
|
-
|
63
|
-
**A sample config can be found in the project root directory.**
|
74
|
+
### Minimal "getting started" configuration
|
64
75
|
|
65
|
-
|
76
|
+
``` yaml
|
77
|
+
:aws:
|
78
|
+
:access_key_id: "your_id"
|
79
|
+
:secret_access_key: "your_key"
|
80
|
+
:dynamo_db_endpoint: "dynamodb.us-east-1.amazonaws.com"
|
66
81
|
|
67
|
-
|
82
|
+
# There are some example rulesets in the rulesets/ directory of this project.
|
83
|
+
:ruleset: "path_to_your_ruleset.rb"
|
68
84
|
|
69
|
-
|
85
|
+
:tables:
|
86
|
+
- "your_table_name"
|
70
87
|
|
71
|
-
|
72
|
-
|
88
|
+
# In dry-run mode, the program will do exactly what it would normally except it
|
89
|
+
# won't touch DynamoDB at all. It will just log the changes it would have made
|
90
|
+
# in production locally.
|
91
|
+
:dry_run: true
|
92
|
+
```
|
73
93
|
|
74
|
-
|
94
|
+
Save this somewhere on your filesystem and point the `dynamo-autoscale`
|
95
|
+
executable to it:
|
75
96
|
|
76
|
-
|
77
|
-
expects.
|
97
|
+
$ dynamo-autoscale path/to/config.yml
|
78
98
|
|
79
99
|
## Logging
|
80
100
|
|
@@ -84,16 +104,8 @@ variable set to `true`:
|
|
84
104
|
|
85
105
|
$ DEBUG=true dynamo-autoscale <args...>
|
86
106
|
|
87
|
-
Also, if you want pretty coloured logging, you can set the `PRETTY_LOG`
|
88
|
-
environment variable to `true`:
|
89
|
-
|
90
|
-
$ PRETTY_LOG=true DEBUG=true dynamo-autoscale <args...>
|
91
|
-
|
92
107
|
## Rulesets
|
93
108
|
|
94
|
-
One of the first things you'll notice upon looking into the `--help` on the
|
95
|
-
executable is that it's looking for a "rule set". What on earth is a rule set?
|
96
|
-
|
97
109
|
A rule set is the primary user input for dynamo-autoscale. It is a DSL for
|
98
110
|
specifying when to increase and decrease your provisioned throughputs. Here is a
|
99
111
|
very basic rule set:
|
@@ -236,10 +248,13 @@ your four downscales for the current day. Or, you can downscale reads and writes
|
|
236
248
|
at the same time and this also costs you one of your four. (Reference:
|
237
249
|
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html)
|
238
250
|
|
239
|
-
Because of this, the actioner can handle the grouping up of downscales
|
240
|
-
|
251
|
+
Because of this, the actioner can handle the grouping up of downscales by adding
|
252
|
+
the following to your config:
|
241
253
|
|
242
|
-
|
254
|
+
``` yaml
|
255
|
+
:group_downscales: true
|
256
|
+
:flush_after: 300
|
257
|
+
```
|
243
258
|
|
244
259
|
What this is saying is that if a write downscale came in, the actioner wouldn't
|
245
260
|
fire it off immediately. It would wait 300 seconds, or 5 minutes, to see if a
|
@@ -248,11 +263,11 @@ time. If no corresponding read came in, after 5 minutes the pending write
|
|
248
263
|
downscale would get "flushed" and applied without a read downscale.
|
249
264
|
|
250
265
|
This technique helps to save downscales on tables that may have unpredictable
|
251
|
-
consumption. You may need to tweak the
|
252
|
-
situation. By default, there is no
|
253
|
-
indefinitely, this may not be desirable.
|
266
|
+
consumption. You may need to tweak the `flush_after` value to match your own
|
267
|
+
situation. By default, there is no `flush_after` and downscales will wait
|
268
|
+
indefinitely, but this may not be desirable.
|
254
269
|
|
255
|
-
##
|
270
|
+
## Signalling
|
256
271
|
|
257
272
|
The `dynamo-autoscale` process responds to the SIGUSR1 and SIGUSR2 signals. What
|
258
273
|
we've done may be a dramatic bastardisation of what signals are intended for or
|
@@ -266,7 +281,7 @@ files in the directory it was run in.
|
|
266
281
|
|
267
282
|
Example:
|
268
283
|
|
269
|
-
$ dynamo-autoscale
|
284
|
+
$ dynamo-autoscale path/to/config.yml
|
270
285
|
# Runs as PID 1234. Wait for some time to pass...
|
271
286
|
$ kill -USR1 1234
|
272
287
|
$ cat some_table.csv
|
@@ -286,7 +301,34 @@ The CSV is in the following format:
|
|
286
301
|
If you send SIGUSR2 to the process as it's running, the process will take all of
|
287
302
|
the data it has on all of its tables and generate a graph for each table using R
|
288
303
|
(see the Graphs section below). This is handy for visualising what the process
|
289
|
-
is doing, especially after doing a few hours of a
|
304
|
+
is doing, especially after doing a few hours of a `dry_run`.
|
305
|
+
|
306
|
+
## Scale Report Emails
|
307
|
+
|
308
|
+
If you would like to receive email notifications whenever a scale event happens,
|
309
|
+
you can specify some email options in your configuration. Specifying the email
|
310
|
+
options implicitly activates email reports. Not including your email config
|
311
|
+
implicitly turns it off.
|
312
|
+
|
313
|
+
Sample email config:
|
314
|
+
|
315
|
+
``` yaml
|
316
|
+
:email:
|
317
|
+
:to: "john.doe@example.com"
|
318
|
+
:from: "dynamo-autoscale@example.com"
|
319
|
+
:via: :smtp
|
320
|
+
:via_options:
|
321
|
+
:port: 25
|
322
|
+
:enable_starttls_auto: false
|
323
|
+
:authentication: :plain
|
324
|
+
:address: "mailserver.example.com"
|
325
|
+
:user_name: "user"
|
326
|
+
:password: "password"
|
327
|
+
```
|
328
|
+
|
329
|
+
We're using Pony internally to send email and this part of the config just gets
|
330
|
+
passed to Pony verbatim. Check out the [Pony](https://github.com/benprew/pony)
|
331
|
+
documentation for more details on the options it supports.
|
290
332
|
|
291
333
|
# Developers / Tooling
|
292
334
|
|
@@ -333,25 +375,21 @@ with the `script/historic_data` executable.
|
|
333
375
|
If you want to test rules on your local machine without having to query
|
334
376
|
CloudWatch or hit DynamoDB, there are tools that facilitate that nicely.
|
335
377
|
|
336
|
-
The first thing you would need to do is gather some historic data. There's a
|
337
|
-
script called `script/historic_data` that you can run to gather data on a
|
338
|
-
specific table and store it into the `data/` directory in a format that all of
|
339
|
-
the other scripts are familiar with.
|
340
|
-
|
341
|
-
Next there are a couple of things you can do.
|
342
|
-
|
343
378
|
### Running a test
|
344
379
|
|
345
380
|
You can run a big batch of data all in one go with the `script/test` script.
|
346
381
|
This script can be invoked like this:
|
347
382
|
|
348
|
-
$ script/test
|
383
|
+
$ script/test path/to/config.yml
|
384
|
+
|
385
|
+
You will need to make sure you have historic data available for whatever tables
|
386
|
+
you have listed in your config file. If you don't, it's easy to gather it:
|
349
387
|
|
350
|
-
|
351
|
-
This will run through all of the data for that table in time order, logging
|
352
|
-
along the way and triggering rules from the rule set if any were defined.
|
388
|
+
$ script/historic_data path/to/config.yml
|
353
389
|
|
354
|
-
|
390
|
+
This script goes off to CloudWatch and pulls down about a week of data for each
|
391
|
+
table you have listed in your config. Then you can continue to re-run the
|
392
|
+
`script/test` command and watch a tonne of log output fly by.
|
355
393
|
|
356
394
|
#### Graphs
|
357
395
|
|
data/bin/dynamo-autoscale
CHANGED
@@ -1,85 +1,24 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'optparse'
|
5
|
-
require 'active_support/all'
|
6
|
-
|
7
|
-
# Force this script into production mode as it's the only thing that will
|
8
|
-
# actually hit DynamoDB in the entire project.
|
9
|
-
ENV['RACK_ENV'] = "production"
|
10
|
-
|
11
|
-
actioner_opts = {}
|
12
|
-
general_opts = {}
|
13
|
-
|
14
|
-
OptionParser.new do |opts|
|
15
|
-
opts.banner = "Usage: dynamo-autoscale ruleset_path table_name [more table names] [options]"
|
16
|
-
|
17
|
-
doc = 'Makes read and write downscales happen at the same time to save ' +
|
18
|
-
'downscales per day.'
|
19
|
-
|
20
|
-
opts.on('-g', '--group-downscales', doc) do
|
21
|
-
actioner_opts[:group_downscales] = true
|
22
|
-
end
|
23
|
-
|
24
|
-
doc = 'Only works in conjunction with --group-downscales. Sets a maximum ' +
|
25
|
-
'amount of time for an operation to be pending before it gets applied to Dynamo'
|
26
|
-
|
27
|
-
opts.on('--flush-after SECONDS', Integer, doc) do |seconds|
|
28
|
-
actioner_opts[:flush_after] = seconds.to_i.seconds
|
29
|
-
end
|
30
|
-
|
31
|
-
doc = 'Stops dynamo-autoscale from talking to DynamoDB. Instead, it just ' +
|
32
|
-
'tracks the changes it would have made locally.'
|
33
|
-
|
34
|
-
opts.on('--dry-run', doc) do
|
35
|
-
general_opts[:dry_run] = true
|
36
|
-
end
|
37
|
-
|
38
|
-
doc = "Sets a minimum value for throughputs to be set to. " +
|
39
|
-
"Defaults to 10."
|
40
|
-
|
41
|
-
opts.on('--minimum-throughput VALUE', Float, doc) do |value|
|
42
|
-
if value < 1.0
|
43
|
-
STDERR.puts "Cannot set minimum throughput to less than 1."
|
44
|
-
exit 1
|
45
|
-
end
|
46
|
-
|
47
|
-
general_opts[:minimum_throughput] = value
|
48
|
-
end
|
49
|
-
|
50
|
-
doc = "Sets a maximum value for throughputs to be set to. " +
|
51
|
-
"Defaults to 20,000."
|
52
|
-
|
53
|
-
opts.on('--maximum-throughput VALUE', Float, doc) do |value|
|
54
|
-
general_opts[:maximum_throughput] = value
|
55
|
-
end
|
56
|
-
|
57
|
-
opts.on( '-h', '--help', 'Display this screen' ) do
|
58
|
-
puts opts
|
59
|
-
exit
|
60
|
-
end
|
61
|
-
end.parse!
|
3
|
+
require_relative '../config/environment/common'
|
62
4
|
|
63
|
-
|
64
|
-
|
5
|
+
if ARGV[0]
|
6
|
+
DynamoAutoscale.setup_from_config(ARGV[0])
|
7
|
+
elsif ARGV[0].nil?
|
8
|
+
STDERR.puts "Usage: dynamo-autoscale path/to/config.yml"
|
65
9
|
|
66
|
-
if tables.empty? or ruleset.nil?
|
67
|
-
STDERR.puts "Usage: dynamo-autoscale ruleset table_name [another_table_name ... ]"
|
68
10
|
exit 1
|
69
|
-
|
11
|
+
elsif ARGV[0] and !File.exists?(ARGV[0])
|
12
|
+
STDERR.puts "Usage: dynamo-autoscale path/to/config.yml"
|
13
|
+
STDERR.puts "Error: The path you specified is to a file that does not exist."
|
70
14
|
|
71
|
-
if actioner_opts[:flush_after] and actioner_opts[:group_downscales].nil?
|
72
|
-
STDERR.puts "Cannot specify a flush_after value with setting --group-downscales."
|
73
15
|
exit 1
|
74
16
|
end
|
75
17
|
|
76
|
-
|
77
|
-
include DynamoAutoscale
|
78
|
-
extend DynamoAutoscale
|
79
|
-
|
80
|
-
logger.debug "Ensuring tables exist in DynamoDB..."
|
18
|
+
DynamoAutoscale.logger.info "Ensuring tables exist in DynamoDB..."
|
81
19
|
dynamo = AWS::DynamoDB.new
|
82
|
-
|
20
|
+
|
21
|
+
DynamoAutoscale.poller_opts[:tables].select! do |table_name|
|
83
22
|
if dynamo.tables[table_name].exists?
|
84
23
|
true
|
85
24
|
else
|
@@ -88,48 +27,11 @@ tables.select! do |table_name|
|
|
88
27
|
end
|
89
28
|
end
|
90
29
|
|
91
|
-
|
92
|
-
STDERR.puts "No valid tables specified."
|
93
|
-
exit 1
|
94
|
-
end
|
95
|
-
|
96
|
-
poller_opts = { tables: tables }
|
97
|
-
|
98
|
-
if general_opts[:dry_run]
|
99
|
-
poller_opts[:filters] = LocalActioner.faux_provisioning_filters
|
100
|
-
end
|
101
|
-
|
102
|
-
logger.debug "Assigning global objects..."
|
103
|
-
DynamoAutoscale.rules = RuleSet.new(ruleset)
|
104
|
-
DynamoAutoscale.dispatcher = Dispatcher.new
|
105
|
-
DynamoAutoscale.poller = CWPoller.new(poller_opts)
|
106
|
-
DynamoAutoscale.actioner_class = general_opts[:dry_run] ? LocalActioner : DynamoActioner
|
107
|
-
DynamoAutoscale.actioner_opts = actioner_opts
|
30
|
+
DynamoAutoscale.poller_class = DynamoAutoscale::CWPoller
|
108
31
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
if general_opts[:maximum_throughput]
|
114
|
-
Actioner.maximum_throughput = general_opts[:maximum_throughput]
|
115
|
-
end
|
116
|
-
|
117
|
-
logger.debug "Registering signal handlers..."
|
118
|
-
Signal.trap("USR1") do
|
119
|
-
logger.info "[signal] Caught SIGUSR1. Dumping CSV for all tables in #{Dir.pwd}"
|
120
|
-
|
121
|
-
DynamoAutoscale.tables.each do |name, table|
|
122
|
-
table.to_csv! path: File.join(Dir.pwd, "#{table.name}.csv")
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
Signal.trap("USR2") do
|
127
|
-
logger.info "[signal] Caught SIGUSR2. Dumping graphs for all tables in #{Dir.pwd}"
|
128
|
-
|
129
|
-
DynamoAutoscale.tables.each do |name, table|
|
130
|
-
table.graph! path: File.join(Dir.pwd, "#{table.name}.png")
|
131
|
-
end
|
32
|
+
unless DynamoAutoscale.config[:dry_run]
|
33
|
+
DynamoAutoscale.actioner_class = DynamoAutoscale::DynamoActioner
|
132
34
|
end
|
133
35
|
|
134
|
-
logger.info "Finished setup. Starting polling loop."
|
36
|
+
DynamoAutoscale.logger.info "Finished setup. Starting polling loop."
|
135
37
|
DynamoAutoscale.poller.run
|
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'optparse'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'timecop'
|
2
5
|
require 'time'
|
3
6
|
require 'csv'
|
4
7
|
require 'tempfile'
|
@@ -6,6 +9,9 @@ require 'aws-sdk'
|
|
6
9
|
require 'active_support/all'
|
7
10
|
require 'rbtree'
|
8
11
|
require 'colored'
|
12
|
+
require 'pp'
|
13
|
+
require 'erb'
|
14
|
+
require 'pony'
|
9
15
|
|
10
16
|
require_relative '../../lib/dynamo-autoscale/logger'
|
11
17
|
require_relative '../../lib/dynamo-autoscale/poller'
|
@@ -24,28 +30,77 @@ module DynamoAutoscale
|
|
24
30
|
File.join(self.root, 'data')
|
25
31
|
end
|
26
32
|
|
27
|
-
def self.
|
28
|
-
|
33
|
+
def self.config
|
34
|
+
@@config ||= {}
|
29
35
|
end
|
30
36
|
|
31
|
-
def self.
|
32
|
-
|
37
|
+
def self.config= new_config
|
38
|
+
@@config = new_config
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.setup_from_config path, overrides = {}
|
42
|
+
logger.debug "[setup] Loading config..."
|
43
|
+
self.config = YAML.load_file(path).merge(overrides)
|
44
|
+
|
45
|
+
if config[:tables].nil? or config[:tables].empty?
|
46
|
+
STDERR.puts "You need to specify at least one table in your config's " +
|
47
|
+
":tables section."
|
33
48
|
|
34
|
-
|
35
|
-
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
filters = config[:dry_run] ? DynamoAutoscale::LocalActioner.faux_provisioning_filters : []
|
53
|
+
if filters.empty?
|
54
|
+
logger.debug "[setup] Not running as a dry run. Hitting production Dynamo."
|
36
55
|
else
|
37
|
-
|
56
|
+
logger.debug "[setup] Running as dry run. No throughputs will be changed."
|
57
|
+
end
|
58
|
+
|
59
|
+
DynamoAutoscale.poller_opts = {
|
60
|
+
tables: config[:tables],
|
61
|
+
filters: filters,
|
62
|
+
}
|
63
|
+
|
64
|
+
logger.debug "[setup] Poller options are: #{DynamoAutoscale.poller_opts}"
|
65
|
+
|
66
|
+
DynamoAutoscale.actioner_opts = {
|
67
|
+
group_downscales: config[:group_downscales],
|
68
|
+
flush_after: config[:flush_after],
|
69
|
+
}
|
70
|
+
|
71
|
+
logger.debug "[setup] Actioner options are: #{DynamoAutoscale.actioner_opts}"
|
72
|
+
|
73
|
+
if config[:minimum_throughput]
|
74
|
+
DynamoAutoscale::Actioner.minimum_throughput = config[:minimum_throughput]
|
38
75
|
end
|
39
76
|
|
40
|
-
|
41
|
-
|
42
|
-
|
77
|
+
if config[:maximum_throughput]
|
78
|
+
DynamoAutoscale::Actioner.maximum_throughput = config[:maximum_throughput]
|
79
|
+
end
|
80
|
+
|
81
|
+
logger.debug "[setup] Minimum throughput set to: " +
|
82
|
+
"#{DynamoAutoscale::Actioner.minimum_throughput}"
|
83
|
+
logger.debug "[setup] Maximum throughput set to: " +
|
84
|
+
"#{DynamoAutoscale::Actioner.maximum_throughput}"
|
85
|
+
|
86
|
+
logger.debug "[setup] Ruleset loading from: #{config[:ruleset]}"
|
87
|
+
DynamoAutoscale.ruleset_location = config[:ruleset]
|
88
|
+
|
89
|
+
logger.debug "[setup] Loaded #{DynamoAutoscale.rules.rules.values.flatten.count} rules."
|
90
|
+
|
91
|
+
DynamoAutoscale.load_services
|
43
92
|
end
|
44
93
|
|
45
94
|
def self.require_all path
|
46
95
|
Dir[File.join(root, path, '*.rb')].each { |file| require file }
|
47
96
|
end
|
48
97
|
|
98
|
+
def self.load_services
|
99
|
+
Dir[File.join(DynamoAutoscale.root, 'config', 'services', '*.rb')].each do |path|
|
100
|
+
load path
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
49
104
|
def self.dispatcher= new_dispatcher
|
50
105
|
@@dispatcher = new_dispatcher
|
51
106
|
end
|
@@ -54,12 +109,28 @@ module DynamoAutoscale
|
|
54
109
|
@@dispatcher ||= Dispatcher.new
|
55
110
|
end
|
56
111
|
|
112
|
+
def self.poller_opts= new_poller_opts
|
113
|
+
@@poller_opts = new_poller_opts
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.poller_opts
|
117
|
+
@@poller_opts ||= {}
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.poller_class= new_poller_class
|
121
|
+
@@poller_class = new_poller_class
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.poller_class
|
125
|
+
@@poller_class ||= LocalDataPoll
|
126
|
+
end
|
127
|
+
|
57
128
|
def self.poller= new_poller
|
58
129
|
@@poller = new_poller
|
59
130
|
end
|
60
131
|
|
61
132
|
def self.poller
|
62
|
-
@@poller ||=
|
133
|
+
@@poller ||= poller_class.new(poller_opts)
|
63
134
|
end
|
64
135
|
|
65
136
|
def self.actioner_class= klass
|
@@ -79,37 +150,41 @@ module DynamoAutoscale
|
|
79
150
|
end
|
80
151
|
|
81
152
|
def self.actioners
|
82
|
-
@@actioners ||= Hash.new
|
153
|
+
@@actioners ||= Hash.new do |h, k|
|
154
|
+
h[k] = actioner_class.new(k, actioner_opts)
|
155
|
+
end
|
83
156
|
end
|
84
157
|
|
85
|
-
def self.
|
86
|
-
@@tables =
|
158
|
+
def self.reset_tables
|
159
|
+
@@tables = Hash.new { |h, k| h[k] = TableTracker.new(k) }
|
87
160
|
end
|
88
161
|
|
89
162
|
def self.tables
|
90
163
|
@@tables ||= Hash.new { |h, k| h[k] = TableTracker.new(k) }
|
91
164
|
end
|
92
165
|
|
93
|
-
def self.
|
94
|
-
@@
|
166
|
+
def self.ruleset_location
|
167
|
+
@@ruleset_location ||= nil
|
95
168
|
end
|
96
169
|
|
97
|
-
def self.
|
98
|
-
@@
|
170
|
+
def self.ruleset_location= new_ruleset_location
|
171
|
+
@@ruleset_location = new_ruleset_location
|
99
172
|
end
|
100
173
|
|
101
|
-
def self.rules
|
102
|
-
@@rules
|
174
|
+
def self.rules
|
175
|
+
@@rules ||= RuleSet.new(ruleset_location)
|
103
176
|
end
|
104
177
|
|
105
|
-
def self.
|
106
|
-
@@
|
178
|
+
def self.current_table= new_current_table
|
179
|
+
@@current_table = new_current_table
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.current_table
|
183
|
+
@@current_table
|
107
184
|
end
|
108
185
|
end
|
109
186
|
|
110
187
|
DynamoAutoscale.require_all 'lib/dynamo-autoscale'
|
111
188
|
DynamoAutoscale.require_all 'lib/dynamo-autoscale/ext/**'
|
112
189
|
|
113
|
-
|
114
|
-
load path
|
115
|
-
end
|
190
|
+
DynamoAutoscale.load_services
|
data/config/environment/test.rb
CHANGED
data/config/services/aws.rb
CHANGED
@@ -1,20 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
if File.exists? './aws.yml'
|
4
|
-
config_location = './aws.yml'
|
5
|
-
elsif ENV['AWS_CONFIG'] and File.exists? ENV['AWS_CONFIG']
|
6
|
-
config_location = ENV['AWS_CONFIG']
|
7
|
-
elsif File.exists?(File.join(DynamoAutoscale.root, 'config', 'aws.yml'))
|
8
|
-
config_location = File.join(DynamoAutoscale.root, 'config', 'aws.yml')
|
9
|
-
end
|
10
|
-
|
11
|
-
if config_location.nil?
|
12
|
-
STDERR.puts "Could not load AWS configuration. Searched in: ./aws.yml and " +
|
13
|
-
"ENV['AWS_CONFIG']"
|
14
|
-
|
15
|
-
exit 1
|
16
|
-
end
|
17
|
-
|
18
|
-
DynamoAutoscale.with_config(config_location, absolute: true) do |config|
|
19
|
-
AWS.config(config)
|
1
|
+
if DynamoAutoscale.config[:aws]
|
2
|
+
AWS.config(DynamoAutoscale.config[:aws])
|
20
3
|
end
|