flapjack 0.8.8 → 0.8.9
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGELOG.md +5 -0
- data/features/notification_rules.feature +7 -6
- data/lib/flapjack/data/contact.rb +1 -0
- data/lib/flapjack/data/notification.rb +8 -6
- data/lib/flapjack/data/notification_rule.rb +31 -5
- data/lib/flapjack/gateways/api/contact_methods.rb +2 -2
- data/lib/flapjack/gateways/jabber.rb +172 -4
- data/lib/flapjack/gateways/web/views/contact.html.erb +2 -0
- data/lib/flapjack/notifier.rb +9 -12
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/data/notification_rule_spec.rb +29 -0
- data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +1 -0
- data/spec/lib/flapjack/gateways/jabber_spec.rb +4 -0
- data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac75cd5f3cf88878ef41b54de2a1d4ca3007387e
|
4
|
+
data.tar.gz: 941ba78adea49cfa2025c5b848d7debf070d37b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d55e5a48109d8eb7733dd45e854ac590b2f069fd6011aeb2017bbe0fbad66feacd41a460c5945bf42953f4afd3486f0be82c5155a3fce2f3ecb3d661c05919b8
|
7
|
+
data.tar.gz: 20666c66b76ef55c0105c1929a86073979280e11b91b31ac9498720bbb751dac3bd72fac3dba1bba747673275bb9bde1cb0f2b417f00f8a4eeed5348ac202505
|
data/.travis.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- "1.9.3"
|
4
|
-
- "2.0
|
5
|
-
- "2.1
|
4
|
+
- "2.0"
|
5
|
+
- "2.1"
|
6
6
|
env:
|
7
7
|
- ENTITIES=10 INTERVAL=120
|
8
8
|
gemfile:
|
@@ -14,4 +14,4 @@ before_script:
|
|
14
14
|
before_install:
|
15
15
|
- git submodule update --init --recursive
|
16
16
|
- gem install bundler
|
17
|
-
script: bundle exec rspec spec && bundle exec cucumber features
|
17
|
+
script: bundle exec rspec spec && bundle exec cucumber features
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## Flapjack Changelog
|
2
2
|
|
3
|
+
# 0.8.9 - 2014-04-21
|
4
|
+
- Feature: Support arbitrary gateways in notifier, queue names from config gh-456 (@auxesis)
|
5
|
+
- Feature: Add chat bot features (ack by regex, query status by regex) gh-459 (@someword)
|
6
|
+
- Feature: Add regex tags to notification rules gh-461 (@jswoods)
|
7
|
+
|
3
8
|
# 0.8.8 - 2014-03-20
|
4
9
|
- Feature: Be able to disable automatic sched maint by setting duration to zero gh-457, gh-458 (@portertech)
|
5
10
|
- Bug: Make bin/flapjack-populator explicitly whinge about `-f` instead of dying gh-455 (@damncabbage)
|
@@ -18,6 +18,7 @@ Feature: Notification rules on a per contact basis
|
|
18
18
|
| 3 | baz | c1,c3 |
|
19
19
|
| 4 | buf | c1,c2,c3 |
|
20
20
|
| 5 | foo-app-01.xyz | c4,c6 |
|
21
|
+
| 6 | blakes7 | c2 |
|
21
22
|
|
22
23
|
And user c1 has the following notification intervals:
|
23
24
|
| email | sms |
|
@@ -43,11 +44,11 @@ Feature: Notification rules on a per contact basis
|
|
43
44
|
| baz | | email | sms,email | | | |
|
44
45
|
|
45
46
|
And user c2 has the following notification rules:
|
46
|
-
| entities
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| bar
|
50
|
-
| bar
|
47
|
+
| entities | tags | warning_media | critical_media | warning_blackhole | critical_blackhole |
|
48
|
+
| | | email | email | | |
|
49
|
+
| | | sms | sms | | |
|
50
|
+
| bar,blakes7 | | email | email,sms | | |
|
51
|
+
| bar,blakes7 | wags | | | true | true |
|
51
52
|
|
52
53
|
And user c3 has the following notification rules:
|
53
54
|
| entities | warning_media | critical_media | warning_blackhole | critical_blackhole |
|
@@ -188,7 +189,7 @@ Feature: Notification rules on a per contact basis
|
|
188
189
|
|
189
190
|
@blackhole @time
|
190
191
|
Scenario: Drop alerts matching a blackhole rule by tags
|
191
|
-
Given the check is check 'wags the dog' on entity '
|
192
|
+
Given the check is check 'wags the dog' on entity 'blakes7'
|
192
193
|
And the check is in an ok state
|
193
194
|
When a warning event is received
|
194
195
|
And 1 minute passes
|
@@ -247,6 +247,7 @@ module Flapjack
|
|
247
247
|
rule = self.add_notification_rule({
|
248
248
|
:entities => [],
|
249
249
|
:tags => Flapjack::Data::TagSet.new([]),
|
250
|
+
:regex_tags => Flapjack::Data::TagSet.new([]),
|
250
251
|
:time_restrictions => [],
|
251
252
|
:warning_media => ALL_MEDIA,
|
252
253
|
:critical_media => ALL_MEDIA,
|
@@ -143,14 +143,16 @@ module Flapjack
|
|
143
143
|
# matchers are rules of the contact that have matched the current event
|
144
144
|
# for time, entity and tags
|
145
145
|
matchers = rules.select do |rule|
|
146
|
-
logger.debug("considering rule with entities: #{rule.entities} and tags: #{rule.
|
147
|
-
rule_has_tags
|
148
|
-
|
146
|
+
logger.debug("considering rule with entities: #{rule.entities}, tags: #{rule.tags.to_json} and regex tags: #{rule.regex_tags.to_json}")
|
147
|
+
rule_has_tags = rule.tags ? (rule.tags.length > 0) : false
|
148
|
+
rule_has_regex_tags = rule.regex_tags ? (rule.regex_tags.length > 0) : false
|
149
|
+
rule_has_entities = rule.entities ? (rule.entities.length > 0) : false
|
149
150
|
|
150
|
-
matches_tags
|
151
|
-
|
151
|
+
matches_tags = rule_has_tags ? rule.match_tags?(@tags) : true
|
152
|
+
matches_regex_tags = rule_has_regex_tags ? rule.match_regex_tags?(@tags) : true
|
153
|
+
matches_entity = rule_has_entities ? rule.match_entity?(@event_id) : true
|
152
154
|
|
153
|
-
((matches_entity && matches_tags) || ! rule.is_specific?) &&
|
155
|
+
((matches_entity && matches_tags && matches_regex_tags) || ! rule.is_specific?) &&
|
154
156
|
rule_occurring_now?(rule, :contact => contact, :default_timezone => default_timezone)
|
155
157
|
end
|
156
158
|
|
@@ -12,8 +12,8 @@ module Flapjack
|
|
12
12
|
|
13
13
|
extend Flapjack::Utility
|
14
14
|
|
15
|
-
attr_accessor :id, :contact_id, :entities, :tags, :
|
16
|
-
:unknown_media, :warning_media, :critical_media,
|
15
|
+
attr_accessor :id, :contact_id, :entities, :tags, :regex_tags,
|
16
|
+
:time_restrictions, :unknown_media, :warning_media, :critical_media,
|
17
17
|
:unknown_blackhole, :warning_blackhole, :critical_blackhole
|
18
18
|
|
19
19
|
def self.exists_with_id?(rule_id, options = {})
|
@@ -74,7 +74,7 @@ module Flapjack
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def to_json(*args)
|
77
|
-
self.class.hashify(:id, :contact_id, :tags, :entities,
|
77
|
+
self.class.hashify(:id, :contact_id, :tags, :regex_tags, :entities,
|
78
78
|
:time_restrictions, :unknown_media, :warning_media, :critical_media,
|
79
79
|
:unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k|
|
80
80
|
[k, self.send(k)]
|
@@ -93,6 +93,18 @@ module Flapjack
|
|
93
93
|
@tags.subset?(event_tags)
|
94
94
|
end
|
95
95
|
|
96
|
+
# regex_tags match?
|
97
|
+
def match_regex_tags?(event_tags)
|
98
|
+
return false unless @regex_tags && @regex_tags.length > 0
|
99
|
+
matches = 0
|
100
|
+
event_tags.each do |event_tag|
|
101
|
+
@regex_tags.each do |regex_tag|
|
102
|
+
matches += 1 if /#{regex_tag}/ === event_tag
|
103
|
+
end
|
104
|
+
end
|
105
|
+
matches >= @regex_tags.length
|
106
|
+
end
|
107
|
+
|
96
108
|
def blackhole?(severity)
|
97
109
|
('unknown'.eql?(severity.downcase) && @unknown_blackhole) ||
|
98
110
|
('warning'.eql?(severity.downcase) && @warning_blackhole) ||
|
@@ -112,7 +124,8 @@ module Flapjack
|
|
112
124
|
|
113
125
|
def is_specific?
|
114
126
|
(!@entities.nil? && !@entities.empty?) ||
|
115
|
-
(!@tags.nil? && !@tags.empty?)
|
127
|
+
(!@tags.nil? && !@tags.empty?) ||
|
128
|
+
(!@regex_tags.nil? && !@regex_tags.empty?)
|
116
129
|
end
|
117
130
|
|
118
131
|
private
|
@@ -137,6 +150,9 @@ module Flapjack
|
|
137
150
|
if rule_data[:tags].is_a?(Array)
|
138
151
|
rule_data[:tags] = Flapjack::Data::TagSet.new(rule_data[:tags])
|
139
152
|
end
|
153
|
+
if rule_data[:regex_tags].is_a?(Array)
|
154
|
+
rule_data[:regex_tags] = Flapjack::Data::TagSet.new(rule_data[:regex_tags])
|
155
|
+
end
|
140
156
|
rule_data
|
141
157
|
end
|
142
158
|
|
@@ -150,12 +166,14 @@ module Flapjack
|
|
150
166
|
return errors unless errors.nil? || errors.empty?
|
151
167
|
|
152
168
|
# whitelisting fields, rather than passing through submitted data directly
|
153
|
-
tag_data
|
169
|
+
tag_data = rule_data[:tags].is_a?(Set) ? rule_data[:tags].to_a : nil
|
170
|
+
regex_tag_data = rule_data[:regex_tags].is_a?(Set) ? rule_data[:regex_tags].to_a : nil
|
154
171
|
json_rule_data = {
|
155
172
|
:id => rule_data[:id].to_s,
|
156
173
|
:contact_id => rule_data[:contact_id].to_s,
|
157
174
|
:entities => Oj.dump(rule_data[:entities]),
|
158
175
|
:tags => Oj.dump(tag_data),
|
176
|
+
:regex_tags => Oj.dump(regex_tag_data),
|
159
177
|
:time_restrictions => Oj.dump(rule_data[:time_restrictions], :mode => :compat),
|
160
178
|
:unknown_media => Oj.dump(rule_data[:unknown_media]),
|
161
179
|
:warning_media => Oj.dump(rule_data[:warning_media]),
|
@@ -250,6 +268,12 @@ module Flapjack
|
|
250
268
|
d[:tags].all? {|et| et.is_a?(String)} ) } =>
|
251
269
|
"tags must be a tag_set of strings",
|
252
270
|
|
271
|
+
proc {|d| !d.has_key?(:regex_tags) ||
|
272
|
+
( d[:regex_tags].nil? ||
|
273
|
+
d[:regex_tags].is_a?(Flapjack::Data::TagSet) &&
|
274
|
+
d[:regex_tags].all? {|et| et.is_a?(String)} ) } =>
|
275
|
+
"regex_tags must be a tag_set of strings",
|
276
|
+
|
253
277
|
proc {|d| !d.has_key?(:time_restrictions) ||
|
254
278
|
( d[:time_restrictions].nil? ||
|
255
279
|
d[:time_restrictions].all? {|tr|
|
@@ -318,6 +342,8 @@ module Flapjack
|
|
318
342
|
@contact_id = rule_data['contact_id']
|
319
343
|
tags = Oj.load(rule_data['tags'] || '')
|
320
344
|
@tags = tags ? Flapjack::Data::TagSet.new(tags) : nil
|
345
|
+
regex_tags = Oj.load(rule_data['regex_tags'] || '')
|
346
|
+
@regex_tags = regex_tags ? Flapjack::Data::TagSet.new(regex_tags) : nil
|
321
347
|
@entities = Oj.load(rule_data['entities'] || '')
|
322
348
|
@time_restrictions = Oj.load(rule_data['time_restrictions'] || '')
|
323
349
|
@unknown_media = Oj.load(rule_data['unknown_media'] || '')
|
@@ -144,7 +144,7 @@ module Flapjack
|
|
144
144
|
|
145
145
|
contact = find_contact(params[:contact_id])
|
146
146
|
|
147
|
-
rule_data = hashify(:entities, :tags,
|
147
|
+
rule_data = hashify(:entities, :tags, :regex_tags,
|
148
148
|
:unknown_media, :warning_media, :critical_media, :time_restrictions,
|
149
149
|
:unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k| [k, params[k]]}
|
150
150
|
|
@@ -167,7 +167,7 @@ module Flapjack
|
|
167
167
|
rule = find_rule(params[:id])
|
168
168
|
contact = find_contact(rule.contact_id)
|
169
169
|
|
170
|
-
rule_data = hashify(:entities, :tags,
|
170
|
+
rule_data = hashify(:entities, :tags, :regex_tags,
|
171
171
|
:unknown_media, :warning_media, :critical_media, :time_restrictions,
|
172
172
|
:unknown_blackhole, :warning_blackhole, :critical_blackhole) {|k| [k, params[k]]}
|
173
173
|
|
@@ -160,7 +160,7 @@ module Flapjack
|
|
160
160
|
out
|
161
161
|
end
|
162
162
|
|
163
|
-
def interpreter(command_raw)
|
163
|
+
def interpreter(command_raw,from)
|
164
164
|
msg = nil
|
165
165
|
action = nil
|
166
166
|
entity_check = nil
|
@@ -224,6 +224,10 @@ module Flapjack
|
|
224
224
|
when /^help$/i
|
225
225
|
msg = "commands: \n" +
|
226
226
|
" ACKID <id> <comment> [duration: <time spec>]\n" +
|
227
|
+
" ack entities /pattern/ <comment> [duration: <time spec>]\n" +
|
228
|
+
" status entities /pattern/\n" +
|
229
|
+
" ack checks /check_pattern/ on /entity_pattern/ <comment> [duration: <time spec>]\n" +
|
230
|
+
" status checks /check_pattern/ on /entity_pattern/\n" +
|
227
231
|
" find entities matching /pattern/\n" +
|
228
232
|
" find checks[ matching /pattern/] on (<entity>|entities matching /pattern/)\n" +
|
229
233
|
" test notifications for <entity>[:<check>]\n" +
|
@@ -358,6 +362,168 @@ module Flapjack
|
|
358
362
|
msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
|
359
363
|
end
|
360
364
|
|
365
|
+
when /^(?:ack )?entities\s+\/(.+)\/(?:\s*(.*?)(?:\s*duration:.*?(\w+.*))?)$/i
|
366
|
+
entity_pattern = $1.chomp.strip
|
367
|
+
comment = $2 ? $2.chomp.strip : nil
|
368
|
+
duration_str = $3 ? $3.chomp.strip : '1 hour'
|
369
|
+
duration = ChronicDuration.parse(duration_str)
|
370
|
+
entity_list = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
|
371
|
+
|
372
|
+
if comment.nil? || (comment.length == 0)
|
373
|
+
comment = "#{from}: Set via chatbot"
|
374
|
+
else
|
375
|
+
comment = "#{from}: #{comment}"
|
376
|
+
end
|
377
|
+
|
378
|
+
if entity_list
|
379
|
+
number_found = entity_list.length
|
380
|
+
case
|
381
|
+
when number_found == 0
|
382
|
+
msg = "found no entities matching /#{pattern}/"
|
383
|
+
when number_found >= 1
|
384
|
+
failing_list = Flapjack::Data::EntityCheck.find_all_failing_by_entity(:redis => @redis)
|
385
|
+
entities = failing_list.select {|k,v| v.count >= 1 && entity_list.include?(k) }
|
386
|
+
if entities.length >= 1
|
387
|
+
entities.each_pair do |entity,check_list|
|
388
|
+
check_list.each do |check|
|
389
|
+
Flapjack::Data::Event.create_acknowledgement(
|
390
|
+
entity, check,
|
391
|
+
:summary => comment,
|
392
|
+
:duration => duration,
|
393
|
+
:redis => @redis
|
394
|
+
)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
msg = failing_list.inject("Ack list:\n") {|memo,kv|
|
398
|
+
kv[1].each {|e| memo << "#{kv[0]}:#{e}\n" }
|
399
|
+
memo
|
400
|
+
}
|
401
|
+
else
|
402
|
+
msg = "found no matching entities with failing checks"
|
403
|
+
end
|
404
|
+
else
|
405
|
+
msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
when /^(?:status )?entities\s+\/(.+)\/.*$/im
|
410
|
+
entity_pattern = $1 ? $1.chomp.strip : nil
|
411
|
+
entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
|
412
|
+
|
413
|
+
if entity_names
|
414
|
+
number_found = entity_names.length
|
415
|
+
case
|
416
|
+
when number_found == 0
|
417
|
+
msg = "found no entities matching /#{pattern}/"
|
418
|
+
when number_found >= 1
|
419
|
+
entities = entity_names.map {|name|
|
420
|
+
Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
|
421
|
+
}.compact.inject({}) {|memo, entity|
|
422
|
+
memo[entity.name] = entity.check_list.map {|check_name|
|
423
|
+
ec = Flapjack::Data::EntityCheck.for_entity(entity, check_name, :redis => @redis)
|
424
|
+
"#{check_name}: #{ec.state}"
|
425
|
+
}
|
426
|
+
memo
|
427
|
+
}
|
428
|
+
msg = entities.inject("Status list:\n") {|memo,kv|
|
429
|
+
kv[1].each {|e| memo << "#{kv[0]}:#{e}\n"}
|
430
|
+
memo
|
431
|
+
}
|
432
|
+
else
|
433
|
+
msg = "found no matching entities with failing checks"
|
434
|
+
end
|
435
|
+
else
|
436
|
+
msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
|
437
|
+
end
|
438
|
+
|
439
|
+
when /^(?:ack )?checks\s+\/(.+)\/\s+on\s+\/(.+)\/(?:\s*(.*?)(?:\s*duration:.*?(\w+.*))?)$/i
|
440
|
+
check_pattern = $1.chomp.strip
|
441
|
+
entity_pattern = $2.chomp.strip
|
442
|
+
comment = $3 ? $3.chomp.strip : nil
|
443
|
+
duration_str = $4 ? $4.chomp.strip : '1 hour'
|
444
|
+
duration = ChronicDuration.parse(duration_str)
|
445
|
+
entity_list = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
|
446
|
+
|
447
|
+
if comment.nil? || (comment.length == 0)
|
448
|
+
comment = "#{from}: Set via chatbot"
|
449
|
+
else
|
450
|
+
comment = "#{from}: #{comment}"
|
451
|
+
end
|
452
|
+
|
453
|
+
if entity_list
|
454
|
+
number_found = entity_list.length
|
455
|
+
case
|
456
|
+
when number_found == 0
|
457
|
+
msg = "found no entities matching /#{entity_pattern}/"
|
458
|
+
when number_found >= 1
|
459
|
+
|
460
|
+
failing_list = Flapjack::Data::EntityCheck.find_all_failing_by_entity(:redis => @redis)
|
461
|
+
|
462
|
+
my_failing_checks = Hash[failing_list.map do |k,v|
|
463
|
+
if entity_list.include?(k)
|
464
|
+
[k, v.keep_if {|e| e =~ /#{check_pattern}/}].compact
|
465
|
+
end
|
466
|
+
end]
|
467
|
+
if my_failing_checks.delete_if {|k,v| v.empty? }.length >= 1
|
468
|
+
my_failing_checks.each_pair do |entity,check_list|
|
469
|
+
check_list.each do |check|
|
470
|
+
Flapjack::Data::Event.create_acknowledgement(
|
471
|
+
entity, check,
|
472
|
+
:summary => comment,
|
473
|
+
:duration => duration,
|
474
|
+
:redis => @redis
|
475
|
+
)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
msg = failing_list.inject("Ack list:\n") {|memo,kv|
|
479
|
+
kv[1].each {|e| memo << "#{kv[0]}:#{e}\n" }
|
480
|
+
memo
|
481
|
+
}
|
482
|
+
else
|
483
|
+
msg = "found no matching failing checks"
|
484
|
+
end
|
485
|
+
else
|
486
|
+
msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
when /^(?:status )checks\s+\/(.+?)\/(?:\s+on\s+)?(?:\/(.+)?\/)?/i
|
491
|
+
check_pattern = $1 ? $1.chomp.strip : nil
|
492
|
+
entity_pattern = $2 ? $2.chomp.strip : '.*'
|
493
|
+
entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
|
494
|
+
|
495
|
+
if entity_names
|
496
|
+
number_found = entity_names.length
|
497
|
+
case
|
498
|
+
when number_found == 0
|
499
|
+
msg = "found no entities matching /#{entity_pattern}/"
|
500
|
+
when number_found >= 1
|
501
|
+
entities = entity_names.map {|name|
|
502
|
+
Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
|
503
|
+
}.compact.inject({}) {|memo, entity|
|
504
|
+
memo[entity.name] = entity.check_list.map {|check_name|
|
505
|
+
if check_name =~ /#{check_pattern}/
|
506
|
+
ec = Flapjack::Data::EntityCheck.for_entity(entity, check_name, :redis => @redis)
|
507
|
+
"#{check_name}: #{ec.state}"
|
508
|
+
end
|
509
|
+
}.compact
|
510
|
+
memo
|
511
|
+
}
|
512
|
+
if entities.delete_if {|k,v| v.empty? }.length >= 1
|
513
|
+
msg = entities.inject("Status list:\n") {|memo,kv|
|
514
|
+
kv[1].each {|e| memo << "#{kv[0]}:#{e}\n" ; memo }
|
515
|
+
memo
|
516
|
+
}
|
517
|
+
else
|
518
|
+
msg = "found no matching checks"
|
519
|
+
end
|
520
|
+
else
|
521
|
+
msg = "found no matching checks"
|
522
|
+
end
|
523
|
+
else
|
524
|
+
msg = "that doesn't seem to be a valid pattern - /#{pattern}/"
|
525
|
+
end
|
526
|
+
|
361
527
|
when /^(.*)/
|
362
528
|
words = $1
|
363
529
|
msg = "what do you mean, '#{words}'? Type 'help' for a list of acceptable commands."
|
@@ -372,11 +538,13 @@ module Flapjack
|
|
372
538
|
@logger.debug("groupchat message received: #{stanza.inspect}")
|
373
539
|
|
374
540
|
if stanza.body =~ /^#{@config['alias']}:\s+(.*)/m
|
375
|
-
command
|
541
|
+
command = $1
|
376
542
|
end
|
377
543
|
|
544
|
+
from = stanza.from
|
545
|
+
|
378
546
|
begin
|
379
|
-
results = interpreter(command)
|
547
|
+
results = interpreter(command, from.resource.to_s)
|
380
548
|
msg = results[:msg]
|
381
549
|
action = results[:action]
|
382
550
|
rescue => e
|
@@ -387,7 +555,7 @@ module Flapjack
|
|
387
555
|
if msg || action
|
388
556
|
EventMachine::Synchrony.next_tick do
|
389
557
|
@logger.info("sending to group chat: #{msg}")
|
390
|
-
say(
|
558
|
+
say(from.stripped, msg, :groupchat)
|
391
559
|
action.call if action
|
392
560
|
end
|
393
561
|
end
|
@@ -103,6 +103,7 @@
|
|
103
103
|
<th>ID</th>
|
104
104
|
<th>Entities</th>
|
105
105
|
<th>Tags</th>
|
106
|
+
<th>Regex Tags</th>
|
106
107
|
<th>Warning Media</th>
|
107
108
|
<th>Critical Media</th>
|
108
109
|
<th>Time Restrictions</th>
|
@@ -113,6 +114,7 @@
|
|
113
114
|
<td><%= h rule.id %></td>
|
114
115
|
<td><%= h( (rule.entities && !rule.entities.empty?) ? rule.entities.join(', ') : '-') %></td>
|
115
116
|
<td><%= h( (rule.tags && !rule.tags.empty?) ? rule.tags.to_a.join(', ') : '-') %></td>
|
117
|
+
<td><%= h( (rule.regex_tags && !rule.regex_tags.empty?) ? rule.regex_tags.to_a.join(', ') : '-') %></td>
|
116
118
|
<td><%= h( (rule.warning_media && !rule.warning_media.empty?) ? rule.warning_media.join(', ') : '-')%></td>
|
117
119
|
<td><%= h( (rule.critical_media && !rule.critical_media.empty?) ? rule.critical_media.join(', ') : '-') %></td>
|
118
120
|
<td><%= h(rule.time_restrictions) %></td>
|
data/lib/flapjack/notifier.rb
CHANGED
@@ -30,10 +30,8 @@ module Flapjack
|
|
30
30
|
|
31
31
|
@notifications_queue = @config['queue'] || 'notifications'
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
:jabber => @config['jabber_queue'],
|
36
|
-
:pagerduty => @config['pagerduty_queue']}
|
33
|
+
queue_configs = @config.find_all {|k, v| k =~ /_queue$/ }
|
34
|
+
@queues = Hash[queue_configs.map {|k, v| [k[/^(.*)_queue$/, 1], v] }]
|
37
35
|
|
38
36
|
notify_logfile = @config['notification_log_file'] || 'log/notify.log'
|
39
37
|
if not File.directory?(File.dirname(notify_logfile))
|
@@ -133,7 +131,7 @@ module Flapjack
|
|
133
131
|
@notifylog.info("#{event_id} | " +
|
134
132
|
"#{notification.type} | #{message.contact.id} | #{media_type} | #{address}")
|
135
133
|
|
136
|
-
unless @queues[media_type.
|
134
|
+
unless @queues[media_type.to_s]
|
137
135
|
@logger.error("no queue for media type: #{media_type}")
|
138
136
|
return
|
139
137
|
end
|
@@ -160,16 +158,15 @@ module Flapjack
|
|
160
158
|
contents_tags = contents['tags']
|
161
159
|
contents['tags'] = contents_tags.is_a?(Set) ? contents_tags.to_a : contents_tags
|
162
160
|
|
163
|
-
# TODO consider changing Resque jobs to use raw blpop like the others
|
164
161
|
case media_type.to_sym
|
165
162
|
when :sms
|
166
|
-
|
163
|
+
# FIXME(@auxesis): change Resque jobs to use raw blpop
|
164
|
+
Resque.enqueue_to(@queues['sms'], Flapjack::Gateways::SmsMessagenet, contents)
|
167
165
|
when :email
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
@redis.rpush(@queues[:pagerduty], Oj.dump(contents))
|
166
|
+
# FIXME(@auxesis): change Resque jobs to use raw blpop
|
167
|
+
Resque.enqueue_to(@queues['email'], Flapjack::Gateways::Email, contents)
|
168
|
+
else
|
169
|
+
@redis.rpush(@queues[media_type.to_s], Oj.dump(contents))
|
173
170
|
end
|
174
171
|
end
|
175
172
|
end
|
data/lib/flapjack/version.rb
CHANGED
@@ -15,6 +15,22 @@ describe Flapjack::Data::NotificationRule, :redis => true do
|
|
15
15
|
let(:rule_data) {
|
16
16
|
{:contact_id => '23',
|
17
17
|
:tags => ["database","physical"],
|
18
|
+
:regex_tags => [],
|
19
|
+
:entities => ["foo-app-01.example.com"],
|
20
|
+
:time_restrictions => [ weekdays_8_18 ],
|
21
|
+
:unknown_media => [],
|
22
|
+
:warning_media => ["email"],
|
23
|
+
:critical_media => ["sms", "email"],
|
24
|
+
:unknown_blackhole => false,
|
25
|
+
:warning_blackhole => false,
|
26
|
+
:critical_blackhole => false
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
let(:regex_rule_data) {
|
31
|
+
{:contact_id => '23',
|
32
|
+
:tags => [],
|
33
|
+
:regex_tags => ["^data.*$","^(physical|bare_metal)$"],
|
18
34
|
:entities => ["foo-app-01.example.com"],
|
19
35
|
:time_restrictions => [ weekdays_8_18 ],
|
20
36
|
:unknown_media => [],
|
@@ -34,6 +50,10 @@ describe Flapjack::Data::NotificationRule, :redis => true do
|
|
34
50
|
Flapjack::Data::NotificationRule.add(rule_data, :redis => @redis)
|
35
51
|
}
|
36
52
|
|
53
|
+
let(:existing_regex_rule) {
|
54
|
+
Flapjack::Data::NotificationRule.add(regex_rule_data, :redis => @redis)
|
55
|
+
}
|
56
|
+
|
37
57
|
it "checks that a notification rule exists" do
|
38
58
|
expect(Flapjack::Data::NotificationRule.exists_with_id?(existing_rule.id, :redis => @redis)).to be true
|
39
59
|
expect(Flapjack::Data::NotificationRule.exists_with_id?('not_there', :redis => @redis)).to be false
|
@@ -87,6 +107,15 @@ describe Flapjack::Data::NotificationRule, :redis => true do
|
|
87
107
|
expect(rule.match_tags?(['virtual'].to_set)).to be false
|
88
108
|
end
|
89
109
|
|
110
|
+
it "checks whether entity tags match a regex" do
|
111
|
+
rule = existing_regex_rule
|
112
|
+
|
113
|
+
expect(rule.match_regex_tags?(['database', 'physical'].to_set)).to be true
|
114
|
+
expect(rule.match_regex_tags?(['database', 'physical', 'beetroot'].to_set)).to be true
|
115
|
+
expect(rule.match_regex_tags?(['database'].to_set)).to be false
|
116
|
+
expect(rule.match_regex_tags?(['virtual'].to_set)).to be false
|
117
|
+
end
|
118
|
+
|
90
119
|
it "checks if blackhole settings for a rule match a severity level" do
|
91
120
|
rule_data[:warning_blackhole] = true
|
92
121
|
rule = Flapjack::Data::NotificationRule.add(rule_data, :redis => @redis)
|
@@ -42,6 +42,7 @@ describe 'Flapjack::Gateways::API::ContactMethods', :sinatra => true, :logger =>
|
|
42
42
|
let(:notification_rule_data) {
|
43
43
|
{"contact_id" => "21",
|
44
44
|
"tags" => ["database","physical"],
|
45
|
+
"regex_tags" => ["^data.*$","^(physical|bare_metal)$"],
|
45
46
|
"entities" => ["foo-app-01.example.com"],
|
46
47
|
"time_restrictions" => nil,
|
47
48
|
"unknown_media" => ["jabber"],
|
@@ -54,6 +54,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
54
54
|
it "receives an acknowledgement message" do
|
55
55
|
expect(stanza).to receive(:body).and_return('flapjack: ACKID 1f8ac10f fixing now duration: 90m')
|
56
56
|
from = double('from')
|
57
|
+
expect(from).to receive(:resource).and_return('sender')
|
57
58
|
expect(from).to receive(:stripped).and_return('sender')
|
58
59
|
expect(stanza).to receive(:from).and_return(from)
|
59
60
|
|
@@ -89,6 +90,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
89
90
|
'<a href="http://example.org/">example.org</a></span>')
|
90
91
|
|
91
92
|
from = double('from')
|
93
|
+
expect(from).to receive(:resource).and_return('sender')
|
92
94
|
expect(from).to receive(:stripped).and_return('sender')
|
93
95
|
expect(stanza).to receive(:from).and_return(from)
|
94
96
|
|
@@ -121,6 +123,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
121
123
|
and_return("flapjack: tell me about \nexample.com")
|
122
124
|
|
123
125
|
from = double('from')
|
126
|
+
expect(from).to receive(:resource).and_return('sender')
|
124
127
|
expect(from).to receive(:stripped).and_return('sender')
|
125
128
|
expect(stanza).to receive(:from).and_return(from)
|
126
129
|
|
@@ -151,6 +154,7 @@ describe Flapjack::Gateways::Jabber, :logger => true do
|
|
151
154
|
it "receives a message it doesn't understand" do
|
152
155
|
expect(stanza).to receive(:body).once.and_return('flapjack: hello!')
|
153
156
|
from = double('from')
|
157
|
+
expect(from).to receive(:resource).and_return('sender')
|
154
158
|
expect(from).to receive(:stripped).and_return('sender')
|
155
159
|
expect(stanza).to receive(:from).and_return(from)
|
156
160
|
|
@@ -44,6 +44,7 @@ describe 'Flapjack::Gateways::JSONAPI::ContactMethods', :sinatra => true, :logge
|
|
44
44
|
let(:notification_rule_data) {
|
45
45
|
{"contact_id" => "21",
|
46
46
|
"tags" => ["database","physical"],
|
47
|
+
"regex_tags" => ["^data.*$","^(physical|bare_metal)$"],
|
47
48
|
"entities" => ["foo-app-01.example.com"],
|
48
49
|
"time_restrictions" => nil,
|
49
50
|
"unknown_media" => ["jabber"],
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flapjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lindsay Holmwood
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-03-
|
13
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: dante
|