flapjack 1.2.0rc1 → 1.2.0rc2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d2385cedabb54ffdf76fab97912ff06918d6d1d
4
- data.tar.gz: 5df58568fccb796ee1f45e332a711b5b01003d15
3
+ metadata.gz: b10a01932fb4fd6a466e2b975764c3c6ff777e9c
4
+ data.tar.gz: e25026116bccc9209d8ca98c05585e89dc4b7ce3
5
5
  SHA512:
6
- metadata.gz: 2192ac69c3abfffd68ab6dd23dbbd4bf2ffb0bbb411620b8c6356857511f6792868a678f15796a8a116bec52b7ff2208b5ff251583fc57825e747816218b3532
7
- data.tar.gz: f7bfa433a64c42747c3b9359c8e28049d618f10ee6c03787df83818a2f63dd7a2c04194c234371f7151d3bfd21b22cf28715f0783d80ef91fb8148e3b80ce941
6
+ metadata.gz: d1e4aeba827545b5b18bc56bd549adff1b93b43bf368cd426d37b847c2d2801ea4e83f22c1af4e87579e947cf8d911a2abcb6025d778d476abcaad4b2ac934ab
7
+ data.tar.gz: e6956faf10c9a12bf9cd08bf56fbe87be986063967ec27e35e77b5ed313b8a3cff6b50ea14a5d58019b9b8f4c29f6bad483d0ecf739e7a0f609f26e3d9dedfeb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Flapjack Changelog
2
2
 
3
+ # 1.2.0rc2 - 2014-10-17
4
+ - Feature: Cache entity and check name <-> id lookups #682 (@ali-graham)
5
+ - Chore: Add last_change field to status_reports in the API (closes: #678) #679 (@Hobbsee)
6
+ - Chore: Move archive cache responsibility to mirror source. #683 (@ali-graham)
7
+ - Bug: jsonapi: GET /entities is non performant #674 (@ali-graham)
8
+
3
9
  # 1.2.0rc1 - 2014-10-08
4
10
  - Feature: Allow updating an entities name via PATCH /entities/id[,id...] #628 (@ali-graham)
5
11
  - Feature: Pact specs for flapjack-diner compatability testing #663 (@ali-graham)
data/Gemfile-ruby1.9.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- flapjack (1.2.0rc1)
4
+ flapjack (1.2.0rc2)
5
5
  activesupport (~> 3.2.14)
6
6
  blather (~> 0.8.3)
7
7
  chronic
@@ -5,6 +5,7 @@ require 'redis'
5
5
  require 'flapjack/configuration'
6
6
  require 'flapjack/data/contact'
7
7
  require 'flapjack/data/entity'
8
+ require 'flapjack/data/migration'
8
9
 
9
10
  module Flapjack
10
11
  module CLI
@@ -61,7 +62,10 @@ module Flapjack
61
62
  private
62
63
 
63
64
  def redis
64
- @redis ||= Redis.new(@redis_options.merge(:driver => :ruby))
65
+ return @redis unless @redis.nil?
66
+ @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
67
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
68
+ @redis
65
69
  end
66
70
 
67
71
  end
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'eventmachine'
4
- require 'em-synchrony'
5
3
  require 'redis'
6
- require 'redis/connection/synchrony'
4
+ require 'hiredis'
7
5
 
8
6
  require 'flapjack/configuration'
9
7
  require 'flapjack/data/event'
10
8
  require 'flapjack/data/entity_check'
9
+ require 'flapjack/data/migration'
11
10
  require 'terminal-table'
12
11
 
13
12
  module Flapjack
@@ -26,7 +25,7 @@ module Flapjack
26
25
  exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
27
26
  end
28
27
 
29
- @redis_options = config.for_redis.merge(:driver => :ruby)
28
+ @redis_options = config.for_redis
30
29
  @options[:redis] = redis
31
30
  end
32
31
 
@@ -67,7 +66,10 @@ module Flapjack
67
66
  private
68
67
 
69
68
  def redis
70
- @redis ||= Redis.new(@redis_options)
69
+ return @redis unless @redis.nil?
70
+ @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
71
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
72
+ @redis
71
73
  end
72
74
 
73
75
  end
@@ -3,6 +3,8 @@
3
3
  require 'hiredis'
4
4
  require 'flapjack/configuration'
5
5
 
6
+ require 'flapjack/data/migration'
7
+
6
8
  module Flapjack
7
9
  module CLI
8
10
  class Purge
@@ -50,7 +52,10 @@ module Flapjack
50
52
  private
51
53
 
52
54
  def redis
53
- @redis ||= Redis.new(@redis_options.merge(:driver => :ruby))
55
+ return @redis unless @redis.nil?
56
+ @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
57
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
58
+ @redis
54
59
  end
55
60
 
56
61
  end
@@ -6,6 +6,7 @@ require 'hiredis'
6
6
 
7
7
  require 'flapjack/configuration'
8
8
  require 'flapjack/data/event'
9
+ require 'flapjack/data/migration'
9
10
  require 'flapjack/patches'
10
11
 
11
12
  # TODO options should be overridden by similar config file options
@@ -19,20 +20,17 @@ module Flapjack
19
20
  @options = options
20
21
 
21
22
  @config = Flapjack::Configuration.new
23
+ @config.load(global_options[:config])
24
+ @config_env = @config.all
22
25
 
23
- if 'mirror'.eql?(@options[:type]) &&
24
- (global_options[:config].nil? || global_options[:config].strip.empty?)
26
+ if @config_env.nil? || @config_env.empty?
27
+ unless 'mirror'.eql?(@options[:type])
28
+ exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
29
+ end
25
30
 
26
31
  @config_env = {}
27
32
  @config_runner = {}
28
33
  else
29
- @config.load(global_options[:config])
30
- @config_env = @config.all
31
-
32
- if @config_env.nil? || @config_env.empty?
33
- exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
34
- end
35
-
36
34
  @config_runner = @config_env["#{@options[:type]}-receiver"] || {}
37
35
  end
38
36
 
@@ -135,7 +133,10 @@ module Flapjack
135
133
  private
136
134
 
137
135
  def redis
138
- @redis ||= Redis.new(@redis_options.merge(:driver => :hiredis))
136
+ return @redis unless @redis.nil?
137
+ @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
138
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
139
+ @redis
139
140
  end
140
141
 
141
142
  def runner(type)
@@ -363,11 +364,18 @@ module Flapjack
363
364
  source_redis = Redis.new(:url => source_addr, :driver => :hiredis)
364
365
 
365
366
  dest_addr = opts[:dest]
366
- dest_redis = Redis.new(:url => dest_addr, :driver => :hiredis)
367
+ dest_redis = case dest_addr
368
+ when Hash
369
+ Redis.new(dest_addr.merge(:driver => :hiredis))
370
+ when String
371
+ Redis.new(:url => dest_addr, :driver => :hiredis)
372
+ else
373
+ exit_now! "could not understand destination Redis config"
374
+ end
375
+
376
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => dest_redis)
367
377
 
368
- refresh_archive_index(source_addr, :source => source_redis, :dest => dest_redis)
369
- archives = mirror_get_archive_keys_stats(source_addr, :source => source_redis,
370
- :dest => dest_redis)
378
+ archives = mirror_get_archive_keys_stats(:source => source_redis)
371
379
  raise "found no archives!" if archives.empty?
372
380
 
373
381
  puts "found archives: #{archives.inspect}"
@@ -410,16 +418,9 @@ module Flapjack
410
418
  next
411
419
  end
412
420
 
413
- archives = mirror_get_archive_keys_stats(source_addr,
414
- :source => source_redis, :dest => dest_redis)
415
-
416
- if archives.any? {|a| a[:size] == 0}
417
- # data may be out of date -- refresh, then reject any immediately
418
- # expired keys directly; don't keep chasing updated data
419
- refresh_archive_index(source_addr, :source => source_redis, :dest => dest_redis)
420
- archives = mirror_get_archive_keys_stats(source_addr,
421
- :source => source_redis, :dest => dest_redis).select {|a| a[:size] > 0}
422
- end
421
+ archives = mirror_get_archive_keys_stats(:source => source_redis).select {|a|
422
+ a[:size] > 0
423
+ }
423
424
 
424
425
  if archives.empty?
425
426
  sleep 1
@@ -439,29 +440,13 @@ module Flapjack
439
440
  end
440
441
  end
441
442
 
442
- def mirror_get_archive_keys_stats(name, opts = {})
443
+ def mirror_get_archive_keys_stats(opts = {})
443
444
  source_redis = opts[:source]
444
- dest_redis = opts[:dest]
445
- dest_redis.smembers("known_events_archive_keys:#{name}").sort.collect do |eak|
445
+ source_redis.smembers("known_events_archive_keys").sort.collect do |eak|
446
446
  {:name => eak, :size => source_redis.llen(eak)}
447
447
  end
448
448
  end
449
449
 
450
- def refresh_archive_index(name, opts = {})
451
- source_redis = opts[:source]
452
- dest_redis = opts[:dest]
453
- # refresh the key name cache, avoid repeated calls to redis KEYS
454
- # this cache will be updated any time a new archive bucket is created
455
- archive_keys = source_redis.keys("events_archive:*").group_by do |ak|
456
- (source_redis.llen(ak) > 0) ? 't' : 'f'
457
- end
458
-
459
- {'f' => :srem, 't' => :sadd}.each_pair do |k, cmd|
460
- next unless archive_keys.has_key?(k) && !archive_keys[k].empty?
461
- dest_redis.send(cmd, "known_events_archive_keys:#{name}", archive_keys[k])
462
- end
463
- end
464
-
465
450
  end
466
451
  end
467
452
  end
@@ -7,6 +7,7 @@ require 'redis/connection/synchrony'
7
7
 
8
8
  require 'flapjack/configuration'
9
9
  require 'flapjack/data/event'
10
+ require 'flapjack/data/migration'
10
11
 
11
12
  module Flapjack
12
13
  module CLI
@@ -51,7 +52,10 @@ module Flapjack
51
52
  private
52
53
 
53
54
  def redis
54
- @redis ||= Redis.new(@redis_options)
55
+ return @redis unless @redis.nil?
56
+ @redis = Redis.new(@redis_options)
57
+ Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
58
+ @redis
55
59
  end
56
60
 
57
61
  def events(opts = {})
@@ -32,7 +32,7 @@ module Flapjack
32
32
  EM.synchrony do
33
33
  setup_signals if options[:signals]
34
34
 
35
- redis = Flapjack::RedisPool.new(:config => @redis_options, :size => 1)
35
+ redis = Flapjack::RedisPool.new(:config => @redis_options, :size => 1, :logger => @logger)
36
36
  ['entity', 'check'].each do |type|
37
37
  discovered = redis.keys("#{type}_tag:*")
38
38
  redis.sadd("known_tags:#{type}_tag", discovered) unless discovered.empty?
@@ -21,19 +21,16 @@ module Flapjack
21
21
  current_entity_names = (options.has_key?(:enabled) && !options[:enabled].nil?) ?
22
22
  Flapjack::Data::Entity.current_names(:redis => redis) : nil
23
23
 
24
- keys = redis.keys("entity_id:*")
25
- return [] unless keys.any?
26
- ids = redis.mget(keys)
27
- keys.inject([]) {|memo, k|
28
- k =~ /^entity_id:(.+)$/; entity_name = $1; entity_id = ids.shift
24
+ entity_names_by_id = redis.hgetall("all_entity_names_by_id")
25
+ return [] if entity_names_by_id.empty?
29
26
 
27
+ entity_names_by_id.inject([]) {|memo, (eid, ename)|
30
28
  if options[:enabled].nil? ||
31
- (options[:enabled].is_a?(TrueClass) && current_entity_names.include?(entity_name) ) ||
32
- (options[:enabled].is_a?(FalseClass) && !current_entity_names.include?(entity_name))
29
+ (options[:enabled].is_a?(TrueClass) && current_entity_names.include?(ename) ) ||
30
+ (options[:enabled].is_a?(FalseClass) && !current_entity_names.include?(ename))
33
31
 
34
- memo << self.new(:name => entity_name, :id => entity_id, :redis => redis)
32
+ memo << self.new(:name => ename, :id => eid, :redis => redis)
35
33
  end
36
-
37
34
  memo
38
35
  }.sort_by(&:name)
39
36
  end
@@ -59,6 +56,7 @@ module Flapjack
59
56
 
60
57
  alerting_check_keys = redis.keys("contact_alerting_checks:*")
61
58
 
59
+ all_checks = {}
62
60
  failed_checks = {}
63
61
  hashes_to_remove = []
64
62
  hashes_to_add = {}
@@ -77,6 +75,9 @@ module Flapjack
77
75
  existing_check = "#{existing_name}:#{ch}"
78
76
  new_check = "#{entity_name}:#{ch}"
79
77
 
78
+ ch_all_score = redis.zscore("all_checks", existing_check)
79
+ all_checks[ch] = ch_all_score unless ch_all_score.nil?
80
+
80
81
  ch_fail_score = redis.zscore("failed_checks", existing_check)
81
82
  failed_checks[ch] = ch_fail_score unless ch_fail_score.nil?
82
83
 
@@ -111,12 +112,18 @@ module Flapjack
111
112
  redis.rename(chk, chk.sub(/^#{Regexp.escape(existing_name)}:/, "#{entity_name}:"))
112
113
  end
113
114
 
115
+ all_checks.each_pair do |ch, score|
116
+ redis.zrem('all_checks', "#{existing_name}:#{ch}")
117
+ redis.zadd('all_checks', score, "#{entity_name}:#{ch}")
118
+ end
119
+
114
120
  # currently failing checks
115
121
  failed_checks.each_pair do |ch, score|
116
122
  redis.zrem('failed_checks', "#{existing_name}:#{ch}")
117
123
  redis.zadd('failed_checks', score, "#{entity_name}:#{ch}")
118
124
  end
119
125
 
126
+ redis.rename("all_checks:#{existing_name}", "all_checks:#{entity_name}")
120
127
  redis.rename("current_checks:#{existing_name}", "current_checks:#{entity_name}")
121
128
 
122
129
  unless current_score.nil?
@@ -160,6 +167,9 @@ module Flapjack
160
167
  keys_to_delete = []
161
168
  keys_to_rename = {}
162
169
 
170
+ all_checks_to_remove = []
171
+ all_checks_to_add = {}
172
+
163
173
  failed_checks_to_remove = []
164
174
  failed_checks_to_add = {}
165
175
 
@@ -182,6 +192,7 @@ module Flapjack
182
192
  old_states = "#{old_check}:states"
183
193
  new_states = "#{current_check}:states"
184
194
 
195
+ all_checks_to_remove << old_check
185
196
  failed_checks_to_remove << old_check
186
197
 
187
198
  if redis.exists("check:#{current_check}")
@@ -195,6 +206,9 @@ module Flapjack
195
206
  keys_to_delete << old_states
196
207
  else
197
208
 
209
+ ch_all_score = redis.zscore("all_checks", old_check)
210
+ all_checks_to_add[current_check] = ch_all_score unless ch_all_score.nil?
211
+
198
212
  # can move a failing checks entry over, if it exists
199
213
  ch_fail_score = redis.zscore("failed_checks", old_check)
200
214
  failed_checks_to_add[current_check] = ch_fail_score unless ch_fail_score.nil?
@@ -240,6 +254,14 @@ module Flapjack
240
254
 
241
255
  end
242
256
 
257
+ # TODO all_checks sorted set -- merge/rename entries
258
+
259
+ if redis.exists("all_checks:#{current_name}")
260
+ keys_to_delete << "all_checks:#{old_name}"
261
+ else
262
+ keys_to_rename["all_checks:#{old_name}"] = "all_checks:#{current_name}"
263
+ end
264
+
243
265
  if redis.exists("current_checks:#{current_name}")
244
266
  keys_to_delete << "current_checks:#{old_name}"
245
267
  else
@@ -339,6 +361,14 @@ module Flapjack
339
361
  redis.zunionstore(dest, [ctk, dest], :aggregate => :max)
340
362
  end
341
363
 
364
+ all_checks_to_remove.each do |actr|
365
+ redis.zrem('all_checks', actr)
366
+ end
367
+
368
+ all_checks_to_add.each_pair do |acta, score|
369
+ redis.zadd('all_checks', score, acta)
370
+ end
371
+
342
372
  failed_checks_to_remove.each do |fctr|
343
373
  redis.zrem('failed_checks', fctr)
344
374
  end
@@ -415,31 +445,33 @@ module Flapjack
415
445
 
416
446
  # if an entity exists with the same name as the incoming data,
417
447
  # use its id; failing that allocate a random one
418
- entity_id = redis.get("entity_id:#{entity_name}")
448
+ entity_id = redis.hget('all_entity_ids_by_name', entity_name)
419
449
 
420
450
  if entity_id.nil? || entity_id.empty?
421
451
  entity_id = SecureRandom.uuid
422
- redis.set("entity_id:#{entity_name}", entity_id)
423
- redis.hset("entity:#{entity_id}", 'name', entity_name)
452
+ redis.hset('all_entity_ids_by_name', entity_name, entity_id)
453
+ redis.hset('all_entity_names_by_id', entity_id, entity_name)
424
454
  end
425
455
  else
426
456
  # most likely from API import
427
- existing_name = redis.hget("entity:#{entity_id}", 'name')
457
+ existing_name = redis.hget('all_entity_names_by_id', entity_id)
428
458
 
429
- if existing_name.nil?
459
+ # if there's an entity with a matching name, this will change its
460
+ # id; if no entity exists it creates a new one
430
461
 
431
- # if there's an entity with a matching name, this will change its
432
- # id; if no entity exists it creates a new one
433
- redis.set("entity_id:#{entity_name}", entity_id)
434
- redis.hset("entity:#{entity_id}", 'name', entity_name)
462
+ if existing_name.nil?
463
+ redis.hset('all_entity_ids_by_name', entity_name, entity_id)
464
+ redis.hset('all_entity_names_by_id', entity_id, entity_name)
435
465
 
436
466
  elsif existing_name != entity_name
437
- if redis.renamenx("entity_id:#{existing_name}", "entity_id:#{entity_name}")
467
+ if redis.hexists('all_entity_ids_by_name', entity_name)
468
+ merge(existing_name, entity_name, :redis => redis)
469
+ else
438
470
  rename(existing_name, entity_name, :redis => redis) {
439
- redis.hset("entity:#{entity_id}", 'name', entity_name)
471
+ redis.hdel('all_entity_ids_by_name', existing_name)
472
+ redis.hset('all_entity_ids_by_name', entity_name, entity_id)
473
+ redis.hset('all_entity_names_by_id', entity_id, entity_name)
440
474
  }
441
- else
442
- merge(existing_name, entity_name, :redis => redis)
443
475
  end
444
476
  end
445
477
  end
@@ -463,7 +495,7 @@ module Flapjack
463
495
 
464
496
  def self.find_by_name(entity_name, options = {})
465
497
  raise "Redis connection not set" unless redis = options[:redis]
466
- entity_id = redis.get("entity_id:#{entity_name}")
498
+ entity_id = redis.hget("all_entity_ids_by_name", entity_name)
467
499
  if entity_id.nil? || entity_id.empty?
468
500
  # key doesn't exist
469
501
  return unless options[:create]
@@ -476,7 +508,7 @@ module Flapjack
476
508
 
477
509
  def self.find_by_id(entity_id, options = {})
478
510
  raise "Redis connection not set" unless redis = options[:redis]
479
- entity_name = redis.hget("entity:#{entity_id}", 'name')
511
+ entity_name = redis.hget("all_entity_names_by_id", entity_id)
480
512
  return if entity_name.nil? || entity_name.empty?
481
513
  self.new(:name => entity_name, :id => entity_id, :redis => redis)
482
514
  end
@@ -495,21 +527,17 @@ module Flapjack
495
527
  # time
496
528
  def self.find_all_name_matching(pattern, options = {})
497
529
  raise "Redis connection not set" unless redis = options[:redis]
530
+ regexp = nil
498
531
  begin
499
- regex = /#{pattern}/
532
+ regexp = Regexp.new(pattern)
500
533
  rescue => e
501
534
  if @logger
502
535
  @logger.info("Jabber#self.find_all_name_matching - unable to use /#{pattern}/ as a regex pattern: #{e}")
503
536
  end
504
- return nil
537
+ regexp = nil
505
538
  end
506
- redis.keys('entity_id:*').inject([]) {|memo, check|
507
- a, entity_name = check.split(':', 2)
508
- if (entity_name =~ regex) && !memo.include?(entity_name)
509
- memo << entity_name
510
- end
511
- memo
512
- }.sort
539
+ return if regexp.nil?
540
+ redis.hkeys('all_entity_ids_by_name').select {|en| regexp === en }.sort
513
541
  end
514
542
 
515
543
  def self.current_names(options = {})
@@ -549,11 +577,12 @@ module Flapjack
549
577
  raise "Redis connection not set" unless redis = options[:redis]
550
578
 
551
579
  entity_ids.inject({}) do |memo, entity_id|
552
- entity_name = redis.hget("entity:#{entity_id}", 'name')
553
- unless entity_name.nil? || entity_name.empty?
554
- checks = Flapjack::Data::EntityCheck.find_all_names_for_entity_name(entity_name, :redis => redis)
555
- memo[entity_id] = checks.collect {|check| "#{entity_name}:#{check}" }
556
- end
580
+ entity_name = redis.hget('entity_names_by_id', entity_id)
581
+ next memo if entity_name.nil? || entity_name.empty?
582
+ en = Regexp.escape(entity_name)
583
+ check_names = redis.keys("check:#{entity_name}:*").map {|c| c.sub(/^check:#{en}:/, '') } |
584
+ Flapjack::Data::EntityCheck.find_current_names_for_entity_name(entity_name, :redis => redis)
585
+ memo[entity_id] = check_names.map {|cn| "#{entity_name}:#{cn}"}
557
586
  memo
558
587
  end
559
588
  end
@@ -568,13 +597,6 @@ module Flapjack
568
597
  checks.length
569
598
  end
570
599
 
571
- # def as_json(*args)
572
- # {
573
- # "id" => self.id,
574
- # "name" => self.name,
575
- # }
576
- # end
577
-
578
600
  def to_jsonapi(opts = {})
579
601
  json_data = {
580
602
  "id" => self.id,