flapjack 1.2.0rc1 → 1.2.0rc2

Sign up to get free protection for your applications and to get access to all the features.
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,