flapjack 0.6.38 → 0.6.39

Sign up to get free protection for your applications and to get access to all the features.
data/flapjack.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
10
10
 
11
11
  # see http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
12
12
  # following a middle road here, not shipping it with the gem :)
13
- gem.files = `git ls-files`.split($\) - ['Gemfile.lock', 'bin/flapjack-bpimport']
13
+ gem.files = `git ls-files`.split($\) - ['Gemfile.lock']
14
14
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
16
  gem.name = "flapjack"
@@ -34,8 +34,6 @@ Gem::Specification.new do |gem|
34
34
  gem.add_dependency 'blather'
35
35
  gem.add_dependency 'chronic'
36
36
  gem.add_dependency 'chronic_duration'
37
- gem.add_dependency 'httparty'
38
37
 
39
38
  gem.add_development_dependency 'rake'
40
- gem.add_development_dependency 'colorize'
41
39
  end
data/lib/flapjack/api.rb CHANGED
@@ -283,7 +283,6 @@ module Flapjack
283
283
  end
284
284
 
285
285
  post '/contacts' do
286
- begin
287
286
  pass unless 'application/json'.eql?(request.content_type)
288
287
  content_type :json
289
288
 
@@ -292,7 +291,7 @@ module Flapjack
292
291
 
293
292
  contacts = params[:contacts]
294
293
  if contacts && contacts.is_a?(Enumerable) && contacts.any? {|c| !c['id'].nil?}
295
- Flapjack::Data::Contact.delete_all
294
+ Flapjack::Data::Contact.delete_all(:redis => @@redis)
296
295
  contacts.each do |contact|
297
296
  unless contact['id']
298
297
  logger.warn "Contact not imported as it has no id: #{contact.inspect}"
@@ -306,9 +305,6 @@ module Flapjack
306
305
  errors << "No valid contacts were submitted"
307
306
  end
308
307
  errors.empty? ? ret : [ret, {}, {:errors => [errors]}.to_json]
309
- rescue Exception => e
310
- puts e.message
311
- end
312
308
  end
313
309
 
314
310
  not_found do
@@ -40,8 +40,7 @@ module Flapjack
40
40
  end
41
41
 
42
42
  def start(options = {})
43
- # FIXME raise error if config not set, or empty
44
-
43
+ @signals = options[:signals]
45
44
  if options[:daemonize]
46
45
  daemonize
47
46
  else
@@ -75,7 +74,6 @@ module Flapjack
75
74
  end
76
75
 
77
76
  EM.synchrony do
78
-
79
77
  @logger.debug "config keys: #{@config.keys}"
80
78
 
81
79
  pikelet_keys = ['executive', 'jabber_gateway', 'pagerduty_gateway',
@@ -99,7 +97,7 @@ module Flapjack
99
97
  end
100
98
  end
101
99
 
102
- setup_signals
100
+ setup_signals if @signals
103
101
  end
104
102
 
105
103
  end
@@ -126,10 +124,9 @@ module Flapjack
126
124
  end
127
125
  return unless pikelet_class
128
126
 
127
+ pikelet = pikelet_class.new
129
128
  f = Fiber.new {
130
129
  begin
131
- pikelet = pikelet_class.new
132
- @pikelets.detect {|p| p[:type] == pikelet_type}[:instance] = pikelet
133
130
  pikelet.bootstrap(:redis => @redis_options, :config => pikelet_cfg)
134
131
  pikelet.main
135
132
  rescue Exception => e
@@ -138,7 +135,7 @@ module Flapjack
138
135
  stop
139
136
  end
140
137
  }
141
- @pikelets << {:fiber => f, :type => pikelet_type}
138
+ @pikelets << {:fiber => f, :type => pikelet_type, :instance => pikelet}
142
139
  f.resume
143
140
  @logger.debug "new fiber created for #{pikelet_type}"
144
141
  end
@@ -159,13 +156,13 @@ module Flapjack
159
156
 
160
157
  port = 3001 if (port.nil? || port <= 0 || port > 65535)
161
158
 
162
- pool = Flapjack::RedisPool.new(:config => @redis_options)
163
- pikelet_class.class_variable_set('@@redis', pool)
159
+ pikelet_class.class_variable_set('@@redis',
160
+ Flapjack::RedisPool.new(:config => @redis_options))
164
161
 
165
162
  Thin::Logging.silent = true
166
163
 
167
164
  pikelet = Thin::Server.new('0.0.0.0', port, pikelet_class, :signals => false)
168
- @pikelets << {:instance => pikelet, :type => pikelet_type, :pool => pool}
165
+ @pikelets << {:instance => pikelet, :type => pikelet_type}
169
166
  pikelet.start
170
167
  @logger.debug "new thin server instance started for #{pikelet_type}"
171
168
  end
@@ -181,10 +178,11 @@ module Flapjack
181
178
 
182
179
  # set up connection pooling, stop resque errors (ensure that it's only
183
180
  # done once)
184
- pool = nil
181
+ @resque_pool = nil
185
182
  if (['email_notifier', 'sms_notifier'] & @pikelets.collect {|p| p[:type]}).empty?
186
183
  pool = Flapjack::RedisPool.new(:config => @redis_options)
187
184
  ::Resque.redis = pool
185
+ @resque_pool = pool
188
186
  ## NB: can override the default 'resque' namespace like this
189
187
  #::Resque.redis.namespace = 'flapjack'
190
188
  end
@@ -210,14 +208,14 @@ module Flapjack
210
208
 
211
209
  pikelet_class.class_variable_set('@@config', pikelet_cfg)
212
210
 
211
+ # TODO error if pikelet_cfg['queue'].nil?
212
+ pikelet = EM::Resque::Worker.new(pikelet_cfg['queue'])
213
+ # # Use these to debug the resque workers
214
+ # pikelet.verbose = true
215
+ # pikelet.very_verbose = true
216
+
213
217
  f = Fiber.new {
214
218
  begin
215
- # TODO error if pikelet_cfg['queue'].nil?
216
- pikelet = EM::Resque::Worker.new(pikelet_cfg['queue'])
217
- @pikelets.detect {|p| p[:type] == pikelet_type}[:instance] = pikelet
218
- # # Use these to debug the resque workers
219
- # flapjack_rsq.verbose = true
220
- #flapjack_rsq.very_verbose = true
221
219
  pikelet.work(0.1)
222
220
  rescue Exception => e
223
221
  trace = e.backtrace.join("\n")
@@ -225,9 +223,7 @@ module Flapjack
225
223
  stop
226
224
  end
227
225
  }
228
- pikelet_values = {:fiber => f, :type => pikelet_type}
229
- pikelet_values[:pool] = pool if pool
230
- @pikelets << pikelet_values
226
+ @pikelets << {:fiber => f, :type => pikelet_type, :instance => pikelet}
231
227
  f.resume
232
228
  @logger.debug "new fiber created for #{pikelet_type}"
233
229
  end
@@ -244,6 +240,8 @@ module Flapjack
244
240
  # end
245
241
  # end
246
242
 
243
+ # TODO whem merged with other changes, have this check pik[:class] instead,
244
+ # makes tests neater
247
245
  def shutdown
248
246
  @pikelets.each do |pik|
249
247
  case pik[:instance]
@@ -278,15 +276,13 @@ module Flapjack
278
276
  if fibers.any?(&:alive?) || thin_pikelets.any?{|tp| !tp.backend.empty? }
279
277
  EM::Synchrony.sleep 0.25
280
278
  else
281
- @pikelets.select {|p| thin_pikelets.include?(p) }.each do |tp|
282
- tp[:pool].empty!
283
- end
284
-
285
- rsq_p = @pikelets.detect {|p|
286
- ['email_notifier', 'sms_notifier'].include?(p[:type]) && !p[:pool].nil?
287
- }
279
+ @resque_pool.empty! if @resque_pool
288
280
 
289
- rsq_p[:pool].empty! if rsq_p
281
+ [Flapjack::Web, Flapjack::API].each do |klass|
282
+ next unless klass.class_variable_defined?('@@redis') &&
283
+ redis = klass.class_variable_get('@@redis')
284
+ redis.empty!
285
+ end
290
286
 
291
287
  EM.stop
292
288
  break
@@ -69,16 +69,18 @@ module Flapjack
69
69
  redis.hmset("contact:#{contact['id']}",
70
70
  *['first_name', 'last_name', 'email'].collect {|f| [f, contact[f]]})
71
71
 
72
- contact['media'].each_pair {|medium, address|
73
- case medium
74
- when 'pagerduty'
75
- redis.hset("contact_media:#{contact['id']}", medium, address['service_key'])
76
- redis.hmset("contact_pagerduty:#{contact['id']}",
77
- *['subdomain', 'username', 'password'].collect {|f| [f, address[f]]})
78
- else
79
- redis.hset("contact_media:#{contact['id']}", medium, address)
80
- end
81
- }
72
+ unless contact['media'].nil?
73
+ contact['media'].each_pair {|medium, address|
74
+ case medium
75
+ when 'pagerduty'
76
+ redis.hset("contact_media:#{contact['id']}", medium, address['service_key'])
77
+ redis.hmset("contact_pagerduty:#{contact['id']}",
78
+ *['subdomain', 'username', 'password'].collect {|f| [f, address[f]]})
79
+ else
80
+ redis.hset("contact_media:#{contact['id']}", medium, address)
81
+ end
82
+ }
83
+ end
82
84
  end
83
85
 
84
86
  def pagerduty_credentials
@@ -12,7 +12,7 @@ module Flapjack
12
12
  raise "Redis connection not set" unless redis = options[:redis]
13
13
  redis.keys("entity_id:*").collect {|k|
14
14
  k =~ /^entity_id:(.+)$/; entity_name = $1
15
- self.new(:name => entity_name, :id => redis.get("entity_id:#{entity_name}").to_i, :redis => redis)
15
+ self.new(:name => entity_name, :id => redis.get("entity_id:#{entity_name}"), :redis => redis)
16
16
  }
17
17
  end
18
18
 
@@ -51,7 +51,7 @@ module Flapjack
51
51
  self.add({'name' => entity_name}, :redis => redis)
52
52
  end
53
53
  self.new(:name => entity_name,
54
- :id => (entity_id.nil? || entity_id.empty?) ? nil : entity_id.to_i,
54
+ :id => (entity_id.nil? || entity_id.empty?) ? nil : entity_id,
55
55
  :redis => redis)
56
56
  end
57
57
 
@@ -368,15 +368,6 @@ module Flapjack
368
368
  :summary => @redis.get("#{@key}:#{ts.first}:summary")}
369
369
  end
370
370
 
371
- def historical_state_after(timestamp)
372
- pos = @redis.zrank("#{@key}:sorted_state_timestamps", timestamp)
373
- ts = @redis.zrange("#{@key}:sorted_state_timestamps", pos + 1, pos + 2)
374
- return if ts.nil? || ts.empty?
375
- {:timestamp => ts.first.to_i,
376
- :state => @redis.get("#{@key}:#{ts.first}:state"),
377
- :summary => @redis.get("#{@key}:#{ts.first}:summary")}
378
- end
379
-
380
371
  # Returns a list of maintenance periods (either unscheduled or scheduled) for this
381
372
  # entity check, sorted by timestamp.
382
373
  #
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'flapjack/data/entity_check'
4
+
5
+ module Flapjack
6
+
7
+ module Data
8
+
9
+ class Global
10
+
11
+ def self.unacknowledged_failing_checks(options = {})
12
+ raise "Redis connection not set" unless redis = options[:redis]
13
+
14
+ redis.zrange('failed_checks', '0', '-1').reject {|entity_check|
15
+ redis.exists(entity_check + ':unscheduled_maintenance')
16
+ }.collect {|entity_check|
17
+ Flapjack::Data::EntityCheck.for_event_id(entity_check, :redis => redis)
18
+ }
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -36,6 +36,7 @@ module Flapjack
36
36
  @notifylog.add(Log4r::FileOutputter.new("notifylog", :filename => notifylog))
37
37
 
38
38
  # FIXME: Put loading filters into separate method
39
+ # FIXME: should we make the filters more configurable by the end user?
39
40
  options = { :log => @logger, :persistence => @redis }
40
41
  @filters = []
41
42
  @filters << Flapjack::Filters::Ok.new(options)
@@ -51,35 +51,27 @@ module Flapjack
51
51
  @config['password'].to_s)
52
52
 
53
53
  register_handler :ready do |stanza|
54
- EM.next_tick do
55
- EM.synchrony do
56
- on_ready(stanza)
57
- end
54
+ EventMachine::Synchrony.next_tick do
55
+ on_ready(stanza)
58
56
  end
59
57
  end
60
58
 
61
59
  register_handler :message, :groupchat?, :body => /^flapjack:\s+/ do |stanza|
62
- EM.next_tick do
63
- EM.synchrony do
64
- on_groupchat(stanza)
65
- end
60
+ EventMachine::Synchrony.next_tick do
61
+ on_groupchat(stanza)
66
62
  end
67
63
  end
68
64
 
69
65
  register_handler :message, :chat? do |stanza|
70
- EM.next_tick do
71
- EM.synchrony do
72
- on_chat(stanza)
73
- end
66
+ EventMachine::Synchrony.next_tick do
67
+ on_chat(stanza)
74
68
  end
75
69
  end
76
70
 
77
71
  register_handler :disconnected do |stanza|
78
72
  ret = true
79
- EM.next_tick do
80
- EM.synchrony do
81
- ret = on_disconnect(stanza)
82
- end
73
+ EventMachine::Synchrony.next_tick do
74
+ ret = on_disconnect(stanza)
83
75
  end
84
76
  ret
85
77
  end
@@ -130,7 +122,7 @@ module Flapjack
130
122
  end
131
123
 
132
124
  four_hours = 4 * 60 * 60
133
- duration = (dur.nil? || (dur <= 0) || (dur > four_hours)) ? four_hours : dur
125
+ duration = (dur.nil? || (dur <= 0)) ? four_hours : dur
134
126
 
135
127
  event_id = @redis_handler.hget('unacknowledged_failures', ackid)
136
128
 
@@ -278,7 +270,7 @@ module Flapjack
278
270
  logger.debug(event.inspect)
279
271
  if 'shutdown'.eql?(type)
280
272
  if should_quit?
281
- EM.next_tick do
273
+ EventMachine::Synchrony.next_tick do
282
274
  # get delays without the next_tick
283
275
  close # Blather::Client.close
284
276
  end
@@ -303,7 +295,7 @@ module Flapjack
303
295
 
304
296
  chat_type = :chat
305
297
  chat_type = :groupchat if @config['rooms'] && @config['rooms'].include?(address)
306
- EM.next_tick do
298
+ EventMachine::Synchrony.next_tick do
307
299
  say(Blather::JID.new(address), msg, chat_type)
308
300
  end
309
301
  end
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- #require 'socket'
3
+ require 'socket'
4
4
 
5
5
  require 'eventmachine'
6
6
  require 'em-synchrony'
@@ -52,35 +52,32 @@ module Flapjack
52
52
  :last_ack_sent => t }
53
53
 
54
54
  @last_alert = nil
55
+ end
55
56
 
57
+ # split out to ease testing
58
+ def register_handlers
56
59
  register_handler :ready do |stanza|
57
- EM.next_tick do
58
- EM.synchrony do
59
- on_ready(stanza)
60
- end
60
+ EventMachine::Synchrony.next_tick do
61
+ on_ready(stanza)
61
62
  end
62
63
  end
63
64
 
64
65
  register_handler :message, :groupchat? do |stanza|
65
- EM.next_tick do
66
- EM.synchrony do
67
- on_groupchat(stanza)
68
- end
66
+ EventMachine::Synchrony.next_tick do
67
+ on_groupchat(stanza)
69
68
  end
70
69
  end
71
70
 
72
71
  register_handler :disconnected do |stanza|
73
72
  ret = true
74
- EM.next_tick do
75
- EM.synchrony do
76
- ret = on_disconnect(stanza)
77
- end
73
+ EventMachine::Synchrony.next_tick do
74
+ ret = on_disconnect(stanza)
78
75
  end
79
76
  ret
80
77
  end
81
-
82
78
  end
83
79
 
80
+
84
81
  # Join the MUC Chat room after connecting.
85
82
  def on_ready(stanza)
86
83
  return if should_quit?
@@ -111,31 +108,37 @@ module Flapjack
111
108
 
112
109
  def on_groupchat(stanza)
113
110
  return if should_quit?
114
- logger.debug("groupchat stanza body: " + stanza.body)
111
+
112
+ stanza_body = stanza.body
113
+
114
+ logger.debug("groupchat stanza body: " + stanza_body)
115
115
  logger.debug("groupchat message received: #{stanza.inspect}")
116
116
 
117
- if stanza.body =~ /^(\w+).*#{Regexp.escape(@check_matcher)}/
117
+ if (stanza_body =~ /^(?:problem|recovery|acknowledgement)/i) &&
118
+ (stanza_body =~ /^(\w+).*#{Regexp.escape(@check_matcher)}/)
119
+
118
120
  # got something interesting
119
- logger.debug("groupchat found the following state for #{@check_matcher}: #{$1.downcase}")
120
- case $1.downcase
121
+ status = $1.downcase
122
+ t = Time.now.to_i
123
+ logger.debug("groupchat found the following state for #{@check_matcher}: #{status}")
124
+
125
+ case status
121
126
  when 'problem'
122
127
  logger.debug("updating @times last_problem")
123
- @times[:last_problem] = Time.new.to_i
128
+ @times[:last_problem] = t
124
129
  when 'recovery'
125
130
  logger.debug("updating @times last_recovery")
126
- @times[:last_recovery] = Time.new.to_i
131
+ @times[:last_recovery] = t
127
132
  when 'acknowledgement'
128
133
  logger.debug("updating @times last_ack")
129
- @times[:last_ack] = Time.new.to_i
134
+ @times[:last_ack] = t
130
135
  end
131
-
132
136
  end
133
137
  logger.debug("@times: #{@times.inspect}")
134
-
135
138
  end
136
139
 
137
140
  def check_timers
138
- t = Time.new.to_i
141
+ t = Time.now.to_i
139
142
  breach = nil
140
143
  @logger.debug("check_timers: inspecting @times #{@times.inspect}")
141
144
  case
@@ -145,7 +148,7 @@ module Flapjack
145
148
  breach = "haven't seen a test recovery notification in the last #{@max_latency} seconds"
146
149
  end
147
150
 
148
- if !@flapjack_ok and !breach
151
+ unless @flapjack_ok || breach
149
152
  emit_jabber("Flapjack Self Monitoring is OK")
150
153
  emit_pagerduty("Flapjack Self Monitoring is OK", 'resolve')
151
154
  end
@@ -218,17 +221,16 @@ module Flapjack
218
221
  write(' ') if connected?
219
222
  end
220
223
 
221
- check_timers_timer = EM::Synchrony.add_periodic_timer(10) do
222
- check_timers
223
- end
224
-
225
224
  setup
225
+ register_handlers
226
226
  connect # Blather::Client.connect
227
227
 
228
- if should_quit?
229
- keepalive_timer.cancel
230
- check_timers_timer.cancel
228
+ until should_quit?
229
+ EM::Synchrony.sleep(10)
230
+ check_timers
231
231
  end
232
+
233
+ keepalive_timer.cancel
232
234
  end
233
235
 
234
236
  end