flapjack 1.0.0 → 1.1.0
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/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +1 -1
- data/Dockerfile +12 -4
- data/README.md +24 -17
- data/etc/flapjack_config.yaml.example +38 -1
- data/features/cli_purge.feature +43 -0
- data/lib/flapjack/cli/flapper.rb +12 -10
- data/lib/flapjack/cli/purge.rb +77 -0
- data/lib/flapjack/cli/receiver.rb +15 -2
- data/lib/flapjack/cli/server.rb +2 -2
- data/lib/flapjack/data/contact.rb +1 -1
- data/lib/flapjack/data/entity_check.rb +50 -4
- data/lib/flapjack/gateways/jabber.rb +14 -14
- data/lib/flapjack/gateways/jsonapi/medium_methods.rb +2 -1
- data/lib/flapjack/gateways/sms_twilio.rb +115 -0
- data/lib/flapjack/gateways/sms_twilio/alert.text.erb +5 -0
- data/lib/flapjack/gateways/sms_twilio/rollup.text.erb +2 -0
- data/lib/flapjack/gateways/web.rb +20 -1
- data/lib/flapjack/gateways/web/public/js/modules/contact.js +6 -4
- data/lib/flapjack/gateways/web/views/checks.html.erb +3 -0
- data/lib/flapjack/gateways/web/views/entities.html.erb +3 -0
- data/lib/flapjack/gateways/web/views/entity.html.erb +3 -0
- data/lib/flapjack/notifier.rb +4 -2
- data/lib/flapjack/pikelet.rb +5 -3
- data/lib/flapjack/version.rb +1 -1
- data/spec/lib/flapjack/data/contact_spec.rb +2 -2
- data/spec/lib/flapjack/data/entity_check_spec.rb +5 -1
- data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +88 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4e8b5d1bee24a164e37f5db62f177d02cb470cb
|
4
|
+
data.tar.gz: f7e916ff508251675628c89ff70a31a030ee31b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
2
2
|
|
3
3
|
[](https://travis-ci.org/flapjack/flapjack)
|
4
4
|
|
data/Dockerfile
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
FROM ubuntu:
|
1
|
+
FROM stackbrew/ubuntu:trusty
|
2
2
|
|
3
|
-
RUN
|
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-
|
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
|
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
|
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
|
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.
|
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
|
-
#
|
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
|
-
|
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 [
|
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
|
-
##
|
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
|
-
#
|
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
|
+
|
data/lib/flapjack/cli/flapper.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
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']
|
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']
|
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']
|
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']
|
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
|
data/lib/flapjack/cli/server.rb
CHANGED
@@ -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']
|
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']
|
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
|
-
|
516
|
-
|
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
|
306
|
-
entity_pattern = $2 ? $2.
|
307
|
-
entity_name
|
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.
|
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.
|
384
|
-
comment = $2 ? $2.
|
385
|
-
duration_str = $3 ? $3.
|
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.
|
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.
|
458
|
-
entity_pattern = $2.
|
459
|
-
comment = $3 ? $3.
|
460
|
-
duration_str = $4 ? $4.
|
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.
|
509
|
-
entity_pattern = $2 ? $2.
|
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(.+)_(
|
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 -%>
|
@@ -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'
|
342
|
-
'sms'
|
343
|
-
'
|
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;
|
data/lib/flapjack/notifier.rb
CHANGED
@@ -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)
|
data/lib/flapjack/pikelet.rb
CHANGED
@@ -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'
|
160
|
-
'sms'
|
161
|
-
'
|
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],
|
data/lib/flapjack/version.rb
CHANGED
@@ -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.
|
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-
|
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
|