interferon 0.1.0 → 0.1.3

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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +4 -0
  3. data/.rubocop_todo.yml +83 -0
  4. data/.travis.yml +4 -1
  5. data/bin/interferon +10 -9
  6. data/interferon.gemspec +18 -17
  7. data/lib/interferon/alert.rb +4 -10
  8. data/lib/interferon/alert_dsl.rb +12 -7
  9. data/lib/interferon/destinations/datadog.rb +103 -103
  10. data/lib/interferon/group_sources/filesystem.rb +5 -5
  11. data/lib/interferon/host_sources/aws_dynamo.rb +17 -19
  12. data/lib/interferon/host_sources/aws_elasticache.rb +20 -22
  13. data/lib/interferon/host_sources/aws_rds.rb +33 -33
  14. data/lib/interferon/host_sources/optica.rb +12 -10
  15. data/lib/interferon/host_sources/optica_services.rb +17 -15
  16. data/lib/interferon/host_sources/test_host_source.rb +1 -1
  17. data/lib/interferon/loaders.rb +4 -5
  18. data/lib/interferon/logging.rb +2 -3
  19. data/lib/interferon/version.rb +1 -1
  20. data/lib/interferon/work_hours_helper.rb +5 -5
  21. data/lib/interferon.rb +79 -80
  22. data/script/pre-commit +15 -20
  23. data/spec/fixtures/loaders/host_sources/test_host_source.rb +1 -1
  24. data/spec/fixtures/loaders/test_sources/order_test_source.rb +1 -1
  25. data/spec/fixtures/loaders/test_sources/test_source.rb +1 -1
  26. data/spec/fixtures/loaders2/test_sources/order_test_source.rb +1 -1
  27. data/spec/fixtures/loaders2/test_sources/secondary_source.rb +1 -1
  28. data/spec/fixtures/loaders2/test_sources/test_source.rb +1 -2
  29. data/spec/helpers/logging_helper.rb +2 -2
  30. data/spec/helpers/mock_alert.rb +1 -1
  31. data/spec/helpers/optica_helper.rb +70 -70
  32. data/spec/lib/interferon/destinations/datadog_spec.rb +58 -59
  33. data/spec/lib/interferon/group_sources/filesystem_spec.rb +29 -24
  34. data/spec/lib/interferon/host_sources/optica_services_spec.rb +11 -9
  35. data/spec/lib/interferon/host_sources/optica_spec.rb +6 -3
  36. data/spec/lib/interferon/loaders_spec.rb +19 -15
  37. data/spec/lib/interferon_spec.rb +61 -59
  38. data/spec/lib/work_hours_helper_spec.rb +15 -15
  39. data/spec/spec_helper.rb +1 -1
  40. metadata +61 -65
data/lib/interferon.rb CHANGED
@@ -6,7 +6,7 @@ require 'interferon/loaders'
6
6
  require 'interferon/alert'
7
7
  require 'interferon/alert_dsl'
8
8
 
9
- #require 'pry' #uncomment if you're debugging
9
+ # require 'pry' #uncomment if you're debugging
10
10
  require 'erb'
11
11
  require 'ostruct'
12
12
  require 'parallel'
@@ -15,17 +15,16 @@ require 'yaml'
15
15
 
16
16
  module Interferon
17
17
  class Interferon
18
-
19
18
  include Logging
20
19
  attr_accessor :host_sources, :destinations, :host_info
21
20
 
22
- DRY_RUN_ALERTS_NAME_PREFIX = '[-dry-run-]'
21
+ DRY_RUN_ALERTS_NAME_PREFIX = '[-dry-run-]'.freeze
23
22
 
24
23
  # groups_sources is a hash from type => options for each group source
25
24
  # host_sources is a hash from type => options for each host source
26
25
  # destinations is a similar hash from type => options for each alerter
27
26
  def initialize(alerts_repo_path, groups_sources, host_sources, destinations,
28
- dry_run=false, processes=nil)
27
+ dry_run = false, processes = nil)
29
28
  @alerts_repo_path = alerts_repo_path
30
29
  @groups_sources = groups_sources
31
30
  @host_sources = host_sources
@@ -36,8 +35,8 @@ module Interferon
36
35
  end
37
36
 
38
37
  def run(dry_run = false)
39
- Signal.trap("TERM") do
40
- log.info "SIGTERM received. shutting down gracefully..."
38
+ Signal.trap('TERM') do
39
+ log.info 'SIGTERM received. shutting down gracefully...'
41
40
  @request_shutdown = true
42
41
  end
43
42
  @dry_run = dry_run
@@ -50,9 +49,7 @@ module Interferon
50
49
 
51
50
  @destinations.each do |dest|
52
51
  dest['options'] ||= {}
53
- if @dry_run
54
- dest['options']['dry_run'] = true
55
- end
52
+ dest['options']['dry_run'] = true if @dry_run
56
53
  end
57
54
 
58
55
  update_alerts(@destinations, hosts, alerts, groups)
@@ -71,7 +68,7 @@ module Interferon
71
68
  # validate that alerts path exists
72
69
  path = File.expand_path(File.join(@alerts_repo_path, 'alerts'))
73
70
  abort("no such directory #{path} for reading alert files") \
74
- unless Dir.exists?(path)
71
+ unless Dir.exist?(path)
75
72
 
76
73
  Dir.glob(File.join(path, '*.rb')) do |alert_file|
77
74
  break if @request_shutdown
@@ -91,7 +88,7 @@ module Interferon
91
88
  statsd.gauge('alerts.read.failed', failed)
92
89
 
93
90
  abort("failed to read #{failed} alerts") if failed > 0
94
- return alerts
91
+ alerts
95
92
  end
96
93
 
97
94
  def read_groups(sources)
@@ -99,7 +96,7 @@ module Interferon
99
96
  loader = GroupSourcesLoader.new([@alerts_repo_path])
100
97
  loader.get_all(sources).each do |source|
101
98
  break if @request_shutdown
102
- source_groups = source.list_groups
99
+ source_groups = source.list_groups { groups }
103
100
 
104
101
  # add all people to groups
105
102
  people_count = 0
@@ -109,16 +106,18 @@ module Interferon
109
106
  people_count += people.count
110
107
  end
111
108
 
112
- log.info "read #{people_count} people in #{source_groups.count} groups from source #{source.class.name}"
109
+ log.info "read #{people_count} people in #{source_groups.count} groups" \
110
+ "from source #{source.class.name}"
113
111
  end
114
112
 
115
- log.info "total of #{groups.values.flatten.count} people in #{groups.count} groups from #{sources.count} sources"
113
+ log.info "total of #{groups.values.flatten.count} people in #{groups.count} groups" \
114
+ "from #{sources.count} sources"
116
115
 
117
116
  statsd.gauge('groups.sources', sources.count)
118
117
  statsd.gauge('groups.count', groups.count)
119
118
  statsd.gauge('groups.people', groups.values.flatten.count)
120
119
 
121
- return groups
120
+ groups
122
121
  end
123
122
 
124
123
  def read_hosts(sources)
@@ -131,14 +130,14 @@ module Interferon
131
130
  source_hosts = source.list_hosts
132
131
  hosts << source_hosts
133
132
 
134
- statsd.gauge('hosts.count', source_hosts.count, :tags => ["source:#{source.class.name}"])
133
+ statsd.gauge('hosts.count', source_hosts.count, tags: ["source:#{source.class.name}"])
135
134
  log.info "read #{source_hosts.count} hosts from source #{source.class.name}"
136
135
  end
137
136
 
138
137
  hosts.flatten!
139
138
  log.info "total of #{hosts.count} entities from #{sources.count} sources"
140
139
 
141
- return hosts
140
+ hosts
142
141
  end
143
142
 
144
143
  def update_alerts(destinations, hosts, alerts, groups)
@@ -169,16 +168,15 @@ module Interferon
169
168
  statsd.histogram(
170
169
  @dry_run ? 'destinations.run_time.dry_run' : 'destinations.run_time',
171
170
  run_time,
172
- :tags => ["destination:#{dest.class.name}"])
173
- log.info "#{dest.class.name} : run completed in %.2f seconds" % (run_time)
171
+ tags: ["destination:#{dest.class.name}"]
172
+ )
173
+ log.info "#{dest.class.name} : run completed in %.2f seconds" % run_time
174
174
 
175
175
  # report destination stats
176
176
  dest.report_stats
177
177
  end
178
178
 
179
- if @dry_run && !dest.api_errors.empty?
180
- raise dest.api_errors.to_s
181
- end
179
+ raise dest.api_errors.to_s if @dry_run && !dest.api_errors.empty?
182
180
  end
183
181
 
184
182
  def do_dry_run_update(dest, hosts, alerts, existing_alerts, groups)
@@ -192,8 +190,8 @@ module Interferon
192
190
  end
193
191
 
194
192
  alerts_queue = build_alerts_queue(hosts, alerts, groups)
195
- updates_queue = alerts_queue.reject do |name, alert_people_pair|
196
- !Interferon::need_update(dest, alert_people_pair, existing_alerts)
193
+ updates_queue = alerts_queue.reject do |_name, alert_people_pair|
194
+ !Interferon.need_update(dest, alert_people_pair, existing_alerts)
197
195
  end
198
196
 
199
197
  # Add dry-run prefix to alerts and delete id to avoid impacting real alerts
@@ -206,7 +204,7 @@ module Interferon
206
204
  end
207
205
 
208
206
  # Build new queue with dry-run prefixes and ensure they are silenced
209
- alerts_queue.each do |name, alert_people_pair|
207
+ alerts_queue.each do |_name, alert_people_pair|
210
208
  alert = alert_people_pair[0]
211
209
  dry_run_alert_name = DRY_RUN_ALERTS_NAME_PREFIX + alert['name']
212
210
  alert.change_name(dry_run_alert_name)
@@ -216,23 +214,23 @@ module Interferon
216
214
  # Create alerts in destination
217
215
  created_alerts = create_alerts(dest, updates_queue)
218
216
 
219
- # Existing alerts are pruned until all that remains are alerts that aren't being generated anymore
217
+ # Existing alerts are pruned until all that remains are
218
+ # alerts that aren't being generated anymore
220
219
  to_remove = existing_alerts.dup
221
- alerts_queue.each do |name, alert_people_pair|
220
+ alerts_queue.each do |_name, alert_people_pair|
222
221
  alert = alert_people_pair[0]
223
222
  old_alerts = to_remove[alert['name']]
224
223
 
225
- if !old_alerts.nil?
226
- if old_alerts['id'].length == 1
227
- to_remove.delete(alert['name'])
228
- else
229
- old_alerts['id'] = old_alerts['id'].drop(1)
230
- end
224
+ next if old_alerts.nil?
225
+ if old_alerts['id'].length == 1
226
+ to_remove.delete(alert['name'])
227
+ else
228
+ old_alerts['id'] = old_alerts['id'].drop(1)
231
229
  end
232
230
  end
233
231
 
234
232
  # Clean up alerts not longer being generated
235
- to_remove.each do |name, alert|
233
+ to_remove.each do |_name, alert|
236
234
  break if @request_shutdown
237
235
  dest.remove_alert(alert)
238
236
  end
@@ -244,35 +242,34 @@ module Interferon
244
242
  dest.remove_alert_by_id(alert_id)
245
243
  end
246
244
  end
247
-
248
245
  end
249
246
 
250
247
  def do_regular_update(dest, hosts, alerts, existing_alerts, groups)
251
248
  alerts_queue = build_alerts_queue(hosts, alerts, groups)
252
- updates_queue = alerts_queue.reject do |name, alert_people_pair|
253
- !Interferon::need_update(dest, alert_people_pair, existing_alerts)
249
+ updates_queue = alerts_queue.reject do |_name, alert_people_pair|
250
+ !Interferon.need_update(dest, alert_people_pair, existing_alerts)
254
251
  end
255
252
 
256
253
  # Create alerts in destination
257
254
  create_alerts(dest, updates_queue)
258
255
 
259
- # Existing alerts are pruned until all that remains are alerts that aren't being generated anymore
256
+ # Existing alerts are pruned until all that remains are
257
+ # alerts that aren't being generated anymore
260
258
  to_remove = existing_alerts.dup
261
- alerts_queue.each do |name, alert_people_pair|
259
+ alerts_queue.each do |_name, alert_people_pair|
262
260
  alert = alert_people_pair[0]
263
261
  old_alerts = to_remove[alert['name']]
264
262
 
265
- if !old_alerts.nil?
266
- if old_alerts['id'].length == 1
267
- to_remove.delete(alert['name'])
268
- else
269
- old_alerts['id'] = old_alerts['id'].drop(1)
270
- end
263
+ next if old_alerts.nil?
264
+ if old_alerts['id'].length == 1
265
+ to_remove.delete(alert['name'])
266
+ else
267
+ old_alerts['id'] = old_alerts['id'].drop(1)
271
268
  end
272
269
  end
273
270
 
274
271
  # Clean up alerts not longer being generated
275
- to_remove.each do |name, alert|
272
+ to_remove.each do |_name, alert|
276
273
  break if @request_shutdown
277
274
  dest.remove_alert(alert)
278
275
  end
@@ -283,10 +280,10 @@ module Interferon
283
280
  alerts_to_create = alerts_queue.keys
284
281
  concurrency = dest.concurrency || 10
285
282
  unless @request_shutdown
286
- threads = concurrency.times.map do |i|
283
+ threads = Array.new(concurrency) do |i|
287
284
  log.info "thread #{i} created"
288
285
  t = Thread.new do
289
- while name = alerts_to_create.shift
286
+ while (name = alerts_to_create.shift)
290
287
  break if @request_shutdown
291
288
  cur_alert, people = alerts_queue[name]
292
289
  log.debug "creating alert for #{cur_alert[:name]}"
@@ -308,10 +305,10 @@ module Interferon
308
305
  break if @request_shutdown
309
306
  alerts_generated = {}
310
307
  counters = {
311
- :errors => 0,
312
- :evals => 0,
313
- :applies => 0,
314
- :hosts => hosts.length
308
+ errors: 0,
309
+ evals: 0,
310
+ applies: 0,
311
+ hosts: hosts.length,
315
312
  }
316
313
  last_eval_error = nil
317
314
 
@@ -347,8 +344,8 @@ module Interferon
347
344
  end
348
345
 
349
346
  # log some of the counters
350
- statsd.gauge('alerts.evaluate.errors', counters[:errors], :tags => ["alert:#{alert}"])
351
- statsd.gauge('alerts.evaluate.applies', counters[:applies], :tags => ["alert:#{alert}"])
347
+ statsd.gauge('alerts.evaluate.errors', counters[:errors], tags: ["alert:#{alert}"])
348
+ statsd.gauge('alerts.evaluate.applies', counters[:applies], tags: ["alert:#{alert}"])
352
349
 
353
350
  if counters[:applies] > 0
354
351
  log.info "alert #{alert} applies to #{counters[:applies]} of #{counters[:hosts]} hosts"
@@ -359,18 +356,19 @@ module Interferon
359
356
  log.error "alert #{alert} failed to evaluate in the context of all hosts!"
360
357
  log.error "last error on alert #{alert}: #{last_eval_error}"
361
358
 
362
- statsd.gauge('alerts.evaluate.failed_on_all', 1, :tags => ["alert:#{alert}"])
363
- log.debug "alert #{alert}: error #{last_eval_error}\n#{last_eval_error.backtrace.join("\n")}"
359
+ statsd.gauge('alerts.evaluate.failed_on_all', 1, tags: ["alert:#{alert}"])
360
+ log.debug "alert #{alert}: " \
361
+ "error #{last_eval_error}\n#{last_eval_error.backtrace.join("\n")}"
364
362
  else
365
- statsd.gauge('alerts.evaluate.failed_on_all', 0, :tags => ["alert:#{alert}"])
363
+ statsd.gauge('alerts.evaluate.failed_on_all', 0, tags: ["alert:#{alert}"])
366
364
  end
367
365
 
368
366
  # did the alert apply to any hosts?
369
367
  if counters[:applies] == 0
370
- statsd.gauge('alerts.evaluate.never_applies', 1, :tags => ["alert:#{alert}"])
368
+ statsd.gauge('alerts.evaluate.never_applies', 1, tags: ["alert:#{alert}"])
371
369
  log.warn "alert #{alert} did not apply to any hosts"
372
370
  else
373
- statsd.gauge('alerts.evaluate.never_applies', 0, :tags => ["alert:#{alert}"])
371
+ statsd.gauge('alerts.evaluate.never_applies', 0, tags: ["alert:#{alert}"])
374
372
  end
375
373
  alerts_generated
376
374
  end
@@ -403,36 +401,37 @@ module Interferon
403
401
  alert, people = alert_people_pair
404
402
 
405
403
  prev_alert = {
406
- :monitor_type => normalize_monitor_type(alert_api_json['type']),
407
- :query => alert_api_json['query'].strip,
408
- :message => alert_api_json['message'].strip,
409
- :notify_no_data => alert_api_json['options']['notify_no_data'],
410
- :notify_audit => alert_api_json['options']['notify_audit'],
411
- :no_data_timeframe => alert_api_json['options']['no_data_timeframe'],
412
- :silenced => alert_api_json['options']['silenced'],
413
- :thresholds => alert_api_json['options']['thresholds'],
414
- :timeout_h => alert_api_json['options']['timeout_h'],
404
+ monitor_type: normalize_monitor_type(alert_api_json['type']),
405
+ query: alert_api_json['query'].strip,
406
+ message: alert_api_json['message'].strip,
407
+ evaluation_delay: alert_api_json['options']['evaluation_delay'],
408
+ notify_no_data: alert_api_json['options']['notify_no_data'],
409
+ notify_audit: alert_api_json['options']['notify_audit'],
410
+ no_data_timeframe: alert_api_json['options']['no_data_timeframe'],
411
+ silenced: alert_api_json['options']['silenced'],
412
+ thresholds: alert_api_json['options']['thresholds'],
413
+ timeout_h: alert_api_json['options']['timeout_h'],
415
414
  }
416
415
 
417
416
  new_alert = {
418
- :monitor_type => normalize_monitor_type(alert['monitor_type']),
419
- :query => alert['metric']['datadog_query'],
420
- :message => dest.generate_message(alert['message'], people).strip,
421
- :notify_no_data => alert['notify_no_data'],
422
- :notify_audit => alert['notify']['audit'],
423
- :no_data_timeframe => alert['no_data_timeframe'],
424
- :silenced => alert['silenced'],
425
- :thresholds => alert['thresholds'],
426
- :timeout_h => alert['timeout_h']
417
+ monitor_type: normalize_monitor_type(alert['monitor_type']),
418
+ query: alert['metric']['datadog_query'],
419
+ message: dest.generate_message(alert['message'], people).strip,
420
+ evaluation_delay: alert['evaluation_delay'],
421
+ notify_no_data: alert['notify_no_data'],
422
+ notify_audit: alert['notify']['audit'],
423
+ no_data_timeframe: alert['no_data_timeframe'],
424
+ silenced: alert['silenced'],
425
+ thresholds: alert['thresholds'],
426
+ timeout_h: alert['timeout_h'],
427
427
  }
428
428
 
429
- if !alert['require_full_window'].nil?
430
- pre_alert[:require_full_window] = alert_api_json['options']['require_full_window']
429
+ unless alert['require_full_window'].nil?
430
+ prev_alert[:require_full_window] = alert_api_json['options']['require_full_window']
431
431
  new_alert[:require_full_window] = alert['require_full_window']
432
432
  end
433
433
 
434
434
  prev_alert == new_alert
435
435
  end
436
-
437
436
  end
438
437
  end
data/script/pre-commit CHANGED
@@ -11,22 +11,20 @@ reasons = []
11
11
  diff = `git diff-index --name-status --cached HEAD`
12
12
  files = diff.split("\n").map(&:split)
13
13
 
14
- added_files = files.
15
- select { |(status, name)| status == 'A' }.
16
- map { |(status, name)| name }.
17
- compact
14
+ added_files = files
15
+ .select { |(status, _name)| status == 'A' }
16
+ .map { |(_status, name)| name }
17
+ .compact
18
18
 
19
- modified_files = files.
20
- select {|(status, name)| status != 'D'}. # ignore deleted files
21
- map {|(status, name)| name}.
22
- compact
19
+ modified_files = files
20
+ .select { |(status, _name)| status != 'D' } # ignore deleted files
21
+ .map { |(_status, name)| name }
22
+ .compact
23
23
 
24
24
  # check for large files
25
25
  added_files.each do |file|
26
26
  size_in_kb = `du -k #{file}`.strip.split.first.to_i
27
- if size_in_kb > 1024
28
- reasons << "#{file} is greater than 1 MB in size"
29
- end
27
+ reasons << "#{file} is greater than 1 MB in size" if size_in_kb > 1024
30
28
  end
31
29
 
32
30
  # Make sure Gemfile.lock was updated if Gemfile changed.
@@ -35,25 +33,22 @@ if modified_files.include?('Gemfile') && !modified_files.include?('Gemfile.lock'
35
33
  end
36
34
 
37
35
  # Check Ruby syntax
38
- modified_files.select {|f| f.match /\.((rb)|(rake))$/}.each do |file|
39
- result = `ruby -c #{file} 2>&1`
40
-
41
- if $? != 0
42
- reasons << "ruby file #{file} failed syntax check"
43
- end
36
+ modified_files.select { |f| f.match(/\.((rb)|(rake))$/) }.each do |file|
37
+ `ruby -c #{file} 2>&1`
38
+ reasons << "ruby file #{file} failed syntax check" if $CHILD_STATUS != 0
44
39
  end
45
40
 
46
41
  # Check JSON syntax
47
- modified_files.select {|f| f.match /(\.json)$/}.each do |file|
42
+ modified_files.select { |f| f.match(/(\.json)$/) }.each do |file|
48
43
  begin
49
44
  JSON.parse(File.read(file))
50
45
  rescue StandardError => e
51
- reasons << "JSON file #{file} contains invalid JSON"
46
+ reasons << "JSON file #{file} contains invalid JSON: #{e}"
52
47
  end
53
48
  end
54
49
 
55
50
  # Check YAML syntax
56
- modified_files.select {|f| f.match /(\.yaml)$/}.each do |file|
51
+ modified_files.select { |f| f.match(/(\.yaml)$/) }.each do |file|
57
52
  begin
58
53
  YAML.parse(File.read(file))
59
54
  rescue YAML::SyntaxError => e
@@ -1,5 +1,5 @@
1
1
  module ::Interferon::HostSources
2
2
  class TestHostSource
3
- DIR = 'loaders'
3
+ DIR = 'loaders'.freeze
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Interferon::TestSources
2
2
  class OrderTestSource
3
- DIR = 'loaders'
3
+ DIR = 'loaders'.freeze
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Interferon::TestSources
2
2
  class TestSource
3
- DIR = 'loaders'
3
+ DIR = 'loaders'.freeze
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Interferon::TestSources
2
2
  class OrderTestSource
3
- DIR = 'loaders2'
3
+ DIR = 'loaders2'.freeze
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Interferon::TestSources
3
3
  class SecondarySource
4
- DIR = 'loaders2'
4
+ DIR = 'loaders2'.freeze
5
5
 
6
6
  attr_accessor :testval
7
7
  def initialize(options)
@@ -1,11 +1,10 @@
1
1
  module Interferon::TestSources
2
2
  class TestSource
3
- DIR = 'loaders2'
3
+ DIR = 'loaders2'.freeze
4
4
 
5
5
  attr_accessor :testval
6
6
  def initialize(options)
7
7
  @testval = options['testval']
8
8
  end
9
-
10
9
  end
11
10
  end
@@ -6,7 +6,7 @@ module Interferon::Logging
6
6
  end
7
7
  end
8
8
 
9
- def self.configure_logger_for(clasname)
10
- return Logger.new(EmptyLogger.new)
9
+ def self.configure_logger_for(_clasname)
10
+ Logger.new(EmptyLogger.new)
11
11
  end
12
12
  end
@@ -6,7 +6,7 @@ module Interferon
6
6
  end
7
7
 
8
8
  def []=(key, val)
9
- @dsl.get_or_set(("@"+ key).to_sym, val, nil, nil)
9
+ @dsl.get_or_set(('@' + key).to_sym, val, nil, nil)
10
10
  end
11
11
  end
12
12
  end