flapjack 1.6.0rc3 → 1.6.0rc4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5a219d75b1878de449c0a2735258b2962516b75b
4
- data.tar.gz: 66d8c984b4204482680ffeaa711f540ab60c4297
3
+ metadata.gz: ebb781f375968f6795459525d4eb476949f19905
4
+ data.tar.gz: 8b942f1c504d9bdd0ea8e3460c217c0fa1fc7167
5
5
  SHA512:
6
- metadata.gz: bb07615b716a155706165d2bec88ec020df60602ef75e45ae8c5911aca3032dc1e1b3198d7a9e972614ea166cc04adfc43d6fe3e94739594e74ad159d43c9912
7
- data.tar.gz: 877f7c37d41c7068799a26012463f254b15c3bd1698ee66eca186f09a4ad317de6f9bf0cbfb446620f586bff2d088a8a9b68cf5c6e817207affd20ed10543d0d
6
+ metadata.gz: f73ba9354de97136e8b49e9980e83e49687c4007b7881583e34a48ad9d252277c27b2c3c205c6f1c115647509b5b4161d0720ce9c6a403cb8db23d98f1b963b1
7
+ data.tar.gz: f6d5980dbd819dac313aaa7b1faaabaae3eb682ce88cc0aab05f17a0c09d030b00121703b20d3584d100a893c776112feee6bc281b73be872db51611d1eb26ba
@@ -1,5 +1,12 @@
1
1
  ## Flapjack Changelog
2
2
 
3
+ # 1.6.0rc4 - 2015-07-09
4
+ - Feature: slack webhook gateway #881 (@mcqueenorama, @ali-graham)
5
+ - Bug: sns gateway debugging and improvements (but still broken) #879 (@ali-graham, @jessereynolds)
6
+
7
+ ## Notes:
8
+ - the SNS gateway signature calculation has been broken since v1.5.0 or earlier. See [#829](https://github.com/flapjack/flapjack/issues/829)
9
+
3
10
  # 1.6.0rc3 - 2015-06-15
4
11
  - Chore/Bug?: SNS gateway improvements (@ali-graham)
5
12
  - Feature: add summary to rollup alerts #869 (@necula-01)
@@ -40,6 +40,7 @@ production:
40
40
  email_queue: email_notifications
41
41
  sms_queue: sms_notifications
42
42
  sms_nexmo_queue: sms_nexmo_notifications
43
+ slack_queue: slack_notifications
43
44
  sms_twilio_queue: sms_twilio_notifications
44
45
  sns_queue: sns_notifications
45
46
  jabber_queue: jabber_notifications
@@ -102,6 +103,21 @@ production:
102
103
  #templates:
103
104
  # rollup.text: '/etc/flapjack/templates/sms/rollup.text.erb'
104
105
  # alert.text: '/etc/flapjack/templates/sms/alert.text.erb'
106
+ # Sends notifications via Slack
107
+ slack:
108
+ enabled: no
109
+ queue: slack_notifications
110
+ account_sid: "webhookbot"
111
+ endpoint: "https://hooks.slack.com/services/xxx/yyy/"
112
+ auth_token: "zzzzz"
113
+ from: ""
114
+ logger:
115
+ level: INFO
116
+ syslog_errors: yes
117
+ # location of custom alert templates
118
+ #templates:
119
+ # rollup.text: '/etc/flapjack/templates/slack/rollup.text.erb'
120
+ # alert.text: '/etc/flapjack/templates/slack/alert.text.erb'
105
121
  # Sends SMS notifications via Twilio
106
122
  sms_twilio:
107
123
  enabled: no
@@ -113,7 +129,6 @@ production:
113
129
  level: INFO
114
130
  syslog_errors: yes
115
131
  # location of custom alert templates
116
- # location of custom alert templates
117
132
  #templates:
118
133
  # rollup.text: '/etc/flapjack/templates/sms_twilio/rollup.text.erb'
119
134
  # alert.text: '/etc/flapjack/templates/sms_twilio/alert.text.erb'
@@ -24,6 +24,7 @@ module Flapjack
24
24
  ALL_MEDIA = [
25
25
  'email',
26
26
  'sms',
27
+ 'slack',
27
28
  'sms_twilio',
28
29
  'sms_nexmo',
29
30
  'jabber',
@@ -391,8 +392,8 @@ module Flapjack
391
392
  @redis.zadd("contact_alerting_checks:#{self.id}:media:#{media}", Time.now.to_i, event_id)
392
393
  end
393
394
 
394
- def remove_alerting_check_for_media(media, check)
395
- @redis.zrem("contact_alerting_checks:#{self.id}:media:#{media}", check)
395
+ def remove_alerting_check_for_media(media, event_id)
396
+ @redis.zrem("contact_alerting_checks:#{self.id}:media:#{media}", event_id)
396
397
  end
397
398
 
398
399
  # removes any checks that are in ok, scheduled or unscheduled maintenance,
@@ -60,7 +60,7 @@ module Flapjack
60
60
  endpoint = "http://#{hostname}/"
61
61
  access_key = @config["access_key"]
62
62
  secret_key = @config["secret_key"]
63
- timestamp = Time.at(alert.time).strftime('%Y-%m-%dT%H:%M:%SZ')
63
+ timestamp = Time.at(alert.time).utc.strftime('%Y-%m-%dT%H:%M:%SZ')
64
64
 
65
65
  address = alert.address
66
66
  notification_id = alert.notification_id
@@ -145,7 +145,7 @@ module Flapjack
145
145
  end
146
146
 
147
147
  def self.get_signature(secret_key, string_to_sign)
148
- signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret_key, string_to_sign)
148
+ signature = OpenSSL::HMAC.digest('sha256', secret_key, string_to_sign)
149
149
 
150
150
  Base64.encode64(signature).strip
151
151
  end
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'em-synchrony'
4
+ require 'em-synchrony/em-http'
5
+ require 'active_support/inflector'
6
+
7
+ require 'flapjack/redis_pool'
8
+
9
+ require 'flapjack/data/alert'
10
+ require 'flapjack/utility'
11
+
12
+ module Flapjack
13
+ module Gateways
14
+ class Slack
15
+
16
+ include Flapjack::Utility
17
+
18
+ def initialize(opts = {})
19
+ @config = opts[:config]
20
+ @logger = opts[:logger]
21
+ @redis_config = opts[:redis_config] || {}
22
+ @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1, :logger => @logger)
23
+
24
+ @logger.info("starting")
25
+ @logger.debug("new slack gateway pikelet with the following options: #{@config.inspect}")
26
+
27
+ @sent = 0
28
+ end
29
+
30
+ def stop
31
+ @logger.info("stopping")
32
+ @should_quit = true
33
+
34
+ redis_uri = @redis_config[:path] ||
35
+ "redis://#{@redis_config[:host] || '127.0.0.1'}:#{@redis_config[:port] || '6379'}/#{@redis_config[:db] || '0'}"
36
+ shutdown_redis = EM::Hiredis.connect(redis_uri)
37
+ shutdown_redis.rpush(@config['queue'], Flapjack.dump_json('notification_type' => 'shutdown'))
38
+ end
39
+
40
+ def start
41
+ queue = @config['queue']
42
+
43
+ until @should_quit
44
+ begin
45
+ @logger.debug("slack gateway is going into blpop mode on #{queue}")
46
+ alert = Flapjack::Data::Alert.next(queue, :redis => @redis, :logger => @logger)
47
+ deliver(alert) unless alert.nil?
48
+ rescue => e
49
+ @logger.error "Error generating or dispatching Slack message: #{e.class}: #{e.message}\n" +
50
+ e.backtrace.join("\n")
51
+ end
52
+ end
53
+ end
54
+
55
+ def deliver(alert)
56
+ account_sid = @config["account_sid"]
57
+ endpoint = @config["endpoint"]
58
+ icon_emoji = @config["icon_emoji"] || ':ghost:'
59
+
60
+ channel = "##{alert.address}"
61
+ channel = '#general' if (channel.size == 1)
62
+ notification_id = alert.notification_id
63
+ message_type = alert.rollup ? 'rollup' : 'alert'
64
+
65
+ slack_template_erb, slack_template =
66
+ load_template(@config['templates'], message_type, 'text',
67
+ File.join(File.dirname(__FILE__), 'slack'))
68
+
69
+ @alert = alert
70
+ bnd = binding
71
+
72
+ begin
73
+ message = slack_template_erb.result(bnd).chomp
74
+ rescue => e
75
+ @logger.error "Error while executing the ERB for an sms: " +
76
+ "ERB being executed: #{slack_template}"
77
+ raise
78
+ end
79
+
80
+ errors = []
81
+
82
+ [
83
+ [endpoint, "Slack endpoint is missing"],
84
+ [account_sid, "Slack account_sid is missing"]
85
+ ].each do |val_err|
86
+
87
+ next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
88
+ errors << val_err.last
89
+ end
90
+
91
+ unless errors.empty?
92
+ errors.each {|err| @logger.error err }
93
+ return
94
+ end
95
+
96
+ payload = Flapjack.dump_json(
97
+ 'channel' => channel,
98
+ 'username' => account_sid,
99
+ 'text' => message,
100
+ 'icon_emoji' => icon_emoji
101
+ )
102
+ @logger.debug "payload: #{payload.inspect}"
103
+
104
+ http = EM::HttpRequest.new("#{endpoint}").post(:body => {'payload' => payload})
105
+
106
+ @logger.debug "server response: #{http.response}"
107
+
108
+ status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
109
+ if (status >= 200) && (status <= 206)
110
+ @sent += 1
111
+ alert.record_send_success!
112
+ @logger.debug "Sent message via Slack, response status is #{status}, " +
113
+ "notification_id: #{notification_id}"
114
+ else
115
+ @logger.error "Failed to send message via Slack, response status is #{status}, " +
116
+ "notification_id: #{notification_id}"
117
+ end
118
+ rescue => e
119
+ @logger.error "Error generating or delivering sms to #{alert.address}: #{e.class}: #{e.message}"
120
+ @logger.error e.backtrace.join("\n")
121
+ raise
122
+ end
123
+
124
+ end
125
+ end
126
+ end
127
+
@@ -0,0 +1,6 @@
1
+ <% summary = @alert.summary -%>
2
+ <%= @alert.type_sentence_case %>: '<%= @alert.check %>' on <%= @alert.entity -%>
3
+ <% unless ['acknowledgement', 'test'].include?(@alert.notification_type) -%>
4
+ is <%= @alert.state_title_case -%>
5
+ <% end -%>
6
+ at <%= Time.at(@alert.time).strftime('%-d %b %H:%M') %><%= (summary.nil? || summary.empty?) ? '' : ", #{summary}" -%>
@@ -0,0 +1,2 @@
1
+ <%= @alert.type_sentence_case %>: <%= @alert.rollup_states_summary -%>
2
+ (<%= @alert.rollup_states_detail_text(:max_checks_per_state => 3) -%>)
@@ -279,7 +279,7 @@
279
279
  initialize: function(options) {
280
280
  var context = this;
281
281
 
282
- _.each(['email', 'sms', 'sms_twilio', 'sms_nexmo', 'sns', 'jabber'], function(type) {
282
+ _.each(['email', 'sms', 'slack', 'sms_twilio', 'sms_nexmo', 'sns', 'jabber'], function(type) {
283
283
  var medium = context.collection.find(function(cm) {
284
284
  return cm.get('type') == type;
285
285
  });
@@ -334,6 +334,7 @@
334
334
  template_values['labels'] = {
335
335
  'email' : 'Email',
336
336
  'sms' : 'SMS (MessageNet)',
337
+ 'slack' : 'Slack',
337
338
  'sms_twilio' : 'SMS (Twilio)',
338
339
  'sms_nexmo' : 'SMS (Nexmo)',
339
340
  'sns' : 'SMS (Amazon SNS)',
@@ -15,6 +15,7 @@ require 'flapjack/utility'
15
15
 
16
16
  require 'flapjack/gateways/email'
17
17
  require 'flapjack/gateways/sms_messagenet'
18
+ require 'flapjack/gateways/slack'
18
19
  require 'flapjack/gateways/sms_twilio'
19
20
  require 'flapjack/gateways/sms_nexmo'
20
21
  require 'flapjack/gateways/aws_sns'
@@ -23,6 +23,7 @@ require 'flapjack/gateways/oobetet'
23
23
  require 'flapjack/gateways/pagerduty'
24
24
  require 'flapjack/gateways/email'
25
25
  require 'flapjack/gateways/sms_messagenet'
26
+ require 'flapjack/gateways/slack'
26
27
  require 'flapjack/gateways/sms_twilio'
27
28
  require 'flapjack/gateways/sms_nexmo'
28
29
  require 'flapjack/gateways/aws_sns'
@@ -104,6 +105,7 @@ module Flapjack
104
105
  'oobetet' => Flapjack::Gateways::Oobetet,
105
106
  'email' => Flapjack::Gateways::Email,
106
107
  'sms' => Flapjack::Gateways::SmsMessagenet,
108
+ 'slack' => Flapjack::Gateways::Slack,
107
109
  'sms_twilio' => Flapjack::Gateways::SmsTwilio,
108
110
  'sms_nexmo' => Flapjack::Gateways::SmsNexmo,
109
111
  'sns' => Flapjack::Gateways::AwsSns}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  module Flapjack
4
- VERSION = "1.6.0rc3"
4
+ VERSION = "1.6.0rc4"
5
5
  end
@@ -22,8 +22,8 @@ describe Flapjack::Data::Contact, :redis => true do
22
22
  :tags => Set.new([]),
23
23
  :time_restrictions => [],
24
24
  :unknown_media => [],
25
- :warning_media => ['email', 'sms', 'sms_twilio', 'sms_nexmo', 'jabber', 'pagerduty', 'sns'],
26
- :critical_media => ['email', 'sms', 'sms_twilio', 'sms_nexmo', 'jabber', 'pagerduty', 'sns'],
25
+ :warning_media => ['email', 'sms', 'slack', 'sms_twilio', 'sms_nexmo', 'jabber', 'pagerduty', 'sns'],
26
+ :critical_media => ['email', 'sms', 'slack', 'sms_twilio', 'sms_nexmo', 'jabber', 'pagerduty', 'sns'],
27
27
  :unknown_blackhole => false,
28
28
  :warning_blackhole => false,
29
29
  :critical_blackhole => false}
@@ -7,9 +7,9 @@ describe Flapjack::Gateways::AwsSns, :logger => true do
7
7
 
8
8
  let(:redis) { double('redis') }
9
9
 
10
- let(:time) { Time.new(2013, 10, 31, 13, 45) }
10
+ let(:time_int) { 1383252300 }
11
11
 
12
- let(:time_str) { Time.at(time.to_i).strftime('%Y-%m-%dT%H:%M:%SZ') }
12
+ let(:time_str) { '2013-10-31T20:45:00Z' }
13
13
 
14
14
  let(:config) { {'region' => 'us-east-1',
15
15
  'access_key' => 'AKIAIOSFODNN7EXAMPLE',
@@ -24,7 +24,7 @@ describe Flapjack::Gateways::AwsSns, :logger => true do
24
24
  'summary' => 'smile',
25
25
  'last_state' => 'problem',
26
26
  'last_summary' => 'frown',
27
- 'time' => time.to_i,
27
+ 'time' => time_int,
28
28
  'address' => 'arn:aws:sns:us-east-1:698519295917:My-Topic',
29
29
  'event_id' => 'example.com:ping',
30
30
  'id' => '123456789',
@@ -34,13 +34,21 @@ describe Flapjack::Gateways::AwsSns, :logger => true do
34
34
  }
35
35
 
36
36
  it "sends an SMS message" do
37
+ # bad, bad, bad...
38
+ t = double('time')
39
+ ut = double('utc_time')
40
+ expect(ut).to receive(:strftime).with('%Y-%m-%dT%H:%M:%SZ').and_return(time_str)
41
+ expect(t).to receive(:utc).and_return(ut)
42
+ expect(t).to receive(:strftime).with('%-d %b %H:%M').and_return('31 Oct 20:45')
43
+ expect(Time).to receive(:at).with(time_int).twice.and_return(t)
44
+
37
45
  req = stub_request(:post, "http://sns.us-east-1.amazonaws.com/").
38
46
  with(:query => hash_including({'Action' => 'Publish',
39
47
  'AWSAccessKeyId' => config['access_key'],
40
48
  'TopicArn' => message['address'],
41
49
  'SignatureVersion' => '2',
42
50
  'SignatureMethod' => 'HmacSHA256',
43
- 'Signature' => 'gxoUQ8qUYBQbqgf3XmbiSPZ8qTJZ9WyC81EKc67FY0g=',
51
+ 'Signature' => '5fWqhmDrZQkQfP7wsxWDdQjzV0BLwm6cZNrNqZ+W/ok=',
44
52
  'Timestamp' => time_str})).
45
53
  to_return(:status => 200)
46
54
 
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/gateways/slack'
3
+
4
+ describe Flapjack::Gateways::Slack, :logger => true do
5
+
6
+ let(:lock) { double(Monitor) }
7
+
8
+ let(:redis) { double('redis') }
9
+
10
+ let(:config) { {'account_sid' => 'flapslack',
11
+ 'endpoint' => 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
12
+ }
13
+ }
14
+
15
+ let(:time) { Time.new(2013, 10, 31, 13, 45) }
16
+
17
+ let(:time_str) { Time.at(time).strftime('%-d %b %H:%M') }
18
+
19
+ let(:message) { {'notification_type' => 'recovery',
20
+ 'contact_first_name' => 'John',
21
+ 'contact_last_name' => 'Smith',
22
+ 'state' => 'ok',
23
+ 'summary' => 'smile',
24
+ 'last_state' => 'problem',
25
+ 'last_summary' => 'frown',
26
+ 'time' => time.to_i,
27
+ 'address' => 'general',
28
+ 'event_id' => 'example.com:ping',
29
+ 'id' => '123456789',
30
+ 'duration' => 55,
31
+ 'state_duration' => 23
32
+ }
33
+ }
34
+
35
+ it "sends a Slack message" do
36
+ payload_json = Flapjack.dump_json(
37
+ 'channel' => '#general',
38
+ 'username' => 'flapslack',
39
+ 'text' => "Recovery: 'ping' on example.com is OK at #{time_str}, smile",
40
+ 'icon_emoji' => ':ghost:'
41
+ )
42
+
43
+ req = stub_request(:post, config['endpoint']).
44
+ with(:body => {'payload' => payload_json}).
45
+ to_return(:status => 200)
46
+
47
+ EM.synchrony do
48
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
49
+
50
+ alert = Flapjack::Data::Alert.new(message, :logger => @logger)
51
+ slack = Flapjack::Gateways::Slack.new(:config => config, :logger => @logger)
52
+ slack.deliver(alert)
53
+ EM.stop
54
+ end
55
+ expect(req).to have_been_requested
56
+ end
57
+
58
+ it "does not send a Slack message with an invalid config" do
59
+ EM.synchrony do
60
+ expect(Flapjack::RedisPool).to receive(:new).and_return(redis)
61
+
62
+ alert = Flapjack::Data::Alert.new(message, :logger => @logger)
63
+ slack = Flapjack::Gateways::Slack.new(:config => config.reject {|k, v| k == 'endpoint'}, :logger => @logger)
64
+ slack.deliver(alert)
65
+ EM.stop
66
+ end
67
+
68
+ expect(WebMock).not_to have_requested(:post, config['endpoint'])
69
+ end
70
+
71
+ end
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: 1.6.0rc3
4
+ version: 1.6.0rc4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lindsay Holmwood
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-06-15 00:00:00.000000000 Z
14
+ date: 2015-07-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: dante
@@ -469,6 +469,9 @@ files:
469
469
  - lib/flapjack/gateways/oobetet.rb
470
470
  - lib/flapjack/gateways/pagerduty.rb
471
471
  - lib/flapjack/gateways/pagerduty/alert.text.erb
472
+ - lib/flapjack/gateways/slack.rb
473
+ - lib/flapjack/gateways/slack/alert.text.erb
474
+ - lib/flapjack/gateways/slack/rollup.text.erb
472
475
  - lib/flapjack/gateways/sms_messagenet.rb
473
476
  - lib/flapjack/gateways/sms_messagenet/alert.text.erb
474
477
  - lib/flapjack/gateways/sms_messagenet/rollup.text.erb
@@ -576,6 +579,7 @@ files:
576
579
  - spec/lib/flapjack/gateways/jsonapi_spec.rb
577
580
  - spec/lib/flapjack/gateways/oobetet_spec.rb
578
581
  - spec/lib/flapjack/gateways/pagerduty_spec.rb
582
+ - spec/lib/flapjack/gateways/slack_spec.rb
579
583
  - spec/lib/flapjack/gateways/sms_messagenet_spec.rb
580
584
  - spec/lib/flapjack/gateways/sms_nexmo_spec.rb
581
585
  - spec/lib/flapjack/gateways/sms_twilio_spec.rb
@@ -700,6 +704,7 @@ test_files:
700
704
  - spec/lib/flapjack/gateways/jsonapi_spec.rb
701
705
  - spec/lib/flapjack/gateways/oobetet_spec.rb
702
706
  - spec/lib/flapjack/gateways/pagerduty_spec.rb
707
+ - spec/lib/flapjack/gateways/slack_spec.rb
703
708
  - spec/lib/flapjack/gateways/sms_messagenet_spec.rb
704
709
  - spec/lib/flapjack/gateways/sms_nexmo_spec.rb
705
710
  - spec/lib/flapjack/gateways/sms_twilio_spec.rb