flapjack 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +11 -12
  4. data/CHANGELOG.md +10 -0
  5. data/Gemfile +0 -7
  6. data/Rakefile +0 -1
  7. data/bin/flapjack +2 -0
  8. data/etc/flapjack_config.yaml.example +20 -0
  9. data/features/ack_after_sched_maint.feature +1 -1
  10. data/features/cli.feature +1 -1
  11. data/features/notification_rules.feature +1 -1
  12. data/features/notifications.feature +0 -9
  13. data/features/rollup.feature +1 -1
  14. data/features/steps/events_steps.rb +20 -8
  15. data/features/steps/notifications_steps.rb +62 -75
  16. data/features/support/env.rb +17 -8
  17. data/flapjack.gemspec +4 -4
  18. data/lib/flapjack.rb +3 -0
  19. data/lib/flapjack/cli/import.rb +1 -0
  20. data/lib/flapjack/cli/maintenance.rb +1 -0
  21. data/lib/flapjack/cli/purge.rb +2 -0
  22. data/lib/flapjack/cli/receiver.rb +1 -0
  23. data/lib/flapjack/cli/simulate.rb +1 -0
  24. data/lib/flapjack/data/alert.rb +28 -1
  25. data/lib/flapjack/data/contact.rb +1 -1
  26. data/lib/flapjack/data/entity.rb +18 -8
  27. data/lib/flapjack/data/entity_check.rb +17 -0
  28. data/lib/flapjack/data/event.rb +33 -15
  29. data/lib/flapjack/data/migration.rb +46 -23
  30. data/lib/flapjack/filters/delays.rb +13 -6
  31. data/lib/flapjack/gateways/aws_sns.rb +115 -88
  32. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -1
  33. data/lib/flapjack/gateways/email.rb +145 -135
  34. data/lib/flapjack/gateways/email/alert.html.erb +6 -4
  35. data/lib/flapjack/gateways/email/alert.text.erb +2 -0
  36. data/lib/flapjack/gateways/jabber.rb +61 -1
  37. data/lib/flapjack/gateways/jabber/alert.text.erb +1 -1
  38. data/lib/flapjack/gateways/pagerduty/alert.text.erb +1 -1
  39. data/lib/flapjack/gateways/sms_gammu.rb +119 -0
  40. data/lib/flapjack/gateways/sms_messagenet.rb +95 -67
  41. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +2 -1
  42. data/lib/flapjack/gateways/sms_twilio.rb +102 -74
  43. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +2 -1
  44. data/lib/flapjack/logger.rb +1 -1
  45. data/lib/flapjack/notifier.rb +5 -14
  46. data/lib/flapjack/patches.rb +0 -58
  47. data/lib/flapjack/pikelet.rb +8 -78
  48. data/lib/flapjack/processor.rb +3 -1
  49. data/lib/flapjack/redis_pool.rb +2 -0
  50. data/lib/flapjack/version.rb +1 -1
  51. data/spec/lib/flapjack/data/contact_spec.rb +2 -2
  52. data/spec/lib/flapjack/data/entity_spec.rb +15 -0
  53. data/spec/lib/flapjack/data/event_spec.rb +2 -2
  54. data/spec/lib/flapjack/data/migration_spec.rb +11 -0
  55. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +12 -8
  56. data/spec/lib/flapjack/gateways/email_spec.rb +56 -51
  57. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +17 -12
  58. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +17 -12
  59. data/spec/lib/flapjack/pikelet_spec.rb +9 -23
  60. data/spec/lib/flapjack/redis_pool_spec.rb +1 -0
  61. data/tasks/profile.rake +25 -109
  62. metadata +37 -39
  63. data/Gemfile-ruby1.9 +0 -30
  64. data/Gemfile-ruby1.9.lock +0 -250
  65. data/tasks/benchmarks.rake +0 -237
@@ -38,8 +38,6 @@ require 'flapjack/notifier'
38
38
  require 'flapjack/processor'
39
39
  require 'flapjack/patches'
40
40
 
41
- require 'resque_spec'
42
-
43
41
  class MockLogger
44
42
  attr_accessor :messages
45
43
 
@@ -122,6 +120,20 @@ redis.flushdb
122
120
  RedisDelorean.before_all(:redis => redis)
123
121
  redis.quit
124
122
 
123
+ # Not the most efficient of operations...
124
+ def redis_peek(queue, start = 0, count = nil)
125
+ size = @notifier_redis.llen(queue)
126
+ start = 0 if start < 0
127
+ count = (size - start) if count.nil? || (count > (size - start))
128
+
129
+ (0..(size - 1)).inject([]) do |memo, n|
130
+ object = @notifier_redis.rpoplpush(queue, queue)
131
+ next memo unless (n >= start || n < (start + count))
132
+ memo << Flapjack.load_json(object)
133
+ memo
134
+ end
135
+ end
136
+
125
137
  Around do |scenario, blk|
126
138
  EM.synchrony do
127
139
  blk.call
@@ -130,11 +142,13 @@ Around do |scenario, blk|
130
142
  end
131
143
 
132
144
  Before do
145
+ @redis_opts = redis_opts
133
146
  @logger = MockLogger.new
134
147
  end
135
148
 
136
149
  After do
137
150
  @logger.messages = []
151
+ @redis_opts = nil
138
152
  end
139
153
 
140
154
  Before('@processor') do
@@ -150,7 +164,7 @@ After('@processor') do
150
164
  end
151
165
 
152
166
  Before('@notifier') do
153
- @notifier = Flapjack::Notifier.new(:logger => @logger,
167
+ @notifier = Flapjack::Notifier.new(:logger => @logger,
154
168
  :redis_config => redis_opts,
155
169
  :config => {'email_queue' => 'email_notifications',
156
170
  'sms_queue' => 'sms_notifications',
@@ -165,11 +179,6 @@ After('@notifier') do
165
179
  @notifier_redis = nil
166
180
  end
167
181
 
168
- Before('@resque') do
169
- ResqueSpec.reset!
170
- @queues = {:email => 'email_queue'}
171
- end
172
-
173
182
  Before('@time') do
174
183
  RedisDelorean.before_each(:redis => @redis || @notifier_redis)
175
184
  end
data/flapjack.gemspec CHANGED
@@ -23,10 +23,9 @@ Gem::Specification.new do |gem|
23
23
  gem.add_dependency 'eventmachine', '~> 1.0.0'
24
24
  gem.add_dependency 'redis', '~> 3.0.6'
25
25
  gem.add_dependency 'hiredis'
26
+ gem.add_dependency 'em-hiredis'
26
27
  gem.add_dependency 'em-synchrony', '~> 1.0.2'
27
28
  gem.add_dependency 'em-http-request'
28
- gem.add_dependency 'em-resque'
29
- gem.add_dependency 'resque', '~> 1.23.0'
30
29
  gem.add_dependency 'sinatra'
31
30
  gem.add_dependency 'rack-fiber_pool'
32
31
  gem.add_dependency 'thin', '~> 1.6.1'
@@ -35,12 +34,13 @@ Gem::Specification.new do |gem|
35
34
  gem.add_dependency 'chronic'
36
35
  gem.add_dependency 'chronic_duration'
37
36
  gem.add_dependency 'terminal-table'
38
- gem.add_dependency 'activesupport', '~> 3.2.14'
37
+ gem.add_dependency 'activesupport'
39
38
  gem.add_dependency 'ice_cube'
40
- gem.add_dependency 'tzinfo', '~> 1.0.1'
39
+ gem.add_dependency 'tzinfo'
41
40
  gem.add_dependency 'tzinfo-data'
42
41
  gem.add_dependency 'rbtrace'
43
42
  gem.add_dependency 'rake'
44
43
  gem.add_dependency 'gli', '= 2.12.0'
45
44
  gem.add_dependency 'nokogiri', '= 1.6.2.1'
45
+ gem.add_dependency 'mysql2'
46
46
  end
data/lib/flapjack.rb CHANGED
@@ -4,6 +4,9 @@ require 'oj'
4
4
 
5
5
  module Flapjack
6
6
 
7
+ DEFAULT_INITIAL_FAILURE_DELAY = 30
8
+ DEFAULT_REPEAT_FAILURE_DELAY = 60
9
+
7
10
  def self.load_json(data)
8
11
  Oj.load(data, :mode => :strict, :symbol_keys => false)
9
12
  end
@@ -65,6 +65,7 @@ module Flapjack
65
65
  return @redis unless @redis.nil?
66
66
  @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
67
67
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
68
+ Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
68
69
  @redis
69
70
  end
70
71
 
@@ -68,6 +68,7 @@ module Flapjack
68
68
  return @redis unless @redis.nil?
69
69
  @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
70
70
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
71
+ Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
71
72
  Flapjack::Data::Migration.validate_scheduled_maintenance_periods(:redis => @redis)
72
73
  @redis
73
74
  end
@@ -40,6 +40,7 @@ module Flapjack
40
40
  purged = checks.inject([]) do |memo, check|
41
41
  pu = check.purge_history(options)
42
42
  memo << pu unless pu == 0
43
+ memo
43
44
  end
44
45
 
45
46
  if purged.empty?
@@ -55,6 +56,7 @@ module Flapjack
55
56
  return @redis unless @redis.nil?
56
57
  @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
57
58
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
59
+ Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
58
60
  @redis
59
61
  end
60
62
 
@@ -144,6 +144,7 @@ module Flapjack
144
144
  return @redis unless @redis.nil?
145
145
  @redis = Redis.new(@redis_options.merge(:driver => :hiredis))
146
146
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
147
+ Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
147
148
  @redis
148
149
  end
149
150
 
@@ -55,6 +55,7 @@ module Flapjack
55
55
  return @redis unless @redis.nil?
56
56
  @redis = Redis.new(@redis_options)
57
57
  Flapjack::Data::Migration.migrate_entity_check_data_if_required(:redis => @redis)
58
+ Flapjack::Data::Migration.clear_orphaned_entity_ids(:redis => @redis)
58
59
  @redis
59
60
  end
60
61
 
@@ -51,7 +51,7 @@ module Flapjack
51
51
 
52
52
  include Flapjack::Utility
53
53
 
54
- def initialize(contents, opts)
54
+ def initialize(contents, opts = {})
55
55
  raise "no logger supplied" unless @logger = opts[:logger]
56
56
 
57
57
  @event_id = contents['event_id']
@@ -103,7 +103,34 @@ module Flapjack
103
103
  details['state'] && allowed_rollup_states.include?(details['state'])
104
104
  end
105
105
  end
106
+ end
107
+
108
+ def self.add(queue, alert_data, opts = {})
109
+ raise "Redis connection not set" unless redis = opts[:redis]
110
+ redis.rpush(queue, Flapjack.dump_json(alert_data))
111
+ end
112
+
113
+ def self.next(queue, opts = {})
114
+ raise "Redis connection not set" unless redis = opts[:redis]
115
+
116
+ defaults = { :block => true }
117
+ options = defaults.merge(opts)
106
118
 
119
+ if options[:block]
120
+ raw = redis.blpop(queue, 0)[1]
121
+ else
122
+ raw = redis.lpop(queue)
123
+ return unless raw
124
+ end
125
+ begin
126
+ parsed = ::Flapjack.load_json( raw )
127
+ rescue Oj::Error => e
128
+ if options[:logger]
129
+ options[:logger].warn("Error deserialising alert json: #{e}, raw json: #{raw.inspect}")
130
+ end
131
+ return nil
132
+ end
133
+ self.new( parsed, :logger => opts[:logger] )
107
134
  end
108
135
 
109
136
  def type
@@ -19,7 +19,7 @@ module Flapjack
19
19
  attr_accessor :id, :first_name, :last_name, :email, :media,
20
20
  :media_intervals, :media_rollup_thresholds, :pagerduty_credentials
21
21
 
22
- ALL_MEDIA = ['email', 'sms', 'sms_twilio', 'jabber', 'pagerduty', 'sns']
22
+ ALL_MEDIA = ['email', 'sms', 'sms_twilio', 'sms_gammu', 'jabber', 'pagerduty', 'sns']
23
23
 
24
24
  def self.all(options = {})
25
25
  raise "Redis connection not set" unless redis = options[:redis]
@@ -469,24 +469,34 @@ module Flapjack
469
469
  end
470
470
  else
471
471
  # most likely from API import
472
- existing_name = redis.hget('all_entity_names_by_id', entity_id)
472
+ this_id_original_name = redis.hget('all_entity_names_by_id', entity_id)
473
473
 
474
474
  # if there's an entity with a matching name, this will change its
475
475
  # id; if no entity exists it creates a new one
476
476
 
477
- if existing_name.nil?
477
+ this_name_original_id = redis.hget('all_entity_ids_by_name', entity_name)
478
+
479
+ if this_id_original_name.nil?
480
+ # no entity exists with a matching id
478
481
  redis.hset('all_entity_ids_by_name', entity_name, entity_id)
479
482
  redis.hset('all_entity_names_by_id', entity_id, entity_name)
480
483
 
481
- elsif existing_name != entity_name
482
- if redis.hexists('all_entity_ids_by_name', entity_name)
483
- merge(existing_name, entity_name, :redis => redis)
484
- else
485
- rename(existing_name, entity_name, :redis => redis) {|multi|
486
- multi.hdel('all_entity_ids_by_name', existing_name)
484
+ unless this_name_original_id.nil?
485
+ # an entity existed with a matching name but a different id
486
+ redis.hdel('all_entity_names_by_id', this_name_original_id)
487
+ end
488
+ elsif this_id_original_name != entity_name
489
+ # a record exists with the provided id but a different name
490
+ if this_name_original_id.nil?
491
+ # there shouldn't be any entity records left without ids (due to
492
+ # the migration code) so this code may not be needed now
493
+ rename(this_id_original_name, entity_name, :redis => redis) {|multi|
494
+ multi.hdel('all_entity_ids_by_name', this_id_original_name)
487
495
  multi.hset('all_entity_ids_by_name', entity_name, entity_id)
488
496
  multi.hset('all_entity_names_by_id', entity_id, entity_name)
489
497
  }
498
+ else
499
+ merge(this_id_original_name, entity_name, :redis => redis)
490
500
  end
491
501
  end
492
502
  end
@@ -606,6 +606,8 @@ module Flapjack
606
606
  details = options[:details]
607
607
  perfdata = options[:perfdata]
608
608
  count = options[:count]
609
+ initial_delay = options[:initial_failure_delay]
610
+ repeat_delay = options[:repeat_failure_delay]
609
611
 
610
612
  old_state = self.state
611
613
 
@@ -651,6 +653,11 @@ module Flapjack
651
653
  # hash summary and details (as they may have changed)
652
654
  multi.hset("check:#{@key}", 'summary', (summary || ''))
653
655
  multi.hset("check:#{@key}", 'details', (details || ''))
656
+
657
+ # NB: delays will revert to defaults if event sources don't continue sending
658
+ # through their custom delays in the event structure
659
+ multi.hset("check:#{@key}", 'initial_failure_delay', (initial_delay || Flapjack::DEFAULT_INITIAL_FAILURE_DELAY))
660
+ multi.hset("check:#{@key}", 'repeat_failure_delay', (repeat_delay || Flapjack::DEFAULT_REPEAT_FAILURE_DELAY))
654
661
  if perfdata
655
662
  multi.hset("check:#{@key}", 'perfdata', format_perfdata(perfdata).to_json)
656
663
  # multi.set("#{@key}:#{timestamp}:perfdata", perfdata)
@@ -777,6 +784,16 @@ module Flapjack
777
784
  data
778
785
  end
779
786
 
787
+ def initial_failure_delay
788
+ delay = @redis.hget("check:#{@key}", 'initial_failure_delay')
789
+ delay.to_i unless delay.nil?
790
+ end
791
+
792
+ def repeat_failure_delay
793
+ delay = @redis.hget("check:#{@key}", 'repeat_failure_delay')
794
+ delay.to_i unless delay.nil?
795
+ end
796
+
780
797
  # Returns a list of states for this entity check, sorted by timestamp.
781
798
  #
782
799
  # start_time and end_time should be passed as integer timestamps; these timestamps
@@ -10,10 +10,13 @@ module Flapjack
10
10
 
11
11
  attr_accessor :counter, :id_hash, :tags
12
12
 
13
- attr_reader :check, :summary, :details, :acknowledgement_id, :perfdata
13
+ attr_reader :check, :summary, :details, :acknowledgement_id, :perfdata,
14
+ :initial_failure_delay, :repeat_failure_delay
14
15
 
15
- REQUIRED_KEYS = ['type', 'state', 'entity', 'check', 'summary']
16
- OPTIONAL_KEYS = ['time', 'details', 'acknowledgement_id', 'duration', 'tags', 'perfdata']
16
+ REQUIRED_KEYS = ['type', 'state', 'entity', 'check']
17
+ OPTIONAL_KEYS = ['time', 'summary', 'details', 'acknowledgement_id',
18
+ 'duration', 'tags', 'perfdata', 'initial_failure_delay',
19
+ 'repeat_failure_delay']
17
20
 
18
21
  VALIDATIONS = {
19
22
  proc {|e| e['type'].is_a?(String) &&
@@ -32,14 +35,24 @@ module Flapjack
32
35
  proc {|e| e['check'].is_a?(String) } =>
33
36
  "check must be a string",
34
37
 
35
- proc {|e| e['summary'].is_a?(String) } =>
36
- "summary must be a string",
37
-
38
38
  proc {|e| e['time'].nil? ||
39
39
  e['time'].is_a?(Integer) ||
40
40
  (e['time'].is_a?(String) && !!(e['time'] =~ /^\d+$/)) } =>
41
41
  "time must be a positive integer, or a string castable to one",
42
42
 
43
+ proc {|e| e['initial_failure_delay'].nil? ||
44
+ e['initial_failure_delay'].is_a?(Integer) ||
45
+ (e['initial_failure_delay'].is_a?(String) && !!(e['initial_failure_delay'] =~ /^\d+$/)) } =>
46
+ "initial_failure_delay must be a positive integer, or a string castable to one",
47
+
48
+ proc {|e| e['repeat_failure_delay'].nil? ||
49
+ e['repeat_failure_delay'].is_a?(Integer) ||
50
+ (e['repeat_failure_delay'].is_a?(String) && !!(e['repeat_failure_delay'] =~ /^\d+$/)) } =>
51
+ "repeat_failure_delay must be a positive integer, or a string castable to one",
52
+
53
+ proc {|e| e['summary'].nil? || e['summary'].is_a?(String) } =>
54
+ "summary must be a string",
55
+
43
56
  proc {|e| e['details'].nil? || e['details'].is_a?(String) } =>
44
57
  "details must be a string",
45
58
 
@@ -169,14 +182,16 @@ module Flapjack
169
182
  end
170
183
 
171
184
  # creates, or modifies, an event object and adds it to the events list in redis
172
- # 'entity' => entity,
173
- # 'check' => check,
174
- # 'type' => 'service',
175
- # 'state' => state,
176
- # 'summary' => check_output,
177
- # 'details' => check_long_output,
178
- # 'perfdata' => perf_data,
179
- # 'time' => timestamp
185
+ # 'entity' => entity,
186
+ # 'check' => check,
187
+ # 'type' => 'service',
188
+ # 'state' => state,
189
+ # 'summary' => check_output,
190
+ # 'details' => check_long_output,
191
+ # 'perfdata' => perf_data,
192
+ # 'time' => timestamp,
193
+ # 'initial_failure_delay' => initial_failure_delay,
194
+ # 'repeat_failure_delay' => repeat_failure_delay
180
195
  def self.add(evt, opts = {})
181
196
  raise "Redis connection not set" unless redis = opts[:redis]
182
197
 
@@ -216,9 +231,12 @@ module Flapjack
216
231
 
217
232
  def initialize(attrs = {})
218
233
  ['type', 'state', 'entity', 'check', 'time', 'summary', 'details',
219
- 'perfdata', 'acknowledgement_id', 'duration'].each do |key|
234
+ 'perfdata', 'acknowledgement_id', 'duration', 'initial_failure_delay',
235
+ 'repeat_failure_delay'].each do |key|
220
236
  instance_variable_set("@#{key}", attrs[key])
221
237
  end
238
+ # summary is optional. set it to nil if it only contains whitespace
239
+ @summary = (@summary.is_a?(String) && ! @summary.strip.empty?) ? @summary.strip : nil
222
240
  # details is optional. set it to nil if it only contains whitespace
223
241
  @details = (@details.is_a?(String) && ! @details.strip.empty?) ? @details.strip : nil
224
242
  # perfdata is optional. set it to nil if it only contains whitespace
@@ -12,9 +12,11 @@ module Flapjack
12
12
  ENTITY_DATA_MIGRATION = 'entity_data_migration'
13
13
 
14
14
  # copied from jsonapi/contact_methods.rb, could extract both into separate file
15
- def self.obtain_semaphore(resource, options = {})
15
+ def self.obtain_semaphore(resource, description, options = {})
16
16
  raise "Redis connection not set" unless redis = options[:redis]
17
17
 
18
+ logger = options[:logger]
19
+
18
20
  semaphore = nil
19
21
  strikes = 0
20
22
  begin
@@ -27,6 +29,18 @@ module Flapjack
27
29
  end
28
30
  sempahore = nil
29
31
  end
32
+
33
+ if semaphore.nil?
34
+ unless logger.nil?
35
+ logger.fatal "Could not obtain lock for data migration (#{reason}). Ensure that " +
36
+ "no other flapjack processes are running that might be executing " +
37
+ "migrations, check logs for any exceptions, manually delete the " +
38
+ "'#{resource}' key from your Flapjack Redis " +
39
+ "database and try running Flapjack again."
40
+ end
41
+ raise "Unable to obtain semaphore #{resource}"
42
+ end
43
+
30
44
  semaphore
31
45
  end
32
46
 
@@ -37,17 +51,8 @@ module Flapjack
37
51
 
38
52
  return if redis.exists('created_ids_for_old_entities_without_ids')
39
53
 
40
- semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION, :redis => redis)
41
- if semaphore.nil?
42
- unless logger.nil?
43
- logger.fatal "Could not obtain lock for data migration (entity id creation). Ensure that " +
44
- "no other flapjack processes are running that might be executing " +
45
- "migrations, check logs for any exceptions, manually delete the " +
46
- "'#{ENTITY_DATA_MIGRATION}' key from your Flapjack Redis " +
47
- "database and try running Flapjack again."
48
- end
49
- raise "Unable to obtain semaphore #{ENTITY_DATA_MIGRATION}"
50
- end
54
+ semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION, 'entity id creation',
55
+ :redis => redis, :logger => logger)
51
56
 
52
57
  begin
53
58
  logger.warn "Ensuring all entities have ids ..." unless logger.nil?
@@ -72,17 +77,8 @@ module Flapjack
72
77
 
73
78
  return if redis.exists('all_checks')
74
79
 
75
- semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION, :redis => redis)
76
- if semaphore.nil?
77
- unless logger.nil?
78
- logger.fatal "Could not obtain lock for entity check data migration. Ensure that " +
79
- "no other flapjack processes are running that might be executing " +
80
- "migrations, check logs for any exceptions, manually delete the " +
81
- "'#{ENTITY_DATA_MIGRATION}' key from your Flapjack Redis " +
82
- "database and try running Flapjack again."
83
- end
84
- raise "Unable to obtain semaphore #{ENTITY_DATA_MIGRATION}"
85
- end
80
+ semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION, 'entity check data',
81
+ :redis => redis, :logger => logger)
86
82
 
87
83
  begin
88
84
  logger.warn "Upgrading Flapjack's entity/check Redis indexes..." unless logger.nil?
@@ -125,6 +121,33 @@ module Flapjack
125
121
  end
126
122
  end
127
123
 
124
+ def self.clear_orphaned_entity_ids(options = {})
125
+ raise "Redis connection not set" unless redis = options[:redis]
126
+
127
+ logger = options[:logger]
128
+
129
+ semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION,
130
+ 'orphaned entity ids', :redis => redis, :logger => logger)
131
+
132
+ begin
133
+ logger.info "Checking for orphaned entity ids..." unless logger.nil?
134
+
135
+ valid_entity_data = redis.hgetall('all_entity_ids_by_name')
136
+
137
+ missing_ids = redis.hgetall('all_entity_names_by_id').reject {|e_id, e_name|
138
+ valid_entity_data[e_name] == e_id
139
+ }
140
+
141
+ unless missing_ids.empty?
142
+ logger.info "Clearing ids (#{missing_ids.inspect})" unless logger.nil?
143
+ redis.hdel('all_entity_names_by_id', missing_ids.keys)
144
+ end
145
+ ensure
146
+ semaphore.release
147
+ logger.info "Finished checking for orphaned entity ids." unless logger.nil?
148
+ end
149
+ end
150
+
128
151
  def self.refresh_archive_index(options = {})
129
152
  raise "Redis connection not set" unless redis = options[:redis]
130
153
  archive_keys = redis.keys('events_archive:*')