flapjack 0.8.8 → 0.8.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|