flapjack 1.1.0 → 1.2.0rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +12 -7
  5. data/CHANGELOG.md +12 -0
  6. data/Gemfile +6 -2
  7. data/Gemfile-ruby1.9 +29 -0
  8. data/Gemfile-ruby1.9.lock +251 -0
  9. data/README.md +2 -2
  10. data/Rakefile +1 -0
  11. data/etc/flapjack_config.yaml.example +2 -2
  12. data/features/steps/events_steps.rb +2 -2
  13. data/features/steps/flapjack-netsaint-parser_steps.rb +1 -1
  14. data/features/support/env.rb +1 -6
  15. data/lib/flapjack/cli/import.rb +2 -5
  16. data/lib/flapjack/cli/purge.rb +4 -4
  17. data/lib/flapjack/cli/receiver.rb +122 -54
  18. data/lib/flapjack/cli/server.rb +0 -5
  19. data/lib/flapjack/coordinator.rb +6 -0
  20. data/lib/flapjack/data/contact.rb +10 -62
  21. data/lib/flapjack/data/entity.rb +36 -52
  22. data/lib/flapjack/data/entity_check.rb +90 -21
  23. data/lib/flapjack/data/event.rb +4 -5
  24. data/lib/flapjack/data/notification.rb +8 -10
  25. data/lib/flapjack/data/notification_rule.rb +32 -35
  26. data/lib/flapjack/data/tagged.rb +48 -0
  27. data/lib/flapjack/gateways/jabber.rb +4 -5
  28. data/lib/flapjack/gateways/jsonapi/check_methods.rb +45 -7
  29. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +1 -1
  30. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +8 -2
  31. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +26 -8
  32. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +13 -9
  33. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +2 -2
  34. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +1 -1
  35. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +24 -17
  36. data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +1 -1
  37. data/lib/flapjack/gateways/jsonapi/report_methods.rb +4 -4
  38. data/lib/flapjack/gateways/jsonapi.rb +52 -31
  39. data/lib/flapjack/gateways/oobetet.rb +2 -3
  40. data/lib/flapjack/gateways/pagerduty.rb +9 -8
  41. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +19 -0
  42. data/lib/flapjack/gateways/web/public/js/flapjack.js +6 -2
  43. data/lib/flapjack/gateways/web/public/js/modules/contact.js +9 -14
  44. data/lib/flapjack/gateways/web/public/js/modules/medium.js +1 -0
  45. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -1
  46. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +3 -3
  47. data/lib/flapjack/gateways/web.rb +8 -7
  48. data/lib/flapjack/notifier.rb +2 -4
  49. data/lib/flapjack/processor.rb +2 -2
  50. data/lib/flapjack/version.rb +1 -1
  51. data/lib/flapjack.rb +10 -0
  52. data/spec/lib/flapjack/coordinator_spec.rb +18 -0
  53. data/spec/lib/flapjack/data/contact_spec.rb +4 -12
  54. data/spec/lib/flapjack/data/entity_check_spec.rb +56 -3
  55. data/spec/lib/flapjack/data/entity_spec.rb +79 -67
  56. data/spec/lib/flapjack/data/event_spec.rb +78 -78
  57. data/spec/lib/flapjack/data/notification_rule_spec.rb +4 -2
  58. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +94 -11
  59. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +84 -0
  60. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +5 -3
  61. data/spec/lib/flapjack/gateways/web_spec.rb +3 -3
  62. data/spec/service_consumers/pact_helper.rb +74 -0
  63. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +4522 -0
  64. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +356 -0
  65. data/spec/spec_helper.rb +0 -8
  66. data/spec/support/jsonapi_helper.rb +1 -1
  67. data/tasks/benchmarks.rake +6 -3
  68. data/tasks/profile.rake +1 -1
  69. data/tmp/acknowledge.rb +0 -3
  70. data/tmp/create_event_ok.rb +0 -3
  71. data/tmp/create_event_unknown.rb +0 -3
  72. data/tmp/create_events_failure.rb +0 -3
  73. data/tmp/create_events_ok.rb +0 -3
  74. data/tmp/create_events_ok_fail_ack_ok.rb +0 -3
  75. data/tmp/create_events_ok_failure.rb +2 -5
  76. data/tmp/create_events_ok_failure_ack.rb +0 -3
  77. data/tmp/test_json_post.rb +4 -3
  78. data/tmp/test_notification_rules_api.rb +2 -3
  79. metadata +13 -8
  80. data/lib/flapjack/data/tag.rb +0 -61
  81. data/lib/flapjack/data/tag_set.rb +0 -16
  82. data/spec/lib/flapjack/data/tag_spec.rb +0 -36
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oj'
4
-
5
3
  require 'flapjack/patches'
6
4
 
7
5
  require 'flapjack/data/contact'
8
6
  require 'flapjack/data/event'
9
7
  require 'flapjack/data/entity'
8
+ require 'flapjack/data/tagged'
9
+
10
10
  #FIXME: Require chronic_duration in the correct place
11
11
  require 'chronic_duration'
12
12
 
@@ -27,8 +27,37 @@ module Flapjack
27
27
  NOTIFICATION_STATES = [:problem, :warning, :critical, :unknown,
28
28
  :recovery, :acknowledgement]
29
29
 
30
+ include Tagged
31
+
30
32
  attr_accessor :entity, :check
31
33
 
34
+ def self.add(check_data, options = {})
35
+ raise "Redis connection not set" unless redis = options[:redis]
36
+
37
+ entity_id = check_data['entity_id']
38
+ raise "Entity id not provided" if entity_id.nil? || entity_id.empty?
39
+
40
+ check_name = check_data['name']
41
+ raise "Name not provided" if check_name.nil? || check_name.empty?
42
+
43
+ ent = Flapjack::Data::Entity.find_by_id(entity_id, :redis => redis)
44
+
45
+ raise "Entity not found for id '#{entity_id}'" if ent.nil?
46
+
47
+ logger = options[:logger]
48
+ timestamp = Time.now.to_i
49
+
50
+ redis.zadd("current_checks:#{ent.name}", timestamp, check_name)
51
+ redis.zadd('current_entities', timestamp, ent.name)
52
+
53
+ c = self.new(ent, check_name, :logger => logger,
54
+ :redis => redis)
55
+ if check_data['tags'] && check_data['tags'].respond_to?(:each)
56
+ c.add_tags(*check_data['tags'])
57
+ end
58
+ c
59
+ end
60
+
32
61
  def self.for_event_id(event_id, options = {})
33
62
  raise "Redis connection not set" unless redis = options[:redis]
34
63
  entity_name, check_name = event_id.split(':', 2)
@@ -36,6 +65,7 @@ module Flapjack
36
65
  logger = options[:logger]
37
66
  entity = Flapjack::Data::Entity.find_by_name(entity_name,
38
67
  :create => create_entity, :logger => logger, :redis => redis)
68
+ return if entity.nil?
39
69
  self.new(entity, check_name, :logger => logger, :redis => redis)
40
70
  end
41
71
 
@@ -65,23 +95,30 @@ module Flapjack
65
95
 
66
96
  def self.all(options = {})
67
97
  raise "Redis connection not set" unless redis = options[:redis]
68
- checks = redis.keys('check:*').map {|c| c.match(/^check:(.*)$/) ; $1}
98
+ checks = redis.keys('check:*').map {|c| c.match(/^check:(.+)$/) ; $1} |
99
+ find_current_names(:redis => redis)
69
100
  checks.map {|ec|
70
- self.for_entity_id(ec, options)
101
+ self.for_event_id(ec, options)
71
102
  }
72
103
  end
73
104
 
74
- def self.find_current_for_entity_name(entity_name, options = {})
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}
109
+ end
110
+
111
+ def self.find_current_names_for_entity_name(entity_name, options = {})
75
112
  raise "Redis connection not set" unless redis = options[:redis]
76
113
  redis.zrange("current_checks:#{entity_name}", 0, -1)
77
114
  end
78
115
 
79
- def self.find_current(options = {})
116
+ def self.find_current_names(options = {})
80
117
  raise "Redis connection not set" unless redis = options[:redis]
81
- self.conflate_to_keys(self.find_current_by_entity(:redis => redis))
118
+ self.conflate_to_keys(self.find_current_names_by_entity(:redis => redis))
82
119
  end
83
120
 
84
- def self.find_current_by_entity(options = {})
121
+ def self.find_current_names_by_entity(options = {})
85
122
  raise "Redis connection not set" unless redis = options[:redis]
86
123
  d = {}
87
124
  redis.zrange("current_entities", 0, -1).each {|entity|
@@ -97,12 +134,12 @@ module Flapjack
97
134
  }
98
135
  end
99
136
 
100
- def self.find_current_failing(options = {})
137
+ def self.find_current_names_failing(options = {})
101
138
  raise "Redis connection not set" unless redis = options[:redis]
102
- self.conflate_to_keys(self.find_current_failing_by_entity(:redis => redis))
139
+ self.conflate_to_keys(self.find_current_names_failing_by_entity(:redis => redis))
103
140
  end
104
141
 
105
- def self.find_current_failing_by_entity(options = {})
142
+ def self.find_current_names_failing_by_entity(options = {})
106
143
  raise "Redis connection not set" unless redis = options[:redis]
107
144
  redis.zrange("failed_checks", 0, -1).inject({}) do |memo, key|
108
145
  entity, check = key.split(':', 2)
@@ -642,13 +679,21 @@ module Flapjack
642
679
  # disables a check (removes currency)
643
680
  def disable!
644
681
  @logger.debug("disabling check [#{@key}]") if @logger
645
- @redis.zrem("current_checks:#{entity.name}", check)
646
- if @redis.zcount("current_checks:#{entity.name}", '-inf', '+inf') == 0
647
- @redis.zrem("current_checks:#{entity.name}", check)
682
+ entity_name = entity.name
683
+ @redis.zrem("current_checks:#{entity_name}", check)
684
+ if @redis.zcount("current_checks:#{entity_name}", '-inf', '+inf') == 0
685
+ @redis.zrem("current_checks:#{entity_name}", check)
648
686
  @redis.zrem("current_entities", entity.name)
649
687
  end
650
688
  end
651
689
 
690
+ def enable!
691
+ timestamp = Time.now.to_i
692
+ entity_name = entity.name
693
+ redis.zadd("current_checks:#{entity_name}", timestamp, check)
694
+ redis.zadd('current_entities', timestamp, entity_name)
695
+ end
696
+
652
697
  def enabled?
653
698
  !!@redis.zscore("current_checks:#{entity.name}", check)
654
699
  end
@@ -855,13 +900,24 @@ module Flapjack
855
900
  }.compact
856
901
  end
857
902
 
858
- def tags
859
- entity, check = @key.split(":", 2)
860
- ta = Flapjack::Data::TagSet.new([])
861
- ta += entity.split('.', 2).map {|x| x.downcase}
862
- ta += check.split(' ').map {|x| x.downcase}
903
+ # override default, which would be 'entity_check_tag'
904
+ def tag_prefix
905
+ 'check_tag'
906
+ end
907
+
908
+ def tags_with_entity_and_check_name
909
+ tags_without_entity_and_check_name
910
+
911
+ # ensure that returned tags include split entity and check words
912
+ @tags += @entity.name.split('.', 2).map {|x| x.downcase} +
913
+ @check.split(' ').map {|x| x.downcase}
914
+
915
+ @tags
863
916
  end
864
917
 
918
+ alias_method :tags_without_entity_and_check_name, :tags
919
+ alias_method :tags, :tags_with_entity_and_check_name
920
+
865
921
  def ack_hash
866
922
  @ack_hash ||= @redis.hget('check_hashes_by_id', @key)
867
923
  if @ack_hash.nil?
@@ -905,14 +961,27 @@ module Flapjack
905
961
  purge_stamps.length
906
962
  end
907
963
 
964
+ def self.enabled_for(check_ids, opts = {})
965
+ raise "Redis connection not set" unless redis = opts[:redis]
966
+
967
+ check_ids.inject([]) do |memo, check_id|
968
+ entity_name, check_name = check_id.split(':', 2)
969
+ memo << check_id unless redis.zscore("current_checks:#{entity_name}", check_name).nil?
970
+ memo
971
+ end
972
+ end
973
+
908
974
  def to_jsonapi(opts = {})
909
- {
975
+ json_data = {
976
+ "id" => @key,
910
977
  "name" => @check,
911
978
  "entity_name" => @entity.name,
979
+ "enabled" => opts[:enabled].is_a?(TrueClass),
912
980
  "links" => {
913
981
  :entities => opts[:entity_ids] || [],
914
982
  }
915
- }.to_json
983
+ }
984
+ Flapjack.dump_json(json_data)
916
985
  end
917
986
 
918
987
  private
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oj'
4
- require 'flapjack/data/tag_set'
3
+ require 'flapjack'
5
4
 
6
5
  module Flapjack
7
6
  module Data
@@ -120,7 +119,7 @@ module Flapjack
120
119
 
121
120
  def self.parse_and_validate(raw, opts = {})
122
121
  errors = []
123
- if parsed = ::Oj.load(raw)
122
+ if parsed = ::Flapjack.load_json(raw)
124
123
  if parsed.is_a?(Hash)
125
124
  errors = validation_errors_for_hash(parsed, opts)
126
125
  else
@@ -177,7 +176,7 @@ module Flapjack
177
176
  raise "Redis connection not set" unless redis = opts[:redis]
178
177
 
179
178
  evt['time'] = Time.now.to_i if evt['time'].nil?
180
- redis.lpush('events', ::Oj.dump(evt))
179
+ redis.lpush('events', ::Flapjack.dump_json(evt))
181
180
  end
182
181
 
183
182
  # Provide a count of the number of events on the queue to be processed.
@@ -220,7 +219,7 @@ module Flapjack
220
219
  # perfdata is optional. set it to nil if it only contains whitespace
221
220
  @perfdata = (@perfdata.is_a?(String) && ! @perfdata.strip.empty?) ? @perfdata.strip : nil
222
221
  if attrs['tags']
223
- @tags = Flapjack::Data::TagSet.new
222
+ @tags = Set.new
224
223
  attrs['tags'].each {|tag| @tags.add(tag)}
225
224
  end
226
225
  end
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oj'
4
-
5
3
  require 'flapjack/data/contact'
6
4
  require 'flapjack/data/event'
7
5
  require 'flapjack/data/message'
@@ -66,7 +64,7 @@ module Flapjack
66
64
  'severity' => opts[:severity],
67
65
  'tags' => tag_data }
68
66
 
69
- redis.rpush(queue, Oj.dump(notif))
67
+ redis.rpush(queue, Flapjack.dump_json(notif))
70
68
  end
71
69
 
72
70
  def self.next(queue, opts = {})
@@ -82,7 +80,7 @@ module Flapjack
82
80
  return unless raw
83
81
  end
84
82
  begin
85
- parsed = ::Oj.load( raw )
83
+ parsed = ::Flapjack.load_json( raw )
86
84
  rescue Oj::Error => e
87
85
  if options[:logger]
88
86
  options[:logger].warn("Error deserialising notification json: #{e}, raw json: #{raw.inspect}")
@@ -133,7 +131,7 @@ module Flapjack
133
131
  media = contact.media
134
132
 
135
133
  logger.debug "Notification#messages: creating messages for contact: #{contact_id} " +
136
- "event_id: \"#{@event_id}\" state: #{@state} event_tags: #{@tags.to_json} media: #{media.inspect}"
134
+ "event_id: \"#{@event_id}\" state: #{@state} event_tags: #{Flapjack.dump_json(@tags)} media: #{media.inspect}"
137
135
  rlen = rules.length
138
136
  logger.debug "found #{rlen} rule#{(rlen == 1) ? '' : 's'} for contact #{contact_id}"
139
137
 
@@ -144,7 +142,7 @@ module Flapjack
144
142
  # for time, entity and tags
145
143
  matchers = rules.select do |rule|
146
144
  logger.debug("considering rule with entities: #{rule.entities}, entities regex: #{rule.regex_entities},
147
- tags: #{rule.tags.to_json} and regex tags: #{rule.regex_tags.to_json}")
145
+ tags: #{Flapjack.dump_json(rule.tags)} and regex tags: #{Flapjack.dump_json(rule.regex_tags)}")
148
146
  rule_has_tags = rule.tags ? (rule.tags.length > 0) : false
149
147
  rule_has_regex_tags = rule.regex_tags ? (rule.regex_tags.length > 0) : false
150
148
  rule_has_entities = rule.entities ? (rule.entities.length > 0) : false
@@ -162,7 +160,7 @@ module Flapjack
162
160
 
163
161
  logger.debug "#{matchers.length} matchers remain for this contact after time, entity and tags are matched:"
164
162
  matchers.each do |matcher|
165
- logger.debug " - #{matcher.to_json}"
163
+ logger.debug " - #{matcher.to_jsonapi}"
166
164
  end
167
165
 
168
166
  # delete any general matchers if there are more specific matchers left
@@ -175,7 +173,7 @@ module Flapjack
175
173
  if num_matchers != matchers.length
176
174
  logger.debug("removal of general matchers when entity specific matchers are present: number of matchers changed from #{num_matchers} to #{matchers.length} for contact id: #{contact_id}")
177
175
  matchers.each do |matcher|
178
- logger.debug " - #{matcher.to_json}"
176
+ logger.debug " - #{matcher.to_jsonapi}"
179
177
  end
180
178
  end
181
179
  end
@@ -185,7 +183,7 @@ module Flapjack
185
183
  if blackhole_matchers.length > 0
186
184
  logger.debug "dropping this media as #{blackhole_matchers.length} blackhole matchers are present:"
187
185
  blackhole_matchers.each {|bm|
188
- logger.debug " - #{bm.to_json}"
186
+ logger.debug " - #{bm.to_jsonapi}"
189
187
  }
190
188
  next
191
189
  else
@@ -264,7 +262,7 @@ module Flapjack
264
262
  @state_duration = opts['state_duration']
265
263
  @type = opts['type']
266
264
  @severity = opts['severity']
267
- @tags = opts['tags'].is_a?(Array) ? Flapjack::Data::TagSet.new(opts['tags']) : nil
265
+ @tags = opts['tags'].is_a?(Array) ? Set.new(opts['tags']) : nil
268
266
  end
269
267
 
270
268
  # # time restrictions match?
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'oj'
4
3
  require 'active_support/time'
5
4
  require 'ice_cube'
6
5
  require 'flapjack/utility'
7
- require 'flapjack/data/tag_set'
8
6
 
9
7
  module Flapjack
10
8
  module Data
@@ -108,20 +106,19 @@ module Flapjack
108
106
  nil
109
107
  end
110
108
 
111
- def to_json(*args)
112
- self.class.hashify(:id, :contact_id, :tags, :regex_tags, :entities, :regex_entities,
113
- :time_restrictions, :unknown_media, :warning_media, :critical_media,
114
- :unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k|
115
- [k, self.send(k)]
116
- }.to_json
117
- end
118
-
119
109
  def to_jsonapi(opts = {})
120
- self.class.hashify(:id, :tags, :regex_tags, :entities, :regex_entities,
110
+ json_data = self.class.hashify(:id, :tags, :regex_tags, :entities, :regex_entities,
121
111
  :time_restrictions, :unknown_media, :warning_media, :critical_media,
122
112
  :unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k|
123
- [k, self.send(k)]
124
- }.merge(:links => {:contacts => [self.contact_id]}).to_json
113
+ case k
114
+ when :tags, :regex_tags
115
+ [k.to_s, self.send(k).to_a.sort]
116
+ else
117
+ [k.to_s, self.send(k)]
118
+ end
119
+ }.merge('links' => {'contacts' => [self.contact_id]})
120
+
121
+ Flapjack.dump_json(json_data)
125
122
  end
126
123
 
127
124
  # entity names match?
@@ -203,10 +200,10 @@ module Flapjack
203
200
  rule_data[:warning_blackhole] = rule_data[:warning_blackhole] || false
204
201
  rule_data[:critical_blackhole] = rule_data[:critical_blackhole] || false
205
202
  if rule_data[:tags].is_a?(Array)
206
- rule_data[:tags] = Flapjack::Data::TagSet.new(rule_data[:tags])
203
+ rule_data[:tags] = Set.new(rule_data[:tags])
207
204
  end
208
205
  if rule_data[:regex_tags].is_a?(Array)
209
- rule_data[:regex_tags] = Flapjack::Data::TagSet.new(rule_data[:regex_tags])
206
+ rule_data[:regex_tags] = Set.new(rule_data[:regex_tags])
210
207
  end
211
208
  rule_data
212
209
  end
@@ -227,14 +224,14 @@ module Flapjack
227
224
  json_rule_data = {
228
225
  :id => rule_data[:id].to_s,
229
226
  :contact_id => rule_data[:contact_id].to_s,
230
- :entities => Oj.dump(rule_data[:entities]),
231
- :regex_entities => Oj.dump(rule_data[:regex_entities]),
232
- :tags => Oj.dump(tag_data),
233
- :regex_tags => Oj.dump(regex_tag_data),
234
- :time_restrictions => Oj.dump(rule_data[:time_restrictions], :mode => :compat),
235
- :unknown_media => Oj.dump(rule_data[:unknown_media]),
236
- :warning_media => Oj.dump(rule_data[:warning_media]),
237
- :critical_media => Oj.dump(rule_data[:critical_media]),
227
+ :entities => Flapjack.dump_json(rule_data[:entities]),
228
+ :regex_entities => Flapjack.dump_json(rule_data[:regex_entities]),
229
+ :tags => Flapjack.dump_json(tag_data),
230
+ :regex_tags => Flapjack.dump_json(regex_tag_data),
231
+ :time_restrictions => Flapjack.dump_json(rule_data[:time_restrictions]),
232
+ :unknown_media => Flapjack.dump_json(rule_data[:unknown_media]),
233
+ :warning_media => Flapjack.dump_json(rule_data[:warning_media]),
234
+ :critical_media => Flapjack.dump_json(rule_data[:critical_media]),
238
235
  :unknown_blackhole => rule_data[:unknown_blackhole],
239
236
  :warning_blackhole => rule_data[:warning_blackhole],
240
237
  :critical_blackhole => rule_data[:critical_blackhole],
@@ -323,13 +320,13 @@ module Flapjack
323
320
 
324
321
  proc {|d| !d.has_key?(:tags) ||
325
322
  ( d[:tags].nil? ||
326
- d[:tags].is_a?(Flapjack::Data::TagSet) &&
323
+ d[:tags].is_a?(Set) &&
327
324
  d[:tags].all? {|et| et.is_a?(String)} ) } =>
328
325
  "tags must be a tag_set of strings",
329
326
 
330
327
  proc {|d| !d.has_key?(:regex_tags) ||
331
328
  ( d[:regex_tags].nil? ||
332
- d[:regex_tags].is_a?(Flapjack::Data::TagSet) &&
329
+ d[:regex_tags].is_a?(Set) &&
333
330
  d[:regex_tags].all? {|et| et.is_a?(String)} ) } =>
334
331
  "regex_tags must be a tag_set of strings",
335
332
 
@@ -400,16 +397,16 @@ module Flapjack
400
397
  rule_data = @redis.hgetall("notification_rule:#{@id}")
401
398
 
402
399
  @contact_id = rule_data['contact_id']
403
- tags = Oj.load(rule_data['tags'] || '')
404
- @tags = tags ? Flapjack::Data::TagSet.new(tags) : nil
405
- regex_tags = Oj.load(rule_data['regex_tags'] || '')
406
- @regex_tags = regex_tags ? Flapjack::Data::TagSet.new(regex_tags) : nil
407
- @entities = Oj.load(rule_data['entities'] || '')
408
- @regex_entities = Oj.load(rule_data['regex_entities'] || '')
409
- @time_restrictions = Oj.load(rule_data['time_restrictions'] || '')
410
- @unknown_media = Oj.load(rule_data['unknown_media'] || '')
411
- @warning_media = Oj.load(rule_data['warning_media'] || '')
412
- @critical_media = Oj.load(rule_data['critical_media'] || '')
400
+ tags = Flapjack.load_json(rule_data['tags'] || '')
401
+ @tags = tags ? Set.new(tags) : nil
402
+ regex_tags = Flapjack.load_json(rule_data['regex_tags'] || '')
403
+ @regex_tags = regex_tags ? Set.new(regex_tags) : nil
404
+ @entities = Flapjack.load_json(rule_data['entities'] || '')
405
+ @regex_entities = Flapjack.load_json(rule_data['regex_entities'] || '')
406
+ @time_restrictions = Flapjack.load_json(rule_data['time_restrictions'] || '')
407
+ @unknown_media = Flapjack.load_json(rule_data['unknown_media'] || '')
408
+ @warning_media = Flapjack.load_json(rule_data['warning_media'] || '')
409
+ @critical_media = Flapjack.load_json(rule_data['critical_media'] || '')
413
410
  @unknown_blackhole = ((rule_data['unknown_blackhole'] || 'false').downcase == 'true')
414
411
  @warning_blackhole = ((rule_data['warning_blackhole'] || 'false').downcase == 'true')
415
412
  @critical_blackhole = ((rule_data['critical_blackhole'] || 'false').downcase == 'true')
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # mixed in to some of the Flapjack data classes
4
+
5
+ module Flapjack
6
+
7
+ module Tagged
8
+
9
+ def tag_prefix
10
+ self.class.name.split('::').last.downcase + '_tag'
11
+ end
12
+
13
+ def known_key
14
+ "known_tags:#{tag_prefix}"
15
+ end
16
+
17
+ # return the set of tags for this object
18
+ def tags
19
+ return @tags unless @tags.nil?
20
+ @tags ||= Set.new( @redis.smembers(known_key).inject([]) {|memo, t|
21
+ tag_key = "#{tag_prefix}:#{t}"
22
+ memo << t if @redis.sismember(tag_key, @id.to_s)
23
+ memo
24
+ })
25
+ end
26
+
27
+ # adds tags to this object
28
+ def add_tags(*enum)
29
+ enum.each do |t|
30
+ @redis.sadd(known_key, t)
31
+ @redis.sadd("#{tag_prefix}:#{t}", @id)
32
+ tags.add(t)
33
+ end
34
+ end
35
+
36
+ # removes tags from this object
37
+ def delete_tags(*enum)
38
+ enum.each do |t|
39
+ tag_key = "#{tag_prefix}:#{t}"
40
+ @redis.srem(tag_key, @id)
41
+ tags.delete(t)
42
+ @redis.srem(known_key, t) if (@redis.scard(tag_key) == 0)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -6,7 +6,6 @@ require 'socket'
6
6
 
7
7
  require 'blather/client/client'
8
8
  require 'chronic_duration'
9
- require 'oj'
10
9
 
11
10
  require 'flapjack/data/entity_check'
12
11
  require 'flapjack/redis_pool'
@@ -69,7 +68,7 @@ module Flapjack
69
68
  redis_uri = @redis_config[:path] ||
70
69
  "redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
71
70
  shutdown_redis = EM::Hiredis.connect(redis_uri)
72
- shutdown_redis.rpush(@config['queue'], Oj.dump('notification_type' => 'shutdown'))
71
+ shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
73
72
  end
74
73
 
75
74
  def setup
@@ -398,7 +397,7 @@ module Flapjack
398
397
  when number_found == 0
399
398
  msg = "found no entities matching /#{entity_pattern}/"
400
399
  when number_found >= 1
401
- failing_list = Flapjack::Data::EntityCheck.find_current_failing_by_entity(:redis => @redis)
400
+ failing_list = Flapjack::Data::EntityCheck.find_current_names_failing_by_entity(:redis => @redis)
402
401
  entities = failing_list.select {|k,v| v.count >= 1 && entity_list.include?(k) }
403
402
  if entities.length >= 1
404
403
  entities.each_pair do |entity,check_list|
@@ -474,7 +473,7 @@ module Flapjack
474
473
  msg = "found no entities matching /#{entity_pattern}/"
475
474
  when number_found >= 1
476
475
 
477
- failing_list = Flapjack::Data::EntityCheck.find_current_failing_by_entity(:redis => @redis)
476
+ failing_list = Flapjack::Data::EntityCheck.find_current_names_failing_by_entity(:redis => @redis)
478
477
 
479
478
  my_failing_checks = Hash[failing_list.map do |k,v|
480
479
  if entity_list.include?(k)
@@ -695,7 +694,7 @@ module Flapjack
695
694
  events[queue] = @redis.blpop(queue, 0)
696
695
  event_json = events[queue][1]
697
696
  begin
698
- event = Oj.load(event_json)
697
+ event = Flapjack.load_json(event_json)
699
698
 
700
699
  @logger.debug('jabber notification event received: ' + event.inspect)
701
700
 
@@ -43,34 +43,72 @@ module Flapjack
43
43
  Flapjack::Data::EntityCheck.for_event_id(req_check, :logger => logger, :redis => redis)
44
44
  end
45
45
  else
46
- Flapjack::Data::EntityCheck.find_current(:redis => redis)
46
+ Flapjack::Data::EntityCheck.all(:logger => logger, :redis => redis)
47
47
  end
48
48
  checks.compact!
49
49
 
50
50
  if requested_checks && checks.empty?
51
- raise Flapjack::Gateways::JSONAPI::ChecksNotFound.new(requested_checks)
51
+ raise Flapjack::Gateways::JSONAPI::EntityChecksNotFound.new(requested_checks)
52
52
  end
53
53
 
54
+ check_ids = checks.collect {|c| "#{c.entity.name}:#{c.check}" }
55
+
56
+ enabled_ids = Flapjack::Data::EntityCheck.enabled_for(check_ids, :redis => redis)
57
+
54
58
  linked_entity_ids = checks.empty? ? [] : checks.inject({}) do |memo, check|
55
- memo[check.key] = check.entity.id
59
+ entity = check.entity
60
+ memo["#{entity.name}:#{check.check}"] = [entity.id]
56
61
  memo
57
62
  end
58
63
 
59
64
  checks_json = checks.collect {|check|
60
- check.to_jsonapi(:entity_ids => linked_entity_ids[check.key])
65
+ check_name = "#{check.entity.name}:#{check.check}"
66
+ check.to_jsonapi(:enabled => enabled_ids.include?(check_name),
67
+ :entity_ids => linked_entity_ids[check_name])
61
68
  }.join(",")
62
69
 
63
70
  '{"checks":[' + checks_json + ']}'
64
71
  end
65
72
 
73
+ app.post '/checks' do
74
+ checks = wrapped_params('checks')
75
+
76
+ check_names = checks.collect{|check_data|
77
+ check = Flapjack::Data::EntityCheck.add(check_data, :redis => redis)
78
+ "#{check.entity.name}:#{check.check}"
79
+ }
80
+
81
+ response.headers['Location'] = "#{request.base_url}/checks/#{check_names.join(',')}"
82
+ status 201
83
+ Flapjack.dump_json(check_names)
84
+ end
85
+
66
86
  app.patch %r{^/checks/(.+)$} do
67
87
  checks_for_check_names(params[:captures][0].split(',')).each do |check|
68
88
  apply_json_patch('checks') do |op, property, linked, value|
69
89
  case op
70
90
  when 'replace'
71
- if ['enabled'].include?(property)
72
- # explicitly checking for false being passed in
73
- check.disable! if value.is_a?(FalseClass)
91
+ case property
92
+ when 'enabled'
93
+ # explicitly checking for true/false being passed in
94
+ case value
95
+ when TrueClass
96
+ check.enable!
97
+ when FalseClass
98
+ check.disable!
99
+ end
100
+ end
101
+ when 'add'
102
+ case linked
103
+ when 'tags'
104
+ value.respond_to?(:each) ? check.add_tags(*value) :
105
+ check.add_tags(value)
106
+ end
107
+ when 'remove'
108
+ case linked
109
+ when 'tags'
110
+ value.respond_to?(:each) ? check.delete_tags(*value) :
111
+ check.delete_tags(value)
74
112
  end
75
113
  end
76
114
  end
@@ -36,7 +36,7 @@ module Flapjack
36
36
  def outage(start_time, end_time, options = {})
37
37
  # hist_states is an array of hashes, with [state, timestamp, summary] keys
38
38
  hist_states = @entity_check.historical_states(start_time, end_time)
39
- return hist_states if hist_states.empty?
39
+ return {:outages => []} if hist_states.empty?
40
40
 
41
41
  initial = @entity_check.historical_state_before(hist_states.first[:timestamp])
42
42
  hist_states.unshift(initial) if initial
@@ -45,7 +45,7 @@ module Flapjack
45
45
  missing_ids = contacts_by_id.select {|k, v| v.nil? }.keys
46
46
  unless missing_ids.empty?
47
47
  semaphore.release
48
- halt(404, "Contacts with ids #{missing_ids.join(', ')} were not found")
48
+ raise Flapjack::Gateways::JSONAPI::ContactsNotFound.new(missing_ids)
49
49
  end
50
50
 
51
51
  block.call(contacts_by_id.select {|k, v| !v.nil? }.values)
@@ -93,7 +93,7 @@ module Flapjack
93
93
 
94
94
  response.headers['Location'] = "#{base_url}/contacts/#{contact_ids.join(',')}"
95
95
  status 201
96
- contact_ids.to_json
96
+ Flapjack.dump_json(contact_ids)
97
97
  end
98
98
 
99
99
  # Returns all (/contacts) or some (/contacts/1,2,3) or one (/contacts/2) contact(s)
@@ -144,6 +144,9 @@ 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)
147
150
  # when 'media' # not supported yet due to id brokenness
148
151
  end
149
152
  when 'remove'
@@ -156,6 +159,9 @@ module Flapjack
156
159
  unless notification_rule.nil?
157
160
  contact.delete_notification_rule(notification_rule)
158
161
  end
162
+ when 'tags'
163
+ value.respond_to?(:each) ? contact.delete_tags(*value) :
164
+ contact.delete_tags(value)
159
165
  # when 'media' # not supported yet due to id brokenness
160
166
  end
161
167
  end