flapjack 1.2.0rc2 → 1.2.0

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.
@@ -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,