flapjack 1.2.0rc1 → 1.2.0rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -47,10 +47,12 @@ module Flapjack
47
47
  logger = options[:logger]
48
48
  timestamp = Time.now.to_i
49
49
 
50
- redis.zadd("current_checks:#{ent.name}", timestamp, check_name)
51
- redis.zadd('current_entities', timestamp, ent.name)
50
+ entity_name = ent.name
52
51
 
53
- c = self.new(ent, check_name, :logger => logger,
52
+ redis.zadd("current_checks:#{entity_name}", timestamp, check_name)
53
+ redis.zadd('current_entities', timestamp, entity_name)
54
+
55
+ c = self.new(ent, check_name, :logger => logger, :timestamp => timestamp,
54
56
  :redis => redis)
55
57
  if check_data['tags'] && check_data['tags'].respond_to?(:each)
56
58
  c.add_tags(*check_data['tags'])
@@ -95,17 +97,9 @@ module Flapjack
95
97
 
96
98
  def self.all(options = {})
97
99
  raise "Redis connection not set" unless redis = options[:redis]
98
- checks = redis.keys('check:*').map {|c| c.match(/^check:(.+)$/) ; $1} |
99
- find_current_names(:redis => redis)
100
- checks.map {|ec|
101
- self.for_event_id(ec, options)
102
- }
103
- end
104
-
105
- def self.find_all_names_for_entity_name(entity_name, options = {})
106
- raise "Redis connection not set" unless redis = options[:redis]
107
- en = Regexp.escape(entity_name)
108
- redis.keys('check:*').map {|c| c.match(/^check:#{en}:(.+)$/); $1}
100
+ redis.zrange("all_checks", 0, -1).collect do |cname|
101
+ self.for_event_id(cname, options)
102
+ end
109
103
  end
110
104
 
111
105
  def self.find_current_names_for_entity_name(entity_name, options = {})
@@ -182,36 +176,42 @@ module Flapjack
182
176
  def self.find_maintenance(options = {})
183
177
  raise "Redis connection not set" unless redis = options[:redis]
184
178
  type = options[:type]
185
- keys = redis.keys("*:#{type}_maintenances")
186
- keys.flat_map { |k|
187
- entity = k.split(':')[0]
188
- check = k.split(':')[1]
179
+
180
+ checks_with_maints = redis.zrange("all_checks", 0, -1).select do |ec_name|
181
+ # not ideal, but redis internals should essentially make this a lot
182
+ # of separate hash lookups
183
+ redis.exists("#{ec_name}:#{type}_maintenances")
184
+ end
185
+
186
+ return [] if checks_with_maints.empty?
187
+
188
+ entity_re = options[:entity].nil? ? nil : Regexp.new(options[:entity])
189
+ check_re = options[:check].nil? ? nil : Regexp.new(options[:check])
190
+ reason_re = options[:reason].nil? ? nil : Regexp.new(options[:reason])
191
+
192
+ checks_with_maints.inject([]) do |memo, k|
193
+ entity, check = k.split(':', 2)
189
194
  ec = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => redis)
190
195
 
191
196
  # Only return entries which match what was passed in
192
- case
193
- when options[:state] && options[:state] != ec.state
194
- nil
195
- when options[:entity] && !Regexp.new(options[:entity]).match(entity)
196
- nil
197
- when options[:check] && !Regexp.new(options[:check]).match(check)
198
- nil
199
- else
200
- windows = ec.maintenances(nil, nil, type.to_sym => true)
201
- windows.map { |window|
202
- entry = { :entity => entity,
203
- :check => check,
204
- :state => ec.state
205
- }
206
- if (options[:reason].nil? || Regexp.new(options[:reason]).match(window[:summary])) &&
207
- check_maintenance_timestamp(options[:started], window[:start_time]) &&
208
- check_maintenance_timestamp(options[:finishing], window[:end_time]) &&
209
- check_maintenance_interval(options[:duration], window[:duration])
210
- entry.merge!(window)
211
- end
212
- }.compact
197
+ next memo if (options[:state] && (options[:state] != ec.state)) ||
198
+ !(entity_re.nil? || entity_re.match(entity)) ||
199
+ !(check_re.nil? || check_re.match(check))
200
+
201
+ ec.maintenances(nil, nil, type.to_sym => true).each do |window|
202
+ next unless (reason_re.nil? || reason_re.match(window[:summary])) &&
203
+ check_maintenance_timestamp(options[:started], window[:start_time]) &&
204
+ check_maintenance_timestamp(options[:finishing], window[:end_time]) &&
205
+ check_maintenance_interval(options[:duration], window[:duration])
206
+
207
+ memo << { :entity => entity,
208
+ :check => check,
209
+ :state => ec.state
210
+ }.merge(window)
213
211
  end
214
- }.compact
212
+
213
+ memo
214
+ end
215
215
  end
216
216
 
217
217
  def self.delete_maintenance(options = {})
@@ -666,6 +666,8 @@ module Flapjack
666
666
 
667
667
  def last_update=(timestamp)
668
668
  @redis.hset("check:#{@key}", 'last_update', timestamp)
669
+ @redis.zadd("all_checks", timestamp, @key)
670
+ @redis.zadd("all_checks:#{entity.name}", timestamp, check)
669
671
  @redis.zadd("current_checks:#{entity.name}", timestamp, check)
670
672
  @redis.zadd('current_entities', timestamp, entity.name)
671
673
  end
@@ -678,8 +680,11 @@ module Flapjack
678
680
 
679
681
  # disables a check (removes currency)
680
682
  def disable!
683
+ timestamp = Time.now.to_i
681
684
  @logger.debug("disabling check [#{@key}]") if @logger
682
685
  entity_name = entity.name
686
+ @redis.zadd("all_checks", timestamp, @key)
687
+ @redis.zadd("all_checks:#{entity_name}", timestamp, check)
683
688
  @redis.zrem("current_checks:#{entity_name}", check)
684
689
  if @redis.zcount("current_checks:#{entity_name}", '-inf', '+inf') == 0
685
690
  @redis.zrem("current_checks:#{entity_name}", check)
@@ -690,8 +695,10 @@ module Flapjack
690
695
  def enable!
691
696
  timestamp = Time.now.to_i
692
697
  entity_name = entity.name
693
- redis.zadd("current_checks:#{entity_name}", timestamp, check)
694
- redis.zadd('current_entities', timestamp, entity_name)
698
+ @redis.zadd("all_checks", timestamp, @key)
699
+ @redis.zadd("all_checks:#{entity_name}", timestamp, check)
700
+ @redis.zadd("current_checks:#{entity_name}", timestamp, check)
701
+ @redis.zadd('current_entities', timestamp, entity_name)
695
702
  end
696
703
 
697
704
  def enabled?
@@ -977,6 +984,7 @@ module Flapjack
977
984
  "name" => @check,
978
985
  "entity_name" => @entity.name,
979
986
  "enabled" => opts[:enabled].is_a?(TrueClass),
987
+ "tags" => self.tags.to_a,
980
988
  "links" => {
981
989
  :entities => opts[:entity_ids] || [],
982
990
  }
@@ -991,6 +999,11 @@ module Flapjack
991
999
  raise "Invalid entity" unless @entity = entity
992
1000
  raise "Invalid check" unless @check = check
993
1001
  @key = "#{entity.name}:#{check}"
1002
+ if @redis.zscore("all_checks", @key).nil?
1003
+ timestamp = options[:timestamp] || Time.now.to_i
1004
+ @redis.zadd("all_checks", timestamp, @key)
1005
+ @redis.zadd("all_checks:#{entity.name}", timestamp, check)
1006
+ end
994
1007
  @logger = options[:logger]
995
1008
  end
996
1009
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'flapjack'
4
4
 
5
+ require 'flapjack/data/migration'
6
+
5
7
  module Flapjack
6
8
  module Data
7
9
  class Event
@@ -77,24 +79,27 @@ module Flapjack
77
79
  :events_archive_maxage => (3 * 60 * 60) }
78
80
  options = defaults.merge(opts)
79
81
 
80
- archive_dest = nil
82
+ archive_dest = nil
81
83
  base_time_str = Time.now.utc.strftime("%Y%m%d%H")
82
84
 
83
85
  if options[:archive_events]
84
86
  archive_dest = "events_archive:#{base_time_str}"
87
+ unless @previous_base_time_str == base_time_str
88
+ Flapjack::Data::Migration.purge_expired_archive_index(:redis => redis)
89
+ end
90
+ @previous_base_time_str = base_time_str
85
91
  if options[:block]
86
92
  raw = redis.brpoplpush(queue, archive_dest, 0)
87
93
  else
88
94
  raw = redis.rpoplpush(queue, archive_dest)
89
95
  return unless raw
90
96
  end
97
+ redis.sadd("known_events_archive_keys", archive_dest)
98
+ elsif options[:block]
99
+ raw = redis.brpop(queue, 0)[1]
91
100
  else
92
- if options[:block]
93
- raw = redis.brpop(queue, 0)[1]
94
- else
95
- raw = redis.rpop(queue)
96
- return unless raw
97
- end
101
+ raw = redis.rpop(queue)
102
+ return unless raw
98
103
  end
99
104
  parsed = parse_and_validate(raw, :logger => options[:logger])
100
105
  if parsed.nil?
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'flapjack/data/semaphore'
4
+
5
+ module Flapjack
6
+ module Data
7
+ class Migration
8
+
9
+ ENTITY_DATA_MIGRATION = 'entity_data_migration'
10
+
11
+ # copied from jsonapi/contact_methods.rb, could extract both into separate file
12
+ def self.obtain_semaphore(resource, options = {})
13
+ raise "Redis connection not set" unless redis = options[:redis]
14
+
15
+ semaphore = nil
16
+ strikes = 0
17
+ begin
18
+ semaphore = Flapjack::Data::Semaphore.new(resource, :redis => redis, :expiry => 60)
19
+ rescue Flapjack::Data::Semaphore::ResourceLocked
20
+ strikes += 1
21
+ if strikes < 5
22
+ sleep 2
23
+ retry
24
+ end
25
+ sempahore = nil
26
+ end
27
+ semaphore
28
+ end
29
+
30
+ def self.migrate_entity_check_data_if_required(options = {})
31
+ raise "Redis connection not set" unless redis = options[:redis]
32
+
33
+ logger = options[:logger]
34
+
35
+ semaphore = obtain_semaphore(ENTITY_DATA_MIGRATION, :redis => redis)
36
+ if semaphore.nil?
37
+ unless logger.nil?
38
+ logger.fatal "Could not obtain lock for data migration. Ensure that " +
39
+ "no other flapjack processes are running that might be executing " +
40
+ "migrations, check logs for any exceptions, manually delete the " +
41
+ "'#{ENTITY_DATA_MIGRATION}' key from your Flapjack Redis " +
42
+ "database and try running Flapjack again."
43
+ end
44
+ exit
45
+ end
46
+
47
+ if redis.exists('all_checks')
48
+ semaphore.release
49
+ return
50
+ end
51
+
52
+ logger.warn "Upgrading Flapjack's entity/check Redis indexes..." unless logger.nil?
53
+
54
+ check_names = redis.keys('check:*').map {|c| c.sub(/^check:/, '') } |
55
+ Flapjack::Data::EntityCheck.find_current_names(:redis => redis)
56
+
57
+ unless check_names.empty?
58
+ timestamp = Time.now.to_i
59
+
60
+ check_names.each do |ecn|
61
+ redis.zadd("all_checks", timestamp, ecn)
62
+ entity_name, check = ecn.split(':', 2)
63
+ redis.zadd("all_checks:#{entity_name}", timestamp, check)
64
+ # not deleting the check hashes, they store useful data
65
+ end
66
+ end
67
+
68
+ logger.warn "Checks indexed." unless logger.nil?
69
+
70
+ entity_name_keys = redis.keys("entity_id:*")
71
+ unless entity_name_keys.empty?
72
+ ids = redis.mget(*entity_name_keys)
73
+
74
+ entity_name_keys.each do |enk|
75
+ enk =~ /^entity_id:(.+)$/; entity_name = $1; entity_id = ids.shift
76
+
77
+ redis.hset('all_entity_names_by_id', entity_id, entity_name)
78
+ redis.hset('all_entity_ids_by_name', entity_name, entity_id)
79
+
80
+ redis.del(enk)
81
+ redis.del("entity:#{entity_id}")
82
+ end
83
+ end
84
+
85
+ logger.warn "Entities indexed." unless logger.nil?
86
+
87
+ semaphore.release
88
+
89
+ logger.warn "Indexing complete." unless logger.nil?
90
+ end
91
+
92
+ def self.refresh_archive_index(options = {})
93
+ raise "Redis connection not set" unless redis = options[:redis]
94
+ archive_keys = redis.keys('events_archive:*')
95
+ if archive_keys.empty?
96
+ redis.del('known_events_archive_keys')
97
+ return
98
+ end
99
+
100
+ grouped_keys = archive_keys.group_by do |ak|
101
+ (redis.llen(ak) > 0) ? 'add' : 'remove'
102
+ end
103
+
104
+ {'remove' => :srem, 'add' => :sadd}.each_pair do |k, cmd|
105
+ next unless grouped_keys.has_key?(k) && !grouped_keys[k].empty?
106
+ redis.send(cmd, 'known_events_archive_keys', grouped_keys[k])
107
+ end
108
+ end
109
+
110
+ def self.purge_expired_archive_index(options = {})
111
+ raise "Redis connection not set" unless redis = options[:redis]
112
+ return unless redis.exists('known_events_archive_keys')
113
+
114
+ redis.smembers('known_events_archive_keys').each do |ak|
115
+ redis.srem('known_events_archive_keys', ak) unless redis.exists(ak)
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -46,9 +46,10 @@ module Flapjack
46
46
  @redis_config = opts[:redis_config] || {}
47
47
  @boot_time = opts[:boot_time]
48
48
 
49
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
50
-
51
49
  @logger = opts[:logger]
50
+
51
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
52
+
52
53
  @logger.debug("Jabber Initializing")
53
54
 
54
55
  @buffer = []
@@ -183,7 +183,7 @@ module Flapjack
183
183
 
184
184
  class << self
185
185
  def start
186
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
186
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
187
187
 
188
188
  @logger.info "starting jsonapi - class"
189
189
 
@@ -28,6 +28,7 @@ module Flapjack
28
28
  'in_unscheduled_maintenance' => @entity_check.in_unscheduled_maintenance?,
29
29
  'in_scheduled_maintenance' => @entity_check.in_scheduled_maintenance?,
30
30
  'last_update' => @entity_check.last_update,
31
+ 'last_change' => @entity_check.last_change,
31
32
  'last_problem_notification' => @entity_check.last_notification_for_state(:problem)[:timestamp],
32
33
  'last_recovery_notification' => @entity_check.last_notification_for_state(:recovery)[:timestamp],
33
34
  'last_acknowledgement_notification' => @entity_check.last_notification_for_state(:acknowledgement)[:timestamp]}
@@ -25,11 +25,11 @@ module Flapjack
25
25
  semaphore = Flapjack::Data::Semaphore.new(resource, :redis => redis, :expiry => 30)
26
26
  rescue Flapjack::Data::Semaphore::ResourceLocked
27
27
  strikes += 1
28
- raise Flapjack::Gateways::JSONAPI::ResourceLocked.new(resource) unless strikes < 3
28
+ raise Flapjack::Gateways::JSONAPI::ResourceLocked.new(resource) if strikes >= 3
29
29
  sleep 1
30
30
  retry
31
31
  end
32
- raise Flapjack::Gateways::JSONAPI::ResourceLocked.new(resource) unless semaphore
32
+ raise Flapjack::Gateways::JSONAPI::ResourceLocked.new(resource) if semaphore.nil?
33
33
  semaphore
34
34
  end
35
35
 
@@ -144,9 +144,6 @@ module Flapjack
144
144
  unless notification_rule.nil?
145
145
  contact.grab_notification_rule(notification_rule)
146
146
  end
147
- when 'tags'
148
- value.respond_to?(:each) ? contact.add_tags(*value) :
149
- contact.add_tags(value)
150
147
  # when 'media' # not supported yet due to id brokenness
151
148
  end
152
149
  when 'remove'
@@ -159,9 +156,6 @@ module Flapjack
159
156
  unless notification_rule.nil?
160
157
  contact.delete_notification_rule(notification_rule)
161
158
  end
162
- when 'tags'
163
- value.respond_to?(:each) ? contact.delete_tags(*value) :
164
- contact.delete_tags(value)
165
159
  # when 'media' # not supported yet due to id brokenness
166
160
  end
167
161
  end
@@ -23,7 +23,7 @@ module Flapjack
23
23
  @config = opts[:config]
24
24
  @logger = opts[:logger]
25
25
  @redis_config = opts[:redis_config] || {}
26
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
26
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
27
27
 
28
28
  @logger.debug("New Pagerduty pikelet with the following options: #{@config.inspect}")
29
29
 
@@ -40,7 +40,7 @@ module Flapjack
40
40
 
41
41
  class << self
42
42
  def start
43
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
43
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
44
44
 
45
45
  @logger.info "starting web - class"
46
46
 
@@ -26,7 +26,7 @@ module Flapjack
26
26
  @config = opts[:config]
27
27
  @redis_config = opts[:redis_config] || {}
28
28
  @logger = opts[:logger]
29
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
29
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
30
30
 
31
31
  @notifications_queue = @config['queue'] || 'notifications'
32
32
 
@@ -97,7 +97,7 @@ module Flapjack
97
97
 
98
98
  def configure_resque
99
99
  unless ::Resque.instance_variable_defined?('@flapjack_pool') && !::Resque.instance_variable_get('@flapjack_pool').nil?
100
- resque_pool = Flapjack::RedisPool.new(:config => @redis_config)
100
+ resque_pool = Flapjack::RedisPool.new(:config => @redis_config, :logger => @logger)
101
101
  ::Resque.instance_variable_set('@flapjack_pool', resque_pool)
102
102
  ::Resque.redis = resque_pool
103
103
  end
@@ -175,7 +175,7 @@ module Flapjack
175
175
 
176
176
  # guard against another Resque pikelet having created the pool already
177
177
  unless defined?(@@redis_connection) && !@@redis_connection.nil?
178
- @@redis_connection = Flapjack::RedisPool.new(:config => @redis_config)
178
+ @@redis_connection = Flapjack::RedisPool.new(:config => @redis_config, :logger => @logger)
179
179
  end
180
180
 
181
181
  pikelet_klass.instance_variable_set('@config', @config)
@@ -26,7 +26,7 @@ module Flapjack
26
26
  @redis_config = opts[:redis_config] || {}
27
27
  @logger = opts[:logger]
28
28
 
29
- @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2)
29
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 2, :logger => @logger)
30
30
 
31
31
  @queue = @config['queue'] || 'events'
32
32