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