flapjack 1.2.0rc2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -163,16 +163,6 @@ module Flapjack
163
163
  }
164
164
  end
165
165
 
166
- def self.conflate_to_keys(entity_checks_hash)
167
- result = []
168
- entity_checks_hash.each {|entity, checks|
169
- checks.each {|check|
170
- result << "#{entity}:#{check}"
171
- }
172
- }
173
- result
174
- end
175
-
176
166
  def self.find_maintenance(options = {})
177
167
  raise "Redis connection not set" unless redis = options[:redis]
178
168
  type = options[:type]
@@ -619,57 +609,54 @@ module Flapjack
619
609
 
620
610
  old_state = self.state
621
611
 
622
- @redis.multi
612
+ @redis.multi do |multi|
623
613
 
624
- if old_state != new_state
614
+ if old_state != new_state
625
615
 
626
- # Note the current state (for speedy lookups)
627
- @redis.hset("check:#{@key}", 'state', new_state)
616
+ # Note the current state (for speedy lookups)
617
+ multi.hset("check:#{@key}", 'state', new_state)
628
618
 
629
- # FIXME: rename to last_state_change?
630
- @redis.hset("check:#{@key}", 'last_change', timestamp)
619
+ # FIXME: rename to last_state_change?
620
+ multi.hset("check:#{@key}", 'last_change', timestamp)
631
621
 
632
- case new_state
633
- when STATE_WARNING, STATE_CRITICAL, STATE_UNKNOWN
634
- @redis.zadd('failed_checks', timestamp, @key)
635
- # FIXME: Iterate through a list of tags associated with an entity:check pair, and update counters
636
- else
637
- @redis.zrem("failed_checks", @key)
638
- # FIXME: Iterate through a list of tags associated with an entity:check pair, and update counters
639
- end
622
+ case new_state
623
+ when STATE_WARNING, STATE_CRITICAL, STATE_UNKNOWN
624
+ multi.zadd('failed_checks', timestamp, @key)
625
+ # FIXME: Iterate through a list of tags associated with an entity:check pair, and update counters
626
+ else
627
+ multi.zrem("failed_checks", @key)
628
+ # FIXME: Iterate through a list of tags associated with an entity:check pair, and update counters
629
+ end
640
630
 
641
- # Retain event data for entity:check pair
642
- # NB (appending to tail as far as Redis is concerned)
643
- @redis.rpush("#{@key}:states", timestamp)
644
- @redis.set("#{@key}:#{timestamp}:state", new_state)
645
- @redis.set("#{@key}:#{timestamp}:summary", summary) if summary
646
- @redis.set("#{@key}:#{timestamp}:details", details) if details
647
- @redis.set("#{@key}:#{timestamp}:count", count) if count
631
+ # Retain event data for entity:check pair
632
+ # NB (appending to tail as far as Redis is concerned)
633
+ multi.rpush("#{@key}:states", timestamp)
634
+ multi.set("#{@key}:#{timestamp}:state", new_state)
635
+ multi.set("#{@key}:#{timestamp}:summary", summary) if summary
636
+ multi.set("#{@key}:#{timestamp}:details", details) if details
637
+ multi.set("#{@key}:#{timestamp}:count", count) if count
648
638
 
649
- @redis.zadd("#{@key}:sorted_state_timestamps", timestamp, timestamp)
650
- end
639
+ multi.zadd("#{@key}:sorted_state_timestamps", timestamp, timestamp)
640
+ end
651
641
 
652
- # Track when we last saw an event for a particular entity:check pair
653
- self.last_update = timestamp
642
+ # Track when we last saw an event for a particular entity:check pair
643
+ # (used to be last_update=, but needs to happen in the multi block)
644
+ multi.hset("check:#{@key}", 'last_update', timestamp)
645
+ multi.zadd("all_checks", timestamp, @key)
646
+ multi.zadd("all_checks:#{entity.name}", timestamp, check)
647
+ multi.zadd("current_checks:#{entity.name}", timestamp, check)
648
+ multi.zadd('current_entities', timestamp, entity.name)
649
+
650
+ # Even if this isn't a state change, we need to update the current state
651
+ # hash summary and details (as they may have changed)
652
+ multi.hset("check:#{@key}", 'summary', (summary || ''))
653
+ multi.hset("check:#{@key}", 'details', (details || ''))
654
+ if perfdata
655
+ multi.hset("check:#{@key}", 'perfdata', format_perfdata(perfdata).to_json)
656
+ # multi.set("#{@key}:#{timestamp}:perfdata", perfdata)
657
+ end
654
658
 
655
- # Even if this isn't a state change, we need to update the current state
656
- # hash summary and details (as they may have changed)
657
- @redis.hset("check:#{@key}", 'summary', (summary || ''))
658
- @redis.hset("check:#{@key}", 'details', (details || ''))
659
- if perfdata
660
- @redis.hset("check:#{@key}", 'perfdata', format_perfdata(perfdata).to_json)
661
- # @redis.set("#{@key}:#{timestamp}:perfdata", perfdata)
662
659
  end
663
-
664
- @redis.exec
665
- end
666
-
667
- def last_update=(timestamp)
668
- @redis.hset("check:#{@key}", 'last_update', timestamp)
669
- @redis.zadd("all_checks", timestamp, @key)
670
- @redis.zadd("all_checks:#{entity.name}", timestamp, check)
671
- @redis.zadd("current_checks:#{entity.name}", timestamp, check)
672
- @redis.zadd('current_entities', timestamp, entity.name)
673
660
  end
674
661
 
675
662
  def last_update
@@ -1007,6 +994,13 @@ module Flapjack
1007
994
  @logger = options[:logger]
1008
995
  end
1009
996
 
997
+ def self.conflate_to_keys(entity_checks_hash)
998
+ entity_checks_hash.inject([]) {|memo, (entity, checks)|
999
+ memo += checks.collect {|check| "#{entity}:#{check}" }
1000
+ memo
1001
+ }
1002
+ end
1003
+
1010
1004
  def format_perfdata(perfdata)
1011
1005
  # example perfdata: time=0.486630s;;;0.000000 size=909B;;;0
1012
1006
  items = perfdata.split(' ')
@@ -107,10 +107,10 @@ module Flapjack
107
107
  # store the raw data in a rejected list
108
108
  rejected_dest = "events_rejected:#{base_time_str}"
109
109
  if options[:archive_events]
110
- redis.multi
111
- redis.lrem(archive_dest, 1, raw)
112
- redis.lpush(rejected_dest, raw)
113
- redis.exec
110
+ redis.multi do |multi|
111
+ multi.lrem(archive_dest, 1, raw)
112
+ multi.lpush(rejected_dest, raw)
113
+ end
114
114
  redis.expire(archive_dest, options[:events_archive_maxage])
115
115
  else
116
116
  redis.lpush(rejected_dest, raw)
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'flapjack/data/contact'
4
+ require 'flapjack/data/entity_check'
5
+
3
6
  require 'flapjack/data/semaphore'
4
7
 
5
8
  module Flapjack
@@ -116,6 +119,32 @@ module Flapjack
116
119
  end
117
120
  end
118
121
 
122
+ def self.correct_notification_rule_contact_linkages(options = {})
123
+ raise "Redis connection not set" unless redis = options[:redis]
124
+
125
+ logger = options[:logger]
126
+
127
+ if redis.exists('corrected_notification_rule_contact_linkages')
128
+ return
129
+ end
130
+
131
+ invalid_notification_rule_keys = redis.keys("notification_rule:*").select {|k|
132
+ contact_id = redis.hget(k, 'contact_id')
133
+ contact_id.nil? || contact_id.empty?
134
+ }.collect {|nrk| nrk.sub(/^notification_rule:/, '') }
135
+
136
+ unless invalid_notification_rule_keys.empty?
137
+ Flapjack::Data::Contact.all(:redis => redis).each do |contact|
138
+ correctable = contact.notification_rule_ids & invalid_notification_rule_keys
139
+ next if correctable.empty?
140
+ correctable.each {|ck| redis.hset("notification_rule:#{ck}", 'contact_id', contact.id) }
141
+ logger.warn "Set contact #{contact.id} for rules #{correctable.join(', ')}" unless logger.nil?
142
+ end
143
+ end
144
+
145
+ redis.set('corrected_notification_rule_contact_linkages', 'true')
146
+ end
147
+
119
148
  end
120
149
  end
121
150
  end
@@ -229,7 +229,7 @@ module Flapjack
229
229
  (request.query_string.length > 0)) ? "?#{request.query_string}" : ""
230
230
  if logger.debug?
231
231
  input = env['rack.input'].read
232
- logger.debug("#{request.request_method} #{request.path_info}#{query_string} #{input}")
232
+ logger.debug("#{request.request_method} #{request.path_info}#{query_string} Headers: #{headers.inspect}, Body: #{input}")
233
233
  elsif logger.info?
234
234
  input = env['rack.input'].read
235
235
  input_short = input.gsub(/\n/, '').gsub(/\s+/, ' ')
@@ -250,8 +250,9 @@ module Flapjack
250
250
  else
251
251
  response.body.to_s
252
252
  end
253
+ headers_debug = response.headers.to_s
253
254
  logger.debug("Returning #{response.status} for #{request.request_method} " +
254
- "#{request.path_info}#{query_string}, body: #{body_debug}")
255
+ "#{request.path_info}#{query_string}, headers: #{headers_debug}, body: #{body_debug}")
255
256
  elsif logger.info?
256
257
  logger.info("Returning #{response.status} for #{request.request_method} " +
257
258
  "#{request.path_info}#{query_string}")
@@ -27,11 +27,18 @@ module Flapjack
27
27
  end
28
28
 
29
29
  checks = if event_ids.nil?
30
- Flapjack::Data::EntityCheck.find_current_names(:redis => redis).collect {|check_name|
31
- find_entity_check_by_name(*check_name.split(':', 2))
32
- }
30
+ Flapjack::Data::EntityCheck.find_current_names(:redis => redis).
31
+ each_with_object([]) do |check_name, memo|
32
+ en, cn = check_name.split(':', 2)
33
+ halt(500, 'Malformed check ID') if en.nil? || cn.nil?
34
+ memo << find_entity_check_by_name(en, cn)
35
+ end
33
36
  elsif !event_ids.empty?
34
- event_ids.collect {|event_id| find_entity_check_by_name(*event_id.split(':', 2)) }
37
+ event_ids.each_with_object([]) do |event_id, memo|
38
+ en, cn = event_id.split(':', 2)
39
+ halt(500, 'Malformed check ID') if en.nil? || cn.nil?
40
+ memo << find_entity_check_by_name(en, cn)
41
+ end
35
42
  else
36
43
  nil
37
44
  end
@@ -57,7 +57,7 @@ module Flapjack
57
57
 
58
58
  @api_url = @config['api_url']
59
59
  if @api_url
60
- if (@api_url =~ /^#{URI::regexp(%w(http https))}$/).nil?
60
+ if URI.regexp(['http', 'https']).match(@api_url).nil?
61
61
  @logger.error "api_url is not a valid http or https URI (#{@api_url}), discarding"
62
62
  @api_url = nil
63
63
  end
@@ -90,7 +90,8 @@ module Flapjack
90
90
 
91
91
  timestamp = Time.now
92
92
  event_id = notification.event_id
93
- entity_check = Flapjack::Data::EntityCheck.for_event_id(event_id, :redis => @redis, :logger => @logger)
93
+ entity_check = Flapjack::Data::EntityCheck.for_event_id(event_id,
94
+ :redis => @redis, :logger => @logger)
94
95
  contacts = entity_check.contacts
95
96
 
96
97
  if contacts.empty?
@@ -99,14 +100,11 @@ module Flapjack
99
100
  return
100
101
  end
101
102
 
102
- messages = notification.messages(contacts, :default_timezone => @default_contact_timezone,
103
- :logger => @logger)
103
+ messages = notification.messages(contacts,
104
+ :default_timezone => @default_contact_timezone, :logger => @logger)
104
105
 
105
106
  notification_contents = notification.contents
106
107
 
107
- in_unscheduled_maintenance = entity_check.in_scheduled_maintenance?
108
- in_scheduled_maintenance = entity_check.in_unscheduled_maintenance?
109
-
110
108
  messages.each do |message|
111
109
  media_type = message.medium
112
110
  address = message.address
@@ -123,9 +121,7 @@ module Flapjack
123
121
  memo
124
122
  end
125
123
  contents['rollup_alerts'] = rollup_alerts
126
-
127
124
  contents['rollup_threshold'] = message.contact.rollup_threshold_for_media(media_type)
128
-
129
125
  end
130
126
 
131
127
  @notifylog.info("#{event_id} | " +
@@ -191,19 +191,19 @@ module Flapjack
191
191
  event.id_hash = entity_check.ack_hash
192
192
  end
193
193
 
194
- @redis.multi
195
- if event.ok?
196
- @redis.hincrby('event_counters', 'ok', 1)
197
- @redis.hincrby("event_counters:#{@instance_id}", 'ok', 1)
198
- elsif event.failure?
199
- @redis.hincrby('event_counters', 'failure', 1)
200
- @redis.hincrby("event_counters:#{@instance_id}", 'failure', 1)
201
- else
202
- @redis.hincrby('event_counters', 'invalid', 1)
203
- @redis.hincrby("event_counters:#{@instance_id}", 'invalid', 1)
204
- @logger.error("Invalid event received: #{event.inspect}")
194
+ @redis.multi do |multi|
195
+ if event.ok?
196
+ multi.hincrby('event_counters', 'ok', 1)
197
+ multi.hincrby("event_counters:#{@instance_id}", 'ok', 1)
198
+ elsif event.failure?
199
+ multi.hincrby('event_counters', 'failure', 1)
200
+ multi.hincrby("event_counters:#{@instance_id}", 'failure', 1)
201
+ else
202
+ multi.hincrby('event_counters', 'invalid', 1)
203
+ multi.hincrby("event_counters:#{@instance_id}", 'invalid', 1)
204
+ @logger.error("Invalid event received: #{event.inspect}")
205
+ end
205
206
  end
206
- @redis.exec
207
207
 
208
208
  previous_state = entity_check.state
209
209
 
@@ -233,14 +233,16 @@ module Flapjack
233
233
  # Action events represent human or automated interaction with Flapjack
234
234
  when 'action'
235
235
  # When an action event is processed, store the event.
236
- @redis.multi
237
- @redis.hset(event.id + ':actions', timestamp, event.state)
238
- @redis.hincrby('event_counters', 'action', 1)
239
- @redis.hincrby("event_counters:#{@instance_id}", 'action', 1)
240
- @redis.exec
236
+ @redis.multi do |multi|
237
+ multi.hset(event.id + ':actions', timestamp, event.state)
238
+ multi.hincrby('event_counters', 'action', 1)
239
+ multi.hincrby("event_counters:#{@instance_id}", 'action', 1)
240
+ end
241
241
  else
242
- @redis.hincrby('event_counters', 'invalid', 1)
243
- @redis.hincrby("event_counters:#{@instance_id}", 'invalid', 1)
242
+ @redis.multi do |multi|
243
+ multi.hincrby('event_counters', 'invalid', 1)
244
+ multi.hincrby("event_counters:#{@instance_id}", 'invalid', 1)
245
+ end
244
246
  @logger.error("Invalid event received: #{event.inspect}")
245
247
  end
246
248
 
@@ -251,12 +253,12 @@ module Flapjack
251
253
  notification_type = Flapjack::Data::Notification.type_for_event(event)
252
254
  max_notified_severity = entity_check.max_notified_severity_of_current_failure
253
255
 
254
- @redis.multi
255
- @redis.set("#{event.id}:last_#{notification_type}_notification", timestamp)
256
- @redis.set("#{event.id}:last_#{event.state}_notification", timestamp) if event.failure?
257
- @redis.rpush("#{event.id}:#{notification_type}_notifications", timestamp)
258
- @redis.rpush("#{event.id}:#{event.state}_notifications", timestamp) if event.failure?
259
- @redis.exec
256
+ @redis.multi do |multi|
257
+ multi.set("#{event.id}:last_#{notification_type}_notification", timestamp)
258
+ multi.set("#{event.id}:last_#{event.state}_notification", timestamp) if event.failure?
259
+ multi.rpush("#{event.id}:#{notification_type}_notifications", timestamp)
260
+ multi.rpush("#{event.id}:#{event.state}_notifications", timestamp) if event.failure?
261
+ end
260
262
 
261
263
  @logger.debug("Notification of type #{notification_type} is being generated for #{event.id}: " + event.inspect)
262
264
 
@@ -21,6 +21,8 @@ module Flapjack
21
21
  logger = opts[:logger]
22
22
  super(:size => @size) {
23
23
  redis = ::Redis.new(config)
24
+ Flapjack::Data::Migration.correct_notification_rule_contact_linkages(:redis => redis,
25
+ :logger => logger)
24
26
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => redis,
25
27
  :logger => logger)
26
28
  Flapjack::Data::Migration.refresh_archive_index(:redis => redis)
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  module Flapjack
4
- VERSION = "1.2.0rc2"
4
+ VERSION = "1.2.0"
5
5
  end
6
6
 
@@ -218,7 +218,12 @@ describe Flapjack::Data::Contact, :redis => true do
218
218
  ec = Flapjack::Data::EntityCheck.for_entity_name(entity_name, 'PING', :redis => @redis)
219
219
  t = Time.now.to_i
220
220
  ec.update_state('ok', :timestamp => t, :summary => 'a')
221
- ec.last_update = t
221
+ # was check.last_update=
222
+ @redis.hset("check:#{entity_name}:PING", 'last_update', t)
223
+ @redis.zadd("all_checks", t, @key)
224
+ @redis.zadd("all_checks:#{entity_name}", t, 'PING')
225
+ @redis.zadd("current_checks:#{entity_name}", t, 'PING')
226
+ @redis.zadd('current_entities', t, entity_name)
222
227
 
223
228
  contact = Flapjack::Data::Contact.find_by_id('c362', :redis => @redis)
224
229
  eandcs = contact.entities(:checks => true)
@@ -1199,7 +1199,13 @@ describe Flapjack::Data::EntityCheck, :redis => true do
1199
1199
  it "updates enabled checks" do
1200
1200
  ts = Time.now.to_i
1201
1201
  ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
1202
- ec.last_update = ts
1202
+
1203
+ # was check.last_update=
1204
+ @redis.hset("check:#{name}:#{check}", 'last_update', ts)
1205
+ @redis.zadd("all_checks", ts, @key)
1206
+ @redis.zadd("all_checks:#{name}", ts, check)
1207
+ @redis.zadd("current_checks:#{name}", ts, check)
1208
+ @redis.zadd('current_entities', ts, name)
1203
1209
 
1204
1210
  saved_check_ts = @redis.zscore("current_checks:#{name}", check)
1205
1211
  expect(saved_check_ts).not_to be_nil
@@ -6,6 +6,7 @@ describe Flapjack::Data::Event do
6
6
  let(:entity_name) { 'xyz-example.com' }
7
7
  let(:check) { 'ping' }
8
8
  let(:redis) { double(::Redis) }
9
+ let(:multi) { double('multi') }
9
10
 
10
11
  let!(:time) { Time.now}
11
12
 
@@ -79,10 +80,9 @@ describe Flapjack::Data::Event do
79
80
  expect(Flapjack::Data::Migration).to receive(:purge_expired_archive_index).with(:redis => redis)
80
81
  expect(redis).to receive(:sadd).
81
82
  with('known_events_archive_keys', /^events_archive:/)
82
- expect(redis).to receive(:multi)
83
- expect(redis).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
84
- expect(redis).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
85
- expect(redis).to receive(:exec)
83
+ expect(redis).to receive(:multi).and_yield(multi)
84
+ expect(multi).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
85
+ expect(multi).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
86
86
  expect(redis).to receive(:expire)
87
87
 
88
88
  result = Flapjack::Data::Event.next('events', :block => true,
@@ -112,10 +112,9 @@ describe Flapjack::Data::Event do
112
112
  expect(Flapjack::Data::Migration).to receive(:purge_expired_archive_index).with(:redis => redis)
113
113
  expect(redis).to receive(:sadd).
114
114
  with('known_events_archive_keys', /^events_archive:/)
115
- expect(redis).to receive(:multi)
116
- expect(redis).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
117
- expect(redis).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
118
- expect(redis).to receive(:exec)
115
+ expect(redis).to receive(:multi).and_yield(multi)
116
+ expect(multi).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
117
+ expect(multi).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
119
118
  expect(redis).to receive(:expire)
120
119
 
121
120
  result = Flapjack::Data::Event.next('events', :block => true,
@@ -145,10 +144,9 @@ describe Flapjack::Data::Event do
145
144
  expect(Flapjack::Data::Migration).to receive(:purge_expired_archive_index).with(:redis => redis)
146
145
  expect(redis).to receive(:sadd).
147
146
  with('known_events_archive_keys', /^events_archive:/)
148
- expect(redis).to receive(:multi)
149
- expect(redis).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
150
- expect(redis).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
151
- expect(redis).to receive(:exec)
147
+ expect(redis).to receive(:multi).and_yield(multi)
148
+ expect(multi).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
149
+ expect(multi).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
152
150
  expect(redis).to receive(:expire)
153
151
 
154
152
  result = Flapjack::Data::Event.next('events', :block => true,
@@ -180,10 +178,9 @@ describe Flapjack::Data::Event do
180
178
  expect(Flapjack::Data::Migration).to receive(:purge_expired_archive_index).with(:redis => redis)
181
179
  expect(redis).to receive(:sadd).
182
180
  with('known_events_archive_keys', /^events_archive:/)
183
- expect(redis).to receive(:multi)
184
- expect(redis).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
185
- expect(redis).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
186
- expect(redis).to receive(:exec)
181
+ expect(redis).to receive(:multi).and_yield(multi)
182
+ expect(multi).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
183
+ expect(multi).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
187
184
  expect(redis).to receive(:expire)
188
185
 
189
186
  result = Flapjack::Data::Event.next('events', :block => true,
@@ -271,10 +268,9 @@ describe Flapjack::Data::Event do
271
268
  expect(Flapjack::Data::Migration).to receive(:purge_expired_archive_index).with(:redis => redis)
272
269
  expect(redis).to receive(:sadd).
273
270
  with('known_events_archive_keys', /^events_archive:/)
274
- expect(redis).to receive(:multi)
275
- expect(redis).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
276
- expect(redis).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
277
- expect(redis).to receive(:exec)
271
+ expect(redis).to receive(:multi).and_yield(multi)
272
+ expect(multi).to receive(:lrem).with(/^events_archive:/, 1, bad_event_json)
273
+ expect(multi).to receive(:lpush).with(/^events_rejected:/, bad_event_json)
278
274
  expect(redis).to receive(:expire)
279
275
 
280
276
  result = Flapjack::Data::Event.next('events', :block => true,