flapjack 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ec94faddf6467adf887a6f66d074a4ac8d807ca
4
- data.tar.gz: 53f73cc61036a9d014a0438e11fff8df0c549cf3
3
+ metadata.gz: a4e8b5d1bee24a164e37f5db62f177d02cb470cb
4
+ data.tar.gz: f7e916ff508251675628c89ff70a31a030ee31b2
5
5
  SHA512:
6
- metadata.gz: c55a5f75ec5ee9b4121e625867d914180263727ad0009d5827fe45cbcb73ea63d115e83db68bd04b09ee8f47a8bd04da3d74983caf22834f31928c5822adefd2
7
- data.tar.gz: dd45f9d97ab302029882dbdd3f3203c03e2c078188d16839c9e18b19ee98482a7fc9b821150c6ac5954cf4620cf54b3fdc292df3e8cb1d4729ad2c6c890f9bfd
6
+ metadata.gz: 4ea75824a365cf143acd0db2581a440799a8d9dda7b093fc55fb3325b05dc5bc4617e64d548bc7529a6bb64a3562f7c202daf9640c4b6c6e489f42119f6e84e0
7
+ data.tar.gz: 05ed36b6fe5ad8745b4e4d27e44f1bdbf7097c59d4ff1bf5a31edf92ab72e157087e904a44d5e2147584eab58fcd050806f59130b77cf69692945d6920e89f77
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## Flapjack Changelog
2
2
 
3
+ # 1.1.0 - 2014-09-10
4
+ - Feature: Add autorefresh for the web GUI (Closes: #494) #607 (@Hobbsee)
5
+ - Feature: twilio sms sending #633 (@jessereynolds)
6
+ - Feature: Flapjack command for httpchecker check engine #631 (@michaelneale)
7
+ - Feature: Purge historical check states cli #625 (@jessereynolds)
8
+ - Chore: bump Dockerfile to trusty and flapjack 1.0 #630 (@jessereynolds)
9
+ - Bug: Check freshness metrics appear to be broken #626 (@jessereynolds)
10
+ - Bug: Fix CMD to start flapjack with new cli format (Dockerfile) #629 (@auxesis)
11
+ - Bug: set key expiry properly for scheduled maintenance spanning current time #634 (@ali-graham)
12
+ - Bug: GET /media/id works for sms_twilio now #638 (@jessereynolds)
13
+ - Bug: expose newer media types in /edit_contacts #640 (@jessereynolds)
14
+
3
15
  # 1.0.0 - 2014-08-21
4
16
  - No changes
5
17
 
data/CONTRIBUTING.md CHANGED
@@ -1,4 +1,4 @@
1
- #Contributing to ![Flapjack](http:////flapjack.io/images/flapjack-2013-notext-transparent-50-50.png "Flapjack") Flapjack
1
+ #Contributing to ![Flapjack](http://flapjack.io/images/flapjack-2013-notext-transparent-50-50.png "Flapjack") Flapjack
2
2
 
3
3
  [![Build Status](https://travis-ci.org/flapjack/flapjack.png)](https://travis-ci.org/flapjack/flapjack)
4
4
 
data/Dockerfile CHANGED
@@ -1,8 +1,16 @@
1
- FROM ubuntu:12.04
1
+ FROM stackbrew/ubuntu:trusty
2
2
 
3
- RUN echo deb http://packages.flapjack.io/deb precise main >> /etc/apt/sources.list
3
+ RUN apt-get install -y gnupg
4
+
5
+ RUN gpg --keyserver keys.gnupg.net --recv-keys 803709B6
6
+ RUN gpg -a --export 803709B6 | apt-key add -
7
+
8
+ RUN echo "deb http://packages.flapjack.io/deb/1.0 trusty main" | tee /etc/apt/sources.list.d/flapjack.list
4
9
  RUN apt-get update
5
- RUN apt-get install -y --force-yes flapjack
10
+ RUN apt-cache policy flapjack
11
+ RUN apt-get install -y flapjack
12
+
13
+ EXPOSE 3080 3081 3071 6380
6
14
 
7
- CMD /etc/init.d/redis-flapjack start && /opt/flapjack/bin/flapjack start --no-daemonize
15
+ CMD /etc/init.d/redis-flapjack start && /opt/flapjack/bin/flapjack server start --no-daemonize
8
16
 
data/README.md CHANGED
@@ -37,37 +37,43 @@ Additional check engines can be supported by adding additional receiver processe
37
37
 
38
38
  **Ubuntu Precise 64 (12.04):**
39
39
 
40
+ Tell apt to trust the Flapjack package signing key:
41
+
42
+ ```
43
+ gpg --keyserver keys.gnupg.net --recv-keys 803709B6
44
+ gpg -a --export 803709B6 | sudo apt-key add -
45
+ ```
46
+
40
47
  Add the Flapjack Debian repository to your Apt sources:
41
48
 
42
49
  ``` text
43
- echo 'deb http://packages.flapjack.io/deb precise main' > /tmp/flapjack.list
44
- sudo cp /tmp/flapjack.list /etc/apt/sources.list.d/flapjack.list
45
- sudo apt-get update
50
+ echo "deb http://packages.flapjack.io/deb/1.0 precise main" | sudo tee /etc/apt/sources.list.d/flapjack.list
46
51
  ```
47
52
 
48
53
  Install the latest Flapjack package:
49
54
 
50
55
  ``` text
56
+ sudo apt-get update
51
57
  sudo apt-get install flapjack
52
58
  ```
53
59
 
54
- Alternatively, [download the deb](http://packages.flapjack.io/deb/pool/main/f/flapjack/) and install using `sudo dpkg -i <filename>`
60
+ Alternatively, [download the deb](http://packages.flapjack.io/deb/1.0/pool/main/f/flapjack/) and install using `sudo dpkg -i <filename>`
55
61
 
56
- The Flapjack package is an [Omnibus](https://github.com/opscode/omnibus-ruby) package and as such contains most dependencies under `/opt/flapjack`, including Redis.
62
+ The Flapjack package is an [Omnibus](https://github.com/opscode/omnibus) package and as such contains most dependencies under `/opt/flapjack`, including Redis.
57
63
 
58
- Installing the package will start Redis and Flapjack. You should now be able to access the Flapjack Web UI at:
64
+ Installing the package will start Redis (non standard port) and Flapjack. You should now be able to access the Flapjack Web UI at:
59
65
 
60
66
  [http://localhost:3080/](http://localhost:3080)
61
67
 
62
- And consume the REST API at:
68
+ And consume the [REST API](http://flapjack.io/docs/1.0/jsonapi/) at:
63
69
 
64
70
  [http://localhost:3081/](http://localhost:3081)
65
71
 
66
- N.B. The Redis installed by Flapjack runs on a non-standard port, so it doesn't conflict with other Redis instances you may already have installed.
72
+ N.B. The Redis installed by Flapjack runs on a non-standard port (6380), so it doesn't conflict with other Redis instances you may already have installed.
67
73
 
68
74
  **Other OSes:**
69
75
 
70
- Currently we only make a package for Ubuntu Precise (amd64). If you feel comfortable getting a ruby 1.9 or 2.0 environment going on your preferred OS, then you can also just install Flapjack from rubygems.org:
76
+ Currently we only make a package for Ubuntu Precise (amd64). If you feel comfortable getting a ruby environment going on your preferred OS, then you can also just install Flapjack from rubygems.org:
71
77
 
72
78
  ```text
73
79
  gem install flapjack
@@ -81,10 +87,10 @@ You'll also need Redis >= 2.6.12.
81
87
 
82
88
  ## Configuring
83
89
 
84
- Have a look at the default config file and modify things as required. See the [Configuring Components](http://flapjack.io/docs/1.0/usage/USING#wiki-configuring_components) section on the wiki for more details.
90
+ Have a look at the [default config file](https://github.com/flapjack/flapjack/blob/master/etc/flapjack_config.yaml.example) and modify things as required. The package installer copies this to `/etc/flapjack/flapjack_config.yaml` if it doesn't already exist.
85
91
 
86
92
  ``` bash
87
- # hack the config
93
+ # edit the config
88
94
  sudo vi /etc/flapjack/flapjack_config.yaml
89
95
 
90
96
  # reload the config
@@ -101,10 +107,10 @@ First up, start Redis if it's not already started:
101
107
 
102
108
  ``` bash
103
109
  # status:
104
- sudo /etc/init.d/redis status
110
+ sudo /etc/init.d/redis-flapjack status
105
111
 
106
112
  # start:
107
- sudo /etc/init.d/redis start
113
+ sudo /etc/init.d/redis-flapjack start
108
114
  ```
109
115
 
110
116
  Operating Flapjack:
@@ -128,11 +134,11 @@ sudo /etc/init.d/flapjack start
128
134
 
129
135
  ## Using - Details
130
136
 
131
- For more information, including full specification of the configuration file and the data import formats, please refer to the [USING](http://flapjack.io/docs/1.0/usage/USING) section of the Flapjack wiki
137
+ We are [updating](https://github.com/flapjack/flapjack/issues/624) this section of the docs.
132
138
 
133
139
  ## Developing Flapjack
134
140
 
135
- Information on developing more Flapjack components or contributing to core Flapjack development can be found in the [DEVELOPING](http://flapjack.io/docs/1.0/developing/DEVELOPING) section of the Flapjack wiki
141
+ Information on developing more Flapjack components or contributing to core Flapjack development can be found in the [Developing](http://flapjack.io/docs/1.0/development/DEVELOPING/) section of [the docs](http://flapjack.io/docs/1.0/).
136
142
 
137
143
  ## Documentation Submodule
138
144
 
@@ -149,6 +155,7 @@ If you make changes to the documentation locally, here's how to publish them:
149
155
  * git add, commit and push from inside the doc subdir
150
156
  * Add, commit and push the doc dir from the root (this updates the pointer in the main git repo to the correct ref in the doc repo, we think...)
151
157
 
152
- ## More on the wiki
158
+ ## RTFM
159
+
160
+ All of [the documentation](http://flapjack.io/docs).
153
161
 
154
- [The Flapjack wiki](http://flapjack.io/docs/1.0/wiki/) has even more goodies
@@ -39,6 +39,7 @@ production:
39
39
  queue: notifications
40
40
  email_queue: email_notifications
41
41
  sms_queue: sms_notifications
42
+ sms_twilio_queue: sms_twilio_notifications
42
43
  sns_queue: sns_notifications
43
44
  jabber_queue: jabber_notifications
44
45
  pagerduty_queue: pagerduty_notifications
@@ -85,7 +86,7 @@ production:
85
86
  # alert.text: '/etc/flapjack/templates/email/alert.text.erb'
86
87
  # rollup.html: '/etc/flapjack/templates/email/rollup.html.erb'
87
88
  # alert.html: '/etc/flapjack/templates/email/alert.html.erb'
88
- # Generates sms notifications
89
+ # Sends SMS notifications via MessageNet (Australia only)
89
90
  sms:
90
91
  enabled: no
91
92
  # the redis queue this pikelet will look for notifications on
@@ -100,6 +101,21 @@ production:
100
101
  #templates:
101
102
  # rollup.text: '/etc/flapjack/templates/sms/rollup.text.erb'
102
103
  # alert.text: '/etc/flapjack/templates/sms/alert.text.erb'
104
+ # Sends SMS notifications via Twilio
105
+ sms_twilio:
106
+ enabled: no
107
+ queue: sms_twilio_notifications
108
+ account_sid: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
109
+ auth_token: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
110
+ from: "+1xxxxxxxxxx"
111
+ logger:
112
+ level: INFO
113
+ syslog_errors: yes
114
+ # location of custom alert templates
115
+ # location of custom alert templates
116
+ #templates:
117
+ # rollup.text: '/etc/flapjack/templates/sms_twilio/rollup.text.erb'
118
+ # alert.text: '/etc/flapjack/templates/sms_twilio/alert.text.erb'
103
119
  # Generates SNS notifications
104
120
  sns:
105
121
  enabled: no
@@ -150,6 +166,8 @@ production:
150
166
  enabled: yes
151
167
  port: 3080
152
168
  timeout: 300
169
+ # Seconds between auto_refresh of entities/checks pages. Set to 0 to disable
170
+ auto_refresh: 120
153
171
  access_log: "/var/log/flapjack/web_access.log"
154
172
  api_url: "http://localhost:3081/"
155
173
  # Full path to location of logo file, e.g. /etc/flapjack/custom_logo.png
@@ -233,6 +251,7 @@ development:
233
251
  queue: notifications
234
252
  email_queue: email_notifications
235
253
  sms_queue: sms_notifications
254
+ sms_twilio_queue: sms_twilio_notifications
236
255
  jabber_queue: jabber_notifications
237
256
  pagerduty_queue: pagerduty_notifications
238
257
  notification_log_file: log/notification.log
@@ -293,6 +312,22 @@ development:
293
312
  #templates:
294
313
  # rollup.text: '/etc/flapjack/templates/sms/rollup.text.erb'
295
314
  # alert.text: '/etc/flapjack/templates/sms/alert.text.erb'
315
+ # Sends SMS messages via Twilio
316
+ sms_twilio:
317
+ enabled: no
318
+ queue: sms_twilio_notifications
319
+ account_sid: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
320
+ auth_token: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
321
+ from: "+1xxxxxxxxxx"
322
+ logger:
323
+ level: INFO
324
+ syslog_errors: yes
325
+ # location of custom alert templates
326
+ # location of custom alert templates
327
+ #templates:
328
+ # rollup.text: '/etc/flapjack/templates/sms_twilio/rollup.text.erb'
329
+ # alert.text: '/etc/flapjack/templates/sms_twilio/alert.text.erb'
330
+ # Generates SNS notifications
296
331
  # Connects to an XMPP (jabber) server, sends notifications (to rooms and individuals),
297
332
  # handles acknowledgements from jabber users and other commands.
298
333
  jabber:
@@ -335,6 +370,8 @@ development:
335
370
  enabled: yes
336
371
  port: 3080
337
372
  timeout: 300
373
+ # Seconds between auto_refresh of entities/checks pages. Set to 0 to disable
374
+ auto_refresh: 120
338
375
  access_log: "log/web_access.log"
339
376
  api_url: "http://localhost:3081/"
340
377
  # Full path to location of logo file, e.g. /etc/flapjack/custom_logo.png
@@ -0,0 +1,43 @@
1
+ @process
2
+ Feature: purge command line
3
+ As a systems administrator
4
+ I should be able to use purge
5
+ From the command line
6
+
7
+ Background:
8
+ Given a file named "purge.yaml" with:
9
+ """
10
+ test:
11
+ redis:
12
+ db: 14
13
+ driver: ruby
14
+ """
15
+
16
+ Scenario: Running with --help shows usage information
17
+ When I run `bundle exec bin/flapjack purge --help`
18
+ Then the exit status should be 0
19
+ And the output should contain "Purge data from Flapjack's database"
20
+ And the output should contain "--check arg"
21
+
22
+ Scenario: Running purge with no arguments exits uncleanly and shows usage
23
+ When I run `bundle exec bin/flapjack purge`
24
+ Then the exit status should not be 0
25
+ And the output should contain "Purge data from Flapjack's database"
26
+
27
+ #flapjack purge check_history --days 90
28
+ Scenario: Purge check data older than 90 days
29
+ When I run `bundle exec bin/flapjack -n test -c tmp/cucumber_cli/purge.yaml purge check_history --days 90`
30
+ Then the exit status should be 0
31
+
32
+ #flapjack purge check_history --days 2 --check "flapper.example:Flapper"
33
+ Scenario: keep only last two days of Flapper state changes
34
+
35
+ #flapjack purge check_history --state-changes +10
36
+ Scenario: purge all state changes except the newest 10 for all checks
37
+
38
+ #flapjack purge disabled_checks
39
+ Scenario: purge all data about disabled checks
40
+
41
+ #flapjack purge stale_checks --days 90
42
+ Scenario: purge all data about checks with no updates in the last 90 days
43
+
@@ -12,9 +12,13 @@ module Flapjack
12
12
  # turn off reverse DNS resolution temporarily
13
13
  orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
14
14
 
15
- UDPSocket.open do |s|
16
- s.connect '64.233.187.99', 1
17
- s.addr.last
15
+ begin
16
+ UDPSocket.open do |s|
17
+ s.connect '64.233.187.99', 1
18
+ s.addr.last
19
+ end
20
+ rescue Errno::ENETUNREACH => e
21
+ '127.0.0.1'
18
22
  end
19
23
  ensure
20
24
  Socket.do_not_reverse_lookup = orig
@@ -36,7 +40,7 @@ module Flapjack
36
40
  when !@options[:pidfile].nil?
37
41
  @options[:pidfile]
38
42
  when !@config_env['pid_dir'].nil?
39
- @config_env['pid_dir'] + 'flapper.pid'
43
+ File.join(@config_env['pid_dir'], 'flapper.pid')
40
44
  else
41
45
  "/var/run/flapjack/flapper.pid"
42
46
  end
@@ -45,7 +49,7 @@ module Flapjack
45
49
  when !@options[:logfile].nil?
46
50
  @options[:logfile]
47
51
  when !@config_env['log_dir'].nil?
48
- @config_env['log_dir'] + 'flapper.log'
52
+ File.join(@config_env['log_dir'], 'flapper.log')
49
53
  else
50
54
  "/var/run/flapjack/flapper.log"
51
55
  end
@@ -58,7 +62,7 @@ module Flapjack
58
62
  print "flapper starting..."
59
63
  print "\n" unless @options[:daemonize]
60
64
  runner.execute(:daemonize => @options[:daemonize]) do
61
- main(@options['bind-ip'], @options['bind-port'].to_i, @options[:frequency])
65
+ main(@options['bind-ip'] || Flapjack::CLI::Flapper.local_ip, @options['bind-port'].to_i, @options[:frequency])
62
66
  end
63
67
  puts " done."
64
68
  end
@@ -184,8 +188,7 @@ command :flapper do |flapper|
184
188
 
185
189
  start.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
186
190
 
187
- start.flag [:b, 'bind-ip'], :desc => 'ADDRESS (IPv4 or IPv6) for flapper to bind to',
188
- :default_value => Flapjack::CLI::Flapper.local_ip
191
+ start.flag [:b, 'bind-ip'], :desc => 'Override ADDRESS (IPv4 or IPv6) for flapper to bind to'
189
192
 
190
193
  start.flag [:P, 'bind-port'], :desc => 'PORT for flapper to bind to (default: 12345)',
191
194
  :default_value => '12345'
@@ -219,8 +222,7 @@ command :flapper do |flapper|
219
222
 
220
223
  restart.flag [:l, 'logfile'], :desc => 'PATH of the logfile to write to'
221
224
 
222
- restart.flag [:b, 'bind-ip'], :desc => 'ADDRESS (IPv4 or IPv6) for flapper to bind to',
223
- :default_value => Flapjack::CLI::Flapper.local_ip
225
+ restart.flag [:b, 'bind-ip'], :desc => 'Override ADDRESS (IPv4 or IPv6) for flapper to bind to'
224
226
 
225
227
  restart.flag [:P, 'bind-port'], :desc => 'PORT for flapper to bind to (default: 12345)',
226
228
  :default_value => 12345
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'hiredis'
4
+ require 'flapjack/configuration'
5
+
6
+ module Flapjack
7
+ module CLI
8
+ class Purge
9
+
10
+ def initialize(global_options, options)
11
+ @global_options = global_options
12
+ @options = options
13
+
14
+ config = Flapjack::Configuration.new
15
+ config.load(global_options[:config])
16
+ @config_env = config.all
17
+
18
+ if @config_env.nil? || @config_env.empty?
19
+ exit_now! "No config data for environment '#{FLAPJACK_ENV}' found in '#{global_options[:config]}'"
20
+ end
21
+
22
+ @redis_options = config.for_redis
23
+ end
24
+
25
+ def check_history
26
+ # find all checks, or the check given
27
+ # purge old data for check
28
+ options = {}
29
+ if @options[:days]
30
+ options[:older_than] = @options[:days].to_i * 24 * 60 * 60
31
+ raise "days must be resolveable to an integer" unless @options[:days].to_i.to_s == @options[:days]
32
+ end
33
+ checks = if @options[:check]
34
+ [Flapjack::Data::EntityCheck.for_event_id(@options[:check], :redis => redis, :create_entity => true)]
35
+ else
36
+ Flapjack::Data::EntityCheck.all(:redis => redis, :create_entity => true)
37
+ end
38
+ purged = checks.map do |check|
39
+ p = check.purge_history(options)
40
+ p == 0 ? nil : p
41
+ end.compact
42
+
43
+ if purged.empty?
44
+ puts "Nothing to do"
45
+ else
46
+ puts "Purged #{purged.reduce(:+) || 0} historical check states over #{purged.length} checks."
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def redis
53
+ @redis ||= Redis.new(@redis_options.merge(:driver => :ruby))
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+
60
+ desc "Purge data from Flapjack's database"
61
+ command :purge do |purge|
62
+
63
+ purge.desc 'Purge check history'
64
+ purge.command :check_history do |check_history|
65
+
66
+ check_history.flag [:d, 'days'], :desc => "purge check history older than DAYS days ago",
67
+ :default_value => 90
68
+
69
+ check_history.flag [:c, 'check'], :desc => "affect history of only the CHECK"
70
+
71
+ check_history.action do |global_options,options,args|
72
+ purge = Flapjack::CLI::Purge.new(global_options, options)
73
+ purge.check_history
74
+ end
75
+ end
76
+
77
+ end
@@ -34,7 +34,7 @@ module Flapjack
34
34
  when !@options[:pidfile].nil?
35
35
  @options[:pidfile]
36
36
  when !@config_env['pid_dir'].nil?
37
- @config_env['pid_dir'] + "#{@options[:type]}-receiver.pid"
37
+ File.join(@config_env['pid_dir'], "#{@options[:type]}-receiver.pid")
38
38
  else
39
39
  "/var/run/flapjack/#{@options[:type]}-receiver.pid"
40
40
  end
@@ -43,7 +43,7 @@ module Flapjack
43
43
  when !@options[:logfile].nil?
44
44
  @options[:logfile]
45
45
  when !@config_env['log_dir'].nil?
46
- @config_env['log_dir'] + "#{@options[:type]}-receiver.log"
46
+ File.join(@config_env['log_dir'], "#{@options[:type]}-receiver.log")
47
47
  else
48
48
  "/var/run/flapjack/#{@options[:type]}-receiver.log"
49
49
  end
@@ -633,6 +633,19 @@ command :receiver do |receiver|
633
633
  end
634
634
  end
635
635
 
636
+ receiver.desc 'HTTP checker for availability checking of services'
637
+ receiver.command :httpchecker do |httpchecker|
638
+ httpchecker.passthrough = true
639
+ httpchecker.action do |global_options, options, args|
640
+ libexec = Pathname.new(__FILE__).parent.parent.parent.parent.join('libexec').expand_path
641
+ httpchecker = libexec.join('httpchecker')
642
+ if httpchecker.exist?
643
+ Kernel.exec(httpchecker.to_s, *ARGV)
644
+ end
645
+ end
646
+ end
647
+
648
+
636
649
  receiver.desc 'HTTP API that caches and submits events'
637
650
  receiver.command :httpbroker do |httpbroker|
638
651
  httpbroker.passthrough = true
@@ -29,7 +29,7 @@ module Flapjack
29
29
  when !@options[:pidfile].nil?
30
30
  @options[:pidfile]
31
31
  when !@config_env['pid_dir'].nil?
32
- @config_env['pid_dir'] + 'flapjack.pid'
32
+ File.join(@config_env['pid_dir'], 'flapjack.pid')
33
33
  else
34
34
  "/var/run/flapjack/flapjack.pid"
35
35
  end
@@ -38,7 +38,7 @@ module Flapjack
38
38
  when !@options[:logfile].nil?
39
39
  @options[:logfile]
40
40
  when !@config_env['log_dir'].nil?
41
- @config_env['log_dir'] + 'flapjack.log'
41
+ File.join(@config_env['log_dir'], 'flapjack.log')
42
42
  else
43
43
  "/var/run/flapjack/flapjack.log"
44
44
  end
@@ -22,7 +22,7 @@ module Flapjack
22
22
  :media_intervals, :media_rollup_thresholds, :pagerduty_credentials
23
23
 
24
24
  TAG_PREFIX = 'contact_tag'
25
- ALL_MEDIA = ['email', 'sms', 'jabber', 'pagerduty', 'sns']
25
+ ALL_MEDIA = ['email', 'sms', 'sms_twilio', 'jabber', 'pagerduty', 'sns']
26
26
 
27
27
  def self.all(options = {})
28
28
  raise "Redis connection not set" unless redis = options[:redis]
@@ -63,6 +63,14 @@ module Flapjack
63
63
  self.new(entity, check, :logger => logger, :redis => redis)
64
64
  end
65
65
 
66
+ def self.all(options = {})
67
+ raise "Redis connection not set" unless redis = options[:redis]
68
+ checks = redis.keys('check:*').map {|c| c.match(/^check:(.*)$/) ; $1}
69
+ checks.map {|ec|
70
+ self.for_entity_id(ec, options)
71
+ }
72
+ end
73
+
66
74
  def self.find_current_for_entity_name(entity_name, options = {})
67
75
  raise "Redis connection not set" unless redis = options[:redis]
68
76
  redis.zrange("current_checks:#{entity_name}", 0, -1)
@@ -370,6 +378,7 @@ module Flapjack
370
378
  #
371
379
  def self.find_all_split_by_freshness(ages, options)
372
380
  raise "Redis connection not set" unless redis = options[:redis]
381
+ logger = options[:logger]
373
382
 
374
383
  raise "ages does not respond_to? :each and :each_with_index" unless ages.respond_to?(:each) && ages.respond_to?(:each_with_index)
375
384
  raise "age values must respond_to? :to_i" unless ages.all? {|age| age.respond_to?(:to_i) }
@@ -382,10 +391,11 @@ module Flapjack
382
391
  checks = []
383
392
  # get all the current checks, with last update time
384
393
  Flapjack::Data::Entity.all(:enabled => true, :redis => redis).each do |entity|
385
- redis.zrange("current_checks:#{entity}", 0, -1, :withscores => true).each do |check, score|
386
- checks << ["#{entity}:#{check}", score]
394
+ redis.zrange("current_checks:#{entity.name}", 0, -1, :withscores => true).each do |check, score|
395
+ checks << ["#{entity.name}:#{check}", score]
387
396
  end
388
397
  end
398
+ logger.debug("found #{checks.length} current checks on enabled entities") if logger
389
399
 
390
400
  skeleton = ages.inject({}) {|memo, age| memo[age] = [] ; memo }
391
401
  age_ranges = ages.reverse.each_cons(2)
@@ -512,8 +522,11 @@ module Flapjack
512
522
  # if multiple scheduled maintenances found, find the end_time furthest in the future
513
523
  most_futuristic = current_sched_ms.max {|sm| sm[:end_time] }
514
524
  start_time = most_futuristic[:start_time]
515
- duration = most_futuristic[:duration]
516
- @redis.setex("#{@key}:scheduled_maintenance", duration.to_i, start_time)
525
+
526
+ duration = most_futuristic[:end_time] - current_time
527
+ if duration > 0
528
+ @redis.setex("#{@key}:scheduled_maintenance", duration.to_i, start_time)
529
+ end
517
530
  end
518
531
 
519
532
  # TODO allow summary to be changed as part of the termination
@@ -859,6 +872,39 @@ module Flapjack
859
872
  @ack_hash
860
873
  end
861
874
 
875
+ def purge_history(opts = {})
876
+ t = Time.now
877
+ older_than = opts[:older_than] # purge older than this number of seconds ago
878
+ raise ":older_than must be supplied" unless older_than
879
+
880
+ purge_stamps = historical_states(-1, t.to_i - older_than).map {|s| s[:timestamp]}
881
+ unless purge_stamps.empty?
882
+ @logger.info "purging #{purge_stamps.length} states from #{@key}" if @logger
883
+ deletees = []
884
+ purge_stamps.each do |timestamp|
885
+ deletees << "#{@key}:#{timestamp}:state"
886
+ deletees << "#{@key}:#{timestamp}:summary"
887
+ deletees << "#{@key}:#{timestamp}:count"
888
+ deletees << "#{@key}:#{timestamp}:check_latency"
889
+ end
890
+ @logger.info " deleting a bunch of keys 100 at a time..." if @logger
891
+ deletees.each_slice(100) do |batch|
892
+ @redis.del(batch)
893
+ end
894
+ @logger.info " removing a range of items from the #{@key}:sorted_state_timestamps sorted set" if @logger
895
+ @redis.zremrangebyscore("#{@key}:sorted_state_timestamps", '-inf', t.to_i - older_than)
896
+ @logger.info " getting the #{@key}:states list" if @logger
897
+ states = @redis.lrange("#{@key}:states", 0, -1)
898
+ index = 0
899
+ while states[index].to_i < older_than do
900
+ index += 1
901
+ end
902
+ @logger.info " trimming the #{@key}:states from #{index}, length #{states.length}" if @logger
903
+ @redis.ltrim("#{@key}:states", index, -1)
904
+ end
905
+ purge_stamps.length
906
+ end
907
+
862
908
  def to_jsonapi(opts = {})
863
909
  {
864
910
  "name" => @check,
@@ -302,9 +302,9 @@ module Flapjack
302
302
  end
303
303
 
304
304
  when /^(?:find )?checks(?:\s+matching\s+\/(.+)\/)?\s+on\s+(?:entities matching\s+\/(.+)\/|([a-z0-9\-\.]+))/im
305
- check_pattern = $1 ? $1.chomp.strip : nil
306
- entity_pattern = $2 ? $2.chomp.strip : nil
307
- entity_name = $3
305
+ check_pattern = $1 ? $1.strip : nil
306
+ entity_pattern = $2 ? $2.strip : nil
307
+ entity_name = $3
308
308
 
309
309
  entity_names = if entity_name
310
310
  [entity_name]
@@ -355,7 +355,7 @@ module Flapjack
355
355
  end
356
356
 
357
357
  when /^(?:find )?entities matching\s+\/(.+)\//im
358
- pattern = $1.chomp.strip
358
+ pattern = $1.strip
359
359
  entity_list = Flapjack::Data::Entity.find_all_name_matching(pattern, :redis => @redis)
360
360
 
361
361
  if entity_list
@@ -380,9 +380,9 @@ module Flapjack
380
380
  end
381
381
 
382
382
  when /^(?:ack )?entities\s+\/(.+)\/(?:\s*(.*?)(?:\s*duration:.*?(\w+.*))?)$/i
383
- entity_pattern = $1.chomp.strip
384
- comment = $2 ? $2.chomp.strip : nil
385
- duration_str = $3 ? $3.chomp.strip : '1 hour'
383
+ entity_pattern = $1.strip
384
+ comment = $2 ? $2.strip : nil
385
+ duration_str = $3 ? $3.strip : '1 hour'
386
386
  duration = ChronicDuration.parse(duration_str)
387
387
  entity_list = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
388
388
 
@@ -424,7 +424,7 @@ module Flapjack
424
424
  end
425
425
 
426
426
  when /^(?:status )?entities\s+\/(.+)\/.*$/im
427
- entity_pattern = $1 ? $1.chomp.strip : nil
427
+ entity_pattern = $1 ? $1.strip : nil
428
428
  entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
429
429
 
430
430
  if entity_names
@@ -454,10 +454,10 @@ module Flapjack
454
454
  end
455
455
 
456
456
  when /^(?:ack )?checks\s+\/(.+)\/\s+on\s+\/(.+)\/(?:\s*(.*?)(?:\s*duration:.*?(\w+.*))?)$/i
457
- check_pattern = $1.chomp.strip
458
- entity_pattern = $2.chomp.strip
459
- comment = $3 ? $3.chomp.strip : nil
460
- duration_str = $4 ? $4.chomp.strip : '1 hour'
457
+ check_pattern = $1.strip
458
+ entity_pattern = $2.strip
459
+ comment = $3 ? $3.strip : nil
460
+ duration_str = $4 ? $4.strip : '1 hour'
461
461
  duration = ChronicDuration.parse(duration_str)
462
462
  entity_list = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
463
463
 
@@ -505,8 +505,8 @@ module Flapjack
505
505
  end
506
506
 
507
507
  when /^(?:status )checks\s+\/(.+?)\/(?:\s+on\s+)?(?:\/(.+)?\/)?/i
508
- check_pattern = $1 ? $1.chomp.strip : nil
509
- entity_pattern = $2 ? $2.chomp.strip : '.*'
508
+ check_pattern = $1 ? $1.strip : nil
509
+ entity_pattern = $2 ? $2.strip : '.*'
510
510
  entity_names = Flapjack::Data::Entity.find_all_name_matching(entity_pattern, :redis => @redis)
511
511
 
512
512
  if entity_names
@@ -36,8 +36,9 @@ module Flapjack
36
36
 
37
37
  contact_cache = {}
38
38
 
39
+ known_media_identifiers = Flapjack::Data::Contact::ALL_MEDIA.reject{|m| m == 'pagerduty'}.join('|')
39
40
  media_ids.split(',').uniq.collect do |m_id|
40
- m_id =~ /\A(.+)_(email|sms|jabber)\z/
41
+ m_id =~ /\A(.+)_(#{known_media_identifiers})\z/
41
42
 
42
43
  contact_id = $1
43
44
  media_type = $2
@@ -0,0 +1,115 @@
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/data/alert'
8
+ require 'flapjack/utility'
9
+
10
+ module Flapjack
11
+ module Gateways
12
+ class SmsTwilio
13
+
14
+ # curl -X POST 'https://api.twilio.com/2010-04-01/Accounts/[AccountSid]/Messages.json' \
15
+ # --data-urlencode 'To=+61414123456' \
16
+ # --data-urlencode 'From=+61414123456' \
17
+ # --data-urlencode 'Body=Sausage' \
18
+ # -u [AccountSid]:[AuthToken]
19
+
20
+ class << self
21
+
22
+ include Flapjack::Utility
23
+
24
+ def start
25
+ @sent = 0
26
+ end
27
+
28
+ def perform(contents)
29
+ @logger.debug "Woo, got a notification to send out: #{contents.inspect}"
30
+ alert = Flapjack::Data::Alert.new(contents, :logger => @logger)
31
+
32
+ account_sid = @config["account_sid"]
33
+ auth_token = @config["auth_token"]
34
+ from = @config["from"]
35
+ endpoint = @config["endpoint"] || "https://api.twilio.com/2010-04-01/Accounts/#{account_sid}/Messages.json"
36
+
37
+ address = alert.address
38
+ notification_id = alert.notification_id
39
+ message_type = alert.rollup ? 'rollup' : 'alert'
40
+
41
+ my_dir = File.dirname(__FILE__)
42
+ sms_template_path = case
43
+ when @config.has_key?('templates') && @config['templates']["#{message_type}.text"]
44
+ @config['templates']["#{message_type}.text"]
45
+ else
46
+ my_dir + "/sms_twilio/#{message_type}.text.erb"
47
+ end
48
+ sms_template = ERB.new(File.read(sms_template_path), nil, '-')
49
+
50
+ @alert = alert
51
+ bnd = binding
52
+
53
+ begin
54
+ message = sms_template.result(bnd).chomp
55
+ rescue => e
56
+ @logger.error "Error while excuting the ERB for an sms: " +
57
+ "ERB being executed: #{sms_template_path}"
58
+ raise
59
+ end
60
+
61
+ if @config.nil? || (@config.respond_to?(:empty?) && @config.empty?)
62
+ @logger.error "sms_twilio config is missing"
63
+ return
64
+ end
65
+
66
+ errors = []
67
+
68
+ safe_message = truncate(message, 159)
69
+
70
+ [[account_sid, "Twilio account_sid is missing"],
71
+ [auth_token, "Twilio auth_token is missing"],
72
+ [from, "SMS from address is missing"],
73
+ [address, "SMS address is missing"],
74
+ [notification_id, "Notification id is missing"]].each do |val_err|
75
+
76
+ next unless val_err.first.nil? || (val_err.first.respond_to?(:empty?) && val_err.first.empty?)
77
+ errors << val_err.last
78
+ end
79
+
80
+ unless errors.empty?
81
+ errors.each {|err| @logger.error err }
82
+ return
83
+ end
84
+
85
+ body_data = {'To' => address,
86
+ 'From' => from,
87
+ 'Body' => safe_message}
88
+ @logger.debug "body_data: #{body_data.inspect}"
89
+ @logger.debug "authorization: [#{account_sid}, #{auth_token[0..2]}...#{auth_token[-3..-1]}]"
90
+
91
+ http = EM::HttpRequest.new(endpoint).post(:body => body_data, :head => {'authorization' => [account_sid, auth_token]})
92
+
93
+ @logger.debug "server response: #{http.response}"
94
+
95
+ status = (http.nil? || http.response_header.nil?) ? nil : http.response_header.status
96
+ if (status >= 200) && (status <= 206)
97
+ @sent += 1
98
+ alert.record_send_success!
99
+ @logger.debug "Sent SMS via Twilio, response status is #{status}, " +
100
+ "notification_id: #{notification_id}"
101
+ else
102
+ @logger.error "Failed to send SMS via Twilio, response status is #{status}, " +
103
+ "notification_id: #{notification_id}"
104
+ end
105
+ rescue => e
106
+ @logger.error "Error generating or delivering sms to #{contents['address']}: #{e.class}: #{e.message}"
107
+ @logger.error e.backtrace.join("\n")
108
+ raise
109
+ end
110
+
111
+ end
112
+ end
113
+ end
114
+ end
115
+
@@ -0,0 +1,5 @@
1
+ <%= @alert.type_sentence_case %>: '<%= @alert.check %>' on <%= @alert.entity -%>
2
+ <% unless ['acknowledgement', 'test'].include?(@alert.notification_type) -%>
3
+ is <%= @alert.state_title_case -%>
4
+ <% end -%>
5
+ at <%= Time.at(@alert.time).strftime('%-d %b %H:%M') %>, <%= @alert.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) -%>)
@@ -95,6 +95,8 @@ module Flapjack
95
95
  @logger.error "logo_image_path '#{logo_image_path}'' does not point to a valid file."
96
96
  end
97
97
  end
98
+
99
+ @auto_refresh = @config['auto_refresh'].respond_to?('to_i') && @config['auto_refresh'].to_i > 0 ? @config['auto_refresh'].to_i : false
98
100
  end
99
101
  end
100
102
 
@@ -133,6 +135,20 @@ module Flapjack
133
135
  @default_logo_url = self.class.instance_variable_get('@default_logo_url')
134
136
  @logo_image_file = self.class.instance_variable_get('@logo_image_file')
135
137
  @logo_image_ext = self.class.instance_variable_get('@logo_image_ext')
138
+ @auto_refresh = self.class.instance_variable_get('@auto_refresh')
139
+
140
+ input = nil
141
+ query_string = (request.query_string.respond_to?(:length) &&
142
+ request.query_string.length > 0) ? "?#{request.query_string}" : ""
143
+ if logger.debug?
144
+ input = env['rack.input'].read
145
+ logger.debug("#{request.request_method} #{request.path_info}#{query_string} #{input}")
146
+ elsif logger.info?
147
+ input = env['rack.input'].read
148
+ input_short = input.gsub(/\n/, '').gsub(/\s+/, ' ')
149
+ logger.info("#{request.request_method} #{request.path_info}#{query_string} #{input_short[0..80]}")
150
+ end
151
+ env['rack.input'].rewind unless input.nil?
136
152
  end
137
153
 
138
154
  get '/img/branding.*' do
@@ -181,8 +197,11 @@ module Flapjack
181
197
  end
182
198
 
183
199
  get '/self_stats' do
200
+ logger.debug "calculating self_stats"
184
201
  self_stats
202
+ logger.debug "calculating entity_stats"
185
203
  entity_stats
204
+ logger.debug "calculating check_stats"
186
205
  check_stats
187
206
 
188
207
  erb 'self_stats.html'.to_sym
@@ -464,7 +483,7 @@ module Flapjack
464
483
  end
465
484
  @event_counters = redis.hgetall('event_counters')
466
485
  @events_queued = redis.llen('events')
467
- @current_checks_ages = Flapjack::Data::EntityCheck.find_all_split_by_freshness([0, 60, 300, 900, 3600], {:redis => redis, :counts => true } )
486
+ @current_checks_ages = Flapjack::Data::EntityCheck.find_all_split_by_freshness([0, 60, 300, 900, 3600], {:redis => redis, :logger => logger, :counts => true } )
468
487
  end
469
488
 
470
489
  def entity_stats(entities = nil)
@@ -287,7 +287,7 @@
287
287
  initialize: function(options) {
288
288
  var context = this;
289
289
 
290
- _.each(['email', 'sms', 'jabber'], function(type) {
290
+ _.each(['email', 'sms', 'sms_twilio', 'sns', 'jabber'], function(type) {
291
291
  var medium = context.collection.find(function(cm) {
292
292
  return cm.get('type') == type;
293
293
  });
@@ -338,9 +338,11 @@
338
338
  render: function() {
339
339
  var template_values = _.clone(this.model.attributes);
340
340
  template_values['labels'] = {
341
- 'email' : 'Email',
342
- 'sms' : 'SMS',
343
- 'jabber' : 'Jabber'
341
+ 'email' : 'Email',
342
+ 'sms' : 'SMS (MessageNet)',
343
+ 'sms_twilio' : 'SMS (Twilio)',
344
+ 'sns' : 'SMS (Amazon SNS)',
345
+ 'jabber' : 'Jabber'
344
346
  };
345
347
  this.$el.html(this.template(template_values));
346
348
  return this;
@@ -1,3 +1,6 @@
1
+ <% if @auto_refresh %>
2
+ <meta http-equiv="refresh" content="<%= @auto_refresh %>" >
3
+ <% end %>
1
4
  <% page_title "#{@adjective.capitalize} Checks" %>
2
5
 
3
6
  <div class="page-header">
@@ -1,3 +1,6 @@
1
+ <% if @auto_refresh %>
2
+ <meta http-equiv="refresh" content="<%= @auto_refresh %>" >
3
+ <% end %>
1
4
  <% page_title "#{@adjective.capitalize} Entities" %>
2
5
 
3
6
  <div class="page-header">
@@ -1,3 +1,6 @@
1
+ <% if @auto_refresh %>
2
+ <meta http-equiv="refresh" content="<%= @auto_refresh %>" >
3
+ <% end %>
1
4
  <% page_title "#{h(@entity)} (entity)" %>
2
5
 
3
6
  <div class="page-header">
@@ -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/sms_twilio'
18
19
  require 'flapjack/gateways/aws_sns'
19
20
 
20
21
  module Flapjack
@@ -159,12 +160,13 @@ module Flapjack
159
160
  contents_tags = contents['tags']
160
161
  contents['tags'] = contents_tags.is_a?(Set) ? contents_tags.to_a : contents_tags
161
162
 
163
+ # FIXME(@auxesis): change Resque jobs to use raw blpop
162
164
  case media_type.to_sym
163
165
  when :sms
164
- # FIXME(@auxesis): change Resque jobs to use raw blpop
165
166
  Resque.enqueue_to(@queues['sms'], Flapjack::Gateways::SmsMessagenet, contents)
167
+ when :sms_twilio
168
+ Resque.enqueue_to(@queues['sms_twilio'], Flapjack::Gateways::SmsTwilio, contents)
166
169
  when :email
167
- # FIXME(@auxesis): change Resque jobs to use raw blpop
168
170
  Resque.enqueue_to(@queues['email'], Flapjack::Gateways::Email, contents)
169
171
  when :sns
170
172
  Resque.enqueue_to(@queues['sns'], Flapjack::Gateways::AwsSns, contents)
@@ -25,6 +25,7 @@ require 'flapjack/gateways/oobetet'
25
25
  require 'flapjack/gateways/pagerduty'
26
26
  require 'flapjack/gateways/email'
27
27
  require 'flapjack/gateways/sms_messagenet'
28
+ require 'flapjack/gateways/sms_twilio'
28
29
  require 'flapjack/gateways/aws_sns'
29
30
  require 'flapjack/gateways/web'
30
31
  require 'flapjack/logger'
@@ -156,9 +157,10 @@ module Flapjack
156
157
 
157
158
  class Resque < Flapjack::Pikelet::Base
158
159
 
159
- PIKELET_TYPES = {'email' => Flapjack::Gateways::Email,
160
- 'sms' => Flapjack::Gateways::SmsMessagenet,
161
- 'sns' => Flapjack::Gateways::AwsSns}
160
+ PIKELET_TYPES = {'email' => Flapjack::Gateways::Email,
161
+ 'sms' => Flapjack::Gateways::SmsMessagenet,
162
+ 'sms_twilio' => Flapjack::Gateways::SmsTwilio,
163
+ 'sns' => Flapjack::Gateways::AwsSns}
162
164
 
163
165
  def self.create(type, opts = {})
164
166
  self.new(type, PIKELET_TYPES[type], :config => opts[:config],
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  module Flapjack
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
6
6
 
@@ -27,8 +27,8 @@ describe Flapjack::Data::Contact, :redis => true do
27
27
  :tags => Flapjack::Data::TagSet.new([]),
28
28
  :time_restrictions => [],
29
29
  :unknown_media => [],
30
- :warning_media => ['email', 'sms', 'jabber', 'pagerduty', 'sns'],
31
- :critical_media => ['email', 'sms', 'jabber', 'pagerduty', 'sns'],
30
+ :warning_media => ['email', 'sms', 'sms_twilio', 'jabber', 'pagerduty', 'sns'],
31
+ :critical_media => ['email', 'sms', 'sms_twilio', 'jabber', 'pagerduty', 'sns'],
32
32
  :unknown_blackhole => false,
33
33
  :warning_blackhole => false,
34
34
  :critical_blackhole => false}
@@ -272,7 +272,6 @@ describe Flapjack::Data::EntityCheck, :redis => true do
272
272
  expect(duration).to eq(half_an_hour)
273
273
  end
274
274
 
275
- # TODO this should probably enforce that it starts in the future
276
275
  it "creates a scheduled maintenance period covering the current time" do
277
276
  t = Time.now.to_i
278
277
  ec = Flapjack::Data::EntityCheck.for_entity_name(name, check, :redis => @redis)
@@ -294,6 +293,11 @@ describe Flapjack::Data::EntityCheck, :redis => true do
294
293
  expect(duration).not_to be_nil
295
294
  expect(duration).to be_a(Float)
296
295
  expect(duration).to eq(2 * (60 * 60))
296
+
297
+ ttl = @redis.ttl("#{name}:#{check}:scheduled_maintenance")
298
+ expect(ttl).to be_within(20).of(60 * 60) # 20-second margin of error,
299
+ # should be large enough for a slow machine running the test -- duration
300
+ # is considered to start at the begininng of the period
297
301
  end
298
302
 
299
303
  it "creates an scheduled maintenance period from a human readable time" do
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/gateways/sms_twilio'
3
+
4
+ describe Flapjack::Gateways::SmsTwilio, :logger => true do
5
+
6
+ let(:lock) { double(Monitor) }
7
+
8
+ let(:config) { {'account_sid' => 'the_account_sid',
9
+ 'auth_token' => 'the_auth_token',
10
+ 'from' => 'the_from_address'
11
+ }
12
+ }
13
+
14
+ let(:time) { Time.new(2013, 10, 31, 13, 45) }
15
+
16
+ let(:time_str) { Time.at(time).strftime('%-d %b %H:%M') }
17
+
18
+ let(:message) { {'notification_type' => 'recovery',
19
+ 'contact_first_name' => 'John',
20
+ 'contact_last_name' => 'Smith',
21
+ 'state' => 'ok',
22
+ 'summary' => 'smile',
23
+ 'last_state' => 'problem',
24
+ 'last_summary' => 'frown',
25
+ 'time' => time.to_i,
26
+ 'address' => '555-555555',
27
+ 'event_id' => 'example.com:ping',
28
+ 'id' => '123456789',
29
+ 'duration' => 55,
30
+ 'state_duration' => 23
31
+ }
32
+ }
33
+
34
+ it "sends an SMS message" do
35
+ req = stub_request(:post, "https://api.twilio.com/2010-04-01/Accounts/the_account_sid/Messages.json").
36
+ to_return(:status => 201)
37
+
38
+ EM.synchrony do
39
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@config', config)
40
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@logger', @logger)
41
+ Flapjack::Gateways::SmsTwilio.start
42
+ Flapjack::Gateways::SmsTwilio.perform(message)
43
+ EM.stop
44
+ end
45
+ expect(req).to have_been_requested
46
+ end
47
+
48
+ it "truncates a long message a" do
49
+ long_msg = message.merge('summary' => 'Four score and seven years ago our ' +
50
+ 'fathers brought forth on this continent, a new nation, conceived in ' +
51
+ 'Liberty, and dedicated to the proposition that all men are created equal.')
52
+
53
+ body = {
54
+ 'To' => '555-555555',
55
+ 'From' => 'the_from_address',
56
+ 'Body' => "Recovery: 'ping' on example.com is " +
57
+ "OK at #{time_str}, Four score and seven years ago " +
58
+ 'our fathers brought forth on this continent, a new ' +
59
+ 'nation, conceived i...'}
60
+ req = stub_request(:post, "https://api.twilio.com/2010-04-01/Accounts/the_account_sid/Messages.json").
61
+ with(:body => body).
62
+ with(:headers => {'Authorization'=>['the_account_sid', 'the_auth_token']}).
63
+ to_return(:status => 200)
64
+
65
+ EM.synchrony do
66
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@config', config)
67
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@logger', @logger)
68
+ Flapjack::Gateways::SmsTwilio.start
69
+ Flapjack::Gateways::SmsTwilio.perform(long_msg)
70
+ EM.stop
71
+ end
72
+ expect(req).to have_been_requested
73
+ end
74
+
75
+ it "does not send an SMS message with an invalid config" do
76
+ EM.synchrony do
77
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@config', config.reject {|k, v| k == 'auth_token'})
78
+ Flapjack::Gateways::SmsTwilio.instance_variable_set('@logger', @logger)
79
+ Flapjack::Gateways::SmsTwilio.start
80
+ Flapjack::Gateways::SmsTwilio.perform(message)
81
+ EM.stop
82
+ end
83
+
84
+ expect(WebMock).not_to have_requested(:post,
85
+ "https://api.twilio.com/2010-04-01/Accounts/the_account_sid/Messages.json")
86
+ end
87
+
88
+ 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.0.0
4
+ version: 1.1.0
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: 2014-08-21 00:00:00.000000000 Z
14
+ date: 2014-09-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: dante
@@ -396,6 +396,7 @@ files:
396
396
  - features/cli_flapjack-nagios-receiver.feature
397
397
  - features/cli_flapjack-populator.feature
398
398
  - features/cli_flapper.feature
399
+ - features/cli_purge.feature
399
400
  - features/cli_receive-events.feature
400
401
  - features/cli_simulate-failed-check.feature
401
402
  - features/events.feature
@@ -418,6 +419,7 @@ files:
418
419
  - lib/flapjack/cli/flapper.rb
419
420
  - lib/flapjack/cli/import.rb
420
421
  - lib/flapjack/cli/maintenance.rb
422
+ - lib/flapjack/cli/purge.rb
421
423
  - lib/flapjack/cli/receiver.rb
422
424
  - lib/flapjack/cli/server.rb
423
425
  - lib/flapjack/cli/simulate.rb
@@ -470,6 +472,9 @@ files:
470
472
  - lib/flapjack/gateways/sms_messagenet.rb
471
473
  - lib/flapjack/gateways/sms_messagenet/alert.text.erb
472
474
  - lib/flapjack/gateways/sms_messagenet/rollup.text.erb
475
+ - lib/flapjack/gateways/sms_twilio.rb
476
+ - lib/flapjack/gateways/sms_twilio/alert.text.erb
477
+ - lib/flapjack/gateways/sms_twilio/rollup.text.erb
473
478
  - lib/flapjack/gateways/web.rb
474
479
  - lib/flapjack/gateways/web/public/css/bootstrap.css
475
480
  - lib/flapjack/gateways/web/public/css/font-awesome.css
@@ -569,6 +574,7 @@ files:
569
574
  - spec/lib/flapjack/gateways/oobetet_spec.rb
570
575
  - spec/lib/flapjack/gateways/pagerduty_spec.rb
571
576
  - spec/lib/flapjack/gateways/sms_messagenet_spec.rb
577
+ - spec/lib/flapjack/gateways/sms_twilio_spec.rb
572
578
  - spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb
573
579
  - spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb
574
580
  - spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb
@@ -640,6 +646,7 @@ test_files:
640
646
  - features/cli_flapjack-nagios-receiver.feature
641
647
  - features/cli_flapjack-populator.feature
642
648
  - features/cli_flapper.feature
649
+ - features/cli_purge.feature
643
650
  - features/cli_receive-events.feature
644
651
  - features/cli_simulate-failed-check.feature
645
652
  - features/events.feature
@@ -687,6 +694,7 @@ test_files:
687
694
  - spec/lib/flapjack/gateways/oobetet_spec.rb
688
695
  - spec/lib/flapjack/gateways/pagerduty_spec.rb
689
696
  - spec/lib/flapjack/gateways/sms_messagenet_spec.rb
697
+ - spec/lib/flapjack/gateways/sms_twilio_spec.rb
690
698
  - spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb
691
699
  - spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb
692
700
  - spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb